18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PCI Bus Services, see include/linux/pci.h for further explanation.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
68c2ecf20Sopenharmony_ci * David Mosberger-Tang
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/acpi.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/delay.h>
148c2ecf20Sopenharmony_ci#include <linux/dmi.h>
158c2ecf20Sopenharmony_ci#include <linux/init.h>
168c2ecf20Sopenharmony_ci#include <linux/msi.h>
178c2ecf20Sopenharmony_ci#include <linux/of.h>
188c2ecf20Sopenharmony_ci#include <linux/pci.h>
198c2ecf20Sopenharmony_ci#include <linux/pm.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci#include <linux/module.h>
228c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
238c2ecf20Sopenharmony_ci#include <linux/string.h>
248c2ecf20Sopenharmony_ci#include <linux/log2.h>
258c2ecf20Sopenharmony_ci#include <linux/logic_pio.h>
268c2ecf20Sopenharmony_ci#include <linux/pm_wakeup.h>
278c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
288c2ecf20Sopenharmony_ci#include <linux/device.h>
298c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
308c2ecf20Sopenharmony_ci#include <linux/pci_hotplug.h>
318c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
328c2ecf20Sopenharmony_ci#include <asm/dma.h>
338c2ecf20Sopenharmony_ci#include <linux/aer.h>
348c2ecf20Sopenharmony_ci#include "pci.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ciDEFINE_MUTEX(pci_slot_mutex);
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ciconst char *pci_power_names[] = {
398c2ecf20Sopenharmony_ci	"error", "D0", "D1", "D2", "D3hot", "D3cold", "unknown",
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_power_names);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ciint isa_dma_bridge_buggy;
448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(isa_dma_bridge_buggy);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ciint pci_pci_problems;
478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_pci_problems);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciunsigned int pci_pm_d3hot_delay;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic void pci_pme_list_scan(struct work_struct *work);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic LIST_HEAD(pci_pme_list);
548c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(pci_pme_list_mutex);
558c2ecf20Sopenharmony_cistatic DECLARE_DELAYED_WORK(pci_pme_work, pci_pme_list_scan);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistruct pci_pme_device {
588c2ecf20Sopenharmony_ci	struct list_head list;
598c2ecf20Sopenharmony_ci	struct pci_dev *dev;
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#define PME_TIMEOUT 1000 /* How long between PME checks */
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic void pci_dev_d3_sleep(struct pci_dev *dev)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	unsigned int delay = dev->d3hot_delay;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if (delay < pci_pm_d3hot_delay)
698c2ecf20Sopenharmony_ci		delay = pci_pm_d3hot_delay;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	if (delay)
728c2ecf20Sopenharmony_ci		msleep(delay);
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_DOMAINS
768c2ecf20Sopenharmony_ciint pci_domains_supported = 1;
778c2ecf20Sopenharmony_ci#endif
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci#define DEFAULT_CARDBUS_IO_SIZE		(256)
808c2ecf20Sopenharmony_ci#define DEFAULT_CARDBUS_MEM_SIZE	(64*1024*1024)
818c2ecf20Sopenharmony_ci/* pci=cbmemsize=nnM,cbiosize=nn can override this */
828c2ecf20Sopenharmony_ciunsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE;
838c2ecf20Sopenharmony_ciunsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#define DEFAULT_HOTPLUG_IO_SIZE		(256)
868c2ecf20Sopenharmony_ci#define DEFAULT_HOTPLUG_MMIO_SIZE	(2*1024*1024)
878c2ecf20Sopenharmony_ci#define DEFAULT_HOTPLUG_MMIO_PREF_SIZE	(2*1024*1024)
888c2ecf20Sopenharmony_ci/* hpiosize=nn can override this */
898c2ecf20Sopenharmony_ciunsigned long pci_hotplug_io_size  = DEFAULT_HOTPLUG_IO_SIZE;
908c2ecf20Sopenharmony_ci/*
918c2ecf20Sopenharmony_ci * pci=hpmmiosize=nnM overrides non-prefetchable MMIO size,
928c2ecf20Sopenharmony_ci * pci=hpmmioprefsize=nnM overrides prefetchable MMIO size;
938c2ecf20Sopenharmony_ci * pci=hpmemsize=nnM overrides both
948c2ecf20Sopenharmony_ci */
958c2ecf20Sopenharmony_ciunsigned long pci_hotplug_mmio_size = DEFAULT_HOTPLUG_MMIO_SIZE;
968c2ecf20Sopenharmony_ciunsigned long pci_hotplug_mmio_pref_size = DEFAULT_HOTPLUG_MMIO_PREF_SIZE;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci#define DEFAULT_HOTPLUG_BUS_SIZE	1
998c2ecf20Sopenharmony_ciunsigned long pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/* PCIe MPS/MRRS strategy; can be overridden by kernel command-line param */
1038c2ecf20Sopenharmony_ci#ifdef CONFIG_PCIE_BUS_TUNE_OFF
1048c2ecf20Sopenharmony_cienum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF;
1058c2ecf20Sopenharmony_ci#elif defined CONFIG_PCIE_BUS_SAFE
1068c2ecf20Sopenharmony_cienum pcie_bus_config_types pcie_bus_config = PCIE_BUS_SAFE;
1078c2ecf20Sopenharmony_ci#elif defined CONFIG_PCIE_BUS_PERFORMANCE
1088c2ecf20Sopenharmony_cienum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PERFORMANCE;
1098c2ecf20Sopenharmony_ci#elif defined CONFIG_PCIE_BUS_PEER2PEER
1108c2ecf20Sopenharmony_cienum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PEER2PEER;
1118c2ecf20Sopenharmony_ci#else
1128c2ecf20Sopenharmony_cienum pcie_bus_config_types pcie_bus_config = PCIE_BUS_DEFAULT;
1138c2ecf20Sopenharmony_ci#endif
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci/*
1168c2ecf20Sopenharmony_ci * The default CLS is used if arch didn't set CLS explicitly and not
1178c2ecf20Sopenharmony_ci * all pci devices agree on the same value.  Arch can override either
1188c2ecf20Sopenharmony_ci * the dfl or actual value as it sees fit.  Don't forget this is
1198c2ecf20Sopenharmony_ci * measured in 32-bit words, not bytes.
1208c2ecf20Sopenharmony_ci */
1218c2ecf20Sopenharmony_ciu8 pci_dfl_cache_line_size = L1_CACHE_BYTES >> 2;
1228c2ecf20Sopenharmony_ciu8 pci_cache_line_size;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci/*
1258c2ecf20Sopenharmony_ci * If we set up a device for bus mastering, we need to check the latency
1268c2ecf20Sopenharmony_ci * timer as certain BIOSes forget to set it properly.
1278c2ecf20Sopenharmony_ci */
1288c2ecf20Sopenharmony_ciunsigned int pcibios_max_latency = 255;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci/* If set, the PCIe ARI capability will not be used. */
1318c2ecf20Sopenharmony_cistatic bool pcie_ari_disabled;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/* If set, the PCIe ATS capability will not be used. */
1348c2ecf20Sopenharmony_cistatic bool pcie_ats_disabled;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci/* If set, the PCI config space of each device is printed during boot. */
1378c2ecf20Sopenharmony_cibool pci_early_dump;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cibool pci_ats_disabled(void)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	return pcie_ats_disabled;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_ats_disabled);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/* Disable bridge_d3 for all PCIe ports */
1468c2ecf20Sopenharmony_cistatic bool pci_bridge_d3_disable;
1478c2ecf20Sopenharmony_ci/* Force bridge_d3 for all PCIe ports */
1488c2ecf20Sopenharmony_cistatic bool pci_bridge_d3_force;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic int __init pcie_port_pm_setup(char *str)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	if (!strcmp(str, "off"))
1538c2ecf20Sopenharmony_ci		pci_bridge_d3_disable = true;
1548c2ecf20Sopenharmony_ci	else if (!strcmp(str, "force"))
1558c2ecf20Sopenharmony_ci		pci_bridge_d3_force = true;
1568c2ecf20Sopenharmony_ci	return 1;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci__setup("pcie_port_pm=", pcie_port_pm_setup);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/**
1618c2ecf20Sopenharmony_ci * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
1628c2ecf20Sopenharmony_ci * @bus: pointer to PCI bus structure to search
1638c2ecf20Sopenharmony_ci *
1648c2ecf20Sopenharmony_ci * Given a PCI bus, returns the highest PCI bus number present in the set
1658c2ecf20Sopenharmony_ci * including the given PCI bus and its list of child PCI buses.
1668c2ecf20Sopenharmony_ci */
1678c2ecf20Sopenharmony_ciunsigned char pci_bus_max_busnr(struct pci_bus *bus)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	struct pci_bus *tmp;
1708c2ecf20Sopenharmony_ci	unsigned char max, n;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	max = bus->busn_res.end;
1738c2ecf20Sopenharmony_ci	list_for_each_entry(tmp, &bus->children, node) {
1748c2ecf20Sopenharmony_ci		n = pci_bus_max_busnr(tmp);
1758c2ecf20Sopenharmony_ci		if (n > max)
1768c2ecf20Sopenharmony_ci			max = n;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci	return max;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_bus_max_busnr);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci/**
1838c2ecf20Sopenharmony_ci * pci_status_get_and_clear_errors - return and clear error bits in PCI_STATUS
1848c2ecf20Sopenharmony_ci * @pdev: the PCI device
1858c2ecf20Sopenharmony_ci *
1868c2ecf20Sopenharmony_ci * Returns error bits set in PCI_STATUS and clears them.
1878c2ecf20Sopenharmony_ci */
1888c2ecf20Sopenharmony_ciint pci_status_get_and_clear_errors(struct pci_dev *pdev)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	u16 status;
1918c2ecf20Sopenharmony_ci	int ret;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	ret = pci_read_config_word(pdev, PCI_STATUS, &status);
1948c2ecf20Sopenharmony_ci	if (ret != PCIBIOS_SUCCESSFUL)
1958c2ecf20Sopenharmony_ci		return -EIO;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	status &= PCI_STATUS_ERROR_BITS;
1988c2ecf20Sopenharmony_ci	if (status)
1998c2ecf20Sopenharmony_ci		pci_write_config_word(pdev, PCI_STATUS, status);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	return status;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_status_get_and_clear_errors);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci#ifdef CONFIG_HAS_IOMEM
2068c2ecf20Sopenharmony_civoid __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct resource *res = &pdev->resource[bar];
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	/*
2118c2ecf20Sopenharmony_ci	 * Make sure the BAR is actually a memory resource, not an IO resource
2128c2ecf20Sopenharmony_ci	 */
2138c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_UNSET || !(res->flags & IORESOURCE_MEM)) {
2148c2ecf20Sopenharmony_ci		pci_warn(pdev, "can't ioremap BAR %d: %pR\n", bar, res);
2158c2ecf20Sopenharmony_ci		return NULL;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci	return ioremap(res->start, resource_size(res));
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_ioremap_bar);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_civoid __iomem *pci_ioremap_wc_bar(struct pci_dev *pdev, int bar)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	/*
2248c2ecf20Sopenharmony_ci	 * Make sure the BAR is actually a memory resource, not an IO resource
2258c2ecf20Sopenharmony_ci	 */
2268c2ecf20Sopenharmony_ci	if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
2278c2ecf20Sopenharmony_ci		WARN_ON(1);
2288c2ecf20Sopenharmony_ci		return NULL;
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci	return ioremap_wc(pci_resource_start(pdev, bar),
2318c2ecf20Sopenharmony_ci			  pci_resource_len(pdev, bar));
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_ioremap_wc_bar);
2348c2ecf20Sopenharmony_ci#endif
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci/**
2378c2ecf20Sopenharmony_ci * pci_dev_str_match_path - test if a path string matches a device
2388c2ecf20Sopenharmony_ci * @dev: the PCI device to test
2398c2ecf20Sopenharmony_ci * @path: string to match the device against
2408c2ecf20Sopenharmony_ci * @endptr: pointer to the string after the match
2418c2ecf20Sopenharmony_ci *
2428c2ecf20Sopenharmony_ci * Test if a string (typically from a kernel parameter) formatted as a
2438c2ecf20Sopenharmony_ci * path of device/function addresses matches a PCI device. The string must
2448c2ecf20Sopenharmony_ci * be of the form:
2458c2ecf20Sopenharmony_ci *
2468c2ecf20Sopenharmony_ci *   [<domain>:]<bus>:<device>.<func>[/<device>.<func>]*
2478c2ecf20Sopenharmony_ci *
2488c2ecf20Sopenharmony_ci * A path for a device can be obtained using 'lspci -t'.  Using a path
2498c2ecf20Sopenharmony_ci * is more robust against bus renumbering than using only a single bus,
2508c2ecf20Sopenharmony_ci * device and function address.
2518c2ecf20Sopenharmony_ci *
2528c2ecf20Sopenharmony_ci * Returns 1 if the string matches the device, 0 if it does not and
2538c2ecf20Sopenharmony_ci * a negative error code if it fails to parse the string.
2548c2ecf20Sopenharmony_ci */
2558c2ecf20Sopenharmony_cistatic int pci_dev_str_match_path(struct pci_dev *dev, const char *path,
2568c2ecf20Sopenharmony_ci				  const char **endptr)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	int ret;
2598c2ecf20Sopenharmony_ci	int seg, bus, slot, func;
2608c2ecf20Sopenharmony_ci	char *wpath, *p;
2618c2ecf20Sopenharmony_ci	char end;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	*endptr = strchrnul(path, ';');
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	wpath = kmemdup_nul(path, *endptr - path, GFP_ATOMIC);
2668c2ecf20Sopenharmony_ci	if (!wpath)
2678c2ecf20Sopenharmony_ci		return -ENOMEM;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	while (1) {
2708c2ecf20Sopenharmony_ci		p = strrchr(wpath, '/');
2718c2ecf20Sopenharmony_ci		if (!p)
2728c2ecf20Sopenharmony_ci			break;
2738c2ecf20Sopenharmony_ci		ret = sscanf(p, "/%x.%x%c", &slot, &func, &end);
2748c2ecf20Sopenharmony_ci		if (ret != 2) {
2758c2ecf20Sopenharmony_ci			ret = -EINVAL;
2768c2ecf20Sopenharmony_ci			goto free_and_exit;
2778c2ecf20Sopenharmony_ci		}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci		if (dev->devfn != PCI_DEVFN(slot, func)) {
2808c2ecf20Sopenharmony_ci			ret = 0;
2818c2ecf20Sopenharmony_ci			goto free_and_exit;
2828c2ecf20Sopenharmony_ci		}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci		/*
2858c2ecf20Sopenharmony_ci		 * Note: we don't need to get a reference to the upstream
2868c2ecf20Sopenharmony_ci		 * bridge because we hold a reference to the top level
2878c2ecf20Sopenharmony_ci		 * device which should hold a reference to the bridge,
2888c2ecf20Sopenharmony_ci		 * and so on.
2898c2ecf20Sopenharmony_ci		 */
2908c2ecf20Sopenharmony_ci		dev = pci_upstream_bridge(dev);
2918c2ecf20Sopenharmony_ci		if (!dev) {
2928c2ecf20Sopenharmony_ci			ret = 0;
2938c2ecf20Sopenharmony_ci			goto free_and_exit;
2948c2ecf20Sopenharmony_ci		}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci		*p = 0;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	ret = sscanf(wpath, "%x:%x:%x.%x%c", &seg, &bus, &slot,
3008c2ecf20Sopenharmony_ci		     &func, &end);
3018c2ecf20Sopenharmony_ci	if (ret != 4) {
3028c2ecf20Sopenharmony_ci		seg = 0;
3038c2ecf20Sopenharmony_ci		ret = sscanf(wpath, "%x:%x.%x%c", &bus, &slot, &func, &end);
3048c2ecf20Sopenharmony_ci		if (ret != 3) {
3058c2ecf20Sopenharmony_ci			ret = -EINVAL;
3068c2ecf20Sopenharmony_ci			goto free_and_exit;
3078c2ecf20Sopenharmony_ci		}
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	ret = (seg == pci_domain_nr(dev->bus) &&
3118c2ecf20Sopenharmony_ci	       bus == dev->bus->number &&
3128c2ecf20Sopenharmony_ci	       dev->devfn == PCI_DEVFN(slot, func));
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cifree_and_exit:
3158c2ecf20Sopenharmony_ci	kfree(wpath);
3168c2ecf20Sopenharmony_ci	return ret;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci/**
3208c2ecf20Sopenharmony_ci * pci_dev_str_match - test if a string matches a device
3218c2ecf20Sopenharmony_ci * @dev: the PCI device to test
3228c2ecf20Sopenharmony_ci * @p: string to match the device against
3238c2ecf20Sopenharmony_ci * @endptr: pointer to the string after the match
3248c2ecf20Sopenharmony_ci *
3258c2ecf20Sopenharmony_ci * Test if a string (typically from a kernel parameter) matches a specified
3268c2ecf20Sopenharmony_ci * PCI device. The string may be of one of the following formats:
3278c2ecf20Sopenharmony_ci *
3288c2ecf20Sopenharmony_ci *   [<domain>:]<bus>:<device>.<func>[/<device>.<func>]*
3298c2ecf20Sopenharmony_ci *   pci:<vendor>:<device>[:<subvendor>:<subdevice>]
3308c2ecf20Sopenharmony_ci *
3318c2ecf20Sopenharmony_ci * The first format specifies a PCI bus/device/function address which
3328c2ecf20Sopenharmony_ci * may change if new hardware is inserted, if motherboard firmware changes,
3338c2ecf20Sopenharmony_ci * or due to changes caused in kernel parameters. If the domain is
3348c2ecf20Sopenharmony_ci * left unspecified, it is taken to be 0.  In order to be robust against
3358c2ecf20Sopenharmony_ci * bus renumbering issues, a path of PCI device/function numbers may be used
3368c2ecf20Sopenharmony_ci * to address the specific device.  The path for a device can be determined
3378c2ecf20Sopenharmony_ci * through the use of 'lspci -t'.
3388c2ecf20Sopenharmony_ci *
3398c2ecf20Sopenharmony_ci * The second format matches devices using IDs in the configuration
3408c2ecf20Sopenharmony_ci * space which may match multiple devices in the system. A value of 0
3418c2ecf20Sopenharmony_ci * for any field will match all devices. (Note: this differs from
3428c2ecf20Sopenharmony_ci * in-kernel code that uses PCI_ANY_ID which is ~0; this is for
3438c2ecf20Sopenharmony_ci * legacy reasons and convenience so users don't have to specify
3448c2ecf20Sopenharmony_ci * FFFFFFFFs on the command line.)
3458c2ecf20Sopenharmony_ci *
3468c2ecf20Sopenharmony_ci * Returns 1 if the string matches the device, 0 if it does not and
3478c2ecf20Sopenharmony_ci * a negative error code if the string cannot be parsed.
3488c2ecf20Sopenharmony_ci */
3498c2ecf20Sopenharmony_cistatic int pci_dev_str_match(struct pci_dev *dev, const char *p,
3508c2ecf20Sopenharmony_ci			     const char **endptr)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	int ret;
3538c2ecf20Sopenharmony_ci	int count;
3548c2ecf20Sopenharmony_ci	unsigned short vendor, device, subsystem_vendor, subsystem_device;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (strncmp(p, "pci:", 4) == 0) {
3578c2ecf20Sopenharmony_ci		/* PCI vendor/device (subvendor/subdevice) IDs are specified */
3588c2ecf20Sopenharmony_ci		p += 4;
3598c2ecf20Sopenharmony_ci		ret = sscanf(p, "%hx:%hx:%hx:%hx%n", &vendor, &device,
3608c2ecf20Sopenharmony_ci			     &subsystem_vendor, &subsystem_device, &count);
3618c2ecf20Sopenharmony_ci		if (ret != 4) {
3628c2ecf20Sopenharmony_ci			ret = sscanf(p, "%hx:%hx%n", &vendor, &device, &count);
3638c2ecf20Sopenharmony_ci			if (ret != 2)
3648c2ecf20Sopenharmony_ci				return -EINVAL;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci			subsystem_vendor = 0;
3678c2ecf20Sopenharmony_ci			subsystem_device = 0;
3688c2ecf20Sopenharmony_ci		}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci		p += count;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci		if ((!vendor || vendor == dev->vendor) &&
3738c2ecf20Sopenharmony_ci		    (!device || device == dev->device) &&
3748c2ecf20Sopenharmony_ci		    (!subsystem_vendor ||
3758c2ecf20Sopenharmony_ci			    subsystem_vendor == dev->subsystem_vendor) &&
3768c2ecf20Sopenharmony_ci		    (!subsystem_device ||
3778c2ecf20Sopenharmony_ci			    subsystem_device == dev->subsystem_device))
3788c2ecf20Sopenharmony_ci			goto found;
3798c2ecf20Sopenharmony_ci	} else {
3808c2ecf20Sopenharmony_ci		/*
3818c2ecf20Sopenharmony_ci		 * PCI Bus, Device, Function IDs are specified
3828c2ecf20Sopenharmony_ci		 * (optionally, may include a path of devfns following it)
3838c2ecf20Sopenharmony_ci		 */
3848c2ecf20Sopenharmony_ci		ret = pci_dev_str_match_path(dev, p, &p);
3858c2ecf20Sopenharmony_ci		if (ret < 0)
3868c2ecf20Sopenharmony_ci			return ret;
3878c2ecf20Sopenharmony_ci		else if (ret)
3888c2ecf20Sopenharmony_ci			goto found;
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	*endptr = p;
3928c2ecf20Sopenharmony_ci	return 0;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cifound:
3958c2ecf20Sopenharmony_ci	*endptr = p;
3968c2ecf20Sopenharmony_ci	return 1;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
4008c2ecf20Sopenharmony_ci				   u8 pos, int cap, int *ttl)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	u8 id;
4038c2ecf20Sopenharmony_ci	u16 ent;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	pci_bus_read_config_byte(bus, devfn, pos, &pos);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	while ((*ttl)--) {
4088c2ecf20Sopenharmony_ci		if (pos < 0x40)
4098c2ecf20Sopenharmony_ci			break;
4108c2ecf20Sopenharmony_ci		pos &= ~3;
4118c2ecf20Sopenharmony_ci		pci_bus_read_config_word(bus, devfn, pos, &ent);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci		id = ent & 0xff;
4148c2ecf20Sopenharmony_ci		if (id == 0xff)
4158c2ecf20Sopenharmony_ci			break;
4168c2ecf20Sopenharmony_ci		if (id == cap)
4178c2ecf20Sopenharmony_ci			return pos;
4188c2ecf20Sopenharmony_ci		pos = (ent >> 8);
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci	return 0;
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_cistatic int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
4248c2ecf20Sopenharmony_ci			       u8 pos, int cap)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	int ttl = PCI_FIND_CAP_TTL;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl);
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ciint pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	return __pci_find_next_cap(dev->bus, dev->devfn,
4348c2ecf20Sopenharmony_ci				   pos + PCI_CAP_LIST_NEXT, cap);
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_find_next_capability);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic int __pci_bus_find_cap_start(struct pci_bus *bus,
4398c2ecf20Sopenharmony_ci				    unsigned int devfn, u8 hdr_type)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	u16 status;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);
4448c2ecf20Sopenharmony_ci	if (!(status & PCI_STATUS_CAP_LIST))
4458c2ecf20Sopenharmony_ci		return 0;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	switch (hdr_type) {
4488c2ecf20Sopenharmony_ci	case PCI_HEADER_TYPE_NORMAL:
4498c2ecf20Sopenharmony_ci	case PCI_HEADER_TYPE_BRIDGE:
4508c2ecf20Sopenharmony_ci		return PCI_CAPABILITY_LIST;
4518c2ecf20Sopenharmony_ci	case PCI_HEADER_TYPE_CARDBUS:
4528c2ecf20Sopenharmony_ci		return PCI_CB_CAPABILITY_LIST;
4538c2ecf20Sopenharmony_ci	}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	return 0;
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci/**
4598c2ecf20Sopenharmony_ci * pci_find_capability - query for devices' capabilities
4608c2ecf20Sopenharmony_ci * @dev: PCI device to query
4618c2ecf20Sopenharmony_ci * @cap: capability code
4628c2ecf20Sopenharmony_ci *
4638c2ecf20Sopenharmony_ci * Tell if a device supports a given PCI capability.
4648c2ecf20Sopenharmony_ci * Returns the address of the requested capability structure within the
4658c2ecf20Sopenharmony_ci * device's PCI configuration space or 0 in case the device does not
4668c2ecf20Sopenharmony_ci * support it.  Possible values for @cap include:
4678c2ecf20Sopenharmony_ci *
4688c2ecf20Sopenharmony_ci *  %PCI_CAP_ID_PM           Power Management
4698c2ecf20Sopenharmony_ci *  %PCI_CAP_ID_AGP          Accelerated Graphics Port
4708c2ecf20Sopenharmony_ci *  %PCI_CAP_ID_VPD          Vital Product Data
4718c2ecf20Sopenharmony_ci *  %PCI_CAP_ID_SLOTID       Slot Identification
4728c2ecf20Sopenharmony_ci *  %PCI_CAP_ID_MSI          Message Signalled Interrupts
4738c2ecf20Sopenharmony_ci *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap
4748c2ecf20Sopenharmony_ci *  %PCI_CAP_ID_PCIX         PCI-X
4758c2ecf20Sopenharmony_ci *  %PCI_CAP_ID_EXP          PCI Express
4768c2ecf20Sopenharmony_ci */
4778c2ecf20Sopenharmony_ciint pci_find_capability(struct pci_dev *dev, int cap)
4788c2ecf20Sopenharmony_ci{
4798c2ecf20Sopenharmony_ci	int pos;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
4828c2ecf20Sopenharmony_ci	if (pos)
4838c2ecf20Sopenharmony_ci		pos = __pci_find_next_cap(dev->bus, dev->devfn, pos, cap);
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	return pos;
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_find_capability);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci/**
4908c2ecf20Sopenharmony_ci * pci_bus_find_capability - query for devices' capabilities
4918c2ecf20Sopenharmony_ci * @bus: the PCI bus to query
4928c2ecf20Sopenharmony_ci * @devfn: PCI device to query
4938c2ecf20Sopenharmony_ci * @cap: capability code
4948c2ecf20Sopenharmony_ci *
4958c2ecf20Sopenharmony_ci * Like pci_find_capability() but works for PCI devices that do not have a
4968c2ecf20Sopenharmony_ci * pci_dev structure set up yet.
4978c2ecf20Sopenharmony_ci *
4988c2ecf20Sopenharmony_ci * Returns the address of the requested capability structure within the
4998c2ecf20Sopenharmony_ci * device's PCI configuration space or 0 in case the device does not
5008c2ecf20Sopenharmony_ci * support it.
5018c2ecf20Sopenharmony_ci */
5028c2ecf20Sopenharmony_ciint pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
5038c2ecf20Sopenharmony_ci{
5048c2ecf20Sopenharmony_ci	int pos;
5058c2ecf20Sopenharmony_ci	u8 hdr_type;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	pos = __pci_bus_find_cap_start(bus, devfn, hdr_type & 0x7f);
5108c2ecf20Sopenharmony_ci	if (pos)
5118c2ecf20Sopenharmony_ci		pos = __pci_find_next_cap(bus, devfn, pos, cap);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	return pos;
5148c2ecf20Sopenharmony_ci}
5158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_bus_find_capability);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci/**
5188c2ecf20Sopenharmony_ci * pci_find_next_ext_capability - Find an extended capability
5198c2ecf20Sopenharmony_ci * @dev: PCI device to query
5208c2ecf20Sopenharmony_ci * @start: address at which to start looking (0 to start at beginning of list)
5218c2ecf20Sopenharmony_ci * @cap: capability code
5228c2ecf20Sopenharmony_ci *
5238c2ecf20Sopenharmony_ci * Returns the address of the next matching extended capability structure
5248c2ecf20Sopenharmony_ci * within the device's PCI configuration space or 0 if the device does
5258c2ecf20Sopenharmony_ci * not support it.  Some capabilities can occur several times, e.g., the
5268c2ecf20Sopenharmony_ci * vendor-specific capability, and this provides a way to find them all.
5278c2ecf20Sopenharmony_ci */
5288c2ecf20Sopenharmony_ciint pci_find_next_ext_capability(struct pci_dev *dev, int start, int cap)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	u32 header;
5318c2ecf20Sopenharmony_ci	int ttl;
5328c2ecf20Sopenharmony_ci	int pos = PCI_CFG_SPACE_SIZE;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	/* minimum 8 bytes per capability */
5358c2ecf20Sopenharmony_ci	ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	if (dev->cfg_size <= PCI_CFG_SPACE_SIZE)
5388c2ecf20Sopenharmony_ci		return 0;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	if (start)
5418c2ecf20Sopenharmony_ci		pos = start;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
5448c2ecf20Sopenharmony_ci		return 0;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	/*
5478c2ecf20Sopenharmony_ci	 * If we have no capabilities, this is indicated by cap ID,
5488c2ecf20Sopenharmony_ci	 * cap version and next pointer all being 0.
5498c2ecf20Sopenharmony_ci	 */
5508c2ecf20Sopenharmony_ci	if (header == 0)
5518c2ecf20Sopenharmony_ci		return 0;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	while (ttl-- > 0) {
5548c2ecf20Sopenharmony_ci		if (PCI_EXT_CAP_ID(header) == cap && pos != start)
5558c2ecf20Sopenharmony_ci			return pos;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci		pos = PCI_EXT_CAP_NEXT(header);
5588c2ecf20Sopenharmony_ci		if (pos < PCI_CFG_SPACE_SIZE)
5598c2ecf20Sopenharmony_ci			break;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci		if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
5628c2ecf20Sopenharmony_ci			break;
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	return 0;
5668c2ecf20Sopenharmony_ci}
5678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_find_next_ext_capability);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci/**
5708c2ecf20Sopenharmony_ci * pci_find_ext_capability - Find an extended capability
5718c2ecf20Sopenharmony_ci * @dev: PCI device to query
5728c2ecf20Sopenharmony_ci * @cap: capability code
5738c2ecf20Sopenharmony_ci *
5748c2ecf20Sopenharmony_ci * Returns the address of the requested extended capability structure
5758c2ecf20Sopenharmony_ci * within the device's PCI configuration space or 0 if the device does
5768c2ecf20Sopenharmony_ci * not support it.  Possible values for @cap include:
5778c2ecf20Sopenharmony_ci *
5788c2ecf20Sopenharmony_ci *  %PCI_EXT_CAP_ID_ERR		Advanced Error Reporting
5798c2ecf20Sopenharmony_ci *  %PCI_EXT_CAP_ID_VC		Virtual Channel
5808c2ecf20Sopenharmony_ci *  %PCI_EXT_CAP_ID_DSN		Device Serial Number
5818c2ecf20Sopenharmony_ci *  %PCI_EXT_CAP_ID_PWR		Power Budgeting
5828c2ecf20Sopenharmony_ci */
5838c2ecf20Sopenharmony_ciint pci_find_ext_capability(struct pci_dev *dev, int cap)
5848c2ecf20Sopenharmony_ci{
5858c2ecf20Sopenharmony_ci	return pci_find_next_ext_capability(dev, 0, cap);
5868c2ecf20Sopenharmony_ci}
5878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_find_ext_capability);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci/**
5908c2ecf20Sopenharmony_ci * pci_get_dsn - Read and return the 8-byte Device Serial Number
5918c2ecf20Sopenharmony_ci * @dev: PCI device to query
5928c2ecf20Sopenharmony_ci *
5938c2ecf20Sopenharmony_ci * Looks up the PCI_EXT_CAP_ID_DSN and reads the 8 bytes of the Device Serial
5948c2ecf20Sopenharmony_ci * Number.
5958c2ecf20Sopenharmony_ci *
5968c2ecf20Sopenharmony_ci * Returns the DSN, or zero if the capability does not exist.
5978c2ecf20Sopenharmony_ci */
5988c2ecf20Sopenharmony_ciu64 pci_get_dsn(struct pci_dev *dev)
5998c2ecf20Sopenharmony_ci{
6008c2ecf20Sopenharmony_ci	u32 dword;
6018c2ecf20Sopenharmony_ci	u64 dsn;
6028c2ecf20Sopenharmony_ci	int pos;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DSN);
6058c2ecf20Sopenharmony_ci	if (!pos)
6068c2ecf20Sopenharmony_ci		return 0;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	/*
6098c2ecf20Sopenharmony_ci	 * The Device Serial Number is two dwords offset 4 bytes from the
6108c2ecf20Sopenharmony_ci	 * capability position. The specification says that the first dword is
6118c2ecf20Sopenharmony_ci	 * the lower half, and the second dword is the upper half.
6128c2ecf20Sopenharmony_ci	 */
6138c2ecf20Sopenharmony_ci	pos += 4;
6148c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, pos, &dword);
6158c2ecf20Sopenharmony_ci	dsn = (u64)dword;
6168c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, pos + 4, &dword);
6178c2ecf20Sopenharmony_ci	dsn |= ((u64)dword) << 32;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	return dsn;
6208c2ecf20Sopenharmony_ci}
6218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_get_dsn);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_cistatic int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap)
6248c2ecf20Sopenharmony_ci{
6258c2ecf20Sopenharmony_ci	int rc, ttl = PCI_FIND_CAP_TTL;
6268c2ecf20Sopenharmony_ci	u8 cap, mask;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	if (ht_cap == HT_CAPTYPE_SLAVE || ht_cap == HT_CAPTYPE_HOST)
6298c2ecf20Sopenharmony_ci		mask = HT_3BIT_CAP_MASK;
6308c2ecf20Sopenharmony_ci	else
6318c2ecf20Sopenharmony_ci		mask = HT_5BIT_CAP_MASK;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, pos,
6348c2ecf20Sopenharmony_ci				      PCI_CAP_ID_HT, &ttl);
6358c2ecf20Sopenharmony_ci	while (pos) {
6368c2ecf20Sopenharmony_ci		rc = pci_read_config_byte(dev, pos + 3, &cap);
6378c2ecf20Sopenharmony_ci		if (rc != PCIBIOS_SUCCESSFUL)
6388c2ecf20Sopenharmony_ci			return 0;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci		if ((cap & mask) == ht_cap)
6418c2ecf20Sopenharmony_ci			return pos;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci		pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn,
6448c2ecf20Sopenharmony_ci					      pos + PCI_CAP_LIST_NEXT,
6458c2ecf20Sopenharmony_ci					      PCI_CAP_ID_HT, &ttl);
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	return 0;
6498c2ecf20Sopenharmony_ci}
6508c2ecf20Sopenharmony_ci/**
6518c2ecf20Sopenharmony_ci * pci_find_next_ht_capability - query a device's Hypertransport capabilities
6528c2ecf20Sopenharmony_ci * @dev: PCI device to query
6538c2ecf20Sopenharmony_ci * @pos: Position from which to continue searching
6548c2ecf20Sopenharmony_ci * @ht_cap: Hypertransport capability code
6558c2ecf20Sopenharmony_ci *
6568c2ecf20Sopenharmony_ci * To be used in conjunction with pci_find_ht_capability() to search for
6578c2ecf20Sopenharmony_ci * all capabilities matching @ht_cap. @pos should always be a value returned
6588c2ecf20Sopenharmony_ci * from pci_find_ht_capability().
6598c2ecf20Sopenharmony_ci *
6608c2ecf20Sopenharmony_ci * NB. To be 100% safe against broken PCI devices, the caller should take
6618c2ecf20Sopenharmony_ci * steps to avoid an infinite loop.
6628c2ecf20Sopenharmony_ci */
6638c2ecf20Sopenharmony_ciint pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	return __pci_find_next_ht_cap(dev, pos + PCI_CAP_LIST_NEXT, ht_cap);
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_find_next_ht_capability);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci/**
6708c2ecf20Sopenharmony_ci * pci_find_ht_capability - query a device's Hypertransport capabilities
6718c2ecf20Sopenharmony_ci * @dev: PCI device to query
6728c2ecf20Sopenharmony_ci * @ht_cap: Hypertransport capability code
6738c2ecf20Sopenharmony_ci *
6748c2ecf20Sopenharmony_ci * Tell if a device supports a given Hypertransport capability.
6758c2ecf20Sopenharmony_ci * Returns an address within the device's PCI configuration space
6768c2ecf20Sopenharmony_ci * or 0 in case the device does not support the request capability.
6778c2ecf20Sopenharmony_ci * The address points to the PCI capability, of type PCI_CAP_ID_HT,
6788c2ecf20Sopenharmony_ci * which has a Hypertransport capability matching @ht_cap.
6798c2ecf20Sopenharmony_ci */
6808c2ecf20Sopenharmony_ciint pci_find_ht_capability(struct pci_dev *dev, int ht_cap)
6818c2ecf20Sopenharmony_ci{
6828c2ecf20Sopenharmony_ci	int pos;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
6858c2ecf20Sopenharmony_ci	if (pos)
6868c2ecf20Sopenharmony_ci		pos = __pci_find_next_ht_cap(dev, pos, ht_cap);
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	return pos;
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_find_ht_capability);
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci/**
6938c2ecf20Sopenharmony_ci * pci_find_parent_resource - return resource region of parent bus of given
6948c2ecf20Sopenharmony_ci *			      region
6958c2ecf20Sopenharmony_ci * @dev: PCI device structure contains resources to be searched
6968c2ecf20Sopenharmony_ci * @res: child resource record for which parent is sought
6978c2ecf20Sopenharmony_ci *
6988c2ecf20Sopenharmony_ci * For given resource region of given device, return the resource region of
6998c2ecf20Sopenharmony_ci * parent bus the given region is contained in.
7008c2ecf20Sopenharmony_ci */
7018c2ecf20Sopenharmony_cistruct resource *pci_find_parent_resource(const struct pci_dev *dev,
7028c2ecf20Sopenharmony_ci					  struct resource *res)
7038c2ecf20Sopenharmony_ci{
7048c2ecf20Sopenharmony_ci	const struct pci_bus *bus = dev->bus;
7058c2ecf20Sopenharmony_ci	struct resource *r;
7068c2ecf20Sopenharmony_ci	int i;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	pci_bus_for_each_resource(bus, r, i) {
7098c2ecf20Sopenharmony_ci		if (!r)
7108c2ecf20Sopenharmony_ci			continue;
7118c2ecf20Sopenharmony_ci		if (resource_contains(r, res)) {
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci			/*
7148c2ecf20Sopenharmony_ci			 * If the window is prefetchable but the BAR is
7158c2ecf20Sopenharmony_ci			 * not, the allocator made a mistake.
7168c2ecf20Sopenharmony_ci			 */
7178c2ecf20Sopenharmony_ci			if (r->flags & IORESOURCE_PREFETCH &&
7188c2ecf20Sopenharmony_ci			    !(res->flags & IORESOURCE_PREFETCH))
7198c2ecf20Sopenharmony_ci				return NULL;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci			/*
7228c2ecf20Sopenharmony_ci			 * If we're below a transparent bridge, there may
7238c2ecf20Sopenharmony_ci			 * be both a positively-decoded aperture and a
7248c2ecf20Sopenharmony_ci			 * subtractively-decoded region that contain the BAR.
7258c2ecf20Sopenharmony_ci			 * We want the positively-decoded one, so this depends
7268c2ecf20Sopenharmony_ci			 * on pci_bus_for_each_resource() giving us those
7278c2ecf20Sopenharmony_ci			 * first.
7288c2ecf20Sopenharmony_ci			 */
7298c2ecf20Sopenharmony_ci			return r;
7308c2ecf20Sopenharmony_ci		}
7318c2ecf20Sopenharmony_ci	}
7328c2ecf20Sopenharmony_ci	return NULL;
7338c2ecf20Sopenharmony_ci}
7348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_find_parent_resource);
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci/**
7378c2ecf20Sopenharmony_ci * pci_find_resource - Return matching PCI device resource
7388c2ecf20Sopenharmony_ci * @dev: PCI device to query
7398c2ecf20Sopenharmony_ci * @res: Resource to look for
7408c2ecf20Sopenharmony_ci *
7418c2ecf20Sopenharmony_ci * Goes over standard PCI resources (BARs) and checks if the given resource
7428c2ecf20Sopenharmony_ci * is partially or fully contained in any of them. In that case the
7438c2ecf20Sopenharmony_ci * matching resource is returned, %NULL otherwise.
7448c2ecf20Sopenharmony_ci */
7458c2ecf20Sopenharmony_cistruct resource *pci_find_resource(struct pci_dev *dev, struct resource *res)
7468c2ecf20Sopenharmony_ci{
7478c2ecf20Sopenharmony_ci	int i;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
7508c2ecf20Sopenharmony_ci		struct resource *r = &dev->resource[i];
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci		if (r->start && resource_contains(r, res))
7538c2ecf20Sopenharmony_ci			return r;
7548c2ecf20Sopenharmony_ci	}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	return NULL;
7578c2ecf20Sopenharmony_ci}
7588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_find_resource);
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci/**
7618c2ecf20Sopenharmony_ci * pci_wait_for_pending - wait for @mask bit(s) to clear in status word @pos
7628c2ecf20Sopenharmony_ci * @dev: the PCI device to operate on
7638c2ecf20Sopenharmony_ci * @pos: config space offset of status word
7648c2ecf20Sopenharmony_ci * @mask: mask of bit(s) to care about in status word
7658c2ecf20Sopenharmony_ci *
7668c2ecf20Sopenharmony_ci * Return 1 when mask bit(s) in status word clear, 0 otherwise.
7678c2ecf20Sopenharmony_ci */
7688c2ecf20Sopenharmony_ciint pci_wait_for_pending(struct pci_dev *dev, int pos, u16 mask)
7698c2ecf20Sopenharmony_ci{
7708c2ecf20Sopenharmony_ci	int i;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	/* Wait for Transaction Pending bit clean */
7738c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
7748c2ecf20Sopenharmony_ci		u16 status;
7758c2ecf20Sopenharmony_ci		if (i)
7768c2ecf20Sopenharmony_ci			msleep((1 << (i - 1)) * 100);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci		pci_read_config_word(dev, pos, &status);
7798c2ecf20Sopenharmony_ci		if (!(status & mask))
7808c2ecf20Sopenharmony_ci			return 1;
7818c2ecf20Sopenharmony_ci	}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	return 0;
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_cistatic int pci_acs_enable;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci/**
7898c2ecf20Sopenharmony_ci * pci_request_acs - ask for ACS to be enabled if supported
7908c2ecf20Sopenharmony_ci */
7918c2ecf20Sopenharmony_civoid pci_request_acs(void)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	pci_acs_enable = 1;
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic const char *disable_acs_redir_param;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci/**
7998c2ecf20Sopenharmony_ci * pci_disable_acs_redir - disable ACS redirect capabilities
8008c2ecf20Sopenharmony_ci * @dev: the PCI device
8018c2ecf20Sopenharmony_ci *
8028c2ecf20Sopenharmony_ci * For only devices specified in the disable_acs_redir parameter.
8038c2ecf20Sopenharmony_ci */
8048c2ecf20Sopenharmony_cistatic void pci_disable_acs_redir(struct pci_dev *dev)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	int ret = 0;
8078c2ecf20Sopenharmony_ci	const char *p;
8088c2ecf20Sopenharmony_ci	int pos;
8098c2ecf20Sopenharmony_ci	u16 ctrl;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	if (!disable_acs_redir_param)
8128c2ecf20Sopenharmony_ci		return;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	p = disable_acs_redir_param;
8158c2ecf20Sopenharmony_ci	while (*p) {
8168c2ecf20Sopenharmony_ci		ret = pci_dev_str_match(dev, p, &p);
8178c2ecf20Sopenharmony_ci		if (ret < 0) {
8188c2ecf20Sopenharmony_ci			pr_info_once("PCI: Can't parse disable_acs_redir parameter: %s\n",
8198c2ecf20Sopenharmony_ci				     disable_acs_redir_param);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci			break;
8228c2ecf20Sopenharmony_ci		} else if (ret == 1) {
8238c2ecf20Sopenharmony_ci			/* Found a match */
8248c2ecf20Sopenharmony_ci			break;
8258c2ecf20Sopenharmony_ci		}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci		if (*p != ';' && *p != ',') {
8288c2ecf20Sopenharmony_ci			/* End of param or invalid format */
8298c2ecf20Sopenharmony_ci			break;
8308c2ecf20Sopenharmony_ci		}
8318c2ecf20Sopenharmony_ci		p++;
8328c2ecf20Sopenharmony_ci	}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	if (ret != 1)
8358c2ecf20Sopenharmony_ci		return;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	if (!pci_dev_specific_disable_acs_redir(dev))
8388c2ecf20Sopenharmony_ci		return;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	pos = dev->acs_cap;
8418c2ecf20Sopenharmony_ci	if (!pos) {
8428c2ecf20Sopenharmony_ci		pci_warn(dev, "cannot disable ACS redirect for this hardware as it does not have ACS capabilities\n");
8438c2ecf20Sopenharmony_ci		return;
8448c2ecf20Sopenharmony_ci	}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	/* P2P Request & Completion Redirect */
8498c2ecf20Sopenharmony_ci	ctrl &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC);
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	pci_info(dev, "disabled ACS redirect\n");
8548c2ecf20Sopenharmony_ci}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci/**
8578c2ecf20Sopenharmony_ci * pci_std_enable_acs - enable ACS on devices using standard ACS capabilities
8588c2ecf20Sopenharmony_ci * @dev: the PCI device
8598c2ecf20Sopenharmony_ci */
8608c2ecf20Sopenharmony_cistatic void pci_std_enable_acs(struct pci_dev *dev)
8618c2ecf20Sopenharmony_ci{
8628c2ecf20Sopenharmony_ci	int pos;
8638c2ecf20Sopenharmony_ci	u16 cap;
8648c2ecf20Sopenharmony_ci	u16 ctrl;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	pos = dev->acs_cap;
8678c2ecf20Sopenharmony_ci	if (!pos)
8688c2ecf20Sopenharmony_ci		return;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
8718c2ecf20Sopenharmony_ci	pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	/* Source Validation */
8748c2ecf20Sopenharmony_ci	ctrl |= (cap & PCI_ACS_SV);
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	/* P2P Request Redirect */
8778c2ecf20Sopenharmony_ci	ctrl |= (cap & PCI_ACS_RR);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	/* P2P Completion Redirect */
8808c2ecf20Sopenharmony_ci	ctrl |= (cap & PCI_ACS_CR);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	/* Upstream Forwarding */
8838c2ecf20Sopenharmony_ci	ctrl |= (cap & PCI_ACS_UF);
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	/* Enable Translation Blocking for external devices */
8868c2ecf20Sopenharmony_ci	if (dev->external_facing || dev->untrusted)
8878c2ecf20Sopenharmony_ci		ctrl |= (cap & PCI_ACS_TB);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci/**
8938c2ecf20Sopenharmony_ci * pci_enable_acs - enable ACS if hardware support it
8948c2ecf20Sopenharmony_ci * @dev: the PCI device
8958c2ecf20Sopenharmony_ci */
8968c2ecf20Sopenharmony_cistatic void pci_enable_acs(struct pci_dev *dev)
8978c2ecf20Sopenharmony_ci{
8988c2ecf20Sopenharmony_ci	if (!pci_acs_enable)
8998c2ecf20Sopenharmony_ci		goto disable_acs_redir;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	if (!pci_dev_specific_enable_acs(dev))
9028c2ecf20Sopenharmony_ci		goto disable_acs_redir;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	pci_std_enable_acs(dev);
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_cidisable_acs_redir:
9078c2ecf20Sopenharmony_ci	/*
9088c2ecf20Sopenharmony_ci	 * Note: pci_disable_acs_redir() must be called even if ACS was not
9098c2ecf20Sopenharmony_ci	 * enabled by the kernel because it may have been enabled by
9108c2ecf20Sopenharmony_ci	 * platform firmware.  So if we are told to disable it, we should
9118c2ecf20Sopenharmony_ci	 * always disable it after setting the kernel's default
9128c2ecf20Sopenharmony_ci	 * preferences.
9138c2ecf20Sopenharmony_ci	 */
9148c2ecf20Sopenharmony_ci	pci_disable_acs_redir(dev);
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci/**
9188c2ecf20Sopenharmony_ci * pci_restore_bars - restore a device's BAR values (e.g. after wake-up)
9198c2ecf20Sopenharmony_ci * @dev: PCI device to have its BARs restored
9208c2ecf20Sopenharmony_ci *
9218c2ecf20Sopenharmony_ci * Restore the BAR values for a given device, so as to make it
9228c2ecf20Sopenharmony_ci * accessible by its driver.
9238c2ecf20Sopenharmony_ci */
9248c2ecf20Sopenharmony_cistatic void pci_restore_bars(struct pci_dev *dev)
9258c2ecf20Sopenharmony_ci{
9268c2ecf20Sopenharmony_ci	int i;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_BRIDGE_RESOURCES; i++)
9298c2ecf20Sopenharmony_ci		pci_update_resource(dev, i);
9308c2ecf20Sopenharmony_ci}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_cistatic const struct pci_platform_pm_ops *pci_platform_pm;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ciint pci_set_platform_pm(const struct pci_platform_pm_ops *ops)
9358c2ecf20Sopenharmony_ci{
9368c2ecf20Sopenharmony_ci	if (!ops->is_manageable || !ops->set_state  || !ops->get_state ||
9378c2ecf20Sopenharmony_ci	    !ops->choose_state  || !ops->set_wakeup || !ops->need_resume)
9388c2ecf20Sopenharmony_ci		return -EINVAL;
9398c2ecf20Sopenharmony_ci	pci_platform_pm = ops;
9408c2ecf20Sopenharmony_ci	return 0;
9418c2ecf20Sopenharmony_ci}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_cistatic inline bool platform_pci_power_manageable(struct pci_dev *dev)
9448c2ecf20Sopenharmony_ci{
9458c2ecf20Sopenharmony_ci	return pci_platform_pm ? pci_platform_pm->is_manageable(dev) : false;
9468c2ecf20Sopenharmony_ci}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_cistatic inline int platform_pci_set_power_state(struct pci_dev *dev,
9498c2ecf20Sopenharmony_ci					       pci_power_t t)
9508c2ecf20Sopenharmony_ci{
9518c2ecf20Sopenharmony_ci	return pci_platform_pm ? pci_platform_pm->set_state(dev, t) : -ENOSYS;
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_cistatic inline pci_power_t platform_pci_get_power_state(struct pci_dev *dev)
9558c2ecf20Sopenharmony_ci{
9568c2ecf20Sopenharmony_ci	return pci_platform_pm ? pci_platform_pm->get_state(dev) : PCI_UNKNOWN;
9578c2ecf20Sopenharmony_ci}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_cistatic inline void platform_pci_refresh_power_state(struct pci_dev *dev)
9608c2ecf20Sopenharmony_ci{
9618c2ecf20Sopenharmony_ci	if (pci_platform_pm && pci_platform_pm->refresh_state)
9628c2ecf20Sopenharmony_ci		pci_platform_pm->refresh_state(dev);
9638c2ecf20Sopenharmony_ci}
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_cistatic inline pci_power_t platform_pci_choose_state(struct pci_dev *dev)
9668c2ecf20Sopenharmony_ci{
9678c2ecf20Sopenharmony_ci	return pci_platform_pm ?
9688c2ecf20Sopenharmony_ci			pci_platform_pm->choose_state(dev) : PCI_POWER_ERROR;
9698c2ecf20Sopenharmony_ci}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_cistatic inline int platform_pci_set_wakeup(struct pci_dev *dev, bool enable)
9728c2ecf20Sopenharmony_ci{
9738c2ecf20Sopenharmony_ci	return pci_platform_pm ?
9748c2ecf20Sopenharmony_ci			pci_platform_pm->set_wakeup(dev, enable) : -ENODEV;
9758c2ecf20Sopenharmony_ci}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_cistatic inline bool platform_pci_need_resume(struct pci_dev *dev)
9788c2ecf20Sopenharmony_ci{
9798c2ecf20Sopenharmony_ci	return pci_platform_pm ? pci_platform_pm->need_resume(dev) : false;
9808c2ecf20Sopenharmony_ci}
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_cistatic inline bool platform_pci_bridge_d3(struct pci_dev *dev)
9838c2ecf20Sopenharmony_ci{
9848c2ecf20Sopenharmony_ci	if (pci_platform_pm && pci_platform_pm->bridge_d3)
9858c2ecf20Sopenharmony_ci		return pci_platform_pm->bridge_d3(dev);
9868c2ecf20Sopenharmony_ci	return false;
9878c2ecf20Sopenharmony_ci}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci/**
9908c2ecf20Sopenharmony_ci * pci_raw_set_power_state - Use PCI PM registers to set the power state of
9918c2ecf20Sopenharmony_ci *			     given PCI device
9928c2ecf20Sopenharmony_ci * @dev: PCI device to handle.
9938c2ecf20Sopenharmony_ci * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
9948c2ecf20Sopenharmony_ci *
9958c2ecf20Sopenharmony_ci * RETURN VALUE:
9968c2ecf20Sopenharmony_ci * -EINVAL if the requested state is invalid.
9978c2ecf20Sopenharmony_ci * -EIO if device does not support PCI PM or its PM capabilities register has a
9988c2ecf20Sopenharmony_ci * wrong version, or device doesn't support the requested state.
9998c2ecf20Sopenharmony_ci * 0 if device already is in the requested state.
10008c2ecf20Sopenharmony_ci * 0 if device's power state has been successfully changed.
10018c2ecf20Sopenharmony_ci */
10028c2ecf20Sopenharmony_cistatic int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
10038c2ecf20Sopenharmony_ci{
10048c2ecf20Sopenharmony_ci	u16 pmcsr;
10058c2ecf20Sopenharmony_ci	bool need_restore = false;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	/* Check if we're already there */
10088c2ecf20Sopenharmony_ci	if (dev->current_state == state)
10098c2ecf20Sopenharmony_ci		return 0;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	if (!dev->pm_cap)
10128c2ecf20Sopenharmony_ci		return -EIO;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	if (state < PCI_D0 || state > PCI_D3hot)
10158c2ecf20Sopenharmony_ci		return -EINVAL;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	/*
10188c2ecf20Sopenharmony_ci	 * Validate transition: We can enter D0 from any state, but if
10198c2ecf20Sopenharmony_ci	 * we're already in a low-power state, we can only go deeper.  E.g.,
10208c2ecf20Sopenharmony_ci	 * we can go from D1 to D3, but we can't go directly from D3 to D1;
10218c2ecf20Sopenharmony_ci	 * we'd have to go from D3 to D0, then to D1.
10228c2ecf20Sopenharmony_ci	 */
10238c2ecf20Sopenharmony_ci	if (state != PCI_D0 && dev->current_state <= PCI_D3cold
10248c2ecf20Sopenharmony_ci	    && dev->current_state > state) {
10258c2ecf20Sopenharmony_ci		pci_err(dev, "invalid power transition (from %s to %s)\n",
10268c2ecf20Sopenharmony_ci			pci_power_name(dev->current_state),
10278c2ecf20Sopenharmony_ci			pci_power_name(state));
10288c2ecf20Sopenharmony_ci		return -EINVAL;
10298c2ecf20Sopenharmony_ci	}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	/* Check if this device supports the desired state */
10328c2ecf20Sopenharmony_ci	if ((state == PCI_D1 && !dev->d1_support)
10338c2ecf20Sopenharmony_ci	   || (state == PCI_D2 && !dev->d2_support))
10348c2ecf20Sopenharmony_ci		return -EIO;
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
10378c2ecf20Sopenharmony_ci	if (pmcsr == (u16) ~0) {
10388c2ecf20Sopenharmony_ci		pci_err(dev, "can't change power state from %s to %s (config space inaccessible)\n",
10398c2ecf20Sopenharmony_ci			pci_power_name(dev->current_state),
10408c2ecf20Sopenharmony_ci			pci_power_name(state));
10418c2ecf20Sopenharmony_ci		return -EIO;
10428c2ecf20Sopenharmony_ci	}
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	/*
10458c2ecf20Sopenharmony_ci	 * If we're (effectively) in D3, force entire word to 0.
10468c2ecf20Sopenharmony_ci	 * This doesn't affect PME_Status, disables PME_En, and
10478c2ecf20Sopenharmony_ci	 * sets PowerState to 0.
10488c2ecf20Sopenharmony_ci	 */
10498c2ecf20Sopenharmony_ci	switch (dev->current_state) {
10508c2ecf20Sopenharmony_ci	case PCI_D0:
10518c2ecf20Sopenharmony_ci	case PCI_D1:
10528c2ecf20Sopenharmony_ci	case PCI_D2:
10538c2ecf20Sopenharmony_ci		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
10548c2ecf20Sopenharmony_ci		pmcsr |= state;
10558c2ecf20Sopenharmony_ci		break;
10568c2ecf20Sopenharmony_ci	case PCI_D3hot:
10578c2ecf20Sopenharmony_ci	case PCI_D3cold:
10588c2ecf20Sopenharmony_ci	case PCI_UNKNOWN: /* Boot-up */
10598c2ecf20Sopenharmony_ci		if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot
10608c2ecf20Sopenharmony_ci		 && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET))
10618c2ecf20Sopenharmony_ci			need_restore = true;
10628c2ecf20Sopenharmony_ci		fallthrough;	/* force to D0 */
10638c2ecf20Sopenharmony_ci	default:
10648c2ecf20Sopenharmony_ci		pmcsr = 0;
10658c2ecf20Sopenharmony_ci		break;
10668c2ecf20Sopenharmony_ci	}
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	/* Enter specified state */
10698c2ecf20Sopenharmony_ci	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	/*
10728c2ecf20Sopenharmony_ci	 * Mandatory power management transition delays; see PCI PM 1.1
10738c2ecf20Sopenharmony_ci	 * 5.6.1 table 18
10748c2ecf20Sopenharmony_ci	 */
10758c2ecf20Sopenharmony_ci	if (state == PCI_D3hot || dev->current_state == PCI_D3hot)
10768c2ecf20Sopenharmony_ci		pci_dev_d3_sleep(dev);
10778c2ecf20Sopenharmony_ci	else if (state == PCI_D2 || dev->current_state == PCI_D2)
10788c2ecf20Sopenharmony_ci		udelay(PCI_PM_D2_DELAY);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
10818c2ecf20Sopenharmony_ci	dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
10828c2ecf20Sopenharmony_ci	if (dev->current_state != state)
10838c2ecf20Sopenharmony_ci		pci_info_ratelimited(dev, "refused to change power state from %s to %s\n",
10848c2ecf20Sopenharmony_ci			 pci_power_name(dev->current_state),
10858c2ecf20Sopenharmony_ci			 pci_power_name(state));
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	/*
10888c2ecf20Sopenharmony_ci	 * According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT
10898c2ecf20Sopenharmony_ci	 * INTERFACE SPECIFICATION, REV. 1.2", a device transitioning
10908c2ecf20Sopenharmony_ci	 * from D3hot to D0 _may_ perform an internal reset, thereby
10918c2ecf20Sopenharmony_ci	 * going to "D0 Uninitialized" rather than "D0 Initialized".
10928c2ecf20Sopenharmony_ci	 * For example, at least some versions of the 3c905B and the
10938c2ecf20Sopenharmony_ci	 * 3c556B exhibit this behaviour.
10948c2ecf20Sopenharmony_ci	 *
10958c2ecf20Sopenharmony_ci	 * At least some laptop BIOSen (e.g. the Thinkpad T21) leave
10968c2ecf20Sopenharmony_ci	 * devices in a D3hot state at boot.  Consequently, we need to
10978c2ecf20Sopenharmony_ci	 * restore at least the BARs so that the device will be
10988c2ecf20Sopenharmony_ci	 * accessible to its driver.
10998c2ecf20Sopenharmony_ci	 */
11008c2ecf20Sopenharmony_ci	if (need_restore)
11018c2ecf20Sopenharmony_ci		pci_restore_bars(dev);
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	if (dev->bus->self)
11048c2ecf20Sopenharmony_ci		pcie_aspm_pm_state_change(dev->bus->self);
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	return 0;
11078c2ecf20Sopenharmony_ci}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci/**
11108c2ecf20Sopenharmony_ci * pci_update_current_state - Read power state of given device and cache it
11118c2ecf20Sopenharmony_ci * @dev: PCI device to handle.
11128c2ecf20Sopenharmony_ci * @state: State to cache in case the device doesn't have the PM capability
11138c2ecf20Sopenharmony_ci *
11148c2ecf20Sopenharmony_ci * The power state is read from the PMCSR register, which however is
11158c2ecf20Sopenharmony_ci * inaccessible in D3cold.  The platform firmware is therefore queried first
11168c2ecf20Sopenharmony_ci * to detect accessibility of the register.  In case the platform firmware
11178c2ecf20Sopenharmony_ci * reports an incorrect state or the device isn't power manageable by the
11188c2ecf20Sopenharmony_ci * platform at all, we try to detect D3cold by testing accessibility of the
11198c2ecf20Sopenharmony_ci * vendor ID in config space.
11208c2ecf20Sopenharmony_ci */
11218c2ecf20Sopenharmony_civoid pci_update_current_state(struct pci_dev *dev, pci_power_t state)
11228c2ecf20Sopenharmony_ci{
11238c2ecf20Sopenharmony_ci	if (platform_pci_get_power_state(dev) == PCI_D3cold ||
11248c2ecf20Sopenharmony_ci	    !pci_device_is_present(dev)) {
11258c2ecf20Sopenharmony_ci		dev->current_state = PCI_D3cold;
11268c2ecf20Sopenharmony_ci	} else if (dev->pm_cap) {
11278c2ecf20Sopenharmony_ci		u16 pmcsr;
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci		pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
11308c2ecf20Sopenharmony_ci		dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
11318c2ecf20Sopenharmony_ci	} else {
11328c2ecf20Sopenharmony_ci		dev->current_state = state;
11338c2ecf20Sopenharmony_ci	}
11348c2ecf20Sopenharmony_ci}
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci/**
11378c2ecf20Sopenharmony_ci * pci_refresh_power_state - Refresh the given device's power state data
11388c2ecf20Sopenharmony_ci * @dev: Target PCI device.
11398c2ecf20Sopenharmony_ci *
11408c2ecf20Sopenharmony_ci * Ask the platform to refresh the devices power state information and invoke
11418c2ecf20Sopenharmony_ci * pci_update_current_state() to update its current PCI power state.
11428c2ecf20Sopenharmony_ci */
11438c2ecf20Sopenharmony_civoid pci_refresh_power_state(struct pci_dev *dev)
11448c2ecf20Sopenharmony_ci{
11458c2ecf20Sopenharmony_ci	if (platform_pci_power_manageable(dev))
11468c2ecf20Sopenharmony_ci		platform_pci_refresh_power_state(dev);
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	pci_update_current_state(dev, dev->current_state);
11498c2ecf20Sopenharmony_ci}
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci/**
11528c2ecf20Sopenharmony_ci * pci_platform_power_transition - Use platform to change device power state
11538c2ecf20Sopenharmony_ci * @dev: PCI device to handle.
11548c2ecf20Sopenharmony_ci * @state: State to put the device into.
11558c2ecf20Sopenharmony_ci */
11568c2ecf20Sopenharmony_ciint pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
11578c2ecf20Sopenharmony_ci{
11588c2ecf20Sopenharmony_ci	int error;
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	if (platform_pci_power_manageable(dev)) {
11618c2ecf20Sopenharmony_ci		error = platform_pci_set_power_state(dev, state);
11628c2ecf20Sopenharmony_ci		if (!error)
11638c2ecf20Sopenharmony_ci			pci_update_current_state(dev, state);
11648c2ecf20Sopenharmony_ci	} else
11658c2ecf20Sopenharmony_ci		error = -ENODEV;
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	if (error && !dev->pm_cap) /* Fall back to PCI_D0 */
11688c2ecf20Sopenharmony_ci		dev->current_state = PCI_D0;
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	return error;
11718c2ecf20Sopenharmony_ci}
11728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_platform_power_transition);
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci/**
11758c2ecf20Sopenharmony_ci * pci_wakeup - Wake up a PCI device
11768c2ecf20Sopenharmony_ci * @pci_dev: Device to handle.
11778c2ecf20Sopenharmony_ci * @ign: ignored parameter
11788c2ecf20Sopenharmony_ci */
11798c2ecf20Sopenharmony_cistatic int pci_wakeup(struct pci_dev *pci_dev, void *ign)
11808c2ecf20Sopenharmony_ci{
11818c2ecf20Sopenharmony_ci	pci_wakeup_event(pci_dev);
11828c2ecf20Sopenharmony_ci	pm_request_resume(&pci_dev->dev);
11838c2ecf20Sopenharmony_ci	return 0;
11848c2ecf20Sopenharmony_ci}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci/**
11878c2ecf20Sopenharmony_ci * pci_wakeup_bus - Walk given bus and wake up devices on it
11888c2ecf20Sopenharmony_ci * @bus: Top bus of the subtree to walk.
11898c2ecf20Sopenharmony_ci */
11908c2ecf20Sopenharmony_civoid pci_wakeup_bus(struct pci_bus *bus)
11918c2ecf20Sopenharmony_ci{
11928c2ecf20Sopenharmony_ci	if (bus)
11938c2ecf20Sopenharmony_ci		pci_walk_bus(bus, pci_wakeup, NULL);
11948c2ecf20Sopenharmony_ci}
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_cistatic int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
11978c2ecf20Sopenharmony_ci{
11988c2ecf20Sopenharmony_ci	int delay = 1;
11998c2ecf20Sopenharmony_ci	u32 id;
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	/*
12028c2ecf20Sopenharmony_ci	 * After reset, the device should not silently discard config
12038c2ecf20Sopenharmony_ci	 * requests, but it may still indicate that it needs more time by
12048c2ecf20Sopenharmony_ci	 * responding to them with CRS completions.  The Root Port will
12058c2ecf20Sopenharmony_ci	 * generally synthesize ~0 data to complete the read (except when
12068c2ecf20Sopenharmony_ci	 * CRS SV is enabled and the read was for the Vendor ID; in that
12078c2ecf20Sopenharmony_ci	 * case it synthesizes 0x0001 data).
12088c2ecf20Sopenharmony_ci	 *
12098c2ecf20Sopenharmony_ci	 * Wait for the device to return a non-CRS completion.  Read the
12108c2ecf20Sopenharmony_ci	 * Command register instead of Vendor ID so we don't have to
12118c2ecf20Sopenharmony_ci	 * contend with the CRS SV value.
12128c2ecf20Sopenharmony_ci	 */
12138c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, PCI_COMMAND, &id);
12148c2ecf20Sopenharmony_ci	while (id == ~0) {
12158c2ecf20Sopenharmony_ci		if (delay > timeout) {
12168c2ecf20Sopenharmony_ci			pci_warn(dev, "not ready %dms after %s; giving up\n",
12178c2ecf20Sopenharmony_ci				 delay - 1, reset_type);
12188c2ecf20Sopenharmony_ci			return -ENOTTY;
12198c2ecf20Sopenharmony_ci		}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci		if (delay > PCI_RESET_WAIT)
12228c2ecf20Sopenharmony_ci			pci_info(dev, "not ready %dms after %s; waiting\n",
12238c2ecf20Sopenharmony_ci				 delay - 1, reset_type);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci		msleep(delay);
12268c2ecf20Sopenharmony_ci		delay *= 2;
12278c2ecf20Sopenharmony_ci		pci_read_config_dword(dev, PCI_COMMAND, &id);
12288c2ecf20Sopenharmony_ci	}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	if (delay > PCI_RESET_WAIT)
12318c2ecf20Sopenharmony_ci		pci_info(dev, "ready %dms after %s\n", delay - 1,
12328c2ecf20Sopenharmony_ci			 reset_type);
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	return 0;
12358c2ecf20Sopenharmony_ci}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci/**
12388c2ecf20Sopenharmony_ci * pci_power_up - Put the given device into D0
12398c2ecf20Sopenharmony_ci * @dev: PCI device to power up
12408c2ecf20Sopenharmony_ci */
12418c2ecf20Sopenharmony_ciint pci_power_up(struct pci_dev *dev)
12428c2ecf20Sopenharmony_ci{
12438c2ecf20Sopenharmony_ci	pci_platform_power_transition(dev, PCI_D0);
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	/*
12468c2ecf20Sopenharmony_ci	 * Mandatory power management transition delays are handled in
12478c2ecf20Sopenharmony_ci	 * pci_pm_resume_noirq() and pci_pm_runtime_resume() of the
12488c2ecf20Sopenharmony_ci	 * corresponding bridge.
12498c2ecf20Sopenharmony_ci	 */
12508c2ecf20Sopenharmony_ci	if (dev->runtime_d3cold) {
12518c2ecf20Sopenharmony_ci		/*
12528c2ecf20Sopenharmony_ci		 * When powering on a bridge from D3cold, the whole hierarchy
12538c2ecf20Sopenharmony_ci		 * may be powered on into D0uninitialized state, resume them to
12548c2ecf20Sopenharmony_ci		 * give them a chance to suspend again
12558c2ecf20Sopenharmony_ci		 */
12568c2ecf20Sopenharmony_ci		pci_wakeup_bus(dev->subordinate);
12578c2ecf20Sopenharmony_ci	}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	return pci_raw_set_power_state(dev, PCI_D0);
12608c2ecf20Sopenharmony_ci}
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci/**
12638c2ecf20Sopenharmony_ci * __pci_dev_set_current_state - Set current state of a PCI device
12648c2ecf20Sopenharmony_ci * @dev: Device to handle
12658c2ecf20Sopenharmony_ci * @data: pointer to state to be set
12668c2ecf20Sopenharmony_ci */
12678c2ecf20Sopenharmony_cistatic int __pci_dev_set_current_state(struct pci_dev *dev, void *data)
12688c2ecf20Sopenharmony_ci{
12698c2ecf20Sopenharmony_ci	pci_power_t state = *(pci_power_t *)data;
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	dev->current_state = state;
12728c2ecf20Sopenharmony_ci	return 0;
12738c2ecf20Sopenharmony_ci}
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci/**
12768c2ecf20Sopenharmony_ci * pci_bus_set_current_state - Walk given bus and set current state of devices
12778c2ecf20Sopenharmony_ci * @bus: Top bus of the subtree to walk.
12788c2ecf20Sopenharmony_ci * @state: state to be set
12798c2ecf20Sopenharmony_ci */
12808c2ecf20Sopenharmony_civoid pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
12818c2ecf20Sopenharmony_ci{
12828c2ecf20Sopenharmony_ci	if (bus)
12838c2ecf20Sopenharmony_ci		pci_walk_bus(bus, __pci_dev_set_current_state, &state);
12848c2ecf20Sopenharmony_ci}
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci/**
12878c2ecf20Sopenharmony_ci * pci_set_power_state - Set the power state of a PCI device
12888c2ecf20Sopenharmony_ci * @dev: PCI device to handle.
12898c2ecf20Sopenharmony_ci * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
12908c2ecf20Sopenharmony_ci *
12918c2ecf20Sopenharmony_ci * Transition a device to a new power state, using the platform firmware and/or
12928c2ecf20Sopenharmony_ci * the device's PCI PM registers.
12938c2ecf20Sopenharmony_ci *
12948c2ecf20Sopenharmony_ci * RETURN VALUE:
12958c2ecf20Sopenharmony_ci * -EINVAL if the requested state is invalid.
12968c2ecf20Sopenharmony_ci * -EIO if device does not support PCI PM or its PM capabilities register has a
12978c2ecf20Sopenharmony_ci * wrong version, or device doesn't support the requested state.
12988c2ecf20Sopenharmony_ci * 0 if the transition is to D1 or D2 but D1 and D2 are not supported.
12998c2ecf20Sopenharmony_ci * 0 if device already is in the requested state.
13008c2ecf20Sopenharmony_ci * 0 if the transition is to D3 but D3 is not supported.
13018c2ecf20Sopenharmony_ci * 0 if device's power state has been successfully changed.
13028c2ecf20Sopenharmony_ci */
13038c2ecf20Sopenharmony_ciint pci_set_power_state(struct pci_dev *dev, pci_power_t state)
13048c2ecf20Sopenharmony_ci{
13058c2ecf20Sopenharmony_ci	int error;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	/* Bound the state we're entering */
13088c2ecf20Sopenharmony_ci	if (state > PCI_D3cold)
13098c2ecf20Sopenharmony_ci		state = PCI_D3cold;
13108c2ecf20Sopenharmony_ci	else if (state < PCI_D0)
13118c2ecf20Sopenharmony_ci		state = PCI_D0;
13128c2ecf20Sopenharmony_ci	else if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci		/*
13158c2ecf20Sopenharmony_ci		 * If the device or the parent bridge do not support PCI
13168c2ecf20Sopenharmony_ci		 * PM, ignore the request if we're doing anything other
13178c2ecf20Sopenharmony_ci		 * than putting it into D0 (which would only happen on
13188c2ecf20Sopenharmony_ci		 * boot).
13198c2ecf20Sopenharmony_ci		 */
13208c2ecf20Sopenharmony_ci		return 0;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	/* Check if we're already there */
13238c2ecf20Sopenharmony_ci	if (dev->current_state == state)
13248c2ecf20Sopenharmony_ci		return 0;
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	if (state == PCI_D0)
13278c2ecf20Sopenharmony_ci		return pci_power_up(dev);
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	/*
13308c2ecf20Sopenharmony_ci	 * This device is quirked not to be put into D3, so don't put it in
13318c2ecf20Sopenharmony_ci	 * D3
13328c2ecf20Sopenharmony_ci	 */
13338c2ecf20Sopenharmony_ci	if (state >= PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3))
13348c2ecf20Sopenharmony_ci		return 0;
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	/*
13378c2ecf20Sopenharmony_ci	 * To put device in D3cold, we put device into D3hot in native
13388c2ecf20Sopenharmony_ci	 * way, then put device into D3cold with platform ops
13398c2ecf20Sopenharmony_ci	 */
13408c2ecf20Sopenharmony_ci	error = pci_raw_set_power_state(dev, state > PCI_D3hot ?
13418c2ecf20Sopenharmony_ci					PCI_D3hot : state);
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	if (pci_platform_power_transition(dev, state))
13448c2ecf20Sopenharmony_ci		return error;
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci	/* Powering off a bridge may power off the whole hierarchy */
13478c2ecf20Sopenharmony_ci	if (state == PCI_D3cold)
13488c2ecf20Sopenharmony_ci		pci_bus_set_current_state(dev->subordinate, PCI_D3cold);
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	return 0;
13518c2ecf20Sopenharmony_ci}
13528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_set_power_state);
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci/**
13558c2ecf20Sopenharmony_ci * pci_choose_state - Choose the power state of a PCI device
13568c2ecf20Sopenharmony_ci * @dev: PCI device to be suspended
13578c2ecf20Sopenharmony_ci * @state: target sleep state for the whole system. This is the value
13588c2ecf20Sopenharmony_ci *	   that is passed to suspend() function.
13598c2ecf20Sopenharmony_ci *
13608c2ecf20Sopenharmony_ci * Returns PCI power state suitable for given device and given system
13618c2ecf20Sopenharmony_ci * message.
13628c2ecf20Sopenharmony_ci */
13638c2ecf20Sopenharmony_cipci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
13648c2ecf20Sopenharmony_ci{
13658c2ecf20Sopenharmony_ci	pci_power_t ret;
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	if (!dev->pm_cap)
13688c2ecf20Sopenharmony_ci		return PCI_D0;
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	ret = platform_pci_choose_state(dev);
13718c2ecf20Sopenharmony_ci	if (ret != PCI_POWER_ERROR)
13728c2ecf20Sopenharmony_ci		return ret;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	switch (state.event) {
13758c2ecf20Sopenharmony_ci	case PM_EVENT_ON:
13768c2ecf20Sopenharmony_ci		return PCI_D0;
13778c2ecf20Sopenharmony_ci	case PM_EVENT_FREEZE:
13788c2ecf20Sopenharmony_ci	case PM_EVENT_PRETHAW:
13798c2ecf20Sopenharmony_ci		/* REVISIT both freeze and pre-thaw "should" use D0 */
13808c2ecf20Sopenharmony_ci	case PM_EVENT_SUSPEND:
13818c2ecf20Sopenharmony_ci	case PM_EVENT_HIBERNATE:
13828c2ecf20Sopenharmony_ci		return PCI_D3hot;
13838c2ecf20Sopenharmony_ci	default:
13848c2ecf20Sopenharmony_ci		pci_info(dev, "unrecognized suspend event %d\n",
13858c2ecf20Sopenharmony_ci			 state.event);
13868c2ecf20Sopenharmony_ci		BUG();
13878c2ecf20Sopenharmony_ci	}
13888c2ecf20Sopenharmony_ci	return PCI_D0;
13898c2ecf20Sopenharmony_ci}
13908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_choose_state);
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci#define PCI_EXP_SAVE_REGS	7
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_cistatic struct pci_cap_saved_state *_pci_find_saved_cap(struct pci_dev *pci_dev,
13958c2ecf20Sopenharmony_ci						       u16 cap, bool extended)
13968c2ecf20Sopenharmony_ci{
13978c2ecf20Sopenharmony_ci	struct pci_cap_saved_state *tmp;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	hlist_for_each_entry(tmp, &pci_dev->saved_cap_space, next) {
14008c2ecf20Sopenharmony_ci		if (tmp->cap.cap_extended == extended && tmp->cap.cap_nr == cap)
14018c2ecf20Sopenharmony_ci			return tmp;
14028c2ecf20Sopenharmony_ci	}
14038c2ecf20Sopenharmony_ci	return NULL;
14048c2ecf20Sopenharmony_ci}
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_cistruct pci_cap_saved_state *pci_find_saved_cap(struct pci_dev *dev, char cap)
14078c2ecf20Sopenharmony_ci{
14088c2ecf20Sopenharmony_ci	return _pci_find_saved_cap(dev, cap, false);
14098c2ecf20Sopenharmony_ci}
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_cistruct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev, u16 cap)
14128c2ecf20Sopenharmony_ci{
14138c2ecf20Sopenharmony_ci	return _pci_find_saved_cap(dev, cap, true);
14148c2ecf20Sopenharmony_ci}
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_cistatic int pci_save_pcie_state(struct pci_dev *dev)
14178c2ecf20Sopenharmony_ci{
14188c2ecf20Sopenharmony_ci	int i = 0;
14198c2ecf20Sopenharmony_ci	struct pci_cap_saved_state *save_state;
14208c2ecf20Sopenharmony_ci	u16 *cap;
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci	if (!pci_is_pcie(dev))
14238c2ecf20Sopenharmony_ci		return 0;
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
14268c2ecf20Sopenharmony_ci	if (!save_state) {
14278c2ecf20Sopenharmony_ci		pci_err(dev, "buffer not found in %s\n", __func__);
14288c2ecf20Sopenharmony_ci		return -ENOMEM;
14298c2ecf20Sopenharmony_ci	}
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	cap = (u16 *)&save_state->cap.data[0];
14328c2ecf20Sopenharmony_ci	pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &cap[i++]);
14338c2ecf20Sopenharmony_ci	pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &cap[i++]);
14348c2ecf20Sopenharmony_ci	pcie_capability_read_word(dev, PCI_EXP_SLTCTL, &cap[i++]);
14358c2ecf20Sopenharmony_ci	pcie_capability_read_word(dev, PCI_EXP_RTCTL,  &cap[i++]);
14368c2ecf20Sopenharmony_ci	pcie_capability_read_word(dev, PCI_EXP_DEVCTL2, &cap[i++]);
14378c2ecf20Sopenharmony_ci	pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &cap[i++]);
14388c2ecf20Sopenharmony_ci	pcie_capability_read_word(dev, PCI_EXP_SLTCTL2, &cap[i++]);
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	return 0;
14418c2ecf20Sopenharmony_ci}
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_cistatic void pci_restore_pcie_state(struct pci_dev *dev)
14448c2ecf20Sopenharmony_ci{
14458c2ecf20Sopenharmony_ci	int i = 0;
14468c2ecf20Sopenharmony_ci	struct pci_cap_saved_state *save_state;
14478c2ecf20Sopenharmony_ci	u16 *cap;
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
14508c2ecf20Sopenharmony_ci	if (!save_state)
14518c2ecf20Sopenharmony_ci		return;
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	cap = (u16 *)&save_state->cap.data[0];
14548c2ecf20Sopenharmony_ci	pcie_capability_write_word(dev, PCI_EXP_DEVCTL, cap[i++]);
14558c2ecf20Sopenharmony_ci	pcie_capability_write_word(dev, PCI_EXP_LNKCTL, cap[i++]);
14568c2ecf20Sopenharmony_ci	pcie_capability_write_word(dev, PCI_EXP_SLTCTL, cap[i++]);
14578c2ecf20Sopenharmony_ci	pcie_capability_write_word(dev, PCI_EXP_RTCTL, cap[i++]);
14588c2ecf20Sopenharmony_ci	pcie_capability_write_word(dev, PCI_EXP_DEVCTL2, cap[i++]);
14598c2ecf20Sopenharmony_ci	pcie_capability_write_word(dev, PCI_EXP_LNKCTL2, cap[i++]);
14608c2ecf20Sopenharmony_ci	pcie_capability_write_word(dev, PCI_EXP_SLTCTL2, cap[i++]);
14618c2ecf20Sopenharmony_ci}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_cistatic int pci_save_pcix_state(struct pci_dev *dev)
14648c2ecf20Sopenharmony_ci{
14658c2ecf20Sopenharmony_ci	int pos;
14668c2ecf20Sopenharmony_ci	struct pci_cap_saved_state *save_state;
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
14698c2ecf20Sopenharmony_ci	if (!pos)
14708c2ecf20Sopenharmony_ci		return 0;
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
14738c2ecf20Sopenharmony_ci	if (!save_state) {
14748c2ecf20Sopenharmony_ci		pci_err(dev, "buffer not found in %s\n", __func__);
14758c2ecf20Sopenharmony_ci		return -ENOMEM;
14768c2ecf20Sopenharmony_ci	}
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	pci_read_config_word(dev, pos + PCI_X_CMD,
14798c2ecf20Sopenharmony_ci			     (u16 *)save_state->cap.data);
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	return 0;
14828c2ecf20Sopenharmony_ci}
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_cistatic void pci_restore_pcix_state(struct pci_dev *dev)
14858c2ecf20Sopenharmony_ci{
14868c2ecf20Sopenharmony_ci	int i = 0, pos;
14878c2ecf20Sopenharmony_ci	struct pci_cap_saved_state *save_state;
14888c2ecf20Sopenharmony_ci	u16 *cap;
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
14918c2ecf20Sopenharmony_ci	pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
14928c2ecf20Sopenharmony_ci	if (!save_state || !pos)
14938c2ecf20Sopenharmony_ci		return;
14948c2ecf20Sopenharmony_ci	cap = (u16 *)&save_state->cap.data[0];
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	pci_write_config_word(dev, pos + PCI_X_CMD, cap[i++]);
14978c2ecf20Sopenharmony_ci}
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_cistatic void pci_save_ltr_state(struct pci_dev *dev)
15008c2ecf20Sopenharmony_ci{
15018c2ecf20Sopenharmony_ci	int ltr;
15028c2ecf20Sopenharmony_ci	struct pci_cap_saved_state *save_state;
15038c2ecf20Sopenharmony_ci	u16 *cap;
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	if (!pci_is_pcie(dev))
15068c2ecf20Sopenharmony_ci		return;
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
15098c2ecf20Sopenharmony_ci	if (!ltr)
15108c2ecf20Sopenharmony_ci		return;
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
15138c2ecf20Sopenharmony_ci	if (!save_state) {
15148c2ecf20Sopenharmony_ci		pci_err(dev, "no suspend buffer for LTR; ASPM issues possible after resume\n");
15158c2ecf20Sopenharmony_ci		return;
15168c2ecf20Sopenharmony_ci	}
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	cap = (u16 *)&save_state->cap.data[0];
15198c2ecf20Sopenharmony_ci	pci_read_config_word(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, cap++);
15208c2ecf20Sopenharmony_ci	pci_read_config_word(dev, ltr + PCI_LTR_MAX_NOSNOOP_LAT, cap++);
15218c2ecf20Sopenharmony_ci}
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_cistatic void pci_restore_ltr_state(struct pci_dev *dev)
15248c2ecf20Sopenharmony_ci{
15258c2ecf20Sopenharmony_ci	struct pci_cap_saved_state *save_state;
15268c2ecf20Sopenharmony_ci	int ltr;
15278c2ecf20Sopenharmony_ci	u16 *cap;
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
15308c2ecf20Sopenharmony_ci	ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
15318c2ecf20Sopenharmony_ci	if (!save_state || !ltr)
15328c2ecf20Sopenharmony_ci		return;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	cap = (u16 *)&save_state->cap.data[0];
15358c2ecf20Sopenharmony_ci	pci_write_config_word(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, *cap++);
15368c2ecf20Sopenharmony_ci	pci_write_config_word(dev, ltr + PCI_LTR_MAX_NOSNOOP_LAT, *cap++);
15378c2ecf20Sopenharmony_ci}
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci/**
15408c2ecf20Sopenharmony_ci * pci_save_state - save the PCI configuration space of a device before
15418c2ecf20Sopenharmony_ci *		    suspending
15428c2ecf20Sopenharmony_ci * @dev: PCI device that we're dealing with
15438c2ecf20Sopenharmony_ci */
15448c2ecf20Sopenharmony_ciint pci_save_state(struct pci_dev *dev)
15458c2ecf20Sopenharmony_ci{
15468c2ecf20Sopenharmony_ci	int i;
15478c2ecf20Sopenharmony_ci	/* XXX: 100% dword access ok here? */
15488c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++) {
15498c2ecf20Sopenharmony_ci		pci_read_config_dword(dev, i * 4, &dev->saved_config_space[i]);
15508c2ecf20Sopenharmony_ci		pci_dbg(dev, "saving config space at offset %#x (reading %#x)\n",
15518c2ecf20Sopenharmony_ci			i * 4, dev->saved_config_space[i]);
15528c2ecf20Sopenharmony_ci	}
15538c2ecf20Sopenharmony_ci	dev->state_saved = true;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	i = pci_save_pcie_state(dev);
15568c2ecf20Sopenharmony_ci	if (i != 0)
15578c2ecf20Sopenharmony_ci		return i;
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	i = pci_save_pcix_state(dev);
15608c2ecf20Sopenharmony_ci	if (i != 0)
15618c2ecf20Sopenharmony_ci		return i;
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	pci_save_ltr_state(dev);
15648c2ecf20Sopenharmony_ci	pci_save_dpc_state(dev);
15658c2ecf20Sopenharmony_ci	pci_save_aer_state(dev);
15668c2ecf20Sopenharmony_ci	return pci_save_vc_state(dev);
15678c2ecf20Sopenharmony_ci}
15688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_save_state);
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_cistatic void pci_restore_config_dword(struct pci_dev *pdev, int offset,
15718c2ecf20Sopenharmony_ci				     u32 saved_val, int retry, bool force)
15728c2ecf20Sopenharmony_ci{
15738c2ecf20Sopenharmony_ci	u32 val;
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, offset, &val);
15768c2ecf20Sopenharmony_ci	if (!force && val == saved_val)
15778c2ecf20Sopenharmony_ci		return;
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	for (;;) {
15808c2ecf20Sopenharmony_ci		pci_dbg(pdev, "restoring config space at offset %#x (was %#x, writing %#x)\n",
15818c2ecf20Sopenharmony_ci			offset, val, saved_val);
15828c2ecf20Sopenharmony_ci		pci_write_config_dword(pdev, offset, saved_val);
15838c2ecf20Sopenharmony_ci		if (retry-- <= 0)
15848c2ecf20Sopenharmony_ci			return;
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci		pci_read_config_dword(pdev, offset, &val);
15878c2ecf20Sopenharmony_ci		if (val == saved_val)
15888c2ecf20Sopenharmony_ci			return;
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci		mdelay(1);
15918c2ecf20Sopenharmony_ci	}
15928c2ecf20Sopenharmony_ci}
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_cistatic void pci_restore_config_space_range(struct pci_dev *pdev,
15958c2ecf20Sopenharmony_ci					   int start, int end, int retry,
15968c2ecf20Sopenharmony_ci					   bool force)
15978c2ecf20Sopenharmony_ci{
15988c2ecf20Sopenharmony_ci	int index;
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	for (index = end; index >= start; index--)
16018c2ecf20Sopenharmony_ci		pci_restore_config_dword(pdev, 4 * index,
16028c2ecf20Sopenharmony_ci					 pdev->saved_config_space[index],
16038c2ecf20Sopenharmony_ci					 retry, force);
16048c2ecf20Sopenharmony_ci}
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_cistatic void pci_restore_config_space(struct pci_dev *pdev)
16078c2ecf20Sopenharmony_ci{
16088c2ecf20Sopenharmony_ci	if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
16098c2ecf20Sopenharmony_ci		pci_restore_config_space_range(pdev, 10, 15, 0, false);
16108c2ecf20Sopenharmony_ci		/* Restore BARs before the command register. */
16118c2ecf20Sopenharmony_ci		pci_restore_config_space_range(pdev, 4, 9, 10, false);
16128c2ecf20Sopenharmony_ci		pci_restore_config_space_range(pdev, 0, 3, 0, false);
16138c2ecf20Sopenharmony_ci	} else if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
16148c2ecf20Sopenharmony_ci		pci_restore_config_space_range(pdev, 12, 15, 0, false);
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci		/*
16178c2ecf20Sopenharmony_ci		 * Force rewriting of prefetch registers to avoid S3 resume
16188c2ecf20Sopenharmony_ci		 * issues on Intel PCI bridges that occur when these
16198c2ecf20Sopenharmony_ci		 * registers are not explicitly written.
16208c2ecf20Sopenharmony_ci		 */
16218c2ecf20Sopenharmony_ci		pci_restore_config_space_range(pdev, 9, 11, 0, true);
16228c2ecf20Sopenharmony_ci		pci_restore_config_space_range(pdev, 0, 8, 0, false);
16238c2ecf20Sopenharmony_ci	} else {
16248c2ecf20Sopenharmony_ci		pci_restore_config_space_range(pdev, 0, 15, 0, false);
16258c2ecf20Sopenharmony_ci	}
16268c2ecf20Sopenharmony_ci}
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_cistatic void pci_restore_rebar_state(struct pci_dev *pdev)
16298c2ecf20Sopenharmony_ci{
16308c2ecf20Sopenharmony_ci	unsigned int pos, nbars, i;
16318c2ecf20Sopenharmony_ci	u32 ctrl;
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR);
16348c2ecf20Sopenharmony_ci	if (!pos)
16358c2ecf20Sopenharmony_ci		return;
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
16388c2ecf20Sopenharmony_ci	nbars = (ctrl & PCI_REBAR_CTRL_NBAR_MASK) >>
16398c2ecf20Sopenharmony_ci		    PCI_REBAR_CTRL_NBAR_SHIFT;
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	for (i = 0; i < nbars; i++, pos += 8) {
16428c2ecf20Sopenharmony_ci		struct resource *res;
16438c2ecf20Sopenharmony_ci		int bar_idx, size;
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci		pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
16468c2ecf20Sopenharmony_ci		bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX;
16478c2ecf20Sopenharmony_ci		res = pdev->resource + bar_idx;
16488c2ecf20Sopenharmony_ci		size = ilog2(resource_size(res)) - 20;
16498c2ecf20Sopenharmony_ci		ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
16508c2ecf20Sopenharmony_ci		ctrl |= size << PCI_REBAR_CTRL_BAR_SHIFT;
16518c2ecf20Sopenharmony_ci		pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl);
16528c2ecf20Sopenharmony_ci	}
16538c2ecf20Sopenharmony_ci}
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci/**
16568c2ecf20Sopenharmony_ci * pci_restore_state - Restore the saved state of a PCI device
16578c2ecf20Sopenharmony_ci * @dev: PCI device that we're dealing with
16588c2ecf20Sopenharmony_ci */
16598c2ecf20Sopenharmony_civoid pci_restore_state(struct pci_dev *dev)
16608c2ecf20Sopenharmony_ci{
16618c2ecf20Sopenharmony_ci	if (!dev->state_saved)
16628c2ecf20Sopenharmony_ci		return;
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	/*
16658c2ecf20Sopenharmony_ci	 * Restore max latencies (in the LTR capability) before enabling
16668c2ecf20Sopenharmony_ci	 * LTR itself (in the PCIe capability).
16678c2ecf20Sopenharmony_ci	 */
16688c2ecf20Sopenharmony_ci	pci_restore_ltr_state(dev);
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	pci_restore_pcie_state(dev);
16718c2ecf20Sopenharmony_ci	pci_restore_pasid_state(dev);
16728c2ecf20Sopenharmony_ci	pci_restore_pri_state(dev);
16738c2ecf20Sopenharmony_ci	pci_restore_ats_state(dev);
16748c2ecf20Sopenharmony_ci	pci_restore_vc_state(dev);
16758c2ecf20Sopenharmony_ci	pci_restore_rebar_state(dev);
16768c2ecf20Sopenharmony_ci	pci_restore_dpc_state(dev);
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	pci_aer_clear_status(dev);
16798c2ecf20Sopenharmony_ci	pci_restore_aer_state(dev);
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	pci_restore_config_space(dev);
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	pci_restore_pcix_state(dev);
16848c2ecf20Sopenharmony_ci	pci_restore_msi_state(dev);
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	/* Restore ACS and IOV configuration state */
16878c2ecf20Sopenharmony_ci	pci_enable_acs(dev);
16888c2ecf20Sopenharmony_ci	pci_restore_iov_state(dev);
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci	dev->state_saved = false;
16918c2ecf20Sopenharmony_ci}
16928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_restore_state);
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_cistruct pci_saved_state {
16958c2ecf20Sopenharmony_ci	u32 config_space[16];
16968c2ecf20Sopenharmony_ci	struct pci_cap_saved_data cap[];
16978c2ecf20Sopenharmony_ci};
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci/**
17008c2ecf20Sopenharmony_ci * pci_store_saved_state - Allocate and return an opaque struct containing
17018c2ecf20Sopenharmony_ci *			   the device saved state.
17028c2ecf20Sopenharmony_ci * @dev: PCI device that we're dealing with
17038c2ecf20Sopenharmony_ci *
17048c2ecf20Sopenharmony_ci * Return NULL if no state or error.
17058c2ecf20Sopenharmony_ci */
17068c2ecf20Sopenharmony_cistruct pci_saved_state *pci_store_saved_state(struct pci_dev *dev)
17078c2ecf20Sopenharmony_ci{
17088c2ecf20Sopenharmony_ci	struct pci_saved_state *state;
17098c2ecf20Sopenharmony_ci	struct pci_cap_saved_state *tmp;
17108c2ecf20Sopenharmony_ci	struct pci_cap_saved_data *cap;
17118c2ecf20Sopenharmony_ci	size_t size;
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	if (!dev->state_saved)
17148c2ecf20Sopenharmony_ci		return NULL;
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	size = sizeof(*state) + sizeof(struct pci_cap_saved_data);
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	hlist_for_each_entry(tmp, &dev->saved_cap_space, next)
17198c2ecf20Sopenharmony_ci		size += sizeof(struct pci_cap_saved_data) + tmp->cap.size;
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	state = kzalloc(size, GFP_KERNEL);
17228c2ecf20Sopenharmony_ci	if (!state)
17238c2ecf20Sopenharmony_ci		return NULL;
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	memcpy(state->config_space, dev->saved_config_space,
17268c2ecf20Sopenharmony_ci	       sizeof(state->config_space));
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	cap = state->cap;
17298c2ecf20Sopenharmony_ci	hlist_for_each_entry(tmp, &dev->saved_cap_space, next) {
17308c2ecf20Sopenharmony_ci		size_t len = sizeof(struct pci_cap_saved_data) + tmp->cap.size;
17318c2ecf20Sopenharmony_ci		memcpy(cap, &tmp->cap, len);
17328c2ecf20Sopenharmony_ci		cap = (struct pci_cap_saved_data *)((u8 *)cap + len);
17338c2ecf20Sopenharmony_ci	}
17348c2ecf20Sopenharmony_ci	/* Empty cap_save terminates list */
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	return state;
17378c2ecf20Sopenharmony_ci}
17388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_store_saved_state);
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci/**
17418c2ecf20Sopenharmony_ci * pci_load_saved_state - Reload the provided save state into struct pci_dev.
17428c2ecf20Sopenharmony_ci * @dev: PCI device that we're dealing with
17438c2ecf20Sopenharmony_ci * @state: Saved state returned from pci_store_saved_state()
17448c2ecf20Sopenharmony_ci */
17458c2ecf20Sopenharmony_ciint pci_load_saved_state(struct pci_dev *dev,
17468c2ecf20Sopenharmony_ci			 struct pci_saved_state *state)
17478c2ecf20Sopenharmony_ci{
17488c2ecf20Sopenharmony_ci	struct pci_cap_saved_data *cap;
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	dev->state_saved = false;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	if (!state)
17538c2ecf20Sopenharmony_ci		return 0;
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	memcpy(dev->saved_config_space, state->config_space,
17568c2ecf20Sopenharmony_ci	       sizeof(state->config_space));
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	cap = state->cap;
17598c2ecf20Sopenharmony_ci	while (cap->size) {
17608c2ecf20Sopenharmony_ci		struct pci_cap_saved_state *tmp;
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci		tmp = _pci_find_saved_cap(dev, cap->cap_nr, cap->cap_extended);
17638c2ecf20Sopenharmony_ci		if (!tmp || tmp->cap.size != cap->size)
17648c2ecf20Sopenharmony_ci			return -EINVAL;
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci		memcpy(tmp->cap.data, cap->data, tmp->cap.size);
17678c2ecf20Sopenharmony_ci		cap = (struct pci_cap_saved_data *)((u8 *)cap +
17688c2ecf20Sopenharmony_ci		       sizeof(struct pci_cap_saved_data) + cap->size);
17698c2ecf20Sopenharmony_ci	}
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	dev->state_saved = true;
17728c2ecf20Sopenharmony_ci	return 0;
17738c2ecf20Sopenharmony_ci}
17748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_load_saved_state);
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci/**
17778c2ecf20Sopenharmony_ci * pci_load_and_free_saved_state - Reload the save state pointed to by state,
17788c2ecf20Sopenharmony_ci *				   and free the memory allocated for it.
17798c2ecf20Sopenharmony_ci * @dev: PCI device that we're dealing with
17808c2ecf20Sopenharmony_ci * @state: Pointer to saved state returned from pci_store_saved_state()
17818c2ecf20Sopenharmony_ci */
17828c2ecf20Sopenharmony_ciint pci_load_and_free_saved_state(struct pci_dev *dev,
17838c2ecf20Sopenharmony_ci				  struct pci_saved_state **state)
17848c2ecf20Sopenharmony_ci{
17858c2ecf20Sopenharmony_ci	int ret = pci_load_saved_state(dev, *state);
17868c2ecf20Sopenharmony_ci	kfree(*state);
17878c2ecf20Sopenharmony_ci	*state = NULL;
17888c2ecf20Sopenharmony_ci	return ret;
17898c2ecf20Sopenharmony_ci}
17908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_load_and_free_saved_state);
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ciint __weak pcibios_enable_device(struct pci_dev *dev, int bars)
17938c2ecf20Sopenharmony_ci{
17948c2ecf20Sopenharmony_ci	return pci_enable_resources(dev, bars);
17958c2ecf20Sopenharmony_ci}
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_cistatic int do_pci_enable_device(struct pci_dev *dev, int bars)
17988c2ecf20Sopenharmony_ci{
17998c2ecf20Sopenharmony_ci	int err;
18008c2ecf20Sopenharmony_ci	struct pci_dev *bridge;
18018c2ecf20Sopenharmony_ci	u16 cmd;
18028c2ecf20Sopenharmony_ci	u8 pin;
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	err = pci_set_power_state(dev, PCI_D0);
18058c2ecf20Sopenharmony_ci	if (err < 0 && err != -EIO)
18068c2ecf20Sopenharmony_ci		return err;
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	bridge = pci_upstream_bridge(dev);
18098c2ecf20Sopenharmony_ci	if (bridge)
18108c2ecf20Sopenharmony_ci		pcie_aspm_powersave_config_link(bridge);
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	err = pcibios_enable_device(dev, bars);
18138c2ecf20Sopenharmony_ci	if (err < 0)
18148c2ecf20Sopenharmony_ci		return err;
18158c2ecf20Sopenharmony_ci	pci_fixup_device(pci_fixup_enable, dev);
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	if (dev->msi_enabled || dev->msix_enabled)
18188c2ecf20Sopenharmony_ci		return 0;
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
18218c2ecf20Sopenharmony_ci	if (pin) {
18228c2ecf20Sopenharmony_ci		pci_read_config_word(dev, PCI_COMMAND, &cmd);
18238c2ecf20Sopenharmony_ci		if (cmd & PCI_COMMAND_INTX_DISABLE)
18248c2ecf20Sopenharmony_ci			pci_write_config_word(dev, PCI_COMMAND,
18258c2ecf20Sopenharmony_ci					      cmd & ~PCI_COMMAND_INTX_DISABLE);
18268c2ecf20Sopenharmony_ci	}
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	return 0;
18298c2ecf20Sopenharmony_ci}
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci/**
18328c2ecf20Sopenharmony_ci * pci_reenable_device - Resume abandoned device
18338c2ecf20Sopenharmony_ci * @dev: PCI device to be resumed
18348c2ecf20Sopenharmony_ci *
18358c2ecf20Sopenharmony_ci * NOTE: This function is a backend of pci_default_resume() and is not supposed
18368c2ecf20Sopenharmony_ci * to be called by normal code, write proper resume handler and use it instead.
18378c2ecf20Sopenharmony_ci */
18388c2ecf20Sopenharmony_ciint pci_reenable_device(struct pci_dev *dev)
18398c2ecf20Sopenharmony_ci{
18408c2ecf20Sopenharmony_ci	if (pci_is_enabled(dev))
18418c2ecf20Sopenharmony_ci		return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
18428c2ecf20Sopenharmony_ci	return 0;
18438c2ecf20Sopenharmony_ci}
18448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_reenable_device);
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_cistatic void pci_enable_bridge(struct pci_dev *dev)
18478c2ecf20Sopenharmony_ci{
18488c2ecf20Sopenharmony_ci	struct pci_dev *bridge;
18498c2ecf20Sopenharmony_ci	int retval;
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	bridge = pci_upstream_bridge(dev);
18528c2ecf20Sopenharmony_ci	if (bridge)
18538c2ecf20Sopenharmony_ci		pci_enable_bridge(bridge);
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci	if (pci_is_enabled(dev)) {
18568c2ecf20Sopenharmony_ci		if (!dev->is_busmaster)
18578c2ecf20Sopenharmony_ci			pci_set_master(dev);
18588c2ecf20Sopenharmony_ci		return;
18598c2ecf20Sopenharmony_ci	}
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	retval = pci_enable_device(dev);
18628c2ecf20Sopenharmony_ci	if (retval)
18638c2ecf20Sopenharmony_ci		pci_err(dev, "Error enabling bridge (%d), continuing\n",
18648c2ecf20Sopenharmony_ci			retval);
18658c2ecf20Sopenharmony_ci	pci_set_master(dev);
18668c2ecf20Sopenharmony_ci}
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_cistatic int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
18698c2ecf20Sopenharmony_ci{
18708c2ecf20Sopenharmony_ci	struct pci_dev *bridge;
18718c2ecf20Sopenharmony_ci	int err;
18728c2ecf20Sopenharmony_ci	int i, bars = 0;
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci	/*
18758c2ecf20Sopenharmony_ci	 * Power state could be unknown at this point, either due to a fresh
18768c2ecf20Sopenharmony_ci	 * boot or a device removal call.  So get the current power state
18778c2ecf20Sopenharmony_ci	 * so that things like MSI message writing will behave as expected
18788c2ecf20Sopenharmony_ci	 * (e.g. if the device really is in D0 at enable time).
18798c2ecf20Sopenharmony_ci	 */
18808c2ecf20Sopenharmony_ci	pci_update_current_state(dev, dev->current_state);
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	if (atomic_inc_return(&dev->enable_cnt) > 1)
18838c2ecf20Sopenharmony_ci		return 0;		/* already enabled */
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	bridge = pci_upstream_bridge(dev);
18868c2ecf20Sopenharmony_ci	if (bridge)
18878c2ecf20Sopenharmony_ci		pci_enable_bridge(bridge);
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	/* only skip sriov related */
18908c2ecf20Sopenharmony_ci	for (i = 0; i <= PCI_ROM_RESOURCE; i++)
18918c2ecf20Sopenharmony_ci		if (dev->resource[i].flags & flags)
18928c2ecf20Sopenharmony_ci			bars |= (1 << i);
18938c2ecf20Sopenharmony_ci	for (i = PCI_BRIDGE_RESOURCES; i < DEVICE_COUNT_RESOURCE; i++)
18948c2ecf20Sopenharmony_ci		if (dev->resource[i].flags & flags)
18958c2ecf20Sopenharmony_ci			bars |= (1 << i);
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	err = do_pci_enable_device(dev, bars);
18988c2ecf20Sopenharmony_ci	if (err < 0)
18998c2ecf20Sopenharmony_ci		atomic_dec(&dev->enable_cnt);
19008c2ecf20Sopenharmony_ci	return err;
19018c2ecf20Sopenharmony_ci}
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci/**
19048c2ecf20Sopenharmony_ci * pci_enable_device_io - Initialize a device for use with IO space
19058c2ecf20Sopenharmony_ci * @dev: PCI device to be initialized
19068c2ecf20Sopenharmony_ci *
19078c2ecf20Sopenharmony_ci * Initialize device before it's used by a driver. Ask low-level code
19088c2ecf20Sopenharmony_ci * to enable I/O resources. Wake up the device if it was suspended.
19098c2ecf20Sopenharmony_ci * Beware, this function can fail.
19108c2ecf20Sopenharmony_ci */
19118c2ecf20Sopenharmony_ciint pci_enable_device_io(struct pci_dev *dev)
19128c2ecf20Sopenharmony_ci{
19138c2ecf20Sopenharmony_ci	return pci_enable_device_flags(dev, IORESOURCE_IO);
19148c2ecf20Sopenharmony_ci}
19158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_enable_device_io);
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci/**
19188c2ecf20Sopenharmony_ci * pci_enable_device_mem - Initialize a device for use with Memory space
19198c2ecf20Sopenharmony_ci * @dev: PCI device to be initialized
19208c2ecf20Sopenharmony_ci *
19218c2ecf20Sopenharmony_ci * Initialize device before it's used by a driver. Ask low-level code
19228c2ecf20Sopenharmony_ci * to enable Memory resources. Wake up the device if it was suspended.
19238c2ecf20Sopenharmony_ci * Beware, this function can fail.
19248c2ecf20Sopenharmony_ci */
19258c2ecf20Sopenharmony_ciint pci_enable_device_mem(struct pci_dev *dev)
19268c2ecf20Sopenharmony_ci{
19278c2ecf20Sopenharmony_ci	return pci_enable_device_flags(dev, IORESOURCE_MEM);
19288c2ecf20Sopenharmony_ci}
19298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_enable_device_mem);
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci/**
19328c2ecf20Sopenharmony_ci * pci_enable_device - Initialize device before it's used by a driver.
19338c2ecf20Sopenharmony_ci * @dev: PCI device to be initialized
19348c2ecf20Sopenharmony_ci *
19358c2ecf20Sopenharmony_ci * Initialize device before it's used by a driver. Ask low-level code
19368c2ecf20Sopenharmony_ci * to enable I/O and memory. Wake up the device if it was suspended.
19378c2ecf20Sopenharmony_ci * Beware, this function can fail.
19388c2ecf20Sopenharmony_ci *
19398c2ecf20Sopenharmony_ci * Note we don't actually enable the device many times if we call
19408c2ecf20Sopenharmony_ci * this function repeatedly (we just increment the count).
19418c2ecf20Sopenharmony_ci */
19428c2ecf20Sopenharmony_ciint pci_enable_device(struct pci_dev *dev)
19438c2ecf20Sopenharmony_ci{
19448c2ecf20Sopenharmony_ci	return pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO);
19458c2ecf20Sopenharmony_ci}
19468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_enable_device);
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci/*
19498c2ecf20Sopenharmony_ci * Managed PCI resources.  This manages device on/off, INTx/MSI/MSI-X
19508c2ecf20Sopenharmony_ci * on/off and BAR regions.  pci_dev itself records MSI/MSI-X status, so
19518c2ecf20Sopenharmony_ci * there's no need to track it separately.  pci_devres is initialized
19528c2ecf20Sopenharmony_ci * when a device is enabled using managed PCI device enable interface.
19538c2ecf20Sopenharmony_ci */
19548c2ecf20Sopenharmony_cistruct pci_devres {
19558c2ecf20Sopenharmony_ci	unsigned int enabled:1;
19568c2ecf20Sopenharmony_ci	unsigned int pinned:1;
19578c2ecf20Sopenharmony_ci	unsigned int orig_intx:1;
19588c2ecf20Sopenharmony_ci	unsigned int restore_intx:1;
19598c2ecf20Sopenharmony_ci	unsigned int mwi:1;
19608c2ecf20Sopenharmony_ci	u32 region_mask;
19618c2ecf20Sopenharmony_ci};
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_cistatic void pcim_release(struct device *gendev, void *res)
19648c2ecf20Sopenharmony_ci{
19658c2ecf20Sopenharmony_ci	struct pci_dev *dev = to_pci_dev(gendev);
19668c2ecf20Sopenharmony_ci	struct pci_devres *this = res;
19678c2ecf20Sopenharmony_ci	int i;
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	if (dev->msi_enabled)
19708c2ecf20Sopenharmony_ci		pci_disable_msi(dev);
19718c2ecf20Sopenharmony_ci	if (dev->msix_enabled)
19728c2ecf20Sopenharmony_ci		pci_disable_msix(dev);
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
19758c2ecf20Sopenharmony_ci		if (this->region_mask & (1 << i))
19768c2ecf20Sopenharmony_ci			pci_release_region(dev, i);
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	if (this->mwi)
19798c2ecf20Sopenharmony_ci		pci_clear_mwi(dev);
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ci	if (this->restore_intx)
19828c2ecf20Sopenharmony_ci		pci_intx(dev, this->orig_intx);
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	if (this->enabled && !this->pinned)
19858c2ecf20Sopenharmony_ci		pci_disable_device(dev);
19868c2ecf20Sopenharmony_ci}
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_cistatic struct pci_devres *get_pci_dr(struct pci_dev *pdev)
19898c2ecf20Sopenharmony_ci{
19908c2ecf20Sopenharmony_ci	struct pci_devres *dr, *new_dr;
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci	dr = devres_find(&pdev->dev, pcim_release, NULL, NULL);
19938c2ecf20Sopenharmony_ci	if (dr)
19948c2ecf20Sopenharmony_ci		return dr;
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	new_dr = devres_alloc(pcim_release, sizeof(*new_dr), GFP_KERNEL);
19978c2ecf20Sopenharmony_ci	if (!new_dr)
19988c2ecf20Sopenharmony_ci		return NULL;
19998c2ecf20Sopenharmony_ci	return devres_get(&pdev->dev, new_dr, NULL, NULL);
20008c2ecf20Sopenharmony_ci}
20018c2ecf20Sopenharmony_ci
20028c2ecf20Sopenharmony_cistatic struct pci_devres *find_pci_dr(struct pci_dev *pdev)
20038c2ecf20Sopenharmony_ci{
20048c2ecf20Sopenharmony_ci	if (pci_is_managed(pdev))
20058c2ecf20Sopenharmony_ci		return devres_find(&pdev->dev, pcim_release, NULL, NULL);
20068c2ecf20Sopenharmony_ci	return NULL;
20078c2ecf20Sopenharmony_ci}
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci/**
20108c2ecf20Sopenharmony_ci * pcim_enable_device - Managed pci_enable_device()
20118c2ecf20Sopenharmony_ci * @pdev: PCI device to be initialized
20128c2ecf20Sopenharmony_ci *
20138c2ecf20Sopenharmony_ci * Managed pci_enable_device().
20148c2ecf20Sopenharmony_ci */
20158c2ecf20Sopenharmony_ciint pcim_enable_device(struct pci_dev *pdev)
20168c2ecf20Sopenharmony_ci{
20178c2ecf20Sopenharmony_ci	struct pci_devres *dr;
20188c2ecf20Sopenharmony_ci	int rc;
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci	dr = get_pci_dr(pdev);
20218c2ecf20Sopenharmony_ci	if (unlikely(!dr))
20228c2ecf20Sopenharmony_ci		return -ENOMEM;
20238c2ecf20Sopenharmony_ci	if (dr->enabled)
20248c2ecf20Sopenharmony_ci		return 0;
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci	rc = pci_enable_device(pdev);
20278c2ecf20Sopenharmony_ci	if (!rc) {
20288c2ecf20Sopenharmony_ci		pdev->is_managed = 1;
20298c2ecf20Sopenharmony_ci		dr->enabled = 1;
20308c2ecf20Sopenharmony_ci	}
20318c2ecf20Sopenharmony_ci	return rc;
20328c2ecf20Sopenharmony_ci}
20338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcim_enable_device);
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci/**
20368c2ecf20Sopenharmony_ci * pcim_pin_device - Pin managed PCI device
20378c2ecf20Sopenharmony_ci * @pdev: PCI device to pin
20388c2ecf20Sopenharmony_ci *
20398c2ecf20Sopenharmony_ci * Pin managed PCI device @pdev.  Pinned device won't be disabled on
20408c2ecf20Sopenharmony_ci * driver detach.  @pdev must have been enabled with
20418c2ecf20Sopenharmony_ci * pcim_enable_device().
20428c2ecf20Sopenharmony_ci */
20438c2ecf20Sopenharmony_civoid pcim_pin_device(struct pci_dev *pdev)
20448c2ecf20Sopenharmony_ci{
20458c2ecf20Sopenharmony_ci	struct pci_devres *dr;
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci	dr = find_pci_dr(pdev);
20488c2ecf20Sopenharmony_ci	WARN_ON(!dr || !dr->enabled);
20498c2ecf20Sopenharmony_ci	if (dr)
20508c2ecf20Sopenharmony_ci		dr->pinned = 1;
20518c2ecf20Sopenharmony_ci}
20528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcim_pin_device);
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci/*
20558c2ecf20Sopenharmony_ci * pcibios_add_device - provide arch specific hooks when adding device dev
20568c2ecf20Sopenharmony_ci * @dev: the PCI device being added
20578c2ecf20Sopenharmony_ci *
20588c2ecf20Sopenharmony_ci * Permits the platform to provide architecture specific functionality when
20598c2ecf20Sopenharmony_ci * devices are added. This is the default implementation. Architecture
20608c2ecf20Sopenharmony_ci * implementations can override this.
20618c2ecf20Sopenharmony_ci */
20628c2ecf20Sopenharmony_ciint __weak pcibios_add_device(struct pci_dev *dev)
20638c2ecf20Sopenharmony_ci{
20648c2ecf20Sopenharmony_ci	return 0;
20658c2ecf20Sopenharmony_ci}
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ci/**
20688c2ecf20Sopenharmony_ci * pcibios_release_device - provide arch specific hooks when releasing
20698c2ecf20Sopenharmony_ci *			    device dev
20708c2ecf20Sopenharmony_ci * @dev: the PCI device being released
20718c2ecf20Sopenharmony_ci *
20728c2ecf20Sopenharmony_ci * Permits the platform to provide architecture specific functionality when
20738c2ecf20Sopenharmony_ci * devices are released. This is the default implementation. Architecture
20748c2ecf20Sopenharmony_ci * implementations can override this.
20758c2ecf20Sopenharmony_ci */
20768c2ecf20Sopenharmony_civoid __weak pcibios_release_device(struct pci_dev *dev) {}
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci/**
20798c2ecf20Sopenharmony_ci * pcibios_disable_device - disable arch specific PCI resources for device dev
20808c2ecf20Sopenharmony_ci * @dev: the PCI device to disable
20818c2ecf20Sopenharmony_ci *
20828c2ecf20Sopenharmony_ci * Disables architecture specific PCI resources for the device. This
20838c2ecf20Sopenharmony_ci * is the default implementation. Architecture implementations can
20848c2ecf20Sopenharmony_ci * override this.
20858c2ecf20Sopenharmony_ci */
20868c2ecf20Sopenharmony_civoid __weak pcibios_disable_device(struct pci_dev *dev) {}
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci/**
20898c2ecf20Sopenharmony_ci * pcibios_penalize_isa_irq - penalize an ISA IRQ
20908c2ecf20Sopenharmony_ci * @irq: ISA IRQ to penalize
20918c2ecf20Sopenharmony_ci * @active: IRQ active or not
20928c2ecf20Sopenharmony_ci *
20938c2ecf20Sopenharmony_ci * Permits the platform to provide architecture-specific functionality when
20948c2ecf20Sopenharmony_ci * penalizing ISA IRQs. This is the default implementation. Architecture
20958c2ecf20Sopenharmony_ci * implementations can override this.
20968c2ecf20Sopenharmony_ci */
20978c2ecf20Sopenharmony_civoid __weak pcibios_penalize_isa_irq(int irq, int active) {}
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_cistatic void do_pci_disable_device(struct pci_dev *dev)
21008c2ecf20Sopenharmony_ci{
21018c2ecf20Sopenharmony_ci	u16 pci_command;
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_ci	pci_read_config_word(dev, PCI_COMMAND, &pci_command);
21048c2ecf20Sopenharmony_ci	if (pci_command & PCI_COMMAND_MASTER) {
21058c2ecf20Sopenharmony_ci		pci_command &= ~PCI_COMMAND_MASTER;
21068c2ecf20Sopenharmony_ci		pci_write_config_word(dev, PCI_COMMAND, pci_command);
21078c2ecf20Sopenharmony_ci	}
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ci	pcibios_disable_device(dev);
21108c2ecf20Sopenharmony_ci}
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci/**
21138c2ecf20Sopenharmony_ci * pci_disable_enabled_device - Disable device without updating enable_cnt
21148c2ecf20Sopenharmony_ci * @dev: PCI device to disable
21158c2ecf20Sopenharmony_ci *
21168c2ecf20Sopenharmony_ci * NOTE: This function is a backend of PCI power management routines and is
21178c2ecf20Sopenharmony_ci * not supposed to be called drivers.
21188c2ecf20Sopenharmony_ci */
21198c2ecf20Sopenharmony_civoid pci_disable_enabled_device(struct pci_dev *dev)
21208c2ecf20Sopenharmony_ci{
21218c2ecf20Sopenharmony_ci	if (pci_is_enabled(dev))
21228c2ecf20Sopenharmony_ci		do_pci_disable_device(dev);
21238c2ecf20Sopenharmony_ci}
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci/**
21268c2ecf20Sopenharmony_ci * pci_disable_device - Disable PCI device after use
21278c2ecf20Sopenharmony_ci * @dev: PCI device to be disabled
21288c2ecf20Sopenharmony_ci *
21298c2ecf20Sopenharmony_ci * Signal to the system that the PCI device is not in use by the system
21308c2ecf20Sopenharmony_ci * anymore.  This only involves disabling PCI bus-mastering, if active.
21318c2ecf20Sopenharmony_ci *
21328c2ecf20Sopenharmony_ci * Note we don't actually disable the device until all callers of
21338c2ecf20Sopenharmony_ci * pci_enable_device() have called pci_disable_device().
21348c2ecf20Sopenharmony_ci */
21358c2ecf20Sopenharmony_civoid pci_disable_device(struct pci_dev *dev)
21368c2ecf20Sopenharmony_ci{
21378c2ecf20Sopenharmony_ci	struct pci_devres *dr;
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_ci	dr = find_pci_dr(dev);
21408c2ecf20Sopenharmony_ci	if (dr)
21418c2ecf20Sopenharmony_ci		dr->enabled = 0;
21428c2ecf20Sopenharmony_ci
21438c2ecf20Sopenharmony_ci	dev_WARN_ONCE(&dev->dev, atomic_read(&dev->enable_cnt) <= 0,
21448c2ecf20Sopenharmony_ci		      "disabling already-disabled device");
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	if (atomic_dec_return(&dev->enable_cnt) != 0)
21478c2ecf20Sopenharmony_ci		return;
21488c2ecf20Sopenharmony_ci
21498c2ecf20Sopenharmony_ci	do_pci_disable_device(dev);
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci	dev->is_busmaster = 0;
21528c2ecf20Sopenharmony_ci}
21538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_disable_device);
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci/**
21568c2ecf20Sopenharmony_ci * pcibios_set_pcie_reset_state - set reset state for device dev
21578c2ecf20Sopenharmony_ci * @dev: the PCIe device reset
21588c2ecf20Sopenharmony_ci * @state: Reset state to enter into
21598c2ecf20Sopenharmony_ci *
21608c2ecf20Sopenharmony_ci * Set the PCIe reset state for the device. This is the default
21618c2ecf20Sopenharmony_ci * implementation. Architecture implementations can override this.
21628c2ecf20Sopenharmony_ci */
21638c2ecf20Sopenharmony_ciint __weak pcibios_set_pcie_reset_state(struct pci_dev *dev,
21648c2ecf20Sopenharmony_ci					enum pcie_reset_state state)
21658c2ecf20Sopenharmony_ci{
21668c2ecf20Sopenharmony_ci	return -EINVAL;
21678c2ecf20Sopenharmony_ci}
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci/**
21708c2ecf20Sopenharmony_ci * pci_set_pcie_reset_state - set reset state for device dev
21718c2ecf20Sopenharmony_ci * @dev: the PCIe device reset
21728c2ecf20Sopenharmony_ci * @state: Reset state to enter into
21738c2ecf20Sopenharmony_ci *
21748c2ecf20Sopenharmony_ci * Sets the PCI reset state for the device.
21758c2ecf20Sopenharmony_ci */
21768c2ecf20Sopenharmony_ciint pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
21778c2ecf20Sopenharmony_ci{
21788c2ecf20Sopenharmony_ci	return pcibios_set_pcie_reset_state(dev, state);
21798c2ecf20Sopenharmony_ci}
21808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_civoid pcie_clear_device_status(struct pci_dev *dev)
21838c2ecf20Sopenharmony_ci{
21848c2ecf20Sopenharmony_ci	u16 sta;
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
21878c2ecf20Sopenharmony_ci	pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
21888c2ecf20Sopenharmony_ci}
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci/**
21918c2ecf20Sopenharmony_ci * pcie_clear_root_pme_status - Clear root port PME interrupt status.
21928c2ecf20Sopenharmony_ci * @dev: PCIe root port or event collector.
21938c2ecf20Sopenharmony_ci */
21948c2ecf20Sopenharmony_civoid pcie_clear_root_pme_status(struct pci_dev *dev)
21958c2ecf20Sopenharmony_ci{
21968c2ecf20Sopenharmony_ci	pcie_capability_set_dword(dev, PCI_EXP_RTSTA, PCI_EXP_RTSTA_PME);
21978c2ecf20Sopenharmony_ci}
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_ci/**
22008c2ecf20Sopenharmony_ci * pci_check_pme_status - Check if given device has generated PME.
22018c2ecf20Sopenharmony_ci * @dev: Device to check.
22028c2ecf20Sopenharmony_ci *
22038c2ecf20Sopenharmony_ci * Check the PME status of the device and if set, clear it and clear PME enable
22048c2ecf20Sopenharmony_ci * (if set).  Return 'true' if PME status and PME enable were both set or
22058c2ecf20Sopenharmony_ci * 'false' otherwise.
22068c2ecf20Sopenharmony_ci */
22078c2ecf20Sopenharmony_cibool pci_check_pme_status(struct pci_dev *dev)
22088c2ecf20Sopenharmony_ci{
22098c2ecf20Sopenharmony_ci	int pmcsr_pos;
22108c2ecf20Sopenharmony_ci	u16 pmcsr;
22118c2ecf20Sopenharmony_ci	bool ret = false;
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci	if (!dev->pm_cap)
22148c2ecf20Sopenharmony_ci		return false;
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	pmcsr_pos = dev->pm_cap + PCI_PM_CTRL;
22178c2ecf20Sopenharmony_ci	pci_read_config_word(dev, pmcsr_pos, &pmcsr);
22188c2ecf20Sopenharmony_ci	if (!(pmcsr & PCI_PM_CTRL_PME_STATUS))
22198c2ecf20Sopenharmony_ci		return false;
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_ci	/* Clear PME status. */
22228c2ecf20Sopenharmony_ci	pmcsr |= PCI_PM_CTRL_PME_STATUS;
22238c2ecf20Sopenharmony_ci	if (pmcsr & PCI_PM_CTRL_PME_ENABLE) {
22248c2ecf20Sopenharmony_ci		/* Disable PME to avoid interrupt flood. */
22258c2ecf20Sopenharmony_ci		pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
22268c2ecf20Sopenharmony_ci		ret = true;
22278c2ecf20Sopenharmony_ci	}
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci	pci_write_config_word(dev, pmcsr_pos, pmcsr);
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_ci	return ret;
22328c2ecf20Sopenharmony_ci}
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci/**
22358c2ecf20Sopenharmony_ci * pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set.
22368c2ecf20Sopenharmony_ci * @dev: Device to handle.
22378c2ecf20Sopenharmony_ci * @pme_poll_reset: Whether or not to reset the device's pme_poll flag.
22388c2ecf20Sopenharmony_ci *
22398c2ecf20Sopenharmony_ci * Check if @dev has generated PME and queue a resume request for it in that
22408c2ecf20Sopenharmony_ci * case.
22418c2ecf20Sopenharmony_ci */
22428c2ecf20Sopenharmony_cistatic int pci_pme_wakeup(struct pci_dev *dev, void *pme_poll_reset)
22438c2ecf20Sopenharmony_ci{
22448c2ecf20Sopenharmony_ci	if (pme_poll_reset && dev->pme_poll)
22458c2ecf20Sopenharmony_ci		dev->pme_poll = false;
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci	if (pci_check_pme_status(dev)) {
22488c2ecf20Sopenharmony_ci		pci_wakeup_event(dev);
22498c2ecf20Sopenharmony_ci		pm_request_resume(&dev->dev);
22508c2ecf20Sopenharmony_ci	}
22518c2ecf20Sopenharmony_ci	return 0;
22528c2ecf20Sopenharmony_ci}
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci/**
22558c2ecf20Sopenharmony_ci * pci_pme_wakeup_bus - Walk given bus and wake up devices on it, if necessary.
22568c2ecf20Sopenharmony_ci * @bus: Top bus of the subtree to walk.
22578c2ecf20Sopenharmony_ci */
22588c2ecf20Sopenharmony_civoid pci_pme_wakeup_bus(struct pci_bus *bus)
22598c2ecf20Sopenharmony_ci{
22608c2ecf20Sopenharmony_ci	if (bus)
22618c2ecf20Sopenharmony_ci		pci_walk_bus(bus, pci_pme_wakeup, (void *)true);
22628c2ecf20Sopenharmony_ci}
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_ci/**
22668c2ecf20Sopenharmony_ci * pci_pme_capable - check the capability of PCI device to generate PME#
22678c2ecf20Sopenharmony_ci * @dev: PCI device to handle.
22688c2ecf20Sopenharmony_ci * @state: PCI state from which device will issue PME#.
22698c2ecf20Sopenharmony_ci */
22708c2ecf20Sopenharmony_cibool pci_pme_capable(struct pci_dev *dev, pci_power_t state)
22718c2ecf20Sopenharmony_ci{
22728c2ecf20Sopenharmony_ci	if (!dev->pm_cap)
22738c2ecf20Sopenharmony_ci		return false;
22748c2ecf20Sopenharmony_ci
22758c2ecf20Sopenharmony_ci	return !!(dev->pme_support & (1 << state));
22768c2ecf20Sopenharmony_ci}
22778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_pme_capable);
22788c2ecf20Sopenharmony_ci
22798c2ecf20Sopenharmony_cistatic void pci_pme_list_scan(struct work_struct *work)
22808c2ecf20Sopenharmony_ci{
22818c2ecf20Sopenharmony_ci	struct pci_pme_device *pme_dev, *n;
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ci	mutex_lock(&pci_pme_list_mutex);
22848c2ecf20Sopenharmony_ci	list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) {
22858c2ecf20Sopenharmony_ci		if (pme_dev->dev->pme_poll) {
22868c2ecf20Sopenharmony_ci			struct pci_dev *bridge;
22878c2ecf20Sopenharmony_ci
22888c2ecf20Sopenharmony_ci			bridge = pme_dev->dev->bus->self;
22898c2ecf20Sopenharmony_ci			/*
22908c2ecf20Sopenharmony_ci			 * If bridge is in low power state, the
22918c2ecf20Sopenharmony_ci			 * configuration space of subordinate devices
22928c2ecf20Sopenharmony_ci			 * may be not accessible
22938c2ecf20Sopenharmony_ci			 */
22948c2ecf20Sopenharmony_ci			if (bridge && bridge->current_state != PCI_D0)
22958c2ecf20Sopenharmony_ci				continue;
22968c2ecf20Sopenharmony_ci			/*
22978c2ecf20Sopenharmony_ci			 * If the device is in D3cold it should not be
22988c2ecf20Sopenharmony_ci			 * polled either.
22998c2ecf20Sopenharmony_ci			 */
23008c2ecf20Sopenharmony_ci			if (pme_dev->dev->current_state == PCI_D3cold)
23018c2ecf20Sopenharmony_ci				continue;
23028c2ecf20Sopenharmony_ci
23038c2ecf20Sopenharmony_ci			pci_pme_wakeup(pme_dev->dev, NULL);
23048c2ecf20Sopenharmony_ci		} else {
23058c2ecf20Sopenharmony_ci			list_del(&pme_dev->list);
23068c2ecf20Sopenharmony_ci			kfree(pme_dev);
23078c2ecf20Sopenharmony_ci		}
23088c2ecf20Sopenharmony_ci	}
23098c2ecf20Sopenharmony_ci	if (!list_empty(&pci_pme_list))
23108c2ecf20Sopenharmony_ci		queue_delayed_work(system_freezable_wq, &pci_pme_work,
23118c2ecf20Sopenharmony_ci				   msecs_to_jiffies(PME_TIMEOUT));
23128c2ecf20Sopenharmony_ci	mutex_unlock(&pci_pme_list_mutex);
23138c2ecf20Sopenharmony_ci}
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_cistatic void __pci_pme_active(struct pci_dev *dev, bool enable)
23168c2ecf20Sopenharmony_ci{
23178c2ecf20Sopenharmony_ci	u16 pmcsr;
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_ci	if (!dev->pme_support)
23208c2ecf20Sopenharmony_ci		return;
23218c2ecf20Sopenharmony_ci
23228c2ecf20Sopenharmony_ci	pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
23238c2ecf20Sopenharmony_ci	/* Clear PME_Status by writing 1 to it and enable PME# */
23248c2ecf20Sopenharmony_ci	pmcsr |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE;
23258c2ecf20Sopenharmony_ci	if (!enable)
23268c2ecf20Sopenharmony_ci		pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
23298c2ecf20Sopenharmony_ci}
23308c2ecf20Sopenharmony_ci
23318c2ecf20Sopenharmony_ci/**
23328c2ecf20Sopenharmony_ci * pci_pme_restore - Restore PME configuration after config space restore.
23338c2ecf20Sopenharmony_ci * @dev: PCI device to update.
23348c2ecf20Sopenharmony_ci */
23358c2ecf20Sopenharmony_civoid pci_pme_restore(struct pci_dev *dev)
23368c2ecf20Sopenharmony_ci{
23378c2ecf20Sopenharmony_ci	u16 pmcsr;
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci	if (!dev->pme_support)
23408c2ecf20Sopenharmony_ci		return;
23418c2ecf20Sopenharmony_ci
23428c2ecf20Sopenharmony_ci	pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
23438c2ecf20Sopenharmony_ci	if (dev->wakeup_prepared) {
23448c2ecf20Sopenharmony_ci		pmcsr |= PCI_PM_CTRL_PME_ENABLE;
23458c2ecf20Sopenharmony_ci		pmcsr &= ~PCI_PM_CTRL_PME_STATUS;
23468c2ecf20Sopenharmony_ci	} else {
23478c2ecf20Sopenharmony_ci		pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
23488c2ecf20Sopenharmony_ci		pmcsr |= PCI_PM_CTRL_PME_STATUS;
23498c2ecf20Sopenharmony_ci	}
23508c2ecf20Sopenharmony_ci	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
23518c2ecf20Sopenharmony_ci}
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci/**
23548c2ecf20Sopenharmony_ci * pci_pme_active - enable or disable PCI device's PME# function
23558c2ecf20Sopenharmony_ci * @dev: PCI device to handle.
23568c2ecf20Sopenharmony_ci * @enable: 'true' to enable PME# generation; 'false' to disable it.
23578c2ecf20Sopenharmony_ci *
23588c2ecf20Sopenharmony_ci * The caller must verify that the device is capable of generating PME# before
23598c2ecf20Sopenharmony_ci * calling this function with @enable equal to 'true'.
23608c2ecf20Sopenharmony_ci */
23618c2ecf20Sopenharmony_civoid pci_pme_active(struct pci_dev *dev, bool enable)
23628c2ecf20Sopenharmony_ci{
23638c2ecf20Sopenharmony_ci	__pci_pme_active(dev, enable);
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci	/*
23668c2ecf20Sopenharmony_ci	 * PCI (as opposed to PCIe) PME requires that the device have
23678c2ecf20Sopenharmony_ci	 * its PME# line hooked up correctly. Not all hardware vendors
23688c2ecf20Sopenharmony_ci	 * do this, so the PME never gets delivered and the device
23698c2ecf20Sopenharmony_ci	 * remains asleep. The easiest way around this is to
23708c2ecf20Sopenharmony_ci	 * periodically walk the list of suspended devices and check
23718c2ecf20Sopenharmony_ci	 * whether any have their PME flag set. The assumption is that
23728c2ecf20Sopenharmony_ci	 * we'll wake up often enough anyway that this won't be a huge
23738c2ecf20Sopenharmony_ci	 * hit, and the power savings from the devices will still be a
23748c2ecf20Sopenharmony_ci	 * win.
23758c2ecf20Sopenharmony_ci	 *
23768c2ecf20Sopenharmony_ci	 * Although PCIe uses in-band PME message instead of PME# line
23778c2ecf20Sopenharmony_ci	 * to report PME, PME does not work for some PCIe devices in
23788c2ecf20Sopenharmony_ci	 * reality.  For example, there are devices that set their PME
23798c2ecf20Sopenharmony_ci	 * status bits, but don't really bother to send a PME message;
23808c2ecf20Sopenharmony_ci	 * there are PCI Express Root Ports that don't bother to
23818c2ecf20Sopenharmony_ci	 * trigger interrupts when they receive PME messages from the
23828c2ecf20Sopenharmony_ci	 * devices below.  So PME poll is used for PCIe devices too.
23838c2ecf20Sopenharmony_ci	 */
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci	if (dev->pme_poll) {
23868c2ecf20Sopenharmony_ci		struct pci_pme_device *pme_dev;
23878c2ecf20Sopenharmony_ci		if (enable) {
23888c2ecf20Sopenharmony_ci			pme_dev = kmalloc(sizeof(struct pci_pme_device),
23898c2ecf20Sopenharmony_ci					  GFP_KERNEL);
23908c2ecf20Sopenharmony_ci			if (!pme_dev) {
23918c2ecf20Sopenharmony_ci				pci_warn(dev, "can't enable PME#\n");
23928c2ecf20Sopenharmony_ci				return;
23938c2ecf20Sopenharmony_ci			}
23948c2ecf20Sopenharmony_ci			pme_dev->dev = dev;
23958c2ecf20Sopenharmony_ci			mutex_lock(&pci_pme_list_mutex);
23968c2ecf20Sopenharmony_ci			list_add(&pme_dev->list, &pci_pme_list);
23978c2ecf20Sopenharmony_ci			if (list_is_singular(&pci_pme_list))
23988c2ecf20Sopenharmony_ci				queue_delayed_work(system_freezable_wq,
23998c2ecf20Sopenharmony_ci						   &pci_pme_work,
24008c2ecf20Sopenharmony_ci						   msecs_to_jiffies(PME_TIMEOUT));
24018c2ecf20Sopenharmony_ci			mutex_unlock(&pci_pme_list_mutex);
24028c2ecf20Sopenharmony_ci		} else {
24038c2ecf20Sopenharmony_ci			mutex_lock(&pci_pme_list_mutex);
24048c2ecf20Sopenharmony_ci			list_for_each_entry(pme_dev, &pci_pme_list, list) {
24058c2ecf20Sopenharmony_ci				if (pme_dev->dev == dev) {
24068c2ecf20Sopenharmony_ci					list_del(&pme_dev->list);
24078c2ecf20Sopenharmony_ci					kfree(pme_dev);
24088c2ecf20Sopenharmony_ci					break;
24098c2ecf20Sopenharmony_ci				}
24108c2ecf20Sopenharmony_ci			}
24118c2ecf20Sopenharmony_ci			mutex_unlock(&pci_pme_list_mutex);
24128c2ecf20Sopenharmony_ci		}
24138c2ecf20Sopenharmony_ci	}
24148c2ecf20Sopenharmony_ci
24158c2ecf20Sopenharmony_ci	pci_dbg(dev, "PME# %s\n", enable ? "enabled" : "disabled");
24168c2ecf20Sopenharmony_ci}
24178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_pme_active);
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_ci/**
24208c2ecf20Sopenharmony_ci * __pci_enable_wake - enable PCI device as wakeup event source
24218c2ecf20Sopenharmony_ci * @dev: PCI device affected
24228c2ecf20Sopenharmony_ci * @state: PCI state from which device will issue wakeup events
24238c2ecf20Sopenharmony_ci * @enable: True to enable event generation; false to disable
24248c2ecf20Sopenharmony_ci *
24258c2ecf20Sopenharmony_ci * This enables the device as a wakeup event source, or disables it.
24268c2ecf20Sopenharmony_ci * When such events involves platform-specific hooks, those hooks are
24278c2ecf20Sopenharmony_ci * called automatically by this routine.
24288c2ecf20Sopenharmony_ci *
24298c2ecf20Sopenharmony_ci * Devices with legacy power management (no standard PCI PM capabilities)
24308c2ecf20Sopenharmony_ci * always require such platform hooks.
24318c2ecf20Sopenharmony_ci *
24328c2ecf20Sopenharmony_ci * RETURN VALUE:
24338c2ecf20Sopenharmony_ci * 0 is returned on success
24348c2ecf20Sopenharmony_ci * -EINVAL is returned if device is not supposed to wake up the system
24358c2ecf20Sopenharmony_ci * Error code depending on the platform is returned if both the platform and
24368c2ecf20Sopenharmony_ci * the native mechanism fail to enable the generation of wake-up events
24378c2ecf20Sopenharmony_ci */
24388c2ecf20Sopenharmony_cistatic int __pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
24398c2ecf20Sopenharmony_ci{
24408c2ecf20Sopenharmony_ci	int ret = 0;
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci	/*
24438c2ecf20Sopenharmony_ci	 * Bridges that are not power-manageable directly only signal
24448c2ecf20Sopenharmony_ci	 * wakeup on behalf of subordinate devices which is set up
24458c2ecf20Sopenharmony_ci	 * elsewhere, so skip them. However, bridges that are
24468c2ecf20Sopenharmony_ci	 * power-manageable may signal wakeup for themselves (for example,
24478c2ecf20Sopenharmony_ci	 * on a hotplug event) and they need to be covered here.
24488c2ecf20Sopenharmony_ci	 */
24498c2ecf20Sopenharmony_ci	if (!pci_power_manageable(dev))
24508c2ecf20Sopenharmony_ci		return 0;
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci	/* Don't do the same thing twice in a row for one device. */
24538c2ecf20Sopenharmony_ci	if (!!enable == !!dev->wakeup_prepared)
24548c2ecf20Sopenharmony_ci		return 0;
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci	/*
24578c2ecf20Sopenharmony_ci	 * According to "PCI System Architecture" 4th ed. by Tom Shanley & Don
24588c2ecf20Sopenharmony_ci	 * Anderson we should be doing PME# wake enable followed by ACPI wake
24598c2ecf20Sopenharmony_ci	 * enable.  To disable wake-up we call the platform first, for symmetry.
24608c2ecf20Sopenharmony_ci	 */
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_ci	if (enable) {
24638c2ecf20Sopenharmony_ci		int error;
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci		/*
24668c2ecf20Sopenharmony_ci		 * Enable PME signaling if the device can signal PME from
24678c2ecf20Sopenharmony_ci		 * D3cold regardless of whether or not it can signal PME from
24688c2ecf20Sopenharmony_ci		 * the current target state, because that will allow it to
24698c2ecf20Sopenharmony_ci		 * signal PME when the hierarchy above it goes into D3cold and
24708c2ecf20Sopenharmony_ci		 * the device itself ends up in D3cold as a result of that.
24718c2ecf20Sopenharmony_ci		 */
24728c2ecf20Sopenharmony_ci		if (pci_pme_capable(dev, state) || pci_pme_capable(dev, PCI_D3cold))
24738c2ecf20Sopenharmony_ci			pci_pme_active(dev, true);
24748c2ecf20Sopenharmony_ci		else
24758c2ecf20Sopenharmony_ci			ret = 1;
24768c2ecf20Sopenharmony_ci		error = platform_pci_set_wakeup(dev, true);
24778c2ecf20Sopenharmony_ci		if (ret)
24788c2ecf20Sopenharmony_ci			ret = error;
24798c2ecf20Sopenharmony_ci		if (!ret)
24808c2ecf20Sopenharmony_ci			dev->wakeup_prepared = true;
24818c2ecf20Sopenharmony_ci	} else {
24828c2ecf20Sopenharmony_ci		platform_pci_set_wakeup(dev, false);
24838c2ecf20Sopenharmony_ci		pci_pme_active(dev, false);
24848c2ecf20Sopenharmony_ci		dev->wakeup_prepared = false;
24858c2ecf20Sopenharmony_ci	}
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci	return ret;
24888c2ecf20Sopenharmony_ci}
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_ci/**
24918c2ecf20Sopenharmony_ci * pci_enable_wake - change wakeup settings for a PCI device
24928c2ecf20Sopenharmony_ci * @pci_dev: Target device
24938c2ecf20Sopenharmony_ci * @state: PCI state from which device will issue wakeup events
24948c2ecf20Sopenharmony_ci * @enable: Whether or not to enable event generation
24958c2ecf20Sopenharmony_ci *
24968c2ecf20Sopenharmony_ci * If @enable is set, check device_may_wakeup() for the device before calling
24978c2ecf20Sopenharmony_ci * __pci_enable_wake() for it.
24988c2ecf20Sopenharmony_ci */
24998c2ecf20Sopenharmony_ciint pci_enable_wake(struct pci_dev *pci_dev, pci_power_t state, bool enable)
25008c2ecf20Sopenharmony_ci{
25018c2ecf20Sopenharmony_ci	if (enable && !device_may_wakeup(&pci_dev->dev))
25028c2ecf20Sopenharmony_ci		return -EINVAL;
25038c2ecf20Sopenharmony_ci
25048c2ecf20Sopenharmony_ci	return __pci_enable_wake(pci_dev, state, enable);
25058c2ecf20Sopenharmony_ci}
25068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_enable_wake);
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_ci/**
25098c2ecf20Sopenharmony_ci * pci_wake_from_d3 - enable/disable device to wake up from D3_hot or D3_cold
25108c2ecf20Sopenharmony_ci * @dev: PCI device to prepare
25118c2ecf20Sopenharmony_ci * @enable: True to enable wake-up event generation; false to disable
25128c2ecf20Sopenharmony_ci *
25138c2ecf20Sopenharmony_ci * Many drivers want the device to wake up the system from D3_hot or D3_cold
25148c2ecf20Sopenharmony_ci * and this function allows them to set that up cleanly - pci_enable_wake()
25158c2ecf20Sopenharmony_ci * should not be called twice in a row to enable wake-up due to PCI PM vs ACPI
25168c2ecf20Sopenharmony_ci * ordering constraints.
25178c2ecf20Sopenharmony_ci *
25188c2ecf20Sopenharmony_ci * This function only returns error code if the device is not allowed to wake
25198c2ecf20Sopenharmony_ci * up the system from sleep or it is not capable of generating PME# from both
25208c2ecf20Sopenharmony_ci * D3_hot and D3_cold and the platform is unable to enable wake-up power for it.
25218c2ecf20Sopenharmony_ci */
25228c2ecf20Sopenharmony_ciint pci_wake_from_d3(struct pci_dev *dev, bool enable)
25238c2ecf20Sopenharmony_ci{
25248c2ecf20Sopenharmony_ci	return pci_pme_capable(dev, PCI_D3cold) ?
25258c2ecf20Sopenharmony_ci			pci_enable_wake(dev, PCI_D3cold, enable) :
25268c2ecf20Sopenharmony_ci			pci_enable_wake(dev, PCI_D3hot, enable);
25278c2ecf20Sopenharmony_ci}
25288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_wake_from_d3);
25298c2ecf20Sopenharmony_ci
25308c2ecf20Sopenharmony_ci/**
25318c2ecf20Sopenharmony_ci * pci_target_state - find an appropriate low power state for a given PCI dev
25328c2ecf20Sopenharmony_ci * @dev: PCI device
25338c2ecf20Sopenharmony_ci * @wakeup: Whether or not wakeup functionality will be enabled for the device.
25348c2ecf20Sopenharmony_ci *
25358c2ecf20Sopenharmony_ci * Use underlying platform code to find a supported low power state for @dev.
25368c2ecf20Sopenharmony_ci * If the platform can't manage @dev, return the deepest state from which it
25378c2ecf20Sopenharmony_ci * can generate wake events, based on any available PME info.
25388c2ecf20Sopenharmony_ci */
25398c2ecf20Sopenharmony_cistatic pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup)
25408c2ecf20Sopenharmony_ci{
25418c2ecf20Sopenharmony_ci	pci_power_t target_state = PCI_D3hot;
25428c2ecf20Sopenharmony_ci
25438c2ecf20Sopenharmony_ci	if (platform_pci_power_manageable(dev)) {
25448c2ecf20Sopenharmony_ci		/*
25458c2ecf20Sopenharmony_ci		 * Call the platform to find the target state for the device.
25468c2ecf20Sopenharmony_ci		 */
25478c2ecf20Sopenharmony_ci		pci_power_t state = platform_pci_choose_state(dev);
25488c2ecf20Sopenharmony_ci
25498c2ecf20Sopenharmony_ci		switch (state) {
25508c2ecf20Sopenharmony_ci		case PCI_POWER_ERROR:
25518c2ecf20Sopenharmony_ci		case PCI_UNKNOWN:
25528c2ecf20Sopenharmony_ci			break;
25538c2ecf20Sopenharmony_ci		case PCI_D1:
25548c2ecf20Sopenharmony_ci		case PCI_D2:
25558c2ecf20Sopenharmony_ci			if (pci_no_d1d2(dev))
25568c2ecf20Sopenharmony_ci				break;
25578c2ecf20Sopenharmony_ci			fallthrough;
25588c2ecf20Sopenharmony_ci		default:
25598c2ecf20Sopenharmony_ci			target_state = state;
25608c2ecf20Sopenharmony_ci		}
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci		return target_state;
25638c2ecf20Sopenharmony_ci	}
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci	if (!dev->pm_cap)
25668c2ecf20Sopenharmony_ci		target_state = PCI_D0;
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_ci	/*
25698c2ecf20Sopenharmony_ci	 * If the device is in D3cold even though it's not power-manageable by
25708c2ecf20Sopenharmony_ci	 * the platform, it may have been powered down by non-standard means.
25718c2ecf20Sopenharmony_ci	 * Best to let it slumber.
25728c2ecf20Sopenharmony_ci	 */
25738c2ecf20Sopenharmony_ci	if (dev->current_state == PCI_D3cold)
25748c2ecf20Sopenharmony_ci		target_state = PCI_D3cold;
25758c2ecf20Sopenharmony_ci
25768c2ecf20Sopenharmony_ci	if (wakeup && dev->pme_support) {
25778c2ecf20Sopenharmony_ci		pci_power_t state = target_state;
25788c2ecf20Sopenharmony_ci
25798c2ecf20Sopenharmony_ci		/*
25808c2ecf20Sopenharmony_ci		 * Find the deepest state from which the device can generate
25818c2ecf20Sopenharmony_ci		 * PME#.
25828c2ecf20Sopenharmony_ci		 */
25838c2ecf20Sopenharmony_ci		while (state && !(dev->pme_support & (1 << state)))
25848c2ecf20Sopenharmony_ci			state--;
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_ci		if (state)
25878c2ecf20Sopenharmony_ci			return state;
25888c2ecf20Sopenharmony_ci		else if (dev->pme_support & 1)
25898c2ecf20Sopenharmony_ci			return PCI_D0;
25908c2ecf20Sopenharmony_ci	}
25918c2ecf20Sopenharmony_ci
25928c2ecf20Sopenharmony_ci	return target_state;
25938c2ecf20Sopenharmony_ci}
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci/**
25968c2ecf20Sopenharmony_ci * pci_prepare_to_sleep - prepare PCI device for system-wide transition
25978c2ecf20Sopenharmony_ci *			  into a sleep state
25988c2ecf20Sopenharmony_ci * @dev: Device to handle.
25998c2ecf20Sopenharmony_ci *
26008c2ecf20Sopenharmony_ci * Choose the power state appropriate for the device depending on whether
26018c2ecf20Sopenharmony_ci * it can wake up the system and/or is power manageable by the platform
26028c2ecf20Sopenharmony_ci * (PCI_D3hot is the default) and put the device into that state.
26038c2ecf20Sopenharmony_ci */
26048c2ecf20Sopenharmony_ciint pci_prepare_to_sleep(struct pci_dev *dev)
26058c2ecf20Sopenharmony_ci{
26068c2ecf20Sopenharmony_ci	bool wakeup = device_may_wakeup(&dev->dev);
26078c2ecf20Sopenharmony_ci	pci_power_t target_state = pci_target_state(dev, wakeup);
26088c2ecf20Sopenharmony_ci	int error;
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci	if (target_state == PCI_POWER_ERROR)
26118c2ecf20Sopenharmony_ci		return -EIO;
26128c2ecf20Sopenharmony_ci
26138c2ecf20Sopenharmony_ci	pci_enable_wake(dev, target_state, wakeup);
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_ci	error = pci_set_power_state(dev, target_state);
26168c2ecf20Sopenharmony_ci
26178c2ecf20Sopenharmony_ci	if (error)
26188c2ecf20Sopenharmony_ci		pci_enable_wake(dev, target_state, false);
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ci	return error;
26218c2ecf20Sopenharmony_ci}
26228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_prepare_to_sleep);
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_ci/**
26258c2ecf20Sopenharmony_ci * pci_back_from_sleep - turn PCI device on during system-wide transition
26268c2ecf20Sopenharmony_ci *			 into working state
26278c2ecf20Sopenharmony_ci * @dev: Device to handle.
26288c2ecf20Sopenharmony_ci *
26298c2ecf20Sopenharmony_ci * Disable device's system wake-up capability and put it into D0.
26308c2ecf20Sopenharmony_ci */
26318c2ecf20Sopenharmony_ciint pci_back_from_sleep(struct pci_dev *dev)
26328c2ecf20Sopenharmony_ci{
26338c2ecf20Sopenharmony_ci	pci_enable_wake(dev, PCI_D0, false);
26348c2ecf20Sopenharmony_ci	return pci_set_power_state(dev, PCI_D0);
26358c2ecf20Sopenharmony_ci}
26368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_back_from_sleep);
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_ci/**
26398c2ecf20Sopenharmony_ci * pci_finish_runtime_suspend - Carry out PCI-specific part of runtime suspend.
26408c2ecf20Sopenharmony_ci * @dev: PCI device being suspended.
26418c2ecf20Sopenharmony_ci *
26428c2ecf20Sopenharmony_ci * Prepare @dev to generate wake-up events at run time and put it into a low
26438c2ecf20Sopenharmony_ci * power state.
26448c2ecf20Sopenharmony_ci */
26458c2ecf20Sopenharmony_ciint pci_finish_runtime_suspend(struct pci_dev *dev)
26468c2ecf20Sopenharmony_ci{
26478c2ecf20Sopenharmony_ci	pci_power_t target_state;
26488c2ecf20Sopenharmony_ci	int error;
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci	target_state = pci_target_state(dev, device_can_wakeup(&dev->dev));
26518c2ecf20Sopenharmony_ci	if (target_state == PCI_POWER_ERROR)
26528c2ecf20Sopenharmony_ci		return -EIO;
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_ci	dev->runtime_d3cold = target_state == PCI_D3cold;
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_ci	__pci_enable_wake(dev, target_state, pci_dev_run_wake(dev));
26578c2ecf20Sopenharmony_ci
26588c2ecf20Sopenharmony_ci	error = pci_set_power_state(dev, target_state);
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_ci	if (error) {
26618c2ecf20Sopenharmony_ci		pci_enable_wake(dev, target_state, false);
26628c2ecf20Sopenharmony_ci		dev->runtime_d3cold = false;
26638c2ecf20Sopenharmony_ci	}
26648c2ecf20Sopenharmony_ci
26658c2ecf20Sopenharmony_ci	return error;
26668c2ecf20Sopenharmony_ci}
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ci/**
26698c2ecf20Sopenharmony_ci * pci_dev_run_wake - Check if device can generate run-time wake-up events.
26708c2ecf20Sopenharmony_ci * @dev: Device to check.
26718c2ecf20Sopenharmony_ci *
26728c2ecf20Sopenharmony_ci * Return true if the device itself is capable of generating wake-up events
26738c2ecf20Sopenharmony_ci * (through the platform or using the native PCIe PME) or if the device supports
26748c2ecf20Sopenharmony_ci * PME and one of its upstream bridges can generate wake-up events.
26758c2ecf20Sopenharmony_ci */
26768c2ecf20Sopenharmony_cibool pci_dev_run_wake(struct pci_dev *dev)
26778c2ecf20Sopenharmony_ci{
26788c2ecf20Sopenharmony_ci	struct pci_bus *bus = dev->bus;
26798c2ecf20Sopenharmony_ci
26808c2ecf20Sopenharmony_ci	if (!dev->pme_support)
26818c2ecf20Sopenharmony_ci		return false;
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci	/* PME-capable in principle, but not from the target power state */
26848c2ecf20Sopenharmony_ci	if (!pci_pme_capable(dev, pci_target_state(dev, true)))
26858c2ecf20Sopenharmony_ci		return false;
26868c2ecf20Sopenharmony_ci
26878c2ecf20Sopenharmony_ci	if (device_can_wakeup(&dev->dev))
26888c2ecf20Sopenharmony_ci		return true;
26898c2ecf20Sopenharmony_ci
26908c2ecf20Sopenharmony_ci	while (bus->parent) {
26918c2ecf20Sopenharmony_ci		struct pci_dev *bridge = bus->self;
26928c2ecf20Sopenharmony_ci
26938c2ecf20Sopenharmony_ci		if (device_can_wakeup(&bridge->dev))
26948c2ecf20Sopenharmony_ci			return true;
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_ci		bus = bus->parent;
26978c2ecf20Sopenharmony_ci	}
26988c2ecf20Sopenharmony_ci
26998c2ecf20Sopenharmony_ci	/* We have reached the root bus. */
27008c2ecf20Sopenharmony_ci	if (bus->bridge)
27018c2ecf20Sopenharmony_ci		return device_can_wakeup(bus->bridge);
27028c2ecf20Sopenharmony_ci
27038c2ecf20Sopenharmony_ci	return false;
27048c2ecf20Sopenharmony_ci}
27058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_dev_run_wake);
27068c2ecf20Sopenharmony_ci
27078c2ecf20Sopenharmony_ci/**
27088c2ecf20Sopenharmony_ci * pci_dev_need_resume - Check if it is necessary to resume the device.
27098c2ecf20Sopenharmony_ci * @pci_dev: Device to check.
27108c2ecf20Sopenharmony_ci *
27118c2ecf20Sopenharmony_ci * Return 'true' if the device is not runtime-suspended or it has to be
27128c2ecf20Sopenharmony_ci * reconfigured due to wakeup settings difference between system and runtime
27138c2ecf20Sopenharmony_ci * suspend, or the current power state of it is not suitable for the upcoming
27148c2ecf20Sopenharmony_ci * (system-wide) transition.
27158c2ecf20Sopenharmony_ci */
27168c2ecf20Sopenharmony_cibool pci_dev_need_resume(struct pci_dev *pci_dev)
27178c2ecf20Sopenharmony_ci{
27188c2ecf20Sopenharmony_ci	struct device *dev = &pci_dev->dev;
27198c2ecf20Sopenharmony_ci	pci_power_t target_state;
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci	if (!pm_runtime_suspended(dev) || platform_pci_need_resume(pci_dev))
27228c2ecf20Sopenharmony_ci		return true;
27238c2ecf20Sopenharmony_ci
27248c2ecf20Sopenharmony_ci	target_state = pci_target_state(pci_dev, device_may_wakeup(dev));
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_ci	/*
27278c2ecf20Sopenharmony_ci	 * If the earlier platform check has not triggered, D3cold is just power
27288c2ecf20Sopenharmony_ci	 * removal on top of D3hot, so no need to resume the device in that
27298c2ecf20Sopenharmony_ci	 * case.
27308c2ecf20Sopenharmony_ci	 */
27318c2ecf20Sopenharmony_ci	return target_state != pci_dev->current_state &&
27328c2ecf20Sopenharmony_ci		target_state != PCI_D3cold &&
27338c2ecf20Sopenharmony_ci		pci_dev->current_state != PCI_D3hot;
27348c2ecf20Sopenharmony_ci}
27358c2ecf20Sopenharmony_ci
27368c2ecf20Sopenharmony_ci/**
27378c2ecf20Sopenharmony_ci * pci_dev_adjust_pme - Adjust PME setting for a suspended device.
27388c2ecf20Sopenharmony_ci * @pci_dev: Device to check.
27398c2ecf20Sopenharmony_ci *
27408c2ecf20Sopenharmony_ci * If the device is suspended and it is not configured for system wakeup,
27418c2ecf20Sopenharmony_ci * disable PME for it to prevent it from waking up the system unnecessarily.
27428c2ecf20Sopenharmony_ci *
27438c2ecf20Sopenharmony_ci * Note that if the device's power state is D3cold and the platform check in
27448c2ecf20Sopenharmony_ci * pci_dev_need_resume() has not triggered, the device's configuration need not
27458c2ecf20Sopenharmony_ci * be changed.
27468c2ecf20Sopenharmony_ci */
27478c2ecf20Sopenharmony_civoid pci_dev_adjust_pme(struct pci_dev *pci_dev)
27488c2ecf20Sopenharmony_ci{
27498c2ecf20Sopenharmony_ci	struct device *dev = &pci_dev->dev;
27508c2ecf20Sopenharmony_ci
27518c2ecf20Sopenharmony_ci	spin_lock_irq(&dev->power.lock);
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci	if (pm_runtime_suspended(dev) && !device_may_wakeup(dev) &&
27548c2ecf20Sopenharmony_ci	    pci_dev->current_state < PCI_D3cold)
27558c2ecf20Sopenharmony_ci		__pci_pme_active(pci_dev, false);
27568c2ecf20Sopenharmony_ci
27578c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev->power.lock);
27588c2ecf20Sopenharmony_ci}
27598c2ecf20Sopenharmony_ci
27608c2ecf20Sopenharmony_ci/**
27618c2ecf20Sopenharmony_ci * pci_dev_complete_resume - Finalize resume from system sleep for a device.
27628c2ecf20Sopenharmony_ci * @pci_dev: Device to handle.
27638c2ecf20Sopenharmony_ci *
27648c2ecf20Sopenharmony_ci * If the device is runtime suspended and wakeup-capable, enable PME for it as
27658c2ecf20Sopenharmony_ci * it might have been disabled during the prepare phase of system suspend if
27668c2ecf20Sopenharmony_ci * the device was not configured for system wakeup.
27678c2ecf20Sopenharmony_ci */
27688c2ecf20Sopenharmony_civoid pci_dev_complete_resume(struct pci_dev *pci_dev)
27698c2ecf20Sopenharmony_ci{
27708c2ecf20Sopenharmony_ci	struct device *dev = &pci_dev->dev;
27718c2ecf20Sopenharmony_ci
27728c2ecf20Sopenharmony_ci	if (!pci_dev_run_wake(pci_dev))
27738c2ecf20Sopenharmony_ci		return;
27748c2ecf20Sopenharmony_ci
27758c2ecf20Sopenharmony_ci	spin_lock_irq(&dev->power.lock);
27768c2ecf20Sopenharmony_ci
27778c2ecf20Sopenharmony_ci	if (pm_runtime_suspended(dev) && pci_dev->current_state < PCI_D3cold)
27788c2ecf20Sopenharmony_ci		__pci_pme_active(pci_dev, true);
27798c2ecf20Sopenharmony_ci
27808c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev->power.lock);
27818c2ecf20Sopenharmony_ci}
27828c2ecf20Sopenharmony_ci
27838c2ecf20Sopenharmony_civoid pci_config_pm_runtime_get(struct pci_dev *pdev)
27848c2ecf20Sopenharmony_ci{
27858c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
27868c2ecf20Sopenharmony_ci	struct device *parent = dev->parent;
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_ci	if (parent)
27898c2ecf20Sopenharmony_ci		pm_runtime_get_sync(parent);
27908c2ecf20Sopenharmony_ci	pm_runtime_get_noresume(dev);
27918c2ecf20Sopenharmony_ci	/*
27928c2ecf20Sopenharmony_ci	 * pdev->current_state is set to PCI_D3cold during suspending,
27938c2ecf20Sopenharmony_ci	 * so wait until suspending completes
27948c2ecf20Sopenharmony_ci	 */
27958c2ecf20Sopenharmony_ci	pm_runtime_barrier(dev);
27968c2ecf20Sopenharmony_ci	/*
27978c2ecf20Sopenharmony_ci	 * Only need to resume devices in D3cold, because config
27988c2ecf20Sopenharmony_ci	 * registers are still accessible for devices suspended but
27998c2ecf20Sopenharmony_ci	 * not in D3cold.
28008c2ecf20Sopenharmony_ci	 */
28018c2ecf20Sopenharmony_ci	if (pdev->current_state == PCI_D3cold)
28028c2ecf20Sopenharmony_ci		pm_runtime_resume(dev);
28038c2ecf20Sopenharmony_ci}
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_civoid pci_config_pm_runtime_put(struct pci_dev *pdev)
28068c2ecf20Sopenharmony_ci{
28078c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
28088c2ecf20Sopenharmony_ci	struct device *parent = dev->parent;
28098c2ecf20Sopenharmony_ci
28108c2ecf20Sopenharmony_ci	pm_runtime_put(dev);
28118c2ecf20Sopenharmony_ci	if (parent)
28128c2ecf20Sopenharmony_ci		pm_runtime_put_sync(parent);
28138c2ecf20Sopenharmony_ci}
28148c2ecf20Sopenharmony_ci
28158c2ecf20Sopenharmony_cistatic const struct dmi_system_id bridge_d3_blacklist[] = {
28168c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
28178c2ecf20Sopenharmony_ci	{
28188c2ecf20Sopenharmony_ci		/*
28198c2ecf20Sopenharmony_ci		 * Gigabyte X299 root port is not marked as hotplug capable
28208c2ecf20Sopenharmony_ci		 * which allows Linux to power manage it.  However, this
28218c2ecf20Sopenharmony_ci		 * confuses the BIOS SMI handler so don't power manage root
28228c2ecf20Sopenharmony_ci		 * ports on that system.
28238c2ecf20Sopenharmony_ci		 */
28248c2ecf20Sopenharmony_ci		.ident = "X299 DESIGNARE EX-CF",
28258c2ecf20Sopenharmony_ci		.matches = {
28268c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
28278c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "X299 DESIGNARE EX-CF"),
28288c2ecf20Sopenharmony_ci		},
28298c2ecf20Sopenharmony_ci	},
28308c2ecf20Sopenharmony_ci	{
28318c2ecf20Sopenharmony_ci		/*
28328c2ecf20Sopenharmony_ci		 * Downstream device is not accessible after putting a root port
28338c2ecf20Sopenharmony_ci		 * into D3cold and back into D0 on Elo Continental Z2 board
28348c2ecf20Sopenharmony_ci		 */
28358c2ecf20Sopenharmony_ci		.ident = "Elo Continental Z2",
28368c2ecf20Sopenharmony_ci		.matches = {
28378c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Elo Touch Solutions"),
28388c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "Geminilake"),
28398c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VERSION, "Continental Z2"),
28408c2ecf20Sopenharmony_ci		},
28418c2ecf20Sopenharmony_ci	},
28428c2ecf20Sopenharmony_ci#endif
28438c2ecf20Sopenharmony_ci	{ }
28448c2ecf20Sopenharmony_ci};
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci/**
28478c2ecf20Sopenharmony_ci * pci_bridge_d3_possible - Is it possible to put the bridge into D3
28488c2ecf20Sopenharmony_ci * @bridge: Bridge to check
28498c2ecf20Sopenharmony_ci *
28508c2ecf20Sopenharmony_ci * This function checks if it is possible to move the bridge to D3.
28518c2ecf20Sopenharmony_ci * Currently we only allow D3 for recent enough PCIe ports and Thunderbolt.
28528c2ecf20Sopenharmony_ci */
28538c2ecf20Sopenharmony_cibool pci_bridge_d3_possible(struct pci_dev *bridge)
28548c2ecf20Sopenharmony_ci{
28558c2ecf20Sopenharmony_ci	if (!pci_is_pcie(bridge))
28568c2ecf20Sopenharmony_ci		return false;
28578c2ecf20Sopenharmony_ci
28588c2ecf20Sopenharmony_ci	switch (pci_pcie_type(bridge)) {
28598c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_ROOT_PORT:
28608c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_UPSTREAM:
28618c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_DOWNSTREAM:
28628c2ecf20Sopenharmony_ci		if (pci_bridge_d3_disable)
28638c2ecf20Sopenharmony_ci			return false;
28648c2ecf20Sopenharmony_ci
28658c2ecf20Sopenharmony_ci		/*
28668c2ecf20Sopenharmony_ci		 * Hotplug ports handled by firmware in System Management Mode
28678c2ecf20Sopenharmony_ci		 * may not be put into D3 by the OS (Thunderbolt on non-Macs).
28688c2ecf20Sopenharmony_ci		 */
28698c2ecf20Sopenharmony_ci		if (bridge->is_hotplug_bridge && !pciehp_is_native(bridge))
28708c2ecf20Sopenharmony_ci			return false;
28718c2ecf20Sopenharmony_ci
28728c2ecf20Sopenharmony_ci		if (pci_bridge_d3_force)
28738c2ecf20Sopenharmony_ci			return true;
28748c2ecf20Sopenharmony_ci
28758c2ecf20Sopenharmony_ci		/* Even the oldest 2010 Thunderbolt controller supports D3. */
28768c2ecf20Sopenharmony_ci		if (bridge->is_thunderbolt)
28778c2ecf20Sopenharmony_ci			return true;
28788c2ecf20Sopenharmony_ci
28798c2ecf20Sopenharmony_ci		/* Platform might know better if the bridge supports D3 */
28808c2ecf20Sopenharmony_ci		if (platform_pci_bridge_d3(bridge))
28818c2ecf20Sopenharmony_ci			return true;
28828c2ecf20Sopenharmony_ci
28838c2ecf20Sopenharmony_ci		/*
28848c2ecf20Sopenharmony_ci		 * Hotplug ports handled natively by the OS were not validated
28858c2ecf20Sopenharmony_ci		 * by vendors for runtime D3 at least until 2018 because there
28868c2ecf20Sopenharmony_ci		 * was no OS support.
28878c2ecf20Sopenharmony_ci		 */
28888c2ecf20Sopenharmony_ci		if (bridge->is_hotplug_bridge)
28898c2ecf20Sopenharmony_ci			return false;
28908c2ecf20Sopenharmony_ci
28918c2ecf20Sopenharmony_ci		if (dmi_check_system(bridge_d3_blacklist))
28928c2ecf20Sopenharmony_ci			return false;
28938c2ecf20Sopenharmony_ci
28948c2ecf20Sopenharmony_ci		/*
28958c2ecf20Sopenharmony_ci		 * It should be safe to put PCIe ports from 2015 or newer
28968c2ecf20Sopenharmony_ci		 * to D3.
28978c2ecf20Sopenharmony_ci		 */
28988c2ecf20Sopenharmony_ci		if (dmi_get_bios_year() >= 2015)
28998c2ecf20Sopenharmony_ci			return true;
29008c2ecf20Sopenharmony_ci		break;
29018c2ecf20Sopenharmony_ci	}
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci	return false;
29048c2ecf20Sopenharmony_ci}
29058c2ecf20Sopenharmony_ci
29068c2ecf20Sopenharmony_cistatic int pci_dev_check_d3cold(struct pci_dev *dev, void *data)
29078c2ecf20Sopenharmony_ci{
29088c2ecf20Sopenharmony_ci	bool *d3cold_ok = data;
29098c2ecf20Sopenharmony_ci
29108c2ecf20Sopenharmony_ci	if (/* The device needs to be allowed to go D3cold ... */
29118c2ecf20Sopenharmony_ci	    dev->no_d3cold || !dev->d3cold_allowed ||
29128c2ecf20Sopenharmony_ci
29138c2ecf20Sopenharmony_ci	    /* ... and if it is wakeup capable to do so from D3cold. */
29148c2ecf20Sopenharmony_ci	    (device_may_wakeup(&dev->dev) &&
29158c2ecf20Sopenharmony_ci	     !pci_pme_capable(dev, PCI_D3cold)) ||
29168c2ecf20Sopenharmony_ci
29178c2ecf20Sopenharmony_ci	    /* If it is a bridge it must be allowed to go to D3. */
29188c2ecf20Sopenharmony_ci	    !pci_power_manageable(dev))
29198c2ecf20Sopenharmony_ci
29208c2ecf20Sopenharmony_ci		*d3cold_ok = false;
29218c2ecf20Sopenharmony_ci
29228c2ecf20Sopenharmony_ci	return !*d3cold_ok;
29238c2ecf20Sopenharmony_ci}
29248c2ecf20Sopenharmony_ci
29258c2ecf20Sopenharmony_ci/*
29268c2ecf20Sopenharmony_ci * pci_bridge_d3_update - Update bridge D3 capabilities
29278c2ecf20Sopenharmony_ci * @dev: PCI device which is changed
29288c2ecf20Sopenharmony_ci *
29298c2ecf20Sopenharmony_ci * Update upstream bridge PM capabilities accordingly depending on if the
29308c2ecf20Sopenharmony_ci * device PM configuration was changed or the device is being removed.  The
29318c2ecf20Sopenharmony_ci * change is also propagated upstream.
29328c2ecf20Sopenharmony_ci */
29338c2ecf20Sopenharmony_civoid pci_bridge_d3_update(struct pci_dev *dev)
29348c2ecf20Sopenharmony_ci{
29358c2ecf20Sopenharmony_ci	bool remove = !device_is_registered(&dev->dev);
29368c2ecf20Sopenharmony_ci	struct pci_dev *bridge;
29378c2ecf20Sopenharmony_ci	bool d3cold_ok = true;
29388c2ecf20Sopenharmony_ci
29398c2ecf20Sopenharmony_ci	bridge = pci_upstream_bridge(dev);
29408c2ecf20Sopenharmony_ci	if (!bridge || !pci_bridge_d3_possible(bridge))
29418c2ecf20Sopenharmony_ci		return;
29428c2ecf20Sopenharmony_ci
29438c2ecf20Sopenharmony_ci	/*
29448c2ecf20Sopenharmony_ci	 * If D3 is currently allowed for the bridge, removing one of its
29458c2ecf20Sopenharmony_ci	 * children won't change that.
29468c2ecf20Sopenharmony_ci	 */
29478c2ecf20Sopenharmony_ci	if (remove && bridge->bridge_d3)
29488c2ecf20Sopenharmony_ci		return;
29498c2ecf20Sopenharmony_ci
29508c2ecf20Sopenharmony_ci	/*
29518c2ecf20Sopenharmony_ci	 * If D3 is currently allowed for the bridge and a child is added or
29528c2ecf20Sopenharmony_ci	 * changed, disallowance of D3 can only be caused by that child, so
29538c2ecf20Sopenharmony_ci	 * we only need to check that single device, not any of its siblings.
29548c2ecf20Sopenharmony_ci	 *
29558c2ecf20Sopenharmony_ci	 * If D3 is currently not allowed for the bridge, checking the device
29568c2ecf20Sopenharmony_ci	 * first may allow us to skip checking its siblings.
29578c2ecf20Sopenharmony_ci	 */
29588c2ecf20Sopenharmony_ci	if (!remove)
29598c2ecf20Sopenharmony_ci		pci_dev_check_d3cold(dev, &d3cold_ok);
29608c2ecf20Sopenharmony_ci
29618c2ecf20Sopenharmony_ci	/*
29628c2ecf20Sopenharmony_ci	 * If D3 is currently not allowed for the bridge, this may be caused
29638c2ecf20Sopenharmony_ci	 * either by the device being changed/removed or any of its siblings,
29648c2ecf20Sopenharmony_ci	 * so we need to go through all children to find out if one of them
29658c2ecf20Sopenharmony_ci	 * continues to block D3.
29668c2ecf20Sopenharmony_ci	 */
29678c2ecf20Sopenharmony_ci	if (d3cold_ok && !bridge->bridge_d3)
29688c2ecf20Sopenharmony_ci		pci_walk_bus(bridge->subordinate, pci_dev_check_d3cold,
29698c2ecf20Sopenharmony_ci			     &d3cold_ok);
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci	if (bridge->bridge_d3 != d3cold_ok) {
29728c2ecf20Sopenharmony_ci		bridge->bridge_d3 = d3cold_ok;
29738c2ecf20Sopenharmony_ci		/* Propagate change to upstream bridges */
29748c2ecf20Sopenharmony_ci		pci_bridge_d3_update(bridge);
29758c2ecf20Sopenharmony_ci	}
29768c2ecf20Sopenharmony_ci}
29778c2ecf20Sopenharmony_ci
29788c2ecf20Sopenharmony_ci/**
29798c2ecf20Sopenharmony_ci * pci_d3cold_enable - Enable D3cold for device
29808c2ecf20Sopenharmony_ci * @dev: PCI device to handle
29818c2ecf20Sopenharmony_ci *
29828c2ecf20Sopenharmony_ci * This function can be used in drivers to enable D3cold from the device
29838c2ecf20Sopenharmony_ci * they handle.  It also updates upstream PCI bridge PM capabilities
29848c2ecf20Sopenharmony_ci * accordingly.
29858c2ecf20Sopenharmony_ci */
29868c2ecf20Sopenharmony_civoid pci_d3cold_enable(struct pci_dev *dev)
29878c2ecf20Sopenharmony_ci{
29888c2ecf20Sopenharmony_ci	if (dev->no_d3cold) {
29898c2ecf20Sopenharmony_ci		dev->no_d3cold = false;
29908c2ecf20Sopenharmony_ci		pci_bridge_d3_update(dev);
29918c2ecf20Sopenharmony_ci	}
29928c2ecf20Sopenharmony_ci}
29938c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_d3cold_enable);
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_ci/**
29968c2ecf20Sopenharmony_ci * pci_d3cold_disable - Disable D3cold for device
29978c2ecf20Sopenharmony_ci * @dev: PCI device to handle
29988c2ecf20Sopenharmony_ci *
29998c2ecf20Sopenharmony_ci * This function can be used in drivers to disable D3cold from the device
30008c2ecf20Sopenharmony_ci * they handle.  It also updates upstream PCI bridge PM capabilities
30018c2ecf20Sopenharmony_ci * accordingly.
30028c2ecf20Sopenharmony_ci */
30038c2ecf20Sopenharmony_civoid pci_d3cold_disable(struct pci_dev *dev)
30048c2ecf20Sopenharmony_ci{
30058c2ecf20Sopenharmony_ci	if (!dev->no_d3cold) {
30068c2ecf20Sopenharmony_ci		dev->no_d3cold = true;
30078c2ecf20Sopenharmony_ci		pci_bridge_d3_update(dev);
30088c2ecf20Sopenharmony_ci	}
30098c2ecf20Sopenharmony_ci}
30108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_d3cold_disable);
30118c2ecf20Sopenharmony_ci
30128c2ecf20Sopenharmony_ci/**
30138c2ecf20Sopenharmony_ci * pci_pm_init - Initialize PM functions of given PCI device
30148c2ecf20Sopenharmony_ci * @dev: PCI device to handle.
30158c2ecf20Sopenharmony_ci */
30168c2ecf20Sopenharmony_civoid pci_pm_init(struct pci_dev *dev)
30178c2ecf20Sopenharmony_ci{
30188c2ecf20Sopenharmony_ci	int pm;
30198c2ecf20Sopenharmony_ci	u16 status;
30208c2ecf20Sopenharmony_ci	u16 pmc;
30218c2ecf20Sopenharmony_ci
30228c2ecf20Sopenharmony_ci	pm_runtime_forbid(&dev->dev);
30238c2ecf20Sopenharmony_ci	pm_runtime_set_active(&dev->dev);
30248c2ecf20Sopenharmony_ci	pm_runtime_enable(&dev->dev);
30258c2ecf20Sopenharmony_ci	device_enable_async_suspend(&dev->dev);
30268c2ecf20Sopenharmony_ci	dev->wakeup_prepared = false;
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_ci	dev->pm_cap = 0;
30298c2ecf20Sopenharmony_ci	dev->pme_support = 0;
30308c2ecf20Sopenharmony_ci
30318c2ecf20Sopenharmony_ci	/* find PCI PM capability in list */
30328c2ecf20Sopenharmony_ci	pm = pci_find_capability(dev, PCI_CAP_ID_PM);
30338c2ecf20Sopenharmony_ci	if (!pm)
30348c2ecf20Sopenharmony_ci		return;
30358c2ecf20Sopenharmony_ci	/* Check device's ability to generate PME# */
30368c2ecf20Sopenharmony_ci	pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc);
30378c2ecf20Sopenharmony_ci
30388c2ecf20Sopenharmony_ci	if ((pmc & PCI_PM_CAP_VER_MASK) > 3) {
30398c2ecf20Sopenharmony_ci		pci_err(dev, "unsupported PM cap regs version (%u)\n",
30408c2ecf20Sopenharmony_ci			pmc & PCI_PM_CAP_VER_MASK);
30418c2ecf20Sopenharmony_ci		return;
30428c2ecf20Sopenharmony_ci	}
30438c2ecf20Sopenharmony_ci
30448c2ecf20Sopenharmony_ci	dev->pm_cap = pm;
30458c2ecf20Sopenharmony_ci	dev->d3hot_delay = PCI_PM_D3HOT_WAIT;
30468c2ecf20Sopenharmony_ci	dev->d3cold_delay = PCI_PM_D3COLD_WAIT;
30478c2ecf20Sopenharmony_ci	dev->bridge_d3 = pci_bridge_d3_possible(dev);
30488c2ecf20Sopenharmony_ci	dev->d3cold_allowed = true;
30498c2ecf20Sopenharmony_ci
30508c2ecf20Sopenharmony_ci	dev->d1_support = false;
30518c2ecf20Sopenharmony_ci	dev->d2_support = false;
30528c2ecf20Sopenharmony_ci	if (!pci_no_d1d2(dev)) {
30538c2ecf20Sopenharmony_ci		if (pmc & PCI_PM_CAP_D1)
30548c2ecf20Sopenharmony_ci			dev->d1_support = true;
30558c2ecf20Sopenharmony_ci		if (pmc & PCI_PM_CAP_D2)
30568c2ecf20Sopenharmony_ci			dev->d2_support = true;
30578c2ecf20Sopenharmony_ci
30588c2ecf20Sopenharmony_ci		if (dev->d1_support || dev->d2_support)
30598c2ecf20Sopenharmony_ci			pci_info(dev, "supports%s%s\n",
30608c2ecf20Sopenharmony_ci				   dev->d1_support ? " D1" : "",
30618c2ecf20Sopenharmony_ci				   dev->d2_support ? " D2" : "");
30628c2ecf20Sopenharmony_ci	}
30638c2ecf20Sopenharmony_ci
30648c2ecf20Sopenharmony_ci	pmc &= PCI_PM_CAP_PME_MASK;
30658c2ecf20Sopenharmony_ci	if (pmc) {
30668c2ecf20Sopenharmony_ci		pci_info(dev, "PME# supported from%s%s%s%s%s\n",
30678c2ecf20Sopenharmony_ci			 (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "",
30688c2ecf20Sopenharmony_ci			 (pmc & PCI_PM_CAP_PME_D1) ? " D1" : "",
30698c2ecf20Sopenharmony_ci			 (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "",
30708c2ecf20Sopenharmony_ci			 (pmc & PCI_PM_CAP_PME_D3hot) ? " D3hot" : "",
30718c2ecf20Sopenharmony_ci			 (pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : "");
30728c2ecf20Sopenharmony_ci		dev->pme_support = pmc >> PCI_PM_CAP_PME_SHIFT;
30738c2ecf20Sopenharmony_ci		dev->pme_poll = true;
30748c2ecf20Sopenharmony_ci		/*
30758c2ecf20Sopenharmony_ci		 * Make device's PM flags reflect the wake-up capability, but
30768c2ecf20Sopenharmony_ci		 * let the user space enable it to wake up the system as needed.
30778c2ecf20Sopenharmony_ci		 */
30788c2ecf20Sopenharmony_ci		device_set_wakeup_capable(&dev->dev, true);
30798c2ecf20Sopenharmony_ci		/* Disable the PME# generation functionality */
30808c2ecf20Sopenharmony_ci		pci_pme_active(dev, false);
30818c2ecf20Sopenharmony_ci	}
30828c2ecf20Sopenharmony_ci
30838c2ecf20Sopenharmony_ci	pci_read_config_word(dev, PCI_STATUS, &status);
30848c2ecf20Sopenharmony_ci	if (status & PCI_STATUS_IMM_READY)
30858c2ecf20Sopenharmony_ci		dev->imm_ready = 1;
30868c2ecf20Sopenharmony_ci}
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_cistatic unsigned long pci_ea_flags(struct pci_dev *dev, u8 prop)
30898c2ecf20Sopenharmony_ci{
30908c2ecf20Sopenharmony_ci	unsigned long flags = IORESOURCE_PCI_FIXED | IORESOURCE_PCI_EA_BEI;
30918c2ecf20Sopenharmony_ci
30928c2ecf20Sopenharmony_ci	switch (prop) {
30938c2ecf20Sopenharmony_ci	case PCI_EA_P_MEM:
30948c2ecf20Sopenharmony_ci	case PCI_EA_P_VF_MEM:
30958c2ecf20Sopenharmony_ci		flags |= IORESOURCE_MEM;
30968c2ecf20Sopenharmony_ci		break;
30978c2ecf20Sopenharmony_ci	case PCI_EA_P_MEM_PREFETCH:
30988c2ecf20Sopenharmony_ci	case PCI_EA_P_VF_MEM_PREFETCH:
30998c2ecf20Sopenharmony_ci		flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
31008c2ecf20Sopenharmony_ci		break;
31018c2ecf20Sopenharmony_ci	case PCI_EA_P_IO:
31028c2ecf20Sopenharmony_ci		flags |= IORESOURCE_IO;
31038c2ecf20Sopenharmony_ci		break;
31048c2ecf20Sopenharmony_ci	default:
31058c2ecf20Sopenharmony_ci		return 0;
31068c2ecf20Sopenharmony_ci	}
31078c2ecf20Sopenharmony_ci
31088c2ecf20Sopenharmony_ci	return flags;
31098c2ecf20Sopenharmony_ci}
31108c2ecf20Sopenharmony_ci
31118c2ecf20Sopenharmony_cistatic struct resource *pci_ea_get_resource(struct pci_dev *dev, u8 bei,
31128c2ecf20Sopenharmony_ci					    u8 prop)
31138c2ecf20Sopenharmony_ci{
31148c2ecf20Sopenharmony_ci	if (bei <= PCI_EA_BEI_BAR5 && prop <= PCI_EA_P_IO)
31158c2ecf20Sopenharmony_ci		return &dev->resource[bei];
31168c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV
31178c2ecf20Sopenharmony_ci	else if (bei >= PCI_EA_BEI_VF_BAR0 && bei <= PCI_EA_BEI_VF_BAR5 &&
31188c2ecf20Sopenharmony_ci		 (prop == PCI_EA_P_VF_MEM || prop == PCI_EA_P_VF_MEM_PREFETCH))
31198c2ecf20Sopenharmony_ci		return &dev->resource[PCI_IOV_RESOURCES +
31208c2ecf20Sopenharmony_ci				      bei - PCI_EA_BEI_VF_BAR0];
31218c2ecf20Sopenharmony_ci#endif
31228c2ecf20Sopenharmony_ci	else if (bei == PCI_EA_BEI_ROM)
31238c2ecf20Sopenharmony_ci		return &dev->resource[PCI_ROM_RESOURCE];
31248c2ecf20Sopenharmony_ci	else
31258c2ecf20Sopenharmony_ci		return NULL;
31268c2ecf20Sopenharmony_ci}
31278c2ecf20Sopenharmony_ci
31288c2ecf20Sopenharmony_ci/* Read an Enhanced Allocation (EA) entry */
31298c2ecf20Sopenharmony_cistatic int pci_ea_read(struct pci_dev *dev, int offset)
31308c2ecf20Sopenharmony_ci{
31318c2ecf20Sopenharmony_ci	struct resource *res;
31328c2ecf20Sopenharmony_ci	int ent_size, ent_offset = offset;
31338c2ecf20Sopenharmony_ci	resource_size_t start, end;
31348c2ecf20Sopenharmony_ci	unsigned long flags;
31358c2ecf20Sopenharmony_ci	u32 dw0, bei, base, max_offset;
31368c2ecf20Sopenharmony_ci	u8 prop;
31378c2ecf20Sopenharmony_ci	bool support_64 = (sizeof(resource_size_t) >= 8);
31388c2ecf20Sopenharmony_ci
31398c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, ent_offset, &dw0);
31408c2ecf20Sopenharmony_ci	ent_offset += 4;
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_ci	/* Entry size field indicates DWORDs after 1st */
31438c2ecf20Sopenharmony_ci	ent_size = ((dw0 & PCI_EA_ES) + 1) << 2;
31448c2ecf20Sopenharmony_ci
31458c2ecf20Sopenharmony_ci	if (!(dw0 & PCI_EA_ENABLE)) /* Entry not enabled */
31468c2ecf20Sopenharmony_ci		goto out;
31478c2ecf20Sopenharmony_ci
31488c2ecf20Sopenharmony_ci	bei = (dw0 & PCI_EA_BEI) >> 4;
31498c2ecf20Sopenharmony_ci	prop = (dw0 & PCI_EA_PP) >> 8;
31508c2ecf20Sopenharmony_ci
31518c2ecf20Sopenharmony_ci	/*
31528c2ecf20Sopenharmony_ci	 * If the Property is in the reserved range, try the Secondary
31538c2ecf20Sopenharmony_ci	 * Property instead.
31548c2ecf20Sopenharmony_ci	 */
31558c2ecf20Sopenharmony_ci	if (prop > PCI_EA_P_BRIDGE_IO && prop < PCI_EA_P_MEM_RESERVED)
31568c2ecf20Sopenharmony_ci		prop = (dw0 & PCI_EA_SP) >> 16;
31578c2ecf20Sopenharmony_ci	if (prop > PCI_EA_P_BRIDGE_IO)
31588c2ecf20Sopenharmony_ci		goto out;
31598c2ecf20Sopenharmony_ci
31608c2ecf20Sopenharmony_ci	res = pci_ea_get_resource(dev, bei, prop);
31618c2ecf20Sopenharmony_ci	if (!res) {
31628c2ecf20Sopenharmony_ci		pci_err(dev, "Unsupported EA entry BEI: %u\n", bei);
31638c2ecf20Sopenharmony_ci		goto out;
31648c2ecf20Sopenharmony_ci	}
31658c2ecf20Sopenharmony_ci
31668c2ecf20Sopenharmony_ci	flags = pci_ea_flags(dev, prop);
31678c2ecf20Sopenharmony_ci	if (!flags) {
31688c2ecf20Sopenharmony_ci		pci_err(dev, "Unsupported EA properties: %#x\n", prop);
31698c2ecf20Sopenharmony_ci		goto out;
31708c2ecf20Sopenharmony_ci	}
31718c2ecf20Sopenharmony_ci
31728c2ecf20Sopenharmony_ci	/* Read Base */
31738c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, ent_offset, &base);
31748c2ecf20Sopenharmony_ci	start = (base & PCI_EA_FIELD_MASK);
31758c2ecf20Sopenharmony_ci	ent_offset += 4;
31768c2ecf20Sopenharmony_ci
31778c2ecf20Sopenharmony_ci	/* Read MaxOffset */
31788c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, ent_offset, &max_offset);
31798c2ecf20Sopenharmony_ci	ent_offset += 4;
31808c2ecf20Sopenharmony_ci
31818c2ecf20Sopenharmony_ci	/* Read Base MSBs (if 64-bit entry) */
31828c2ecf20Sopenharmony_ci	if (base & PCI_EA_IS_64) {
31838c2ecf20Sopenharmony_ci		u32 base_upper;
31848c2ecf20Sopenharmony_ci
31858c2ecf20Sopenharmony_ci		pci_read_config_dword(dev, ent_offset, &base_upper);
31868c2ecf20Sopenharmony_ci		ent_offset += 4;
31878c2ecf20Sopenharmony_ci
31888c2ecf20Sopenharmony_ci		flags |= IORESOURCE_MEM_64;
31898c2ecf20Sopenharmony_ci
31908c2ecf20Sopenharmony_ci		/* entry starts above 32-bit boundary, can't use */
31918c2ecf20Sopenharmony_ci		if (!support_64 && base_upper)
31928c2ecf20Sopenharmony_ci			goto out;
31938c2ecf20Sopenharmony_ci
31948c2ecf20Sopenharmony_ci		if (support_64)
31958c2ecf20Sopenharmony_ci			start |= ((u64)base_upper << 32);
31968c2ecf20Sopenharmony_ci	}
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_ci	end = start + (max_offset | 0x03);
31998c2ecf20Sopenharmony_ci
32008c2ecf20Sopenharmony_ci	/* Read MaxOffset MSBs (if 64-bit entry) */
32018c2ecf20Sopenharmony_ci	if (max_offset & PCI_EA_IS_64) {
32028c2ecf20Sopenharmony_ci		u32 max_offset_upper;
32038c2ecf20Sopenharmony_ci
32048c2ecf20Sopenharmony_ci		pci_read_config_dword(dev, ent_offset, &max_offset_upper);
32058c2ecf20Sopenharmony_ci		ent_offset += 4;
32068c2ecf20Sopenharmony_ci
32078c2ecf20Sopenharmony_ci		flags |= IORESOURCE_MEM_64;
32088c2ecf20Sopenharmony_ci
32098c2ecf20Sopenharmony_ci		/* entry too big, can't use */
32108c2ecf20Sopenharmony_ci		if (!support_64 && max_offset_upper)
32118c2ecf20Sopenharmony_ci			goto out;
32128c2ecf20Sopenharmony_ci
32138c2ecf20Sopenharmony_ci		if (support_64)
32148c2ecf20Sopenharmony_ci			end += ((u64)max_offset_upper << 32);
32158c2ecf20Sopenharmony_ci	}
32168c2ecf20Sopenharmony_ci
32178c2ecf20Sopenharmony_ci	if (end < start) {
32188c2ecf20Sopenharmony_ci		pci_err(dev, "EA Entry crosses address boundary\n");
32198c2ecf20Sopenharmony_ci		goto out;
32208c2ecf20Sopenharmony_ci	}
32218c2ecf20Sopenharmony_ci
32228c2ecf20Sopenharmony_ci	if (ent_size != ent_offset - offset) {
32238c2ecf20Sopenharmony_ci		pci_err(dev, "EA Entry Size (%d) does not match length read (%d)\n",
32248c2ecf20Sopenharmony_ci			ent_size, ent_offset - offset);
32258c2ecf20Sopenharmony_ci		goto out;
32268c2ecf20Sopenharmony_ci	}
32278c2ecf20Sopenharmony_ci
32288c2ecf20Sopenharmony_ci	res->name = pci_name(dev);
32298c2ecf20Sopenharmony_ci	res->start = start;
32308c2ecf20Sopenharmony_ci	res->end = end;
32318c2ecf20Sopenharmony_ci	res->flags = flags;
32328c2ecf20Sopenharmony_ci
32338c2ecf20Sopenharmony_ci	if (bei <= PCI_EA_BEI_BAR5)
32348c2ecf20Sopenharmony_ci		pci_info(dev, "BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
32358c2ecf20Sopenharmony_ci			   bei, res, prop);
32368c2ecf20Sopenharmony_ci	else if (bei == PCI_EA_BEI_ROM)
32378c2ecf20Sopenharmony_ci		pci_info(dev, "ROM: %pR (from Enhanced Allocation, properties %#02x)\n",
32388c2ecf20Sopenharmony_ci			   res, prop);
32398c2ecf20Sopenharmony_ci	else if (bei >= PCI_EA_BEI_VF_BAR0 && bei <= PCI_EA_BEI_VF_BAR5)
32408c2ecf20Sopenharmony_ci		pci_info(dev, "VF BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
32418c2ecf20Sopenharmony_ci			   bei - PCI_EA_BEI_VF_BAR0, res, prop);
32428c2ecf20Sopenharmony_ci	else
32438c2ecf20Sopenharmony_ci		pci_info(dev, "BEI %d res: %pR (from Enhanced Allocation, properties %#02x)\n",
32448c2ecf20Sopenharmony_ci			   bei, res, prop);
32458c2ecf20Sopenharmony_ci
32468c2ecf20Sopenharmony_ciout:
32478c2ecf20Sopenharmony_ci	return offset + ent_size;
32488c2ecf20Sopenharmony_ci}
32498c2ecf20Sopenharmony_ci
32508c2ecf20Sopenharmony_ci/* Enhanced Allocation Initialization */
32518c2ecf20Sopenharmony_civoid pci_ea_init(struct pci_dev *dev)
32528c2ecf20Sopenharmony_ci{
32538c2ecf20Sopenharmony_ci	int ea;
32548c2ecf20Sopenharmony_ci	u8 num_ent;
32558c2ecf20Sopenharmony_ci	int offset;
32568c2ecf20Sopenharmony_ci	int i;
32578c2ecf20Sopenharmony_ci
32588c2ecf20Sopenharmony_ci	/* find PCI EA capability in list */
32598c2ecf20Sopenharmony_ci	ea = pci_find_capability(dev, PCI_CAP_ID_EA);
32608c2ecf20Sopenharmony_ci	if (!ea)
32618c2ecf20Sopenharmony_ci		return;
32628c2ecf20Sopenharmony_ci
32638c2ecf20Sopenharmony_ci	/* determine the number of entries */
32648c2ecf20Sopenharmony_ci	pci_bus_read_config_byte(dev->bus, dev->devfn, ea + PCI_EA_NUM_ENT,
32658c2ecf20Sopenharmony_ci					&num_ent);
32668c2ecf20Sopenharmony_ci	num_ent &= PCI_EA_NUM_ENT_MASK;
32678c2ecf20Sopenharmony_ci
32688c2ecf20Sopenharmony_ci	offset = ea + PCI_EA_FIRST_ENT;
32698c2ecf20Sopenharmony_ci
32708c2ecf20Sopenharmony_ci	/* Skip DWORD 2 for type 1 functions */
32718c2ecf20Sopenharmony_ci	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
32728c2ecf20Sopenharmony_ci		offset += 4;
32738c2ecf20Sopenharmony_ci
32748c2ecf20Sopenharmony_ci	/* parse each EA entry */
32758c2ecf20Sopenharmony_ci	for (i = 0; i < num_ent; ++i)
32768c2ecf20Sopenharmony_ci		offset = pci_ea_read(dev, offset);
32778c2ecf20Sopenharmony_ci}
32788c2ecf20Sopenharmony_ci
32798c2ecf20Sopenharmony_cistatic void pci_add_saved_cap(struct pci_dev *pci_dev,
32808c2ecf20Sopenharmony_ci	struct pci_cap_saved_state *new_cap)
32818c2ecf20Sopenharmony_ci{
32828c2ecf20Sopenharmony_ci	hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space);
32838c2ecf20Sopenharmony_ci}
32848c2ecf20Sopenharmony_ci
32858c2ecf20Sopenharmony_ci/**
32868c2ecf20Sopenharmony_ci * _pci_add_cap_save_buffer - allocate buffer for saving given
32878c2ecf20Sopenharmony_ci *			      capability registers
32888c2ecf20Sopenharmony_ci * @dev: the PCI device
32898c2ecf20Sopenharmony_ci * @cap: the capability to allocate the buffer for
32908c2ecf20Sopenharmony_ci * @extended: Standard or Extended capability ID
32918c2ecf20Sopenharmony_ci * @size: requested size of the buffer
32928c2ecf20Sopenharmony_ci */
32938c2ecf20Sopenharmony_cistatic int _pci_add_cap_save_buffer(struct pci_dev *dev, u16 cap,
32948c2ecf20Sopenharmony_ci				    bool extended, unsigned int size)
32958c2ecf20Sopenharmony_ci{
32968c2ecf20Sopenharmony_ci	int pos;
32978c2ecf20Sopenharmony_ci	struct pci_cap_saved_state *save_state;
32988c2ecf20Sopenharmony_ci
32998c2ecf20Sopenharmony_ci	if (extended)
33008c2ecf20Sopenharmony_ci		pos = pci_find_ext_capability(dev, cap);
33018c2ecf20Sopenharmony_ci	else
33028c2ecf20Sopenharmony_ci		pos = pci_find_capability(dev, cap);
33038c2ecf20Sopenharmony_ci
33048c2ecf20Sopenharmony_ci	if (!pos)
33058c2ecf20Sopenharmony_ci		return 0;
33068c2ecf20Sopenharmony_ci
33078c2ecf20Sopenharmony_ci	save_state = kzalloc(sizeof(*save_state) + size, GFP_KERNEL);
33088c2ecf20Sopenharmony_ci	if (!save_state)
33098c2ecf20Sopenharmony_ci		return -ENOMEM;
33108c2ecf20Sopenharmony_ci
33118c2ecf20Sopenharmony_ci	save_state->cap.cap_nr = cap;
33128c2ecf20Sopenharmony_ci	save_state->cap.cap_extended = extended;
33138c2ecf20Sopenharmony_ci	save_state->cap.size = size;
33148c2ecf20Sopenharmony_ci	pci_add_saved_cap(dev, save_state);
33158c2ecf20Sopenharmony_ci
33168c2ecf20Sopenharmony_ci	return 0;
33178c2ecf20Sopenharmony_ci}
33188c2ecf20Sopenharmony_ci
33198c2ecf20Sopenharmony_ciint pci_add_cap_save_buffer(struct pci_dev *dev, char cap, unsigned int size)
33208c2ecf20Sopenharmony_ci{
33218c2ecf20Sopenharmony_ci	return _pci_add_cap_save_buffer(dev, cap, false, size);
33228c2ecf20Sopenharmony_ci}
33238c2ecf20Sopenharmony_ci
33248c2ecf20Sopenharmony_ciint pci_add_ext_cap_save_buffer(struct pci_dev *dev, u16 cap, unsigned int size)
33258c2ecf20Sopenharmony_ci{
33268c2ecf20Sopenharmony_ci	return _pci_add_cap_save_buffer(dev, cap, true, size);
33278c2ecf20Sopenharmony_ci}
33288c2ecf20Sopenharmony_ci
33298c2ecf20Sopenharmony_ci/**
33308c2ecf20Sopenharmony_ci * pci_allocate_cap_save_buffers - allocate buffers for saving capabilities
33318c2ecf20Sopenharmony_ci * @dev: the PCI device
33328c2ecf20Sopenharmony_ci */
33338c2ecf20Sopenharmony_civoid pci_allocate_cap_save_buffers(struct pci_dev *dev)
33348c2ecf20Sopenharmony_ci{
33358c2ecf20Sopenharmony_ci	int error;
33368c2ecf20Sopenharmony_ci
33378c2ecf20Sopenharmony_ci	error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_EXP,
33388c2ecf20Sopenharmony_ci					PCI_EXP_SAVE_REGS * sizeof(u16));
33398c2ecf20Sopenharmony_ci	if (error)
33408c2ecf20Sopenharmony_ci		pci_err(dev, "unable to preallocate PCI Express save buffer\n");
33418c2ecf20Sopenharmony_ci
33428c2ecf20Sopenharmony_ci	error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_PCIX, sizeof(u16));
33438c2ecf20Sopenharmony_ci	if (error)
33448c2ecf20Sopenharmony_ci		pci_err(dev, "unable to preallocate PCI-X save buffer\n");
33458c2ecf20Sopenharmony_ci
33468c2ecf20Sopenharmony_ci	error = pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_LTR,
33478c2ecf20Sopenharmony_ci					    2 * sizeof(u16));
33488c2ecf20Sopenharmony_ci	if (error)
33498c2ecf20Sopenharmony_ci		pci_err(dev, "unable to allocate suspend buffer for LTR\n");
33508c2ecf20Sopenharmony_ci
33518c2ecf20Sopenharmony_ci	pci_allocate_vc_save_buffers(dev);
33528c2ecf20Sopenharmony_ci}
33538c2ecf20Sopenharmony_ci
33548c2ecf20Sopenharmony_civoid pci_free_cap_save_buffers(struct pci_dev *dev)
33558c2ecf20Sopenharmony_ci{
33568c2ecf20Sopenharmony_ci	struct pci_cap_saved_state *tmp;
33578c2ecf20Sopenharmony_ci	struct hlist_node *n;
33588c2ecf20Sopenharmony_ci
33598c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(tmp, n, &dev->saved_cap_space, next)
33608c2ecf20Sopenharmony_ci		kfree(tmp);
33618c2ecf20Sopenharmony_ci}
33628c2ecf20Sopenharmony_ci
33638c2ecf20Sopenharmony_ci/**
33648c2ecf20Sopenharmony_ci * pci_configure_ari - enable or disable ARI forwarding
33658c2ecf20Sopenharmony_ci * @dev: the PCI device
33668c2ecf20Sopenharmony_ci *
33678c2ecf20Sopenharmony_ci * If @dev and its upstream bridge both support ARI, enable ARI in the
33688c2ecf20Sopenharmony_ci * bridge.  Otherwise, disable ARI in the bridge.
33698c2ecf20Sopenharmony_ci */
33708c2ecf20Sopenharmony_civoid pci_configure_ari(struct pci_dev *dev)
33718c2ecf20Sopenharmony_ci{
33728c2ecf20Sopenharmony_ci	u32 cap;
33738c2ecf20Sopenharmony_ci	struct pci_dev *bridge;
33748c2ecf20Sopenharmony_ci
33758c2ecf20Sopenharmony_ci	if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn)
33768c2ecf20Sopenharmony_ci		return;
33778c2ecf20Sopenharmony_ci
33788c2ecf20Sopenharmony_ci	bridge = dev->bus->self;
33798c2ecf20Sopenharmony_ci	if (!bridge)
33808c2ecf20Sopenharmony_ci		return;
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_ci	pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap);
33838c2ecf20Sopenharmony_ci	if (!(cap & PCI_EXP_DEVCAP2_ARI))
33848c2ecf20Sopenharmony_ci		return;
33858c2ecf20Sopenharmony_ci
33868c2ecf20Sopenharmony_ci	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI)) {
33878c2ecf20Sopenharmony_ci		pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2,
33888c2ecf20Sopenharmony_ci					 PCI_EXP_DEVCTL2_ARI);
33898c2ecf20Sopenharmony_ci		bridge->ari_enabled = 1;
33908c2ecf20Sopenharmony_ci	} else {
33918c2ecf20Sopenharmony_ci		pcie_capability_clear_word(bridge, PCI_EXP_DEVCTL2,
33928c2ecf20Sopenharmony_ci					   PCI_EXP_DEVCTL2_ARI);
33938c2ecf20Sopenharmony_ci		bridge->ari_enabled = 0;
33948c2ecf20Sopenharmony_ci	}
33958c2ecf20Sopenharmony_ci}
33968c2ecf20Sopenharmony_ci
33978c2ecf20Sopenharmony_cistatic bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
33988c2ecf20Sopenharmony_ci{
33998c2ecf20Sopenharmony_ci	int pos;
34008c2ecf20Sopenharmony_ci	u16 cap, ctrl;
34018c2ecf20Sopenharmony_ci
34028c2ecf20Sopenharmony_ci	pos = pdev->acs_cap;
34038c2ecf20Sopenharmony_ci	if (!pos)
34048c2ecf20Sopenharmony_ci		return false;
34058c2ecf20Sopenharmony_ci
34068c2ecf20Sopenharmony_ci	/*
34078c2ecf20Sopenharmony_ci	 * Except for egress control, capabilities are either required
34088c2ecf20Sopenharmony_ci	 * or only required if controllable.  Features missing from the
34098c2ecf20Sopenharmony_ci	 * capability field can therefore be assumed as hard-wired enabled.
34108c2ecf20Sopenharmony_ci	 */
34118c2ecf20Sopenharmony_ci	pci_read_config_word(pdev, pos + PCI_ACS_CAP, &cap);
34128c2ecf20Sopenharmony_ci	acs_flags &= (cap | PCI_ACS_EC);
34138c2ecf20Sopenharmony_ci
34148c2ecf20Sopenharmony_ci	pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
34158c2ecf20Sopenharmony_ci	return (ctrl & acs_flags) == acs_flags;
34168c2ecf20Sopenharmony_ci}
34178c2ecf20Sopenharmony_ci
34188c2ecf20Sopenharmony_ci/**
34198c2ecf20Sopenharmony_ci * pci_acs_enabled - test ACS against required flags for a given device
34208c2ecf20Sopenharmony_ci * @pdev: device to test
34218c2ecf20Sopenharmony_ci * @acs_flags: required PCI ACS flags
34228c2ecf20Sopenharmony_ci *
34238c2ecf20Sopenharmony_ci * Return true if the device supports the provided flags.  Automatically
34248c2ecf20Sopenharmony_ci * filters out flags that are not implemented on multifunction devices.
34258c2ecf20Sopenharmony_ci *
34268c2ecf20Sopenharmony_ci * Note that this interface checks the effective ACS capabilities of the
34278c2ecf20Sopenharmony_ci * device rather than the actual capabilities.  For instance, most single
34288c2ecf20Sopenharmony_ci * function endpoints are not required to support ACS because they have no
34298c2ecf20Sopenharmony_ci * opportunity for peer-to-peer access.  We therefore return 'true'
34308c2ecf20Sopenharmony_ci * regardless of whether the device exposes an ACS capability.  This makes
34318c2ecf20Sopenharmony_ci * it much easier for callers of this function to ignore the actual type
34328c2ecf20Sopenharmony_ci * or topology of the device when testing ACS support.
34338c2ecf20Sopenharmony_ci */
34348c2ecf20Sopenharmony_cibool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags)
34358c2ecf20Sopenharmony_ci{
34368c2ecf20Sopenharmony_ci	int ret;
34378c2ecf20Sopenharmony_ci
34388c2ecf20Sopenharmony_ci	ret = pci_dev_specific_acs_enabled(pdev, acs_flags);
34398c2ecf20Sopenharmony_ci	if (ret >= 0)
34408c2ecf20Sopenharmony_ci		return ret > 0;
34418c2ecf20Sopenharmony_ci
34428c2ecf20Sopenharmony_ci	/*
34438c2ecf20Sopenharmony_ci	 * Conventional PCI and PCI-X devices never support ACS, either
34448c2ecf20Sopenharmony_ci	 * effectively or actually.  The shared bus topology implies that
34458c2ecf20Sopenharmony_ci	 * any device on the bus can receive or snoop DMA.
34468c2ecf20Sopenharmony_ci	 */
34478c2ecf20Sopenharmony_ci	if (!pci_is_pcie(pdev))
34488c2ecf20Sopenharmony_ci		return false;
34498c2ecf20Sopenharmony_ci
34508c2ecf20Sopenharmony_ci	switch (pci_pcie_type(pdev)) {
34518c2ecf20Sopenharmony_ci	/*
34528c2ecf20Sopenharmony_ci	 * PCI/X-to-PCIe bridges are not specifically mentioned by the spec,
34538c2ecf20Sopenharmony_ci	 * but since their primary interface is PCI/X, we conservatively
34548c2ecf20Sopenharmony_ci	 * handle them as we would a non-PCIe device.
34558c2ecf20Sopenharmony_ci	 */
34568c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_PCIE_BRIDGE:
34578c2ecf20Sopenharmony_ci	/*
34588c2ecf20Sopenharmony_ci	 * PCIe 3.0, 6.12.1 excludes ACS on these devices.  "ACS is never
34598c2ecf20Sopenharmony_ci	 * applicable... must never implement an ACS Extended Capability...".
34608c2ecf20Sopenharmony_ci	 * This seems arbitrary, but we take a conservative interpretation
34618c2ecf20Sopenharmony_ci	 * of this statement.
34628c2ecf20Sopenharmony_ci	 */
34638c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_PCI_BRIDGE:
34648c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_RC_EC:
34658c2ecf20Sopenharmony_ci		return false;
34668c2ecf20Sopenharmony_ci	/*
34678c2ecf20Sopenharmony_ci	 * PCIe 3.0, 6.12.1.1 specifies that downstream and root ports should
34688c2ecf20Sopenharmony_ci	 * implement ACS in order to indicate their peer-to-peer capabilities,
34698c2ecf20Sopenharmony_ci	 * regardless of whether they are single- or multi-function devices.
34708c2ecf20Sopenharmony_ci	 */
34718c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_DOWNSTREAM:
34728c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_ROOT_PORT:
34738c2ecf20Sopenharmony_ci		return pci_acs_flags_enabled(pdev, acs_flags);
34748c2ecf20Sopenharmony_ci	/*
34758c2ecf20Sopenharmony_ci	 * PCIe 3.0, 6.12.1.2 specifies ACS capabilities that should be
34768c2ecf20Sopenharmony_ci	 * implemented by the remaining PCIe types to indicate peer-to-peer
34778c2ecf20Sopenharmony_ci	 * capabilities, but only when they are part of a multifunction
34788c2ecf20Sopenharmony_ci	 * device.  The footnote for section 6.12 indicates the specific
34798c2ecf20Sopenharmony_ci	 * PCIe types included here.
34808c2ecf20Sopenharmony_ci	 */
34818c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_ENDPOINT:
34828c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_UPSTREAM:
34838c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_LEG_END:
34848c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_RC_END:
34858c2ecf20Sopenharmony_ci		if (!pdev->multifunction)
34868c2ecf20Sopenharmony_ci			break;
34878c2ecf20Sopenharmony_ci
34888c2ecf20Sopenharmony_ci		return pci_acs_flags_enabled(pdev, acs_flags);
34898c2ecf20Sopenharmony_ci	}
34908c2ecf20Sopenharmony_ci
34918c2ecf20Sopenharmony_ci	/*
34928c2ecf20Sopenharmony_ci	 * PCIe 3.0, 6.12.1.3 specifies no ACS capabilities are applicable
34938c2ecf20Sopenharmony_ci	 * to single function devices with the exception of downstream ports.
34948c2ecf20Sopenharmony_ci	 */
34958c2ecf20Sopenharmony_ci	return true;
34968c2ecf20Sopenharmony_ci}
34978c2ecf20Sopenharmony_ci
34988c2ecf20Sopenharmony_ci/**
34998c2ecf20Sopenharmony_ci * pci_acs_path_enable - test ACS flags from start to end in a hierarchy
35008c2ecf20Sopenharmony_ci * @start: starting downstream device
35018c2ecf20Sopenharmony_ci * @end: ending upstream device or NULL to search to the root bus
35028c2ecf20Sopenharmony_ci * @acs_flags: required flags
35038c2ecf20Sopenharmony_ci *
35048c2ecf20Sopenharmony_ci * Walk up a device tree from start to end testing PCI ACS support.  If
35058c2ecf20Sopenharmony_ci * any step along the way does not support the required flags, return false.
35068c2ecf20Sopenharmony_ci */
35078c2ecf20Sopenharmony_cibool pci_acs_path_enabled(struct pci_dev *start,
35088c2ecf20Sopenharmony_ci			  struct pci_dev *end, u16 acs_flags)
35098c2ecf20Sopenharmony_ci{
35108c2ecf20Sopenharmony_ci	struct pci_dev *pdev, *parent = start;
35118c2ecf20Sopenharmony_ci
35128c2ecf20Sopenharmony_ci	do {
35138c2ecf20Sopenharmony_ci		pdev = parent;
35148c2ecf20Sopenharmony_ci
35158c2ecf20Sopenharmony_ci		if (!pci_acs_enabled(pdev, acs_flags))
35168c2ecf20Sopenharmony_ci			return false;
35178c2ecf20Sopenharmony_ci
35188c2ecf20Sopenharmony_ci		if (pci_is_root_bus(pdev->bus))
35198c2ecf20Sopenharmony_ci			return (end == NULL);
35208c2ecf20Sopenharmony_ci
35218c2ecf20Sopenharmony_ci		parent = pdev->bus->self;
35228c2ecf20Sopenharmony_ci	} while (pdev != end);
35238c2ecf20Sopenharmony_ci
35248c2ecf20Sopenharmony_ci	return true;
35258c2ecf20Sopenharmony_ci}
35268c2ecf20Sopenharmony_ci
35278c2ecf20Sopenharmony_ci/**
35288c2ecf20Sopenharmony_ci * pci_acs_init - Initialize ACS if hardware supports it
35298c2ecf20Sopenharmony_ci * @dev: the PCI device
35308c2ecf20Sopenharmony_ci */
35318c2ecf20Sopenharmony_civoid pci_acs_init(struct pci_dev *dev)
35328c2ecf20Sopenharmony_ci{
35338c2ecf20Sopenharmony_ci	dev->acs_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
35348c2ecf20Sopenharmony_ci
35358c2ecf20Sopenharmony_ci	/*
35368c2ecf20Sopenharmony_ci	 * Attempt to enable ACS regardless of capability because some Root
35378c2ecf20Sopenharmony_ci	 * Ports (e.g. those quirked with *_intel_pch_acs_*) do not have
35388c2ecf20Sopenharmony_ci	 * the standard ACS capability but still support ACS via those
35398c2ecf20Sopenharmony_ci	 * quirks.
35408c2ecf20Sopenharmony_ci	 */
35418c2ecf20Sopenharmony_ci	pci_enable_acs(dev);
35428c2ecf20Sopenharmony_ci}
35438c2ecf20Sopenharmony_ci
35448c2ecf20Sopenharmony_ci/**
35458c2ecf20Sopenharmony_ci * pci_rebar_find_pos - find position of resize ctrl reg for BAR
35468c2ecf20Sopenharmony_ci * @pdev: PCI device
35478c2ecf20Sopenharmony_ci * @bar: BAR to find
35488c2ecf20Sopenharmony_ci *
35498c2ecf20Sopenharmony_ci * Helper to find the position of the ctrl register for a BAR.
35508c2ecf20Sopenharmony_ci * Returns -ENOTSUPP if resizable BARs are not supported at all.
35518c2ecf20Sopenharmony_ci * Returns -ENOENT if no ctrl register for the BAR could be found.
35528c2ecf20Sopenharmony_ci */
35538c2ecf20Sopenharmony_cistatic int pci_rebar_find_pos(struct pci_dev *pdev, int bar)
35548c2ecf20Sopenharmony_ci{
35558c2ecf20Sopenharmony_ci	unsigned int pos, nbars, i;
35568c2ecf20Sopenharmony_ci	u32 ctrl;
35578c2ecf20Sopenharmony_ci
35588c2ecf20Sopenharmony_ci	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR);
35598c2ecf20Sopenharmony_ci	if (!pos)
35608c2ecf20Sopenharmony_ci		return -ENOTSUPP;
35618c2ecf20Sopenharmony_ci
35628c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
35638c2ecf20Sopenharmony_ci	nbars = (ctrl & PCI_REBAR_CTRL_NBAR_MASK) >>
35648c2ecf20Sopenharmony_ci		    PCI_REBAR_CTRL_NBAR_SHIFT;
35658c2ecf20Sopenharmony_ci
35668c2ecf20Sopenharmony_ci	for (i = 0; i < nbars; i++, pos += 8) {
35678c2ecf20Sopenharmony_ci		int bar_idx;
35688c2ecf20Sopenharmony_ci
35698c2ecf20Sopenharmony_ci		pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
35708c2ecf20Sopenharmony_ci		bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX;
35718c2ecf20Sopenharmony_ci		if (bar_idx == bar)
35728c2ecf20Sopenharmony_ci			return pos;
35738c2ecf20Sopenharmony_ci	}
35748c2ecf20Sopenharmony_ci
35758c2ecf20Sopenharmony_ci	return -ENOENT;
35768c2ecf20Sopenharmony_ci}
35778c2ecf20Sopenharmony_ci
35788c2ecf20Sopenharmony_ci/**
35798c2ecf20Sopenharmony_ci * pci_rebar_get_possible_sizes - get possible sizes for BAR
35808c2ecf20Sopenharmony_ci * @pdev: PCI device
35818c2ecf20Sopenharmony_ci * @bar: BAR to query
35828c2ecf20Sopenharmony_ci *
35838c2ecf20Sopenharmony_ci * Get the possible sizes of a resizable BAR as bitmask defined in the spec
35848c2ecf20Sopenharmony_ci * (bit 0=1MB, bit 19=512GB). Returns 0 if BAR isn't resizable.
35858c2ecf20Sopenharmony_ci */
35868c2ecf20Sopenharmony_ciu32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar)
35878c2ecf20Sopenharmony_ci{
35888c2ecf20Sopenharmony_ci	int pos;
35898c2ecf20Sopenharmony_ci	u32 cap;
35908c2ecf20Sopenharmony_ci
35918c2ecf20Sopenharmony_ci	pos = pci_rebar_find_pos(pdev, bar);
35928c2ecf20Sopenharmony_ci	if (pos < 0)
35938c2ecf20Sopenharmony_ci		return 0;
35948c2ecf20Sopenharmony_ci
35958c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, pos + PCI_REBAR_CAP, &cap);
35968c2ecf20Sopenharmony_ci	cap &= PCI_REBAR_CAP_SIZES;
35978c2ecf20Sopenharmony_ci
35988c2ecf20Sopenharmony_ci	/* Sapphire RX 5600 XT Pulse has an invalid cap dword for BAR 0 */
35998c2ecf20Sopenharmony_ci	if (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x731f &&
36008c2ecf20Sopenharmony_ci	    bar == 0 && cap == 0x7000)
36018c2ecf20Sopenharmony_ci		cap = 0x3f000;
36028c2ecf20Sopenharmony_ci
36038c2ecf20Sopenharmony_ci	return cap >> 4;
36048c2ecf20Sopenharmony_ci}
36058c2ecf20Sopenharmony_ci
36068c2ecf20Sopenharmony_ci/**
36078c2ecf20Sopenharmony_ci * pci_rebar_get_current_size - get the current size of a BAR
36088c2ecf20Sopenharmony_ci * @pdev: PCI device
36098c2ecf20Sopenharmony_ci * @bar: BAR to set size to
36108c2ecf20Sopenharmony_ci *
36118c2ecf20Sopenharmony_ci * Read the size of a BAR from the resizable BAR config.
36128c2ecf20Sopenharmony_ci * Returns size if found or negative error code.
36138c2ecf20Sopenharmony_ci */
36148c2ecf20Sopenharmony_ciint pci_rebar_get_current_size(struct pci_dev *pdev, int bar)
36158c2ecf20Sopenharmony_ci{
36168c2ecf20Sopenharmony_ci	int pos;
36178c2ecf20Sopenharmony_ci	u32 ctrl;
36188c2ecf20Sopenharmony_ci
36198c2ecf20Sopenharmony_ci	pos = pci_rebar_find_pos(pdev, bar);
36208c2ecf20Sopenharmony_ci	if (pos < 0)
36218c2ecf20Sopenharmony_ci		return pos;
36228c2ecf20Sopenharmony_ci
36238c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
36248c2ecf20Sopenharmony_ci	return (ctrl & PCI_REBAR_CTRL_BAR_SIZE) >> PCI_REBAR_CTRL_BAR_SHIFT;
36258c2ecf20Sopenharmony_ci}
36268c2ecf20Sopenharmony_ci
36278c2ecf20Sopenharmony_ci/**
36288c2ecf20Sopenharmony_ci * pci_rebar_set_size - set a new size for a BAR
36298c2ecf20Sopenharmony_ci * @pdev: PCI device
36308c2ecf20Sopenharmony_ci * @bar: BAR to set size to
36318c2ecf20Sopenharmony_ci * @size: new size as defined in the spec (0=1MB, 19=512GB)
36328c2ecf20Sopenharmony_ci *
36338c2ecf20Sopenharmony_ci * Set the new size of a BAR as defined in the spec.
36348c2ecf20Sopenharmony_ci * Returns zero if resizing was successful, error code otherwise.
36358c2ecf20Sopenharmony_ci */
36368c2ecf20Sopenharmony_ciint pci_rebar_set_size(struct pci_dev *pdev, int bar, int size)
36378c2ecf20Sopenharmony_ci{
36388c2ecf20Sopenharmony_ci	int pos;
36398c2ecf20Sopenharmony_ci	u32 ctrl;
36408c2ecf20Sopenharmony_ci
36418c2ecf20Sopenharmony_ci	pos = pci_rebar_find_pos(pdev, bar);
36428c2ecf20Sopenharmony_ci	if (pos < 0)
36438c2ecf20Sopenharmony_ci		return pos;
36448c2ecf20Sopenharmony_ci
36458c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
36468c2ecf20Sopenharmony_ci	ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
36478c2ecf20Sopenharmony_ci	ctrl |= size << PCI_REBAR_CTRL_BAR_SHIFT;
36488c2ecf20Sopenharmony_ci	pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl);
36498c2ecf20Sopenharmony_ci	return 0;
36508c2ecf20Sopenharmony_ci}
36518c2ecf20Sopenharmony_ci
36528c2ecf20Sopenharmony_ci/**
36538c2ecf20Sopenharmony_ci * pci_enable_atomic_ops_to_root - enable AtomicOp requests to root port
36548c2ecf20Sopenharmony_ci * @dev: the PCI device
36558c2ecf20Sopenharmony_ci * @cap_mask: mask of desired AtomicOp sizes, including one or more of:
36568c2ecf20Sopenharmony_ci *	PCI_EXP_DEVCAP2_ATOMIC_COMP32
36578c2ecf20Sopenharmony_ci *	PCI_EXP_DEVCAP2_ATOMIC_COMP64
36588c2ecf20Sopenharmony_ci *	PCI_EXP_DEVCAP2_ATOMIC_COMP128
36598c2ecf20Sopenharmony_ci *
36608c2ecf20Sopenharmony_ci * Return 0 if all upstream bridges support AtomicOp routing, egress
36618c2ecf20Sopenharmony_ci * blocking is disabled on all upstream ports, and the root port supports
36628c2ecf20Sopenharmony_ci * the requested completion capabilities (32-bit, 64-bit and/or 128-bit
36638c2ecf20Sopenharmony_ci * AtomicOp completion), or negative otherwise.
36648c2ecf20Sopenharmony_ci */
36658c2ecf20Sopenharmony_ciint pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask)
36668c2ecf20Sopenharmony_ci{
36678c2ecf20Sopenharmony_ci	struct pci_bus *bus = dev->bus;
36688c2ecf20Sopenharmony_ci	struct pci_dev *bridge;
36698c2ecf20Sopenharmony_ci	u32 cap, ctl2;
36708c2ecf20Sopenharmony_ci
36718c2ecf20Sopenharmony_ci	if (!pci_is_pcie(dev))
36728c2ecf20Sopenharmony_ci		return -EINVAL;
36738c2ecf20Sopenharmony_ci
36748c2ecf20Sopenharmony_ci	/*
36758c2ecf20Sopenharmony_ci	 * Per PCIe r4.0, sec 6.15, endpoints and root ports may be
36768c2ecf20Sopenharmony_ci	 * AtomicOp requesters.  For now, we only support endpoints as
36778c2ecf20Sopenharmony_ci	 * requesters and root ports as completers.  No endpoints as
36788c2ecf20Sopenharmony_ci	 * completers, and no peer-to-peer.
36798c2ecf20Sopenharmony_ci	 */
36808c2ecf20Sopenharmony_ci
36818c2ecf20Sopenharmony_ci	switch (pci_pcie_type(dev)) {
36828c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_ENDPOINT:
36838c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_LEG_END:
36848c2ecf20Sopenharmony_ci	case PCI_EXP_TYPE_RC_END:
36858c2ecf20Sopenharmony_ci		break;
36868c2ecf20Sopenharmony_ci	default:
36878c2ecf20Sopenharmony_ci		return -EINVAL;
36888c2ecf20Sopenharmony_ci	}
36898c2ecf20Sopenharmony_ci
36908c2ecf20Sopenharmony_ci	while (bus->parent) {
36918c2ecf20Sopenharmony_ci		bridge = bus->self;
36928c2ecf20Sopenharmony_ci
36938c2ecf20Sopenharmony_ci		pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap);
36948c2ecf20Sopenharmony_ci
36958c2ecf20Sopenharmony_ci		switch (pci_pcie_type(bridge)) {
36968c2ecf20Sopenharmony_ci		/* Ensure switch ports support AtomicOp routing */
36978c2ecf20Sopenharmony_ci		case PCI_EXP_TYPE_UPSTREAM:
36988c2ecf20Sopenharmony_ci		case PCI_EXP_TYPE_DOWNSTREAM:
36998c2ecf20Sopenharmony_ci			if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE))
37008c2ecf20Sopenharmony_ci				return -EINVAL;
37018c2ecf20Sopenharmony_ci			break;
37028c2ecf20Sopenharmony_ci
37038c2ecf20Sopenharmony_ci		/* Ensure root port supports all the sizes we care about */
37048c2ecf20Sopenharmony_ci		case PCI_EXP_TYPE_ROOT_PORT:
37058c2ecf20Sopenharmony_ci			if ((cap & cap_mask) != cap_mask)
37068c2ecf20Sopenharmony_ci				return -EINVAL;
37078c2ecf20Sopenharmony_ci			break;
37088c2ecf20Sopenharmony_ci		}
37098c2ecf20Sopenharmony_ci
37108c2ecf20Sopenharmony_ci		/* Ensure upstream ports don't block AtomicOps on egress */
37118c2ecf20Sopenharmony_ci		if (pci_pcie_type(bridge) == PCI_EXP_TYPE_UPSTREAM) {
37128c2ecf20Sopenharmony_ci			pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2,
37138c2ecf20Sopenharmony_ci						   &ctl2);
37148c2ecf20Sopenharmony_ci			if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK)
37158c2ecf20Sopenharmony_ci				return -EINVAL;
37168c2ecf20Sopenharmony_ci		}
37178c2ecf20Sopenharmony_ci
37188c2ecf20Sopenharmony_ci		bus = bus->parent;
37198c2ecf20Sopenharmony_ci	}
37208c2ecf20Sopenharmony_ci
37218c2ecf20Sopenharmony_ci	pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
37228c2ecf20Sopenharmony_ci				 PCI_EXP_DEVCTL2_ATOMIC_REQ);
37238c2ecf20Sopenharmony_ci	return 0;
37248c2ecf20Sopenharmony_ci}
37258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_enable_atomic_ops_to_root);
37268c2ecf20Sopenharmony_ci
37278c2ecf20Sopenharmony_ci/**
37288c2ecf20Sopenharmony_ci * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
37298c2ecf20Sopenharmony_ci * @dev: the PCI device
37308c2ecf20Sopenharmony_ci * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD)
37318c2ecf20Sopenharmony_ci *
37328c2ecf20Sopenharmony_ci * Perform INTx swizzling for a device behind one level of bridge.  This is
37338c2ecf20Sopenharmony_ci * required by section 9.1 of the PCI-to-PCI bridge specification for devices
37348c2ecf20Sopenharmony_ci * behind bridges on add-in cards.  For devices with ARI enabled, the slot
37358c2ecf20Sopenharmony_ci * number is always 0 (see the Implementation Note in section 2.2.8.1 of
37368c2ecf20Sopenharmony_ci * the PCI Express Base Specification, Revision 2.1)
37378c2ecf20Sopenharmony_ci */
37388c2ecf20Sopenharmony_ciu8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin)
37398c2ecf20Sopenharmony_ci{
37408c2ecf20Sopenharmony_ci	int slot;
37418c2ecf20Sopenharmony_ci
37428c2ecf20Sopenharmony_ci	if (pci_ari_enabled(dev->bus))
37438c2ecf20Sopenharmony_ci		slot = 0;
37448c2ecf20Sopenharmony_ci	else
37458c2ecf20Sopenharmony_ci		slot = PCI_SLOT(dev->devfn);
37468c2ecf20Sopenharmony_ci
37478c2ecf20Sopenharmony_ci	return (((pin - 1) + slot) % 4) + 1;
37488c2ecf20Sopenharmony_ci}
37498c2ecf20Sopenharmony_ci
37508c2ecf20Sopenharmony_ciint pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
37518c2ecf20Sopenharmony_ci{
37528c2ecf20Sopenharmony_ci	u8 pin;
37538c2ecf20Sopenharmony_ci
37548c2ecf20Sopenharmony_ci	pin = dev->pin;
37558c2ecf20Sopenharmony_ci	if (!pin)
37568c2ecf20Sopenharmony_ci		return -1;
37578c2ecf20Sopenharmony_ci
37588c2ecf20Sopenharmony_ci	while (!pci_is_root_bus(dev->bus)) {
37598c2ecf20Sopenharmony_ci		pin = pci_swizzle_interrupt_pin(dev, pin);
37608c2ecf20Sopenharmony_ci		dev = dev->bus->self;
37618c2ecf20Sopenharmony_ci	}
37628c2ecf20Sopenharmony_ci	*bridge = dev;
37638c2ecf20Sopenharmony_ci	return pin;
37648c2ecf20Sopenharmony_ci}
37658c2ecf20Sopenharmony_ci
37668c2ecf20Sopenharmony_ci/**
37678c2ecf20Sopenharmony_ci * pci_common_swizzle - swizzle INTx all the way to root bridge
37688c2ecf20Sopenharmony_ci * @dev: the PCI device
37698c2ecf20Sopenharmony_ci * @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD)
37708c2ecf20Sopenharmony_ci *
37718c2ecf20Sopenharmony_ci * Perform INTx swizzling for a device.  This traverses through all PCI-to-PCI
37728c2ecf20Sopenharmony_ci * bridges all the way up to a PCI root bus.
37738c2ecf20Sopenharmony_ci */
37748c2ecf20Sopenharmony_ciu8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)
37758c2ecf20Sopenharmony_ci{
37768c2ecf20Sopenharmony_ci	u8 pin = *pinp;
37778c2ecf20Sopenharmony_ci
37788c2ecf20Sopenharmony_ci	while (!pci_is_root_bus(dev->bus)) {
37798c2ecf20Sopenharmony_ci		pin = pci_swizzle_interrupt_pin(dev, pin);
37808c2ecf20Sopenharmony_ci		dev = dev->bus->self;
37818c2ecf20Sopenharmony_ci	}
37828c2ecf20Sopenharmony_ci	*pinp = pin;
37838c2ecf20Sopenharmony_ci	return PCI_SLOT(dev->devfn);
37848c2ecf20Sopenharmony_ci}
37858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_common_swizzle);
37868c2ecf20Sopenharmony_ci
37878c2ecf20Sopenharmony_ci/**
37888c2ecf20Sopenharmony_ci * pci_release_region - Release a PCI bar
37898c2ecf20Sopenharmony_ci * @pdev: PCI device whose resources were previously reserved by
37908c2ecf20Sopenharmony_ci *	  pci_request_region()
37918c2ecf20Sopenharmony_ci * @bar: BAR to release
37928c2ecf20Sopenharmony_ci *
37938c2ecf20Sopenharmony_ci * Releases the PCI I/O and memory resources previously reserved by a
37948c2ecf20Sopenharmony_ci * successful call to pci_request_region().  Call this function only
37958c2ecf20Sopenharmony_ci * after all use of the PCI regions has ceased.
37968c2ecf20Sopenharmony_ci */
37978c2ecf20Sopenharmony_civoid pci_release_region(struct pci_dev *pdev, int bar)
37988c2ecf20Sopenharmony_ci{
37998c2ecf20Sopenharmony_ci	struct pci_devres *dr;
38008c2ecf20Sopenharmony_ci
38018c2ecf20Sopenharmony_ci	if (pci_resource_len(pdev, bar) == 0)
38028c2ecf20Sopenharmony_ci		return;
38038c2ecf20Sopenharmony_ci	if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
38048c2ecf20Sopenharmony_ci		release_region(pci_resource_start(pdev, bar),
38058c2ecf20Sopenharmony_ci				pci_resource_len(pdev, bar));
38068c2ecf20Sopenharmony_ci	else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
38078c2ecf20Sopenharmony_ci		release_mem_region(pci_resource_start(pdev, bar),
38088c2ecf20Sopenharmony_ci				pci_resource_len(pdev, bar));
38098c2ecf20Sopenharmony_ci
38108c2ecf20Sopenharmony_ci	dr = find_pci_dr(pdev);
38118c2ecf20Sopenharmony_ci	if (dr)
38128c2ecf20Sopenharmony_ci		dr->region_mask &= ~(1 << bar);
38138c2ecf20Sopenharmony_ci}
38148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_release_region);
38158c2ecf20Sopenharmony_ci
38168c2ecf20Sopenharmony_ci/**
38178c2ecf20Sopenharmony_ci * __pci_request_region - Reserved PCI I/O and memory resource
38188c2ecf20Sopenharmony_ci * @pdev: PCI device whose resources are to be reserved
38198c2ecf20Sopenharmony_ci * @bar: BAR to be reserved
38208c2ecf20Sopenharmony_ci * @res_name: Name to be associated with resource.
38218c2ecf20Sopenharmony_ci * @exclusive: whether the region access is exclusive or not
38228c2ecf20Sopenharmony_ci *
38238c2ecf20Sopenharmony_ci * Mark the PCI region associated with PCI device @pdev BAR @bar as
38248c2ecf20Sopenharmony_ci * being reserved by owner @res_name.  Do not access any
38258c2ecf20Sopenharmony_ci * address inside the PCI regions unless this call returns
38268c2ecf20Sopenharmony_ci * successfully.
38278c2ecf20Sopenharmony_ci *
38288c2ecf20Sopenharmony_ci * If @exclusive is set, then the region is marked so that userspace
38298c2ecf20Sopenharmony_ci * is explicitly not allowed to map the resource via /dev/mem or
38308c2ecf20Sopenharmony_ci * sysfs MMIO access.
38318c2ecf20Sopenharmony_ci *
38328c2ecf20Sopenharmony_ci * Returns 0 on success, or %EBUSY on error.  A warning
38338c2ecf20Sopenharmony_ci * message is also printed on failure.
38348c2ecf20Sopenharmony_ci */
38358c2ecf20Sopenharmony_cistatic int __pci_request_region(struct pci_dev *pdev, int bar,
38368c2ecf20Sopenharmony_ci				const char *res_name, int exclusive)
38378c2ecf20Sopenharmony_ci{
38388c2ecf20Sopenharmony_ci	struct pci_devres *dr;
38398c2ecf20Sopenharmony_ci
38408c2ecf20Sopenharmony_ci	if (pci_resource_len(pdev, bar) == 0)
38418c2ecf20Sopenharmony_ci		return 0;
38428c2ecf20Sopenharmony_ci
38438c2ecf20Sopenharmony_ci	if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) {
38448c2ecf20Sopenharmony_ci		if (!request_region(pci_resource_start(pdev, bar),
38458c2ecf20Sopenharmony_ci			    pci_resource_len(pdev, bar), res_name))
38468c2ecf20Sopenharmony_ci			goto err_out;
38478c2ecf20Sopenharmony_ci	} else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
38488c2ecf20Sopenharmony_ci		if (!__request_mem_region(pci_resource_start(pdev, bar),
38498c2ecf20Sopenharmony_ci					pci_resource_len(pdev, bar), res_name,
38508c2ecf20Sopenharmony_ci					exclusive))
38518c2ecf20Sopenharmony_ci			goto err_out;
38528c2ecf20Sopenharmony_ci	}
38538c2ecf20Sopenharmony_ci
38548c2ecf20Sopenharmony_ci	dr = find_pci_dr(pdev);
38558c2ecf20Sopenharmony_ci	if (dr)
38568c2ecf20Sopenharmony_ci		dr->region_mask |= 1 << bar;
38578c2ecf20Sopenharmony_ci
38588c2ecf20Sopenharmony_ci	return 0;
38598c2ecf20Sopenharmony_ci
38608c2ecf20Sopenharmony_cierr_out:
38618c2ecf20Sopenharmony_ci	pci_warn(pdev, "BAR %d: can't reserve %pR\n", bar,
38628c2ecf20Sopenharmony_ci		 &pdev->resource[bar]);
38638c2ecf20Sopenharmony_ci	return -EBUSY;
38648c2ecf20Sopenharmony_ci}
38658c2ecf20Sopenharmony_ci
38668c2ecf20Sopenharmony_ci/**
38678c2ecf20Sopenharmony_ci * pci_request_region - Reserve PCI I/O and memory resource
38688c2ecf20Sopenharmony_ci * @pdev: PCI device whose resources are to be reserved
38698c2ecf20Sopenharmony_ci * @bar: BAR to be reserved
38708c2ecf20Sopenharmony_ci * @res_name: Name to be associated with resource
38718c2ecf20Sopenharmony_ci *
38728c2ecf20Sopenharmony_ci * Mark the PCI region associated with PCI device @pdev BAR @bar as
38738c2ecf20Sopenharmony_ci * being reserved by owner @res_name.  Do not access any
38748c2ecf20Sopenharmony_ci * address inside the PCI regions unless this call returns
38758c2ecf20Sopenharmony_ci * successfully.
38768c2ecf20Sopenharmony_ci *
38778c2ecf20Sopenharmony_ci * Returns 0 on success, or %EBUSY on error.  A warning
38788c2ecf20Sopenharmony_ci * message is also printed on failure.
38798c2ecf20Sopenharmony_ci */
38808c2ecf20Sopenharmony_ciint pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
38818c2ecf20Sopenharmony_ci{
38828c2ecf20Sopenharmony_ci	return __pci_request_region(pdev, bar, res_name, 0);
38838c2ecf20Sopenharmony_ci}
38848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_request_region);
38858c2ecf20Sopenharmony_ci
38868c2ecf20Sopenharmony_ci/**
38878c2ecf20Sopenharmony_ci * pci_release_selected_regions - Release selected PCI I/O and memory resources
38888c2ecf20Sopenharmony_ci * @pdev: PCI device whose resources were previously reserved
38898c2ecf20Sopenharmony_ci * @bars: Bitmask of BARs to be released
38908c2ecf20Sopenharmony_ci *
38918c2ecf20Sopenharmony_ci * Release selected PCI I/O and memory resources previously reserved.
38928c2ecf20Sopenharmony_ci * Call this function only after all use of the PCI regions has ceased.
38938c2ecf20Sopenharmony_ci */
38948c2ecf20Sopenharmony_civoid pci_release_selected_regions(struct pci_dev *pdev, int bars)
38958c2ecf20Sopenharmony_ci{
38968c2ecf20Sopenharmony_ci	int i;
38978c2ecf20Sopenharmony_ci
38988c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++)
38998c2ecf20Sopenharmony_ci		if (bars & (1 << i))
39008c2ecf20Sopenharmony_ci			pci_release_region(pdev, i);
39018c2ecf20Sopenharmony_ci}
39028c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_release_selected_regions);
39038c2ecf20Sopenharmony_ci
39048c2ecf20Sopenharmony_cistatic int __pci_request_selected_regions(struct pci_dev *pdev, int bars,
39058c2ecf20Sopenharmony_ci					  const char *res_name, int excl)
39068c2ecf20Sopenharmony_ci{
39078c2ecf20Sopenharmony_ci	int i;
39088c2ecf20Sopenharmony_ci
39098c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++)
39108c2ecf20Sopenharmony_ci		if (bars & (1 << i))
39118c2ecf20Sopenharmony_ci			if (__pci_request_region(pdev, i, res_name, excl))
39128c2ecf20Sopenharmony_ci				goto err_out;
39138c2ecf20Sopenharmony_ci	return 0;
39148c2ecf20Sopenharmony_ci
39158c2ecf20Sopenharmony_cierr_out:
39168c2ecf20Sopenharmony_ci	while (--i >= 0)
39178c2ecf20Sopenharmony_ci		if (bars & (1 << i))
39188c2ecf20Sopenharmony_ci			pci_release_region(pdev, i);
39198c2ecf20Sopenharmony_ci
39208c2ecf20Sopenharmony_ci	return -EBUSY;
39218c2ecf20Sopenharmony_ci}
39228c2ecf20Sopenharmony_ci
39238c2ecf20Sopenharmony_ci
39248c2ecf20Sopenharmony_ci/**
39258c2ecf20Sopenharmony_ci * pci_request_selected_regions - Reserve selected PCI I/O and memory resources
39268c2ecf20Sopenharmony_ci * @pdev: PCI device whose resources are to be reserved
39278c2ecf20Sopenharmony_ci * @bars: Bitmask of BARs to be requested
39288c2ecf20Sopenharmony_ci * @res_name: Name to be associated with resource
39298c2ecf20Sopenharmony_ci */
39308c2ecf20Sopenharmony_ciint pci_request_selected_regions(struct pci_dev *pdev, int bars,
39318c2ecf20Sopenharmony_ci				 const char *res_name)
39328c2ecf20Sopenharmony_ci{
39338c2ecf20Sopenharmony_ci	return __pci_request_selected_regions(pdev, bars, res_name, 0);
39348c2ecf20Sopenharmony_ci}
39358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_request_selected_regions);
39368c2ecf20Sopenharmony_ci
39378c2ecf20Sopenharmony_ciint pci_request_selected_regions_exclusive(struct pci_dev *pdev, int bars,
39388c2ecf20Sopenharmony_ci					   const char *res_name)
39398c2ecf20Sopenharmony_ci{
39408c2ecf20Sopenharmony_ci	return __pci_request_selected_regions(pdev, bars, res_name,
39418c2ecf20Sopenharmony_ci			IORESOURCE_EXCLUSIVE);
39428c2ecf20Sopenharmony_ci}
39438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_request_selected_regions_exclusive);
39448c2ecf20Sopenharmony_ci
39458c2ecf20Sopenharmony_ci/**
39468c2ecf20Sopenharmony_ci * pci_release_regions - Release reserved PCI I/O and memory resources
39478c2ecf20Sopenharmony_ci * @pdev: PCI device whose resources were previously reserved by
39488c2ecf20Sopenharmony_ci *	  pci_request_regions()
39498c2ecf20Sopenharmony_ci *
39508c2ecf20Sopenharmony_ci * Releases all PCI I/O and memory resources previously reserved by a
39518c2ecf20Sopenharmony_ci * successful call to pci_request_regions().  Call this function only
39528c2ecf20Sopenharmony_ci * after all use of the PCI regions has ceased.
39538c2ecf20Sopenharmony_ci */
39548c2ecf20Sopenharmony_ci
39558c2ecf20Sopenharmony_civoid pci_release_regions(struct pci_dev *pdev)
39568c2ecf20Sopenharmony_ci{
39578c2ecf20Sopenharmony_ci	pci_release_selected_regions(pdev, (1 << PCI_STD_NUM_BARS) - 1);
39588c2ecf20Sopenharmony_ci}
39598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_release_regions);
39608c2ecf20Sopenharmony_ci
39618c2ecf20Sopenharmony_ci/**
39628c2ecf20Sopenharmony_ci * pci_request_regions - Reserve PCI I/O and memory resources
39638c2ecf20Sopenharmony_ci * @pdev: PCI device whose resources are to be reserved
39648c2ecf20Sopenharmony_ci * @res_name: Name to be associated with resource.
39658c2ecf20Sopenharmony_ci *
39668c2ecf20Sopenharmony_ci * Mark all PCI regions associated with PCI device @pdev as
39678c2ecf20Sopenharmony_ci * being reserved by owner @res_name.  Do not access any
39688c2ecf20Sopenharmony_ci * address inside the PCI regions unless this call returns
39698c2ecf20Sopenharmony_ci * successfully.
39708c2ecf20Sopenharmony_ci *
39718c2ecf20Sopenharmony_ci * Returns 0 on success, or %EBUSY on error.  A warning
39728c2ecf20Sopenharmony_ci * message is also printed on failure.
39738c2ecf20Sopenharmony_ci */
39748c2ecf20Sopenharmony_ciint pci_request_regions(struct pci_dev *pdev, const char *res_name)
39758c2ecf20Sopenharmony_ci{
39768c2ecf20Sopenharmony_ci	return pci_request_selected_regions(pdev,
39778c2ecf20Sopenharmony_ci			((1 << PCI_STD_NUM_BARS) - 1), res_name);
39788c2ecf20Sopenharmony_ci}
39798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_request_regions);
39808c2ecf20Sopenharmony_ci
39818c2ecf20Sopenharmony_ci/**
39828c2ecf20Sopenharmony_ci * pci_request_regions_exclusive - Reserve PCI I/O and memory resources
39838c2ecf20Sopenharmony_ci * @pdev: PCI device whose resources are to be reserved
39848c2ecf20Sopenharmony_ci * @res_name: Name to be associated with resource.
39858c2ecf20Sopenharmony_ci *
39868c2ecf20Sopenharmony_ci * Mark all PCI regions associated with PCI device @pdev as being reserved
39878c2ecf20Sopenharmony_ci * by owner @res_name.  Do not access any address inside the PCI regions
39888c2ecf20Sopenharmony_ci * unless this call returns successfully.
39898c2ecf20Sopenharmony_ci *
39908c2ecf20Sopenharmony_ci * pci_request_regions_exclusive() will mark the region so that /dev/mem
39918c2ecf20Sopenharmony_ci * and the sysfs MMIO access will not be allowed.
39928c2ecf20Sopenharmony_ci *
39938c2ecf20Sopenharmony_ci * Returns 0 on success, or %EBUSY on error.  A warning message is also
39948c2ecf20Sopenharmony_ci * printed on failure.
39958c2ecf20Sopenharmony_ci */
39968c2ecf20Sopenharmony_ciint pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name)
39978c2ecf20Sopenharmony_ci{
39988c2ecf20Sopenharmony_ci	return pci_request_selected_regions_exclusive(pdev,
39998c2ecf20Sopenharmony_ci				((1 << PCI_STD_NUM_BARS) - 1), res_name);
40008c2ecf20Sopenharmony_ci}
40018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_request_regions_exclusive);
40028c2ecf20Sopenharmony_ci
40038c2ecf20Sopenharmony_ci/*
40048c2ecf20Sopenharmony_ci * Record the PCI IO range (expressed as CPU physical address + size).
40058c2ecf20Sopenharmony_ci * Return a negative value if an error has occurred, zero otherwise
40068c2ecf20Sopenharmony_ci */
40078c2ecf20Sopenharmony_ciint pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr,
40088c2ecf20Sopenharmony_ci			resource_size_t	size)
40098c2ecf20Sopenharmony_ci{
40108c2ecf20Sopenharmony_ci	int ret = 0;
40118c2ecf20Sopenharmony_ci#ifdef PCI_IOBASE
40128c2ecf20Sopenharmony_ci	struct logic_pio_hwaddr *range;
40138c2ecf20Sopenharmony_ci
40148c2ecf20Sopenharmony_ci	if (!size || addr + size < addr)
40158c2ecf20Sopenharmony_ci		return -EINVAL;
40168c2ecf20Sopenharmony_ci
40178c2ecf20Sopenharmony_ci	range = kzalloc(sizeof(*range), GFP_ATOMIC);
40188c2ecf20Sopenharmony_ci	if (!range)
40198c2ecf20Sopenharmony_ci		return -ENOMEM;
40208c2ecf20Sopenharmony_ci
40218c2ecf20Sopenharmony_ci	range->fwnode = fwnode;
40228c2ecf20Sopenharmony_ci	range->size = size;
40238c2ecf20Sopenharmony_ci	range->hw_start = addr;
40248c2ecf20Sopenharmony_ci	range->flags = LOGIC_PIO_CPU_MMIO;
40258c2ecf20Sopenharmony_ci
40268c2ecf20Sopenharmony_ci	ret = logic_pio_register_range(range);
40278c2ecf20Sopenharmony_ci	if (ret)
40288c2ecf20Sopenharmony_ci		kfree(range);
40298c2ecf20Sopenharmony_ci
40308c2ecf20Sopenharmony_ci	/* Ignore duplicates due to deferred probing */
40318c2ecf20Sopenharmony_ci	if (ret == -EEXIST)
40328c2ecf20Sopenharmony_ci		ret = 0;
40338c2ecf20Sopenharmony_ci#endif
40348c2ecf20Sopenharmony_ci
40358c2ecf20Sopenharmony_ci	return ret;
40368c2ecf20Sopenharmony_ci}
40378c2ecf20Sopenharmony_ci
40388c2ecf20Sopenharmony_ciphys_addr_t pci_pio_to_address(unsigned long pio)
40398c2ecf20Sopenharmony_ci{
40408c2ecf20Sopenharmony_ci	phys_addr_t address = (phys_addr_t)OF_BAD_ADDR;
40418c2ecf20Sopenharmony_ci
40428c2ecf20Sopenharmony_ci#ifdef PCI_IOBASE
40438c2ecf20Sopenharmony_ci	if (pio >= MMIO_UPPER_LIMIT)
40448c2ecf20Sopenharmony_ci		return address;
40458c2ecf20Sopenharmony_ci
40468c2ecf20Sopenharmony_ci	address = logic_pio_to_hwaddr(pio);
40478c2ecf20Sopenharmony_ci#endif
40488c2ecf20Sopenharmony_ci
40498c2ecf20Sopenharmony_ci	return address;
40508c2ecf20Sopenharmony_ci}
40518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_pio_to_address);
40528c2ecf20Sopenharmony_ci
40538c2ecf20Sopenharmony_ciunsigned long __weak pci_address_to_pio(phys_addr_t address)
40548c2ecf20Sopenharmony_ci{
40558c2ecf20Sopenharmony_ci#ifdef PCI_IOBASE
40568c2ecf20Sopenharmony_ci	return logic_pio_trans_cpuaddr(address);
40578c2ecf20Sopenharmony_ci#else
40588c2ecf20Sopenharmony_ci	if (address > IO_SPACE_LIMIT)
40598c2ecf20Sopenharmony_ci		return (unsigned long)-1;
40608c2ecf20Sopenharmony_ci
40618c2ecf20Sopenharmony_ci	return (unsigned long) address;
40628c2ecf20Sopenharmony_ci#endif
40638c2ecf20Sopenharmony_ci}
40648c2ecf20Sopenharmony_ci
40658c2ecf20Sopenharmony_ci/**
40668c2ecf20Sopenharmony_ci * pci_remap_iospace - Remap the memory mapped I/O space
40678c2ecf20Sopenharmony_ci * @res: Resource describing the I/O space
40688c2ecf20Sopenharmony_ci * @phys_addr: physical address of range to be mapped
40698c2ecf20Sopenharmony_ci *
40708c2ecf20Sopenharmony_ci * Remap the memory mapped I/O space described by the @res and the CPU
40718c2ecf20Sopenharmony_ci * physical address @phys_addr into virtual address space.  Only
40728c2ecf20Sopenharmony_ci * architectures that have memory mapped IO functions defined (and the
40738c2ecf20Sopenharmony_ci * PCI_IOBASE value defined) should call this function.
40748c2ecf20Sopenharmony_ci */
40758c2ecf20Sopenharmony_ciint pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
40768c2ecf20Sopenharmony_ci{
40778c2ecf20Sopenharmony_ci#if defined(PCI_IOBASE) && defined(CONFIG_MMU)
40788c2ecf20Sopenharmony_ci	unsigned long vaddr = (unsigned long)PCI_IOBASE + res->start;
40798c2ecf20Sopenharmony_ci
40808c2ecf20Sopenharmony_ci	if (!(res->flags & IORESOURCE_IO))
40818c2ecf20Sopenharmony_ci		return -EINVAL;
40828c2ecf20Sopenharmony_ci
40838c2ecf20Sopenharmony_ci	if (res->end > IO_SPACE_LIMIT)
40848c2ecf20Sopenharmony_ci		return -EINVAL;
40858c2ecf20Sopenharmony_ci
40868c2ecf20Sopenharmony_ci	return ioremap_page_range(vaddr, vaddr + resource_size(res), phys_addr,
40878c2ecf20Sopenharmony_ci				  pgprot_device(PAGE_KERNEL));
40888c2ecf20Sopenharmony_ci#else
40898c2ecf20Sopenharmony_ci	/*
40908c2ecf20Sopenharmony_ci	 * This architecture does not have memory mapped I/O space,
40918c2ecf20Sopenharmony_ci	 * so this function should never be called
40928c2ecf20Sopenharmony_ci	 */
40938c2ecf20Sopenharmony_ci	WARN_ONCE(1, "This architecture does not support memory mapped I/O\n");
40948c2ecf20Sopenharmony_ci	return -ENODEV;
40958c2ecf20Sopenharmony_ci#endif
40968c2ecf20Sopenharmony_ci}
40978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_remap_iospace);
40988c2ecf20Sopenharmony_ci
40998c2ecf20Sopenharmony_ci/**
41008c2ecf20Sopenharmony_ci * pci_unmap_iospace - Unmap the memory mapped I/O space
41018c2ecf20Sopenharmony_ci * @res: resource to be unmapped
41028c2ecf20Sopenharmony_ci *
41038c2ecf20Sopenharmony_ci * Unmap the CPU virtual address @res from virtual address space.  Only
41048c2ecf20Sopenharmony_ci * architectures that have memory mapped IO functions defined (and the
41058c2ecf20Sopenharmony_ci * PCI_IOBASE value defined) should call this function.
41068c2ecf20Sopenharmony_ci */
41078c2ecf20Sopenharmony_civoid pci_unmap_iospace(struct resource *res)
41088c2ecf20Sopenharmony_ci{
41098c2ecf20Sopenharmony_ci#if defined(PCI_IOBASE) && defined(CONFIG_MMU)
41108c2ecf20Sopenharmony_ci	unsigned long vaddr = (unsigned long)PCI_IOBASE + res->start;
41118c2ecf20Sopenharmony_ci
41128c2ecf20Sopenharmony_ci	unmap_kernel_range(vaddr, resource_size(res));
41138c2ecf20Sopenharmony_ci#endif
41148c2ecf20Sopenharmony_ci}
41158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_unmap_iospace);
41168c2ecf20Sopenharmony_ci
41178c2ecf20Sopenharmony_cistatic void devm_pci_unmap_iospace(struct device *dev, void *ptr)
41188c2ecf20Sopenharmony_ci{
41198c2ecf20Sopenharmony_ci	struct resource **res = ptr;
41208c2ecf20Sopenharmony_ci
41218c2ecf20Sopenharmony_ci	pci_unmap_iospace(*res);
41228c2ecf20Sopenharmony_ci}
41238c2ecf20Sopenharmony_ci
41248c2ecf20Sopenharmony_ci/**
41258c2ecf20Sopenharmony_ci * devm_pci_remap_iospace - Managed pci_remap_iospace()
41268c2ecf20Sopenharmony_ci * @dev: Generic device to remap IO address for
41278c2ecf20Sopenharmony_ci * @res: Resource describing the I/O space
41288c2ecf20Sopenharmony_ci * @phys_addr: physical address of range to be mapped
41298c2ecf20Sopenharmony_ci *
41308c2ecf20Sopenharmony_ci * Managed pci_remap_iospace().  Map is automatically unmapped on driver
41318c2ecf20Sopenharmony_ci * detach.
41328c2ecf20Sopenharmony_ci */
41338c2ecf20Sopenharmony_ciint devm_pci_remap_iospace(struct device *dev, const struct resource *res,
41348c2ecf20Sopenharmony_ci			   phys_addr_t phys_addr)
41358c2ecf20Sopenharmony_ci{
41368c2ecf20Sopenharmony_ci	const struct resource **ptr;
41378c2ecf20Sopenharmony_ci	int error;
41388c2ecf20Sopenharmony_ci
41398c2ecf20Sopenharmony_ci	ptr = devres_alloc(devm_pci_unmap_iospace, sizeof(*ptr), GFP_KERNEL);
41408c2ecf20Sopenharmony_ci	if (!ptr)
41418c2ecf20Sopenharmony_ci		return -ENOMEM;
41428c2ecf20Sopenharmony_ci
41438c2ecf20Sopenharmony_ci	error = pci_remap_iospace(res, phys_addr);
41448c2ecf20Sopenharmony_ci	if (error) {
41458c2ecf20Sopenharmony_ci		devres_free(ptr);
41468c2ecf20Sopenharmony_ci	} else	{
41478c2ecf20Sopenharmony_ci		*ptr = res;
41488c2ecf20Sopenharmony_ci		devres_add(dev, ptr);
41498c2ecf20Sopenharmony_ci	}
41508c2ecf20Sopenharmony_ci
41518c2ecf20Sopenharmony_ci	return error;
41528c2ecf20Sopenharmony_ci}
41538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devm_pci_remap_iospace);
41548c2ecf20Sopenharmony_ci
41558c2ecf20Sopenharmony_ci/**
41568c2ecf20Sopenharmony_ci * devm_pci_remap_cfgspace - Managed pci_remap_cfgspace()
41578c2ecf20Sopenharmony_ci * @dev: Generic device to remap IO address for
41588c2ecf20Sopenharmony_ci * @offset: Resource address to map
41598c2ecf20Sopenharmony_ci * @size: Size of map
41608c2ecf20Sopenharmony_ci *
41618c2ecf20Sopenharmony_ci * Managed pci_remap_cfgspace().  Map is automatically unmapped on driver
41628c2ecf20Sopenharmony_ci * detach.
41638c2ecf20Sopenharmony_ci */
41648c2ecf20Sopenharmony_civoid __iomem *devm_pci_remap_cfgspace(struct device *dev,
41658c2ecf20Sopenharmony_ci				      resource_size_t offset,
41668c2ecf20Sopenharmony_ci				      resource_size_t size)
41678c2ecf20Sopenharmony_ci{
41688c2ecf20Sopenharmony_ci	void __iomem **ptr, *addr;
41698c2ecf20Sopenharmony_ci
41708c2ecf20Sopenharmony_ci	ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
41718c2ecf20Sopenharmony_ci	if (!ptr)
41728c2ecf20Sopenharmony_ci		return NULL;
41738c2ecf20Sopenharmony_ci
41748c2ecf20Sopenharmony_ci	addr = pci_remap_cfgspace(offset, size);
41758c2ecf20Sopenharmony_ci	if (addr) {
41768c2ecf20Sopenharmony_ci		*ptr = addr;
41778c2ecf20Sopenharmony_ci		devres_add(dev, ptr);
41788c2ecf20Sopenharmony_ci	} else
41798c2ecf20Sopenharmony_ci		devres_free(ptr);
41808c2ecf20Sopenharmony_ci
41818c2ecf20Sopenharmony_ci	return addr;
41828c2ecf20Sopenharmony_ci}
41838c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devm_pci_remap_cfgspace);
41848c2ecf20Sopenharmony_ci
41858c2ecf20Sopenharmony_ci/**
41868c2ecf20Sopenharmony_ci * devm_pci_remap_cfg_resource - check, request region and ioremap cfg resource
41878c2ecf20Sopenharmony_ci * @dev: generic device to handle the resource for
41888c2ecf20Sopenharmony_ci * @res: configuration space resource to be handled
41898c2ecf20Sopenharmony_ci *
41908c2ecf20Sopenharmony_ci * Checks that a resource is a valid memory region, requests the memory
41918c2ecf20Sopenharmony_ci * region and ioremaps with pci_remap_cfgspace() API that ensures the
41928c2ecf20Sopenharmony_ci * proper PCI configuration space memory attributes are guaranteed.
41938c2ecf20Sopenharmony_ci *
41948c2ecf20Sopenharmony_ci * All operations are managed and will be undone on driver detach.
41958c2ecf20Sopenharmony_ci *
41968c2ecf20Sopenharmony_ci * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
41978c2ecf20Sopenharmony_ci * on failure. Usage example::
41988c2ecf20Sopenharmony_ci *
41998c2ecf20Sopenharmony_ci *	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
42008c2ecf20Sopenharmony_ci *	base = devm_pci_remap_cfg_resource(&pdev->dev, res);
42018c2ecf20Sopenharmony_ci *	if (IS_ERR(base))
42028c2ecf20Sopenharmony_ci *		return PTR_ERR(base);
42038c2ecf20Sopenharmony_ci */
42048c2ecf20Sopenharmony_civoid __iomem *devm_pci_remap_cfg_resource(struct device *dev,
42058c2ecf20Sopenharmony_ci					  struct resource *res)
42068c2ecf20Sopenharmony_ci{
42078c2ecf20Sopenharmony_ci	resource_size_t size;
42088c2ecf20Sopenharmony_ci	const char *name;
42098c2ecf20Sopenharmony_ci	void __iomem *dest_ptr;
42108c2ecf20Sopenharmony_ci
42118c2ecf20Sopenharmony_ci	BUG_ON(!dev);
42128c2ecf20Sopenharmony_ci
42138c2ecf20Sopenharmony_ci	if (!res || resource_type(res) != IORESOURCE_MEM) {
42148c2ecf20Sopenharmony_ci		dev_err(dev, "invalid resource\n");
42158c2ecf20Sopenharmony_ci		return IOMEM_ERR_PTR(-EINVAL);
42168c2ecf20Sopenharmony_ci	}
42178c2ecf20Sopenharmony_ci
42188c2ecf20Sopenharmony_ci	size = resource_size(res);
42198c2ecf20Sopenharmony_ci	name = res->name ?: dev_name(dev);
42208c2ecf20Sopenharmony_ci
42218c2ecf20Sopenharmony_ci	if (!devm_request_mem_region(dev, res->start, size, name)) {
42228c2ecf20Sopenharmony_ci		dev_err(dev, "can't request region for resource %pR\n", res);
42238c2ecf20Sopenharmony_ci		return IOMEM_ERR_PTR(-EBUSY);
42248c2ecf20Sopenharmony_ci	}
42258c2ecf20Sopenharmony_ci
42268c2ecf20Sopenharmony_ci	dest_ptr = devm_pci_remap_cfgspace(dev, res->start, size);
42278c2ecf20Sopenharmony_ci	if (!dest_ptr) {
42288c2ecf20Sopenharmony_ci		dev_err(dev, "ioremap failed for resource %pR\n", res);
42298c2ecf20Sopenharmony_ci		devm_release_mem_region(dev, res->start, size);
42308c2ecf20Sopenharmony_ci		dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
42318c2ecf20Sopenharmony_ci	}
42328c2ecf20Sopenharmony_ci
42338c2ecf20Sopenharmony_ci	return dest_ptr;
42348c2ecf20Sopenharmony_ci}
42358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devm_pci_remap_cfg_resource);
42368c2ecf20Sopenharmony_ci
42378c2ecf20Sopenharmony_cistatic void __pci_set_master(struct pci_dev *dev, bool enable)
42388c2ecf20Sopenharmony_ci{
42398c2ecf20Sopenharmony_ci	u16 old_cmd, cmd;
42408c2ecf20Sopenharmony_ci
42418c2ecf20Sopenharmony_ci	pci_read_config_word(dev, PCI_COMMAND, &old_cmd);
42428c2ecf20Sopenharmony_ci	if (enable)
42438c2ecf20Sopenharmony_ci		cmd = old_cmd | PCI_COMMAND_MASTER;
42448c2ecf20Sopenharmony_ci	else
42458c2ecf20Sopenharmony_ci		cmd = old_cmd & ~PCI_COMMAND_MASTER;
42468c2ecf20Sopenharmony_ci	if (cmd != old_cmd) {
42478c2ecf20Sopenharmony_ci		pci_dbg(dev, "%s bus mastering\n",
42488c2ecf20Sopenharmony_ci			enable ? "enabling" : "disabling");
42498c2ecf20Sopenharmony_ci		pci_write_config_word(dev, PCI_COMMAND, cmd);
42508c2ecf20Sopenharmony_ci	}
42518c2ecf20Sopenharmony_ci	dev->is_busmaster = enable;
42528c2ecf20Sopenharmony_ci}
42538c2ecf20Sopenharmony_ci
42548c2ecf20Sopenharmony_ci/**
42558c2ecf20Sopenharmony_ci * pcibios_setup - process "pci=" kernel boot arguments
42568c2ecf20Sopenharmony_ci * @str: string used to pass in "pci=" kernel boot arguments
42578c2ecf20Sopenharmony_ci *
42588c2ecf20Sopenharmony_ci * Process kernel boot arguments.  This is the default implementation.
42598c2ecf20Sopenharmony_ci * Architecture specific implementations can override this as necessary.
42608c2ecf20Sopenharmony_ci */
42618c2ecf20Sopenharmony_cichar * __weak __init pcibios_setup(char *str)
42628c2ecf20Sopenharmony_ci{
42638c2ecf20Sopenharmony_ci	return str;
42648c2ecf20Sopenharmony_ci}
42658c2ecf20Sopenharmony_ci
42668c2ecf20Sopenharmony_ci/**
42678c2ecf20Sopenharmony_ci * pcibios_set_master - enable PCI bus-mastering for device dev
42688c2ecf20Sopenharmony_ci * @dev: the PCI device to enable
42698c2ecf20Sopenharmony_ci *
42708c2ecf20Sopenharmony_ci * Enables PCI bus-mastering for the device.  This is the default
42718c2ecf20Sopenharmony_ci * implementation.  Architecture specific implementations can override
42728c2ecf20Sopenharmony_ci * this if necessary.
42738c2ecf20Sopenharmony_ci */
42748c2ecf20Sopenharmony_civoid __weak pcibios_set_master(struct pci_dev *dev)
42758c2ecf20Sopenharmony_ci{
42768c2ecf20Sopenharmony_ci	u8 lat;
42778c2ecf20Sopenharmony_ci
42788c2ecf20Sopenharmony_ci	/* The latency timer doesn't apply to PCIe (either Type 0 or Type 1) */
42798c2ecf20Sopenharmony_ci	if (pci_is_pcie(dev))
42808c2ecf20Sopenharmony_ci		return;
42818c2ecf20Sopenharmony_ci
42828c2ecf20Sopenharmony_ci	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
42838c2ecf20Sopenharmony_ci	if (lat < 16)
42848c2ecf20Sopenharmony_ci		lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
42858c2ecf20Sopenharmony_ci	else if (lat > pcibios_max_latency)
42868c2ecf20Sopenharmony_ci		lat = pcibios_max_latency;
42878c2ecf20Sopenharmony_ci	else
42888c2ecf20Sopenharmony_ci		return;
42898c2ecf20Sopenharmony_ci
42908c2ecf20Sopenharmony_ci	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
42918c2ecf20Sopenharmony_ci}
42928c2ecf20Sopenharmony_ci
42938c2ecf20Sopenharmony_ci/**
42948c2ecf20Sopenharmony_ci * pci_set_master - enables bus-mastering for device dev
42958c2ecf20Sopenharmony_ci * @dev: the PCI device to enable
42968c2ecf20Sopenharmony_ci *
42978c2ecf20Sopenharmony_ci * Enables bus-mastering on the device and calls pcibios_set_master()
42988c2ecf20Sopenharmony_ci * to do the needed arch specific settings.
42998c2ecf20Sopenharmony_ci */
43008c2ecf20Sopenharmony_civoid pci_set_master(struct pci_dev *dev)
43018c2ecf20Sopenharmony_ci{
43028c2ecf20Sopenharmony_ci	__pci_set_master(dev, true);
43038c2ecf20Sopenharmony_ci	pcibios_set_master(dev);
43048c2ecf20Sopenharmony_ci}
43058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_set_master);
43068c2ecf20Sopenharmony_ci
43078c2ecf20Sopenharmony_ci/**
43088c2ecf20Sopenharmony_ci * pci_clear_master - disables bus-mastering for device dev
43098c2ecf20Sopenharmony_ci * @dev: the PCI device to disable
43108c2ecf20Sopenharmony_ci */
43118c2ecf20Sopenharmony_civoid pci_clear_master(struct pci_dev *dev)
43128c2ecf20Sopenharmony_ci{
43138c2ecf20Sopenharmony_ci	__pci_set_master(dev, false);
43148c2ecf20Sopenharmony_ci}
43158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_clear_master);
43168c2ecf20Sopenharmony_ci
43178c2ecf20Sopenharmony_ci/**
43188c2ecf20Sopenharmony_ci * pci_set_cacheline_size - ensure the CACHE_LINE_SIZE register is programmed
43198c2ecf20Sopenharmony_ci * @dev: the PCI device for which MWI is to be enabled
43208c2ecf20Sopenharmony_ci *
43218c2ecf20Sopenharmony_ci * Helper function for pci_set_mwi.
43228c2ecf20Sopenharmony_ci * Originally copied from drivers/net/acenic.c.
43238c2ecf20Sopenharmony_ci * Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>.
43248c2ecf20Sopenharmony_ci *
43258c2ecf20Sopenharmony_ci * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
43268c2ecf20Sopenharmony_ci */
43278c2ecf20Sopenharmony_ciint pci_set_cacheline_size(struct pci_dev *dev)
43288c2ecf20Sopenharmony_ci{
43298c2ecf20Sopenharmony_ci	u8 cacheline_size;
43308c2ecf20Sopenharmony_ci
43318c2ecf20Sopenharmony_ci	if (!pci_cache_line_size)
43328c2ecf20Sopenharmony_ci		return -EINVAL;
43338c2ecf20Sopenharmony_ci
43348c2ecf20Sopenharmony_ci	/* Validate current setting: the PCI_CACHE_LINE_SIZE must be
43358c2ecf20Sopenharmony_ci	   equal to or multiple of the right value. */
43368c2ecf20Sopenharmony_ci	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cacheline_size);
43378c2ecf20Sopenharmony_ci	if (cacheline_size >= pci_cache_line_size &&
43388c2ecf20Sopenharmony_ci	    (cacheline_size % pci_cache_line_size) == 0)
43398c2ecf20Sopenharmony_ci		return 0;
43408c2ecf20Sopenharmony_ci
43418c2ecf20Sopenharmony_ci	/* Write the correct value. */
43428c2ecf20Sopenharmony_ci	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size);
43438c2ecf20Sopenharmony_ci	/* Read it back. */
43448c2ecf20Sopenharmony_ci	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cacheline_size);
43458c2ecf20Sopenharmony_ci	if (cacheline_size == pci_cache_line_size)
43468c2ecf20Sopenharmony_ci		return 0;
43478c2ecf20Sopenharmony_ci
43488c2ecf20Sopenharmony_ci	pci_info(dev, "cache line size of %d is not supported\n",
43498c2ecf20Sopenharmony_ci		   pci_cache_line_size << 2);
43508c2ecf20Sopenharmony_ci
43518c2ecf20Sopenharmony_ci	return -EINVAL;
43528c2ecf20Sopenharmony_ci}
43538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_set_cacheline_size);
43548c2ecf20Sopenharmony_ci
43558c2ecf20Sopenharmony_ci/**
43568c2ecf20Sopenharmony_ci * pci_set_mwi - enables memory-write-invalidate PCI transaction
43578c2ecf20Sopenharmony_ci * @dev: the PCI device for which MWI is enabled
43588c2ecf20Sopenharmony_ci *
43598c2ecf20Sopenharmony_ci * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND.
43608c2ecf20Sopenharmony_ci *
43618c2ecf20Sopenharmony_ci * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
43628c2ecf20Sopenharmony_ci */
43638c2ecf20Sopenharmony_ciint pci_set_mwi(struct pci_dev *dev)
43648c2ecf20Sopenharmony_ci{
43658c2ecf20Sopenharmony_ci#ifdef PCI_DISABLE_MWI
43668c2ecf20Sopenharmony_ci	return 0;
43678c2ecf20Sopenharmony_ci#else
43688c2ecf20Sopenharmony_ci	int rc;
43698c2ecf20Sopenharmony_ci	u16 cmd;
43708c2ecf20Sopenharmony_ci
43718c2ecf20Sopenharmony_ci	rc = pci_set_cacheline_size(dev);
43728c2ecf20Sopenharmony_ci	if (rc)
43738c2ecf20Sopenharmony_ci		return rc;
43748c2ecf20Sopenharmony_ci
43758c2ecf20Sopenharmony_ci	pci_read_config_word(dev, PCI_COMMAND, &cmd);
43768c2ecf20Sopenharmony_ci	if (!(cmd & PCI_COMMAND_INVALIDATE)) {
43778c2ecf20Sopenharmony_ci		pci_dbg(dev, "enabling Mem-Wr-Inval\n");
43788c2ecf20Sopenharmony_ci		cmd |= PCI_COMMAND_INVALIDATE;
43798c2ecf20Sopenharmony_ci		pci_write_config_word(dev, PCI_COMMAND, cmd);
43808c2ecf20Sopenharmony_ci	}
43818c2ecf20Sopenharmony_ci	return 0;
43828c2ecf20Sopenharmony_ci#endif
43838c2ecf20Sopenharmony_ci}
43848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_set_mwi);
43858c2ecf20Sopenharmony_ci
43868c2ecf20Sopenharmony_ci/**
43878c2ecf20Sopenharmony_ci * pcim_set_mwi - a device-managed pci_set_mwi()
43888c2ecf20Sopenharmony_ci * @dev: the PCI device for which MWI is enabled
43898c2ecf20Sopenharmony_ci *
43908c2ecf20Sopenharmony_ci * Managed pci_set_mwi().
43918c2ecf20Sopenharmony_ci *
43928c2ecf20Sopenharmony_ci * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
43938c2ecf20Sopenharmony_ci */
43948c2ecf20Sopenharmony_ciint pcim_set_mwi(struct pci_dev *dev)
43958c2ecf20Sopenharmony_ci{
43968c2ecf20Sopenharmony_ci	struct pci_devres *dr;
43978c2ecf20Sopenharmony_ci
43988c2ecf20Sopenharmony_ci	dr = find_pci_dr(dev);
43998c2ecf20Sopenharmony_ci	if (!dr)
44008c2ecf20Sopenharmony_ci		return -ENOMEM;
44018c2ecf20Sopenharmony_ci
44028c2ecf20Sopenharmony_ci	dr->mwi = 1;
44038c2ecf20Sopenharmony_ci	return pci_set_mwi(dev);
44048c2ecf20Sopenharmony_ci}
44058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcim_set_mwi);
44068c2ecf20Sopenharmony_ci
44078c2ecf20Sopenharmony_ci/**
44088c2ecf20Sopenharmony_ci * pci_try_set_mwi - enables memory-write-invalidate PCI transaction
44098c2ecf20Sopenharmony_ci * @dev: the PCI device for which MWI is enabled
44108c2ecf20Sopenharmony_ci *
44118c2ecf20Sopenharmony_ci * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND.
44128c2ecf20Sopenharmony_ci * Callers are not required to check the return value.
44138c2ecf20Sopenharmony_ci *
44148c2ecf20Sopenharmony_ci * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
44158c2ecf20Sopenharmony_ci */
44168c2ecf20Sopenharmony_ciint pci_try_set_mwi(struct pci_dev *dev)
44178c2ecf20Sopenharmony_ci{
44188c2ecf20Sopenharmony_ci#ifdef PCI_DISABLE_MWI
44198c2ecf20Sopenharmony_ci	return 0;
44208c2ecf20Sopenharmony_ci#else
44218c2ecf20Sopenharmony_ci	return pci_set_mwi(dev);
44228c2ecf20Sopenharmony_ci#endif
44238c2ecf20Sopenharmony_ci}
44248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_try_set_mwi);
44258c2ecf20Sopenharmony_ci
44268c2ecf20Sopenharmony_ci/**
44278c2ecf20Sopenharmony_ci * pci_clear_mwi - disables Memory-Write-Invalidate for device dev
44288c2ecf20Sopenharmony_ci * @dev: the PCI device to disable
44298c2ecf20Sopenharmony_ci *
44308c2ecf20Sopenharmony_ci * Disables PCI Memory-Write-Invalidate transaction on the device
44318c2ecf20Sopenharmony_ci */
44328c2ecf20Sopenharmony_civoid pci_clear_mwi(struct pci_dev *dev)
44338c2ecf20Sopenharmony_ci{
44348c2ecf20Sopenharmony_ci#ifndef PCI_DISABLE_MWI
44358c2ecf20Sopenharmony_ci	u16 cmd;
44368c2ecf20Sopenharmony_ci
44378c2ecf20Sopenharmony_ci	pci_read_config_word(dev, PCI_COMMAND, &cmd);
44388c2ecf20Sopenharmony_ci	if (cmd & PCI_COMMAND_INVALIDATE) {
44398c2ecf20Sopenharmony_ci		cmd &= ~PCI_COMMAND_INVALIDATE;
44408c2ecf20Sopenharmony_ci		pci_write_config_word(dev, PCI_COMMAND, cmd);
44418c2ecf20Sopenharmony_ci	}
44428c2ecf20Sopenharmony_ci#endif
44438c2ecf20Sopenharmony_ci}
44448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_clear_mwi);
44458c2ecf20Sopenharmony_ci
44468c2ecf20Sopenharmony_ci/**
44478c2ecf20Sopenharmony_ci * pci_intx - enables/disables PCI INTx for device dev
44488c2ecf20Sopenharmony_ci * @pdev: the PCI device to operate on
44498c2ecf20Sopenharmony_ci * @enable: boolean: whether to enable or disable PCI INTx
44508c2ecf20Sopenharmony_ci *
44518c2ecf20Sopenharmony_ci * Enables/disables PCI INTx for device @pdev
44528c2ecf20Sopenharmony_ci */
44538c2ecf20Sopenharmony_civoid pci_intx(struct pci_dev *pdev, int enable)
44548c2ecf20Sopenharmony_ci{
44558c2ecf20Sopenharmony_ci	u16 pci_command, new;
44568c2ecf20Sopenharmony_ci
44578c2ecf20Sopenharmony_ci	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
44588c2ecf20Sopenharmony_ci
44598c2ecf20Sopenharmony_ci	if (enable)
44608c2ecf20Sopenharmony_ci		new = pci_command & ~PCI_COMMAND_INTX_DISABLE;
44618c2ecf20Sopenharmony_ci	else
44628c2ecf20Sopenharmony_ci		new = pci_command | PCI_COMMAND_INTX_DISABLE;
44638c2ecf20Sopenharmony_ci
44648c2ecf20Sopenharmony_ci	if (new != pci_command) {
44658c2ecf20Sopenharmony_ci		struct pci_devres *dr;
44668c2ecf20Sopenharmony_ci
44678c2ecf20Sopenharmony_ci		pci_write_config_word(pdev, PCI_COMMAND, new);
44688c2ecf20Sopenharmony_ci
44698c2ecf20Sopenharmony_ci		dr = find_pci_dr(pdev);
44708c2ecf20Sopenharmony_ci		if (dr && !dr->restore_intx) {
44718c2ecf20Sopenharmony_ci			dr->restore_intx = 1;
44728c2ecf20Sopenharmony_ci			dr->orig_intx = !enable;
44738c2ecf20Sopenharmony_ci		}
44748c2ecf20Sopenharmony_ci	}
44758c2ecf20Sopenharmony_ci}
44768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_intx);
44778c2ecf20Sopenharmony_ci
44788c2ecf20Sopenharmony_cistatic bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask)
44798c2ecf20Sopenharmony_ci{
44808c2ecf20Sopenharmony_ci	struct pci_bus *bus = dev->bus;
44818c2ecf20Sopenharmony_ci	bool mask_updated = true;
44828c2ecf20Sopenharmony_ci	u32 cmd_status_dword;
44838c2ecf20Sopenharmony_ci	u16 origcmd, newcmd;
44848c2ecf20Sopenharmony_ci	unsigned long flags;
44858c2ecf20Sopenharmony_ci	bool irq_pending;
44868c2ecf20Sopenharmony_ci
44878c2ecf20Sopenharmony_ci	/*
44888c2ecf20Sopenharmony_ci	 * We do a single dword read to retrieve both command and status.
44898c2ecf20Sopenharmony_ci	 * Document assumptions that make this possible.
44908c2ecf20Sopenharmony_ci	 */
44918c2ecf20Sopenharmony_ci	BUILD_BUG_ON(PCI_COMMAND % 4);
44928c2ecf20Sopenharmony_ci	BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS);
44938c2ecf20Sopenharmony_ci
44948c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pci_lock, flags);
44958c2ecf20Sopenharmony_ci
44968c2ecf20Sopenharmony_ci	bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword);
44978c2ecf20Sopenharmony_ci
44988c2ecf20Sopenharmony_ci	irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT;
44998c2ecf20Sopenharmony_ci
45008c2ecf20Sopenharmony_ci	/*
45018c2ecf20Sopenharmony_ci	 * Check interrupt status register to see whether our device
45028c2ecf20Sopenharmony_ci	 * triggered the interrupt (when masking) or the next IRQ is
45038c2ecf20Sopenharmony_ci	 * already pending (when unmasking).
45048c2ecf20Sopenharmony_ci	 */
45058c2ecf20Sopenharmony_ci	if (mask != irq_pending) {
45068c2ecf20Sopenharmony_ci		mask_updated = false;
45078c2ecf20Sopenharmony_ci		goto done;
45088c2ecf20Sopenharmony_ci	}
45098c2ecf20Sopenharmony_ci
45108c2ecf20Sopenharmony_ci	origcmd = cmd_status_dword;
45118c2ecf20Sopenharmony_ci	newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE;
45128c2ecf20Sopenharmony_ci	if (mask)
45138c2ecf20Sopenharmony_ci		newcmd |= PCI_COMMAND_INTX_DISABLE;
45148c2ecf20Sopenharmony_ci	if (newcmd != origcmd)
45158c2ecf20Sopenharmony_ci		bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd);
45168c2ecf20Sopenharmony_ci
45178c2ecf20Sopenharmony_cidone:
45188c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pci_lock, flags);
45198c2ecf20Sopenharmony_ci
45208c2ecf20Sopenharmony_ci	return mask_updated;
45218c2ecf20Sopenharmony_ci}
45228c2ecf20Sopenharmony_ci
45238c2ecf20Sopenharmony_ci/**
45248c2ecf20Sopenharmony_ci * pci_check_and_mask_intx - mask INTx on pending interrupt
45258c2ecf20Sopenharmony_ci * @dev: the PCI device to operate on
45268c2ecf20Sopenharmony_ci *
45278c2ecf20Sopenharmony_ci * Check if the device dev has its INTx line asserted, mask it and return
45288c2ecf20Sopenharmony_ci * true in that case. False is returned if no interrupt was pending.
45298c2ecf20Sopenharmony_ci */
45308c2ecf20Sopenharmony_cibool pci_check_and_mask_intx(struct pci_dev *dev)
45318c2ecf20Sopenharmony_ci{
45328c2ecf20Sopenharmony_ci	return pci_check_and_set_intx_mask(dev, true);
45338c2ecf20Sopenharmony_ci}
45348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_check_and_mask_intx);
45358c2ecf20Sopenharmony_ci
45368c2ecf20Sopenharmony_ci/**
45378c2ecf20Sopenharmony_ci * pci_check_and_unmask_intx - unmask INTx if no interrupt is pending
45388c2ecf20Sopenharmony_ci * @dev: the PCI device to operate on
45398c2ecf20Sopenharmony_ci *
45408c2ecf20Sopenharmony_ci * Check if the device dev has its INTx line asserted, unmask it if not and
45418c2ecf20Sopenharmony_ci * return true. False is returned and the mask remains active if there was
45428c2ecf20Sopenharmony_ci * still an interrupt pending.
45438c2ecf20Sopenharmony_ci */
45448c2ecf20Sopenharmony_cibool pci_check_and_unmask_intx(struct pci_dev *dev)
45458c2ecf20Sopenharmony_ci{
45468c2ecf20Sopenharmony_ci	return pci_check_and_set_intx_mask(dev, false);
45478c2ecf20Sopenharmony_ci}
45488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);
45498c2ecf20Sopenharmony_ci
45508c2ecf20Sopenharmony_ci/**
45518c2ecf20Sopenharmony_ci * pci_wait_for_pending_transaction - wait for pending transaction
45528c2ecf20Sopenharmony_ci * @dev: the PCI device to operate on
45538c2ecf20Sopenharmony_ci *
45548c2ecf20Sopenharmony_ci * Return 0 if transaction is pending 1 otherwise.
45558c2ecf20Sopenharmony_ci */
45568c2ecf20Sopenharmony_ciint pci_wait_for_pending_transaction(struct pci_dev *dev)
45578c2ecf20Sopenharmony_ci{
45588c2ecf20Sopenharmony_ci	if (!pci_is_pcie(dev))
45598c2ecf20Sopenharmony_ci		return 1;
45608c2ecf20Sopenharmony_ci
45618c2ecf20Sopenharmony_ci	return pci_wait_for_pending(dev, pci_pcie_cap(dev) + PCI_EXP_DEVSTA,
45628c2ecf20Sopenharmony_ci				    PCI_EXP_DEVSTA_TRPND);
45638c2ecf20Sopenharmony_ci}
45648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_wait_for_pending_transaction);
45658c2ecf20Sopenharmony_ci
45668c2ecf20Sopenharmony_ci/**
45678c2ecf20Sopenharmony_ci * pcie_has_flr - check if a device supports function level resets
45688c2ecf20Sopenharmony_ci * @dev: device to check
45698c2ecf20Sopenharmony_ci *
45708c2ecf20Sopenharmony_ci * Returns true if the device advertises support for PCIe function level
45718c2ecf20Sopenharmony_ci * resets.
45728c2ecf20Sopenharmony_ci */
45738c2ecf20Sopenharmony_cibool pcie_has_flr(struct pci_dev *dev)
45748c2ecf20Sopenharmony_ci{
45758c2ecf20Sopenharmony_ci	u32 cap;
45768c2ecf20Sopenharmony_ci
45778c2ecf20Sopenharmony_ci	if (dev->dev_flags & PCI_DEV_FLAGS_NO_FLR_RESET)
45788c2ecf20Sopenharmony_ci		return false;
45798c2ecf20Sopenharmony_ci
45808c2ecf20Sopenharmony_ci	pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
45818c2ecf20Sopenharmony_ci	return cap & PCI_EXP_DEVCAP_FLR;
45828c2ecf20Sopenharmony_ci}
45838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pcie_has_flr);
45848c2ecf20Sopenharmony_ci
45858c2ecf20Sopenharmony_ci/**
45868c2ecf20Sopenharmony_ci * pcie_flr - initiate a PCIe function level reset
45878c2ecf20Sopenharmony_ci * @dev: device to reset
45888c2ecf20Sopenharmony_ci *
45898c2ecf20Sopenharmony_ci * Initiate a function level reset on @dev.  The caller should ensure the
45908c2ecf20Sopenharmony_ci * device supports FLR before calling this function, e.g. by using the
45918c2ecf20Sopenharmony_ci * pcie_has_flr() helper.
45928c2ecf20Sopenharmony_ci */
45938c2ecf20Sopenharmony_ciint pcie_flr(struct pci_dev *dev)
45948c2ecf20Sopenharmony_ci{
45958c2ecf20Sopenharmony_ci	if (!pci_wait_for_pending_transaction(dev))
45968c2ecf20Sopenharmony_ci		pci_err(dev, "timed out waiting for pending transaction; performing function level reset anyway\n");
45978c2ecf20Sopenharmony_ci
45988c2ecf20Sopenharmony_ci	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
45998c2ecf20Sopenharmony_ci
46008c2ecf20Sopenharmony_ci	if (dev->imm_ready)
46018c2ecf20Sopenharmony_ci		return 0;
46028c2ecf20Sopenharmony_ci
46038c2ecf20Sopenharmony_ci	/*
46048c2ecf20Sopenharmony_ci	 * Per PCIe r4.0, sec 6.6.2, a device must complete an FLR within
46058c2ecf20Sopenharmony_ci	 * 100ms, but may silently discard requests while the FLR is in
46068c2ecf20Sopenharmony_ci	 * progress.  Wait 100ms before trying to access the device.
46078c2ecf20Sopenharmony_ci	 */
46088c2ecf20Sopenharmony_ci	msleep(100);
46098c2ecf20Sopenharmony_ci
46108c2ecf20Sopenharmony_ci	return pci_dev_wait(dev, "FLR", PCIE_RESET_READY_POLL_MS);
46118c2ecf20Sopenharmony_ci}
46128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pcie_flr);
46138c2ecf20Sopenharmony_ci
46148c2ecf20Sopenharmony_cistatic int pci_af_flr(struct pci_dev *dev, int probe)
46158c2ecf20Sopenharmony_ci{
46168c2ecf20Sopenharmony_ci	int pos;
46178c2ecf20Sopenharmony_ci	u8 cap;
46188c2ecf20Sopenharmony_ci
46198c2ecf20Sopenharmony_ci	pos = pci_find_capability(dev, PCI_CAP_ID_AF);
46208c2ecf20Sopenharmony_ci	if (!pos)
46218c2ecf20Sopenharmony_ci		return -ENOTTY;
46228c2ecf20Sopenharmony_ci
46238c2ecf20Sopenharmony_ci	if (dev->dev_flags & PCI_DEV_FLAGS_NO_FLR_RESET)
46248c2ecf20Sopenharmony_ci		return -ENOTTY;
46258c2ecf20Sopenharmony_ci
46268c2ecf20Sopenharmony_ci	pci_read_config_byte(dev, pos + PCI_AF_CAP, &cap);
46278c2ecf20Sopenharmony_ci	if (!(cap & PCI_AF_CAP_TP) || !(cap & PCI_AF_CAP_FLR))
46288c2ecf20Sopenharmony_ci		return -ENOTTY;
46298c2ecf20Sopenharmony_ci
46308c2ecf20Sopenharmony_ci	if (probe)
46318c2ecf20Sopenharmony_ci		return 0;
46328c2ecf20Sopenharmony_ci
46338c2ecf20Sopenharmony_ci	/*
46348c2ecf20Sopenharmony_ci	 * Wait for Transaction Pending bit to clear.  A word-aligned test
46358c2ecf20Sopenharmony_ci	 * is used, so we use the control offset rather than status and shift
46368c2ecf20Sopenharmony_ci	 * the test bit to match.
46378c2ecf20Sopenharmony_ci	 */
46388c2ecf20Sopenharmony_ci	if (!pci_wait_for_pending(dev, pos + PCI_AF_CTRL,
46398c2ecf20Sopenharmony_ci				 PCI_AF_STATUS_TP << 8))
46408c2ecf20Sopenharmony_ci		pci_err(dev, "timed out waiting for pending transaction; performing AF function level reset anyway\n");
46418c2ecf20Sopenharmony_ci
46428c2ecf20Sopenharmony_ci	pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
46438c2ecf20Sopenharmony_ci
46448c2ecf20Sopenharmony_ci	if (dev->imm_ready)
46458c2ecf20Sopenharmony_ci		return 0;
46468c2ecf20Sopenharmony_ci
46478c2ecf20Sopenharmony_ci	/*
46488c2ecf20Sopenharmony_ci	 * Per Advanced Capabilities for Conventional PCI ECN, 13 April 2006,
46498c2ecf20Sopenharmony_ci	 * updated 27 July 2006; a device must complete an FLR within
46508c2ecf20Sopenharmony_ci	 * 100ms, but may silently discard requests while the FLR is in
46518c2ecf20Sopenharmony_ci	 * progress.  Wait 100ms before trying to access the device.
46528c2ecf20Sopenharmony_ci	 */
46538c2ecf20Sopenharmony_ci	msleep(100);
46548c2ecf20Sopenharmony_ci
46558c2ecf20Sopenharmony_ci	return pci_dev_wait(dev, "AF_FLR", PCIE_RESET_READY_POLL_MS);
46568c2ecf20Sopenharmony_ci}
46578c2ecf20Sopenharmony_ci
46588c2ecf20Sopenharmony_ci/**
46598c2ecf20Sopenharmony_ci * pci_pm_reset - Put device into PCI_D3 and back into PCI_D0.
46608c2ecf20Sopenharmony_ci * @dev: Device to reset.
46618c2ecf20Sopenharmony_ci * @probe: If set, only check if the device can be reset this way.
46628c2ecf20Sopenharmony_ci *
46638c2ecf20Sopenharmony_ci * If @dev supports native PCI PM and its PCI_PM_CTRL_NO_SOFT_RESET flag is
46648c2ecf20Sopenharmony_ci * unset, it will be reinitialized internally when going from PCI_D3hot to
46658c2ecf20Sopenharmony_ci * PCI_D0.  If that's the case and the device is not in a low-power state
46668c2ecf20Sopenharmony_ci * already, force it into PCI_D3hot and back to PCI_D0, causing it to be reset.
46678c2ecf20Sopenharmony_ci *
46688c2ecf20Sopenharmony_ci * NOTE: This causes the caller to sleep for twice the device power transition
46698c2ecf20Sopenharmony_ci * cooldown period, which for the D0->D3hot and D3hot->D0 transitions is 10 ms
46708c2ecf20Sopenharmony_ci * by default (i.e. unless the @dev's d3hot_delay field has a different value).
46718c2ecf20Sopenharmony_ci * Moreover, only devices in D0 can be reset by this function.
46728c2ecf20Sopenharmony_ci */
46738c2ecf20Sopenharmony_cistatic int pci_pm_reset(struct pci_dev *dev, int probe)
46748c2ecf20Sopenharmony_ci{
46758c2ecf20Sopenharmony_ci	u16 csr;
46768c2ecf20Sopenharmony_ci
46778c2ecf20Sopenharmony_ci	if (!dev->pm_cap || dev->dev_flags & PCI_DEV_FLAGS_NO_PM_RESET)
46788c2ecf20Sopenharmony_ci		return -ENOTTY;
46798c2ecf20Sopenharmony_ci
46808c2ecf20Sopenharmony_ci	pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &csr);
46818c2ecf20Sopenharmony_ci	if (csr & PCI_PM_CTRL_NO_SOFT_RESET)
46828c2ecf20Sopenharmony_ci		return -ENOTTY;
46838c2ecf20Sopenharmony_ci
46848c2ecf20Sopenharmony_ci	if (probe)
46858c2ecf20Sopenharmony_ci		return 0;
46868c2ecf20Sopenharmony_ci
46878c2ecf20Sopenharmony_ci	if (dev->current_state != PCI_D0)
46888c2ecf20Sopenharmony_ci		return -EINVAL;
46898c2ecf20Sopenharmony_ci
46908c2ecf20Sopenharmony_ci	csr &= ~PCI_PM_CTRL_STATE_MASK;
46918c2ecf20Sopenharmony_ci	csr |= PCI_D3hot;
46928c2ecf20Sopenharmony_ci	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
46938c2ecf20Sopenharmony_ci	pci_dev_d3_sleep(dev);
46948c2ecf20Sopenharmony_ci
46958c2ecf20Sopenharmony_ci	csr &= ~PCI_PM_CTRL_STATE_MASK;
46968c2ecf20Sopenharmony_ci	csr |= PCI_D0;
46978c2ecf20Sopenharmony_ci	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
46988c2ecf20Sopenharmony_ci	pci_dev_d3_sleep(dev);
46998c2ecf20Sopenharmony_ci
47008c2ecf20Sopenharmony_ci	return pci_dev_wait(dev, "PM D3hot->D0", PCIE_RESET_READY_POLL_MS);
47018c2ecf20Sopenharmony_ci}
47028c2ecf20Sopenharmony_ci
47038c2ecf20Sopenharmony_ci/**
47048c2ecf20Sopenharmony_ci * pcie_wait_for_link_delay - Wait until link is active or inactive
47058c2ecf20Sopenharmony_ci * @pdev: Bridge device
47068c2ecf20Sopenharmony_ci * @active: waiting for active or inactive?
47078c2ecf20Sopenharmony_ci * @delay: Delay to wait after link has become active (in ms)
47088c2ecf20Sopenharmony_ci *
47098c2ecf20Sopenharmony_ci * Use this to wait till link becomes active or inactive.
47108c2ecf20Sopenharmony_ci */
47118c2ecf20Sopenharmony_cistatic bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active,
47128c2ecf20Sopenharmony_ci				     int delay)
47138c2ecf20Sopenharmony_ci{
47148c2ecf20Sopenharmony_ci	int timeout = 1000;
47158c2ecf20Sopenharmony_ci	bool ret;
47168c2ecf20Sopenharmony_ci	u16 lnk_status;
47178c2ecf20Sopenharmony_ci
47188c2ecf20Sopenharmony_ci	/*
47198c2ecf20Sopenharmony_ci	 * Some controllers might not implement link active reporting. In this
47208c2ecf20Sopenharmony_ci	 * case, we wait for 1000 ms + any delay requested by the caller.
47218c2ecf20Sopenharmony_ci	 */
47228c2ecf20Sopenharmony_ci	if (!pdev->link_active_reporting) {
47238c2ecf20Sopenharmony_ci		msleep(timeout + delay);
47248c2ecf20Sopenharmony_ci		return true;
47258c2ecf20Sopenharmony_ci	}
47268c2ecf20Sopenharmony_ci
47278c2ecf20Sopenharmony_ci	/*
47288c2ecf20Sopenharmony_ci	 * PCIe r4.0 sec 6.6.1, a component must enter LTSSM Detect within 20ms,
47298c2ecf20Sopenharmony_ci	 * after which we should expect an link active if the reset was
47308c2ecf20Sopenharmony_ci	 * successful. If so, software must wait a minimum 100ms before sending
47318c2ecf20Sopenharmony_ci	 * configuration requests to devices downstream this port.
47328c2ecf20Sopenharmony_ci	 *
47338c2ecf20Sopenharmony_ci	 * If the link fails to activate, either the device was physically
47348c2ecf20Sopenharmony_ci	 * removed or the link is permanently failed.
47358c2ecf20Sopenharmony_ci	 */
47368c2ecf20Sopenharmony_ci	if (active)
47378c2ecf20Sopenharmony_ci		msleep(20);
47388c2ecf20Sopenharmony_ci	for (;;) {
47398c2ecf20Sopenharmony_ci		pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
47408c2ecf20Sopenharmony_ci		ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
47418c2ecf20Sopenharmony_ci		if (ret == active)
47428c2ecf20Sopenharmony_ci			break;
47438c2ecf20Sopenharmony_ci		if (timeout <= 0)
47448c2ecf20Sopenharmony_ci			break;
47458c2ecf20Sopenharmony_ci		msleep(10);
47468c2ecf20Sopenharmony_ci		timeout -= 10;
47478c2ecf20Sopenharmony_ci	}
47488c2ecf20Sopenharmony_ci	if (active && ret)
47498c2ecf20Sopenharmony_ci		msleep(delay);
47508c2ecf20Sopenharmony_ci
47518c2ecf20Sopenharmony_ci	return ret == active;
47528c2ecf20Sopenharmony_ci}
47538c2ecf20Sopenharmony_ci
47548c2ecf20Sopenharmony_ci/**
47558c2ecf20Sopenharmony_ci * pcie_wait_for_link - Wait until link is active or inactive
47568c2ecf20Sopenharmony_ci * @pdev: Bridge device
47578c2ecf20Sopenharmony_ci * @active: waiting for active or inactive?
47588c2ecf20Sopenharmony_ci *
47598c2ecf20Sopenharmony_ci * Use this to wait till link becomes active or inactive.
47608c2ecf20Sopenharmony_ci */
47618c2ecf20Sopenharmony_cibool pcie_wait_for_link(struct pci_dev *pdev, bool active)
47628c2ecf20Sopenharmony_ci{
47638c2ecf20Sopenharmony_ci	return pcie_wait_for_link_delay(pdev, active, 100);
47648c2ecf20Sopenharmony_ci}
47658c2ecf20Sopenharmony_ci
47668c2ecf20Sopenharmony_ci/*
47678c2ecf20Sopenharmony_ci * Find maximum D3cold delay required by all the devices on the bus.  The
47688c2ecf20Sopenharmony_ci * spec says 100 ms, but firmware can lower it and we allow drivers to
47698c2ecf20Sopenharmony_ci * increase it as well.
47708c2ecf20Sopenharmony_ci *
47718c2ecf20Sopenharmony_ci * Called with @pci_bus_sem locked for reading.
47728c2ecf20Sopenharmony_ci */
47738c2ecf20Sopenharmony_cistatic int pci_bus_max_d3cold_delay(const struct pci_bus *bus)
47748c2ecf20Sopenharmony_ci{
47758c2ecf20Sopenharmony_ci	const struct pci_dev *pdev;
47768c2ecf20Sopenharmony_ci	int min_delay = 100;
47778c2ecf20Sopenharmony_ci	int max_delay = 0;
47788c2ecf20Sopenharmony_ci
47798c2ecf20Sopenharmony_ci	list_for_each_entry(pdev, &bus->devices, bus_list) {
47808c2ecf20Sopenharmony_ci		if (pdev->d3cold_delay < min_delay)
47818c2ecf20Sopenharmony_ci			min_delay = pdev->d3cold_delay;
47828c2ecf20Sopenharmony_ci		if (pdev->d3cold_delay > max_delay)
47838c2ecf20Sopenharmony_ci			max_delay = pdev->d3cold_delay;
47848c2ecf20Sopenharmony_ci	}
47858c2ecf20Sopenharmony_ci
47868c2ecf20Sopenharmony_ci	return max(min_delay, max_delay);
47878c2ecf20Sopenharmony_ci}
47888c2ecf20Sopenharmony_ci
47898c2ecf20Sopenharmony_ci/**
47908c2ecf20Sopenharmony_ci * pci_bridge_wait_for_secondary_bus - Wait for secondary bus to be accessible
47918c2ecf20Sopenharmony_ci * @dev: PCI bridge
47928c2ecf20Sopenharmony_ci * @reset_type: reset type in human-readable form
47938c2ecf20Sopenharmony_ci * @timeout: maximum time to wait for devices on secondary bus (milliseconds)
47948c2ecf20Sopenharmony_ci *
47958c2ecf20Sopenharmony_ci * Handle necessary delays before access to the devices on the secondary
47968c2ecf20Sopenharmony_ci * side of the bridge are permitted after D3cold to D0 transition
47978c2ecf20Sopenharmony_ci * or Conventional Reset.
47988c2ecf20Sopenharmony_ci *
47998c2ecf20Sopenharmony_ci * For PCIe this means the delays in PCIe 5.0 section 6.6.1. For
48008c2ecf20Sopenharmony_ci * conventional PCI it means Tpvrh + Trhfa specified in PCI 3.0 section
48018c2ecf20Sopenharmony_ci * 4.3.2.
48028c2ecf20Sopenharmony_ci *
48038c2ecf20Sopenharmony_ci * Return 0 on success or -ENOTTY if the first device on the secondary bus
48048c2ecf20Sopenharmony_ci * failed to become accessible.
48058c2ecf20Sopenharmony_ci */
48068c2ecf20Sopenharmony_ciint pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type,
48078c2ecf20Sopenharmony_ci				      int timeout)
48088c2ecf20Sopenharmony_ci{
48098c2ecf20Sopenharmony_ci	struct pci_dev *child;
48108c2ecf20Sopenharmony_ci	int delay, ret = 0;
48118c2ecf20Sopenharmony_ci
48128c2ecf20Sopenharmony_ci	if (pci_dev_is_disconnected(dev))
48138c2ecf20Sopenharmony_ci		return 0;
48148c2ecf20Sopenharmony_ci
48158c2ecf20Sopenharmony_ci	if (!pci_is_bridge(dev))
48168c2ecf20Sopenharmony_ci		return 0;
48178c2ecf20Sopenharmony_ci
48188c2ecf20Sopenharmony_ci	down_read(&pci_bus_sem);
48198c2ecf20Sopenharmony_ci
48208c2ecf20Sopenharmony_ci	/*
48218c2ecf20Sopenharmony_ci	 * We only deal with devices that are present currently on the bus.
48228c2ecf20Sopenharmony_ci	 * For any hot-added devices the access delay is handled in pciehp
48238c2ecf20Sopenharmony_ci	 * board_added(). In case of ACPI hotplug the firmware is expected
48248c2ecf20Sopenharmony_ci	 * to configure the devices before OS is notified.
48258c2ecf20Sopenharmony_ci	 */
48268c2ecf20Sopenharmony_ci	if (!dev->subordinate || list_empty(&dev->subordinate->devices)) {
48278c2ecf20Sopenharmony_ci		up_read(&pci_bus_sem);
48288c2ecf20Sopenharmony_ci		return 0;
48298c2ecf20Sopenharmony_ci	}
48308c2ecf20Sopenharmony_ci
48318c2ecf20Sopenharmony_ci	/* Take d3cold_delay requirements into account */
48328c2ecf20Sopenharmony_ci	delay = pci_bus_max_d3cold_delay(dev->subordinate);
48338c2ecf20Sopenharmony_ci	if (!delay) {
48348c2ecf20Sopenharmony_ci		up_read(&pci_bus_sem);
48358c2ecf20Sopenharmony_ci		return 0;
48368c2ecf20Sopenharmony_ci	}
48378c2ecf20Sopenharmony_ci
48388c2ecf20Sopenharmony_ci	child = pci_dev_get(list_first_entry(&dev->subordinate->devices,
48398c2ecf20Sopenharmony_ci					     struct pci_dev, bus_list));
48408c2ecf20Sopenharmony_ci	up_read(&pci_bus_sem);
48418c2ecf20Sopenharmony_ci
48428c2ecf20Sopenharmony_ci	/*
48438c2ecf20Sopenharmony_ci	 * Conventional PCI and PCI-X we need to wait Tpvrh + Trhfa before
48448c2ecf20Sopenharmony_ci	 * accessing the device after reset (that is 1000 ms + 100 ms).
48458c2ecf20Sopenharmony_ci	 */
48468c2ecf20Sopenharmony_ci	if (!pci_is_pcie(dev)) {
48478c2ecf20Sopenharmony_ci		pci_dbg(dev, "waiting %d ms for secondary bus\n", 1000 + delay);
48488c2ecf20Sopenharmony_ci		msleep(1000 + delay);
48498c2ecf20Sopenharmony_ci		goto put_child;
48508c2ecf20Sopenharmony_ci	}
48518c2ecf20Sopenharmony_ci
48528c2ecf20Sopenharmony_ci	/*
48538c2ecf20Sopenharmony_ci	 * For PCIe downstream and root ports that do not support speeds
48548c2ecf20Sopenharmony_ci	 * greater than 5 GT/s need to wait minimum 100 ms. For higher
48558c2ecf20Sopenharmony_ci	 * speeds (gen3) we need to wait first for the data link layer to
48568c2ecf20Sopenharmony_ci	 * become active.
48578c2ecf20Sopenharmony_ci	 *
48588c2ecf20Sopenharmony_ci	 * However, 100 ms is the minimum and the PCIe spec says the
48598c2ecf20Sopenharmony_ci	 * software must allow at least 1s before it can determine that the
48608c2ecf20Sopenharmony_ci	 * device that did not respond is a broken device. There is
48618c2ecf20Sopenharmony_ci	 * evidence that 100 ms is not always enough, for example certain
48628c2ecf20Sopenharmony_ci	 * Titan Ridge xHCI controller does not always respond to
48638c2ecf20Sopenharmony_ci	 * configuration requests if we only wait for 100 ms (see
48648c2ecf20Sopenharmony_ci	 * https://bugzilla.kernel.org/show_bug.cgi?id=203885).
48658c2ecf20Sopenharmony_ci	 *
48668c2ecf20Sopenharmony_ci	 * Therefore we wait for 100 ms and check for the device presence
48678c2ecf20Sopenharmony_ci	 * until the timeout expires.
48688c2ecf20Sopenharmony_ci	 */
48698c2ecf20Sopenharmony_ci	if (!pcie_downstream_port(dev))
48708c2ecf20Sopenharmony_ci		goto put_child;
48718c2ecf20Sopenharmony_ci
48728c2ecf20Sopenharmony_ci	if (pcie_get_speed_cap(dev) <= PCIE_SPEED_5_0GT) {
48738c2ecf20Sopenharmony_ci		pci_dbg(dev, "waiting %d ms for downstream link\n", delay);
48748c2ecf20Sopenharmony_ci		msleep(delay);
48758c2ecf20Sopenharmony_ci	} else {
48768c2ecf20Sopenharmony_ci		pci_dbg(dev, "waiting %d ms for downstream link, after activation\n",
48778c2ecf20Sopenharmony_ci			delay);
48788c2ecf20Sopenharmony_ci		if (!pcie_wait_for_link_delay(dev, true, delay)) {
48798c2ecf20Sopenharmony_ci			/* Did not train, no need to wait any further */
48808c2ecf20Sopenharmony_ci			pci_info(dev, "Data Link Layer Link Active not set in 1000 msec\n");
48818c2ecf20Sopenharmony_ci			ret = -ENOTTY;
48828c2ecf20Sopenharmony_ci			goto put_child;
48838c2ecf20Sopenharmony_ci		}
48848c2ecf20Sopenharmony_ci	}
48858c2ecf20Sopenharmony_ci
48868c2ecf20Sopenharmony_ci	ret = pci_dev_wait(child, reset_type, timeout - delay);
48878c2ecf20Sopenharmony_ci
48888c2ecf20Sopenharmony_ciput_child:
48898c2ecf20Sopenharmony_ci	pci_dev_put(child);
48908c2ecf20Sopenharmony_ci	return ret;
48918c2ecf20Sopenharmony_ci}
48928c2ecf20Sopenharmony_ci
48938c2ecf20Sopenharmony_civoid pci_reset_secondary_bus(struct pci_dev *dev)
48948c2ecf20Sopenharmony_ci{
48958c2ecf20Sopenharmony_ci	u16 ctrl;
48968c2ecf20Sopenharmony_ci
48978c2ecf20Sopenharmony_ci	pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl);
48988c2ecf20Sopenharmony_ci	ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
48998c2ecf20Sopenharmony_ci	pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
49008c2ecf20Sopenharmony_ci
49018c2ecf20Sopenharmony_ci	/*
49028c2ecf20Sopenharmony_ci	 * PCI spec v3.0 7.6.4.2 requires minimum Trst of 1ms.  Double
49038c2ecf20Sopenharmony_ci	 * this to 2ms to ensure that we meet the minimum requirement.
49048c2ecf20Sopenharmony_ci	 */
49058c2ecf20Sopenharmony_ci	msleep(2);
49068c2ecf20Sopenharmony_ci
49078c2ecf20Sopenharmony_ci	ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
49088c2ecf20Sopenharmony_ci	pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
49098c2ecf20Sopenharmony_ci}
49108c2ecf20Sopenharmony_ci
49118c2ecf20Sopenharmony_civoid __weak pcibios_reset_secondary_bus(struct pci_dev *dev)
49128c2ecf20Sopenharmony_ci{
49138c2ecf20Sopenharmony_ci	pci_reset_secondary_bus(dev);
49148c2ecf20Sopenharmony_ci}
49158c2ecf20Sopenharmony_ci
49168c2ecf20Sopenharmony_ci/**
49178c2ecf20Sopenharmony_ci * pci_bridge_secondary_bus_reset - Reset the secondary bus on a PCI bridge.
49188c2ecf20Sopenharmony_ci * @dev: Bridge device
49198c2ecf20Sopenharmony_ci *
49208c2ecf20Sopenharmony_ci * Use the bridge control register to assert reset on the secondary bus.
49218c2ecf20Sopenharmony_ci * Devices on the secondary bus are left in power-on state.
49228c2ecf20Sopenharmony_ci */
49238c2ecf20Sopenharmony_ciint pci_bridge_secondary_bus_reset(struct pci_dev *dev)
49248c2ecf20Sopenharmony_ci{
49258c2ecf20Sopenharmony_ci	pcibios_reset_secondary_bus(dev);
49268c2ecf20Sopenharmony_ci
49278c2ecf20Sopenharmony_ci	return pci_bridge_wait_for_secondary_bus(dev, "bus reset",
49288c2ecf20Sopenharmony_ci						 PCIE_RESET_READY_POLL_MS);
49298c2ecf20Sopenharmony_ci}
49308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_bridge_secondary_bus_reset);
49318c2ecf20Sopenharmony_ci
49328c2ecf20Sopenharmony_cistatic int pci_parent_bus_reset(struct pci_dev *dev, int probe)
49338c2ecf20Sopenharmony_ci{
49348c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
49358c2ecf20Sopenharmony_ci
49368c2ecf20Sopenharmony_ci	if (pci_is_root_bus(dev->bus) || dev->subordinate ||
49378c2ecf20Sopenharmony_ci	    !dev->bus->self || dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
49388c2ecf20Sopenharmony_ci		return -ENOTTY;
49398c2ecf20Sopenharmony_ci
49408c2ecf20Sopenharmony_ci	list_for_each_entry(pdev, &dev->bus->devices, bus_list)
49418c2ecf20Sopenharmony_ci		if (pdev != dev)
49428c2ecf20Sopenharmony_ci			return -ENOTTY;
49438c2ecf20Sopenharmony_ci
49448c2ecf20Sopenharmony_ci	if (probe)
49458c2ecf20Sopenharmony_ci		return 0;
49468c2ecf20Sopenharmony_ci
49478c2ecf20Sopenharmony_ci	return pci_bridge_secondary_bus_reset(dev->bus->self);
49488c2ecf20Sopenharmony_ci}
49498c2ecf20Sopenharmony_ci
49508c2ecf20Sopenharmony_cistatic int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe)
49518c2ecf20Sopenharmony_ci{
49528c2ecf20Sopenharmony_ci	int rc = -ENOTTY;
49538c2ecf20Sopenharmony_ci
49548c2ecf20Sopenharmony_ci	if (!hotplug || !try_module_get(hotplug->owner))
49558c2ecf20Sopenharmony_ci		return rc;
49568c2ecf20Sopenharmony_ci
49578c2ecf20Sopenharmony_ci	if (hotplug->ops->reset_slot)
49588c2ecf20Sopenharmony_ci		rc = hotplug->ops->reset_slot(hotplug, probe);
49598c2ecf20Sopenharmony_ci
49608c2ecf20Sopenharmony_ci	module_put(hotplug->owner);
49618c2ecf20Sopenharmony_ci
49628c2ecf20Sopenharmony_ci	return rc;
49638c2ecf20Sopenharmony_ci}
49648c2ecf20Sopenharmony_ci
49658c2ecf20Sopenharmony_cistatic int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
49668c2ecf20Sopenharmony_ci{
49678c2ecf20Sopenharmony_ci	if (dev->multifunction || dev->subordinate || !dev->slot ||
49688c2ecf20Sopenharmony_ci	    dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
49698c2ecf20Sopenharmony_ci		return -ENOTTY;
49708c2ecf20Sopenharmony_ci
49718c2ecf20Sopenharmony_ci	return pci_reset_hotplug_slot(dev->slot->hotplug, probe);
49728c2ecf20Sopenharmony_ci}
49738c2ecf20Sopenharmony_ci
49748c2ecf20Sopenharmony_cistatic void pci_dev_lock(struct pci_dev *dev)
49758c2ecf20Sopenharmony_ci{
49768c2ecf20Sopenharmony_ci	/* block PM suspend, driver probe, etc. */
49778c2ecf20Sopenharmony_ci	device_lock(&dev->dev);
49788c2ecf20Sopenharmony_ci	pci_cfg_access_lock(dev);
49798c2ecf20Sopenharmony_ci}
49808c2ecf20Sopenharmony_ci
49818c2ecf20Sopenharmony_ci/* Return 1 on successful lock, 0 on contention */
49828c2ecf20Sopenharmony_cistatic int pci_dev_trylock(struct pci_dev *dev)
49838c2ecf20Sopenharmony_ci{
49848c2ecf20Sopenharmony_ci	if (device_trylock(&dev->dev)) {
49858c2ecf20Sopenharmony_ci		if (pci_cfg_access_trylock(dev))
49868c2ecf20Sopenharmony_ci			return 1;
49878c2ecf20Sopenharmony_ci		device_unlock(&dev->dev);
49888c2ecf20Sopenharmony_ci	}
49898c2ecf20Sopenharmony_ci
49908c2ecf20Sopenharmony_ci	return 0;
49918c2ecf20Sopenharmony_ci}
49928c2ecf20Sopenharmony_ci
49938c2ecf20Sopenharmony_cistatic void pci_dev_unlock(struct pci_dev *dev)
49948c2ecf20Sopenharmony_ci{
49958c2ecf20Sopenharmony_ci	pci_cfg_access_unlock(dev);
49968c2ecf20Sopenharmony_ci	device_unlock(&dev->dev);
49978c2ecf20Sopenharmony_ci}
49988c2ecf20Sopenharmony_ci
49998c2ecf20Sopenharmony_cistatic void pci_dev_save_and_disable(struct pci_dev *dev)
50008c2ecf20Sopenharmony_ci{
50018c2ecf20Sopenharmony_ci	const struct pci_error_handlers *err_handler =
50028c2ecf20Sopenharmony_ci			dev->driver ? dev->driver->err_handler : NULL;
50038c2ecf20Sopenharmony_ci
50048c2ecf20Sopenharmony_ci	/*
50058c2ecf20Sopenharmony_ci	 * dev->driver->err_handler->reset_prepare() is protected against
50068c2ecf20Sopenharmony_ci	 * races with ->remove() by the device lock, which must be held by
50078c2ecf20Sopenharmony_ci	 * the caller.
50088c2ecf20Sopenharmony_ci	 */
50098c2ecf20Sopenharmony_ci	if (err_handler && err_handler->reset_prepare)
50108c2ecf20Sopenharmony_ci		err_handler->reset_prepare(dev);
50118c2ecf20Sopenharmony_ci
50128c2ecf20Sopenharmony_ci	/*
50138c2ecf20Sopenharmony_ci	 * Wake-up device prior to save.  PM registers default to D0 after
50148c2ecf20Sopenharmony_ci	 * reset and a simple register restore doesn't reliably return
50158c2ecf20Sopenharmony_ci	 * to a non-D0 state anyway.
50168c2ecf20Sopenharmony_ci	 */
50178c2ecf20Sopenharmony_ci	pci_set_power_state(dev, PCI_D0);
50188c2ecf20Sopenharmony_ci
50198c2ecf20Sopenharmony_ci	pci_save_state(dev);
50208c2ecf20Sopenharmony_ci	/*
50218c2ecf20Sopenharmony_ci	 * Disable the device by clearing the Command register, except for
50228c2ecf20Sopenharmony_ci	 * INTx-disable which is set.  This not only disables MMIO and I/O port
50238c2ecf20Sopenharmony_ci	 * BARs, but also prevents the device from being Bus Master, preventing
50248c2ecf20Sopenharmony_ci	 * DMA from the device including MSI/MSI-X interrupts.  For PCI 2.3
50258c2ecf20Sopenharmony_ci	 * compliant devices, INTx-disable prevents legacy interrupts.
50268c2ecf20Sopenharmony_ci	 */
50278c2ecf20Sopenharmony_ci	pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
50288c2ecf20Sopenharmony_ci}
50298c2ecf20Sopenharmony_ci
50308c2ecf20Sopenharmony_cistatic void pci_dev_restore(struct pci_dev *dev)
50318c2ecf20Sopenharmony_ci{
50328c2ecf20Sopenharmony_ci	const struct pci_error_handlers *err_handler =
50338c2ecf20Sopenharmony_ci			dev->driver ? dev->driver->err_handler : NULL;
50348c2ecf20Sopenharmony_ci
50358c2ecf20Sopenharmony_ci	pci_restore_state(dev);
50368c2ecf20Sopenharmony_ci
50378c2ecf20Sopenharmony_ci	/*
50388c2ecf20Sopenharmony_ci	 * dev->driver->err_handler->reset_done() is protected against
50398c2ecf20Sopenharmony_ci	 * races with ->remove() by the device lock, which must be held by
50408c2ecf20Sopenharmony_ci	 * the caller.
50418c2ecf20Sopenharmony_ci	 */
50428c2ecf20Sopenharmony_ci	if (err_handler && err_handler->reset_done)
50438c2ecf20Sopenharmony_ci		err_handler->reset_done(dev);
50448c2ecf20Sopenharmony_ci}
50458c2ecf20Sopenharmony_ci
50468c2ecf20Sopenharmony_ci/**
50478c2ecf20Sopenharmony_ci * __pci_reset_function_locked - reset a PCI device function while holding
50488c2ecf20Sopenharmony_ci * the @dev mutex lock.
50498c2ecf20Sopenharmony_ci * @dev: PCI device to reset
50508c2ecf20Sopenharmony_ci *
50518c2ecf20Sopenharmony_ci * Some devices allow an individual function to be reset without affecting
50528c2ecf20Sopenharmony_ci * other functions in the same device.  The PCI device must be responsive
50538c2ecf20Sopenharmony_ci * to PCI config space in order to use this function.
50548c2ecf20Sopenharmony_ci *
50558c2ecf20Sopenharmony_ci * The device function is presumed to be unused and the caller is holding
50568c2ecf20Sopenharmony_ci * the device mutex lock when this function is called.
50578c2ecf20Sopenharmony_ci *
50588c2ecf20Sopenharmony_ci * Resetting the device will make the contents of PCI configuration space
50598c2ecf20Sopenharmony_ci * random, so any caller of this must be prepared to reinitialise the
50608c2ecf20Sopenharmony_ci * device including MSI, bus mastering, BARs, decoding IO and memory spaces,
50618c2ecf20Sopenharmony_ci * etc.
50628c2ecf20Sopenharmony_ci *
50638c2ecf20Sopenharmony_ci * Returns 0 if the device function was successfully reset or negative if the
50648c2ecf20Sopenharmony_ci * device doesn't support resetting a single function.
50658c2ecf20Sopenharmony_ci */
50668c2ecf20Sopenharmony_ciint __pci_reset_function_locked(struct pci_dev *dev)
50678c2ecf20Sopenharmony_ci{
50688c2ecf20Sopenharmony_ci	int rc;
50698c2ecf20Sopenharmony_ci
50708c2ecf20Sopenharmony_ci	might_sleep();
50718c2ecf20Sopenharmony_ci
50728c2ecf20Sopenharmony_ci	/*
50738c2ecf20Sopenharmony_ci	 * A reset method returns -ENOTTY if it doesn't support this device
50748c2ecf20Sopenharmony_ci	 * and we should try the next method.
50758c2ecf20Sopenharmony_ci	 *
50768c2ecf20Sopenharmony_ci	 * If it returns 0 (success), we're finished.  If it returns any
50778c2ecf20Sopenharmony_ci	 * other error, we're also finished: this indicates that further
50788c2ecf20Sopenharmony_ci	 * reset mechanisms might be broken on the device.
50798c2ecf20Sopenharmony_ci	 */
50808c2ecf20Sopenharmony_ci	rc = pci_dev_specific_reset(dev, 0);
50818c2ecf20Sopenharmony_ci	if (rc != -ENOTTY)
50828c2ecf20Sopenharmony_ci		return rc;
50838c2ecf20Sopenharmony_ci	if (pcie_has_flr(dev)) {
50848c2ecf20Sopenharmony_ci		rc = pcie_flr(dev);
50858c2ecf20Sopenharmony_ci		if (rc != -ENOTTY)
50868c2ecf20Sopenharmony_ci			return rc;
50878c2ecf20Sopenharmony_ci	}
50888c2ecf20Sopenharmony_ci	rc = pci_af_flr(dev, 0);
50898c2ecf20Sopenharmony_ci	if (rc != -ENOTTY)
50908c2ecf20Sopenharmony_ci		return rc;
50918c2ecf20Sopenharmony_ci	rc = pci_pm_reset(dev, 0);
50928c2ecf20Sopenharmony_ci	if (rc != -ENOTTY)
50938c2ecf20Sopenharmony_ci		return rc;
50948c2ecf20Sopenharmony_ci	rc = pci_dev_reset_slot_function(dev, 0);
50958c2ecf20Sopenharmony_ci	if (rc != -ENOTTY)
50968c2ecf20Sopenharmony_ci		return rc;
50978c2ecf20Sopenharmony_ci	return pci_parent_bus_reset(dev, 0);
50988c2ecf20Sopenharmony_ci}
50998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__pci_reset_function_locked);
51008c2ecf20Sopenharmony_ci
51018c2ecf20Sopenharmony_ci/**
51028c2ecf20Sopenharmony_ci * pci_probe_reset_function - check whether the device can be safely reset
51038c2ecf20Sopenharmony_ci * @dev: PCI device to reset
51048c2ecf20Sopenharmony_ci *
51058c2ecf20Sopenharmony_ci * Some devices allow an individual function to be reset without affecting
51068c2ecf20Sopenharmony_ci * other functions in the same device.  The PCI device must be responsive
51078c2ecf20Sopenharmony_ci * to PCI config space in order to use this function.
51088c2ecf20Sopenharmony_ci *
51098c2ecf20Sopenharmony_ci * Returns 0 if the device function can be reset or negative if the
51108c2ecf20Sopenharmony_ci * device doesn't support resetting a single function.
51118c2ecf20Sopenharmony_ci */
51128c2ecf20Sopenharmony_ciint pci_probe_reset_function(struct pci_dev *dev)
51138c2ecf20Sopenharmony_ci{
51148c2ecf20Sopenharmony_ci	int rc;
51158c2ecf20Sopenharmony_ci
51168c2ecf20Sopenharmony_ci	might_sleep();
51178c2ecf20Sopenharmony_ci
51188c2ecf20Sopenharmony_ci	rc = pci_dev_specific_reset(dev, 1);
51198c2ecf20Sopenharmony_ci	if (rc != -ENOTTY)
51208c2ecf20Sopenharmony_ci		return rc;
51218c2ecf20Sopenharmony_ci	if (pcie_has_flr(dev))
51228c2ecf20Sopenharmony_ci		return 0;
51238c2ecf20Sopenharmony_ci	rc = pci_af_flr(dev, 1);
51248c2ecf20Sopenharmony_ci	if (rc != -ENOTTY)
51258c2ecf20Sopenharmony_ci		return rc;
51268c2ecf20Sopenharmony_ci	rc = pci_pm_reset(dev, 1);
51278c2ecf20Sopenharmony_ci	if (rc != -ENOTTY)
51288c2ecf20Sopenharmony_ci		return rc;
51298c2ecf20Sopenharmony_ci	rc = pci_dev_reset_slot_function(dev, 1);
51308c2ecf20Sopenharmony_ci	if (rc != -ENOTTY)
51318c2ecf20Sopenharmony_ci		return rc;
51328c2ecf20Sopenharmony_ci
51338c2ecf20Sopenharmony_ci	return pci_parent_bus_reset(dev, 1);
51348c2ecf20Sopenharmony_ci}
51358c2ecf20Sopenharmony_ci
51368c2ecf20Sopenharmony_ci/**
51378c2ecf20Sopenharmony_ci * pci_reset_function - quiesce and reset a PCI device function
51388c2ecf20Sopenharmony_ci * @dev: PCI device to reset
51398c2ecf20Sopenharmony_ci *
51408c2ecf20Sopenharmony_ci * Some devices allow an individual function to be reset without affecting
51418c2ecf20Sopenharmony_ci * other functions in the same device.  The PCI device must be responsive
51428c2ecf20Sopenharmony_ci * to PCI config space in order to use this function.
51438c2ecf20Sopenharmony_ci *
51448c2ecf20Sopenharmony_ci * This function does not just reset the PCI portion of a device, but
51458c2ecf20Sopenharmony_ci * clears all the state associated with the device.  This function differs
51468c2ecf20Sopenharmony_ci * from __pci_reset_function_locked() in that it saves and restores device state
51478c2ecf20Sopenharmony_ci * over the reset and takes the PCI device lock.
51488c2ecf20Sopenharmony_ci *
51498c2ecf20Sopenharmony_ci * Returns 0 if the device function was successfully reset or negative if the
51508c2ecf20Sopenharmony_ci * device doesn't support resetting a single function.
51518c2ecf20Sopenharmony_ci */
51528c2ecf20Sopenharmony_ciint pci_reset_function(struct pci_dev *dev)
51538c2ecf20Sopenharmony_ci{
51548c2ecf20Sopenharmony_ci	int rc;
51558c2ecf20Sopenharmony_ci
51568c2ecf20Sopenharmony_ci	if (!dev->reset_fn)
51578c2ecf20Sopenharmony_ci		return -ENOTTY;
51588c2ecf20Sopenharmony_ci
51598c2ecf20Sopenharmony_ci	pci_dev_lock(dev);
51608c2ecf20Sopenharmony_ci	pci_dev_save_and_disable(dev);
51618c2ecf20Sopenharmony_ci
51628c2ecf20Sopenharmony_ci	rc = __pci_reset_function_locked(dev);
51638c2ecf20Sopenharmony_ci
51648c2ecf20Sopenharmony_ci	pci_dev_restore(dev);
51658c2ecf20Sopenharmony_ci	pci_dev_unlock(dev);
51668c2ecf20Sopenharmony_ci
51678c2ecf20Sopenharmony_ci	return rc;
51688c2ecf20Sopenharmony_ci}
51698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_reset_function);
51708c2ecf20Sopenharmony_ci
51718c2ecf20Sopenharmony_ci/**
51728c2ecf20Sopenharmony_ci * pci_reset_function_locked - quiesce and reset a PCI device function
51738c2ecf20Sopenharmony_ci * @dev: PCI device to reset
51748c2ecf20Sopenharmony_ci *
51758c2ecf20Sopenharmony_ci * Some devices allow an individual function to be reset without affecting
51768c2ecf20Sopenharmony_ci * other functions in the same device.  The PCI device must be responsive
51778c2ecf20Sopenharmony_ci * to PCI config space in order to use this function.
51788c2ecf20Sopenharmony_ci *
51798c2ecf20Sopenharmony_ci * This function does not just reset the PCI portion of a device, but
51808c2ecf20Sopenharmony_ci * clears all the state associated with the device.  This function differs
51818c2ecf20Sopenharmony_ci * from __pci_reset_function_locked() in that it saves and restores device state
51828c2ecf20Sopenharmony_ci * over the reset.  It also differs from pci_reset_function() in that it
51838c2ecf20Sopenharmony_ci * requires the PCI device lock to be held.
51848c2ecf20Sopenharmony_ci *
51858c2ecf20Sopenharmony_ci * Returns 0 if the device function was successfully reset or negative if the
51868c2ecf20Sopenharmony_ci * device doesn't support resetting a single function.
51878c2ecf20Sopenharmony_ci */
51888c2ecf20Sopenharmony_ciint pci_reset_function_locked(struct pci_dev *dev)
51898c2ecf20Sopenharmony_ci{
51908c2ecf20Sopenharmony_ci	int rc;
51918c2ecf20Sopenharmony_ci
51928c2ecf20Sopenharmony_ci	if (!dev->reset_fn)
51938c2ecf20Sopenharmony_ci		return -ENOTTY;
51948c2ecf20Sopenharmony_ci
51958c2ecf20Sopenharmony_ci	pci_dev_save_and_disable(dev);
51968c2ecf20Sopenharmony_ci
51978c2ecf20Sopenharmony_ci	rc = __pci_reset_function_locked(dev);
51988c2ecf20Sopenharmony_ci
51998c2ecf20Sopenharmony_ci	pci_dev_restore(dev);
52008c2ecf20Sopenharmony_ci
52018c2ecf20Sopenharmony_ci	return rc;
52028c2ecf20Sopenharmony_ci}
52038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_reset_function_locked);
52048c2ecf20Sopenharmony_ci
52058c2ecf20Sopenharmony_ci/**
52068c2ecf20Sopenharmony_ci * pci_try_reset_function - quiesce and reset a PCI device function
52078c2ecf20Sopenharmony_ci * @dev: PCI device to reset
52088c2ecf20Sopenharmony_ci *
52098c2ecf20Sopenharmony_ci * Same as above, except return -EAGAIN if unable to lock device.
52108c2ecf20Sopenharmony_ci */
52118c2ecf20Sopenharmony_ciint pci_try_reset_function(struct pci_dev *dev)
52128c2ecf20Sopenharmony_ci{
52138c2ecf20Sopenharmony_ci	int rc;
52148c2ecf20Sopenharmony_ci
52158c2ecf20Sopenharmony_ci	if (!dev->reset_fn)
52168c2ecf20Sopenharmony_ci		return -ENOTTY;
52178c2ecf20Sopenharmony_ci
52188c2ecf20Sopenharmony_ci	if (!pci_dev_trylock(dev))
52198c2ecf20Sopenharmony_ci		return -EAGAIN;
52208c2ecf20Sopenharmony_ci
52218c2ecf20Sopenharmony_ci	pci_dev_save_and_disable(dev);
52228c2ecf20Sopenharmony_ci	rc = __pci_reset_function_locked(dev);
52238c2ecf20Sopenharmony_ci	pci_dev_restore(dev);
52248c2ecf20Sopenharmony_ci	pci_dev_unlock(dev);
52258c2ecf20Sopenharmony_ci
52268c2ecf20Sopenharmony_ci	return rc;
52278c2ecf20Sopenharmony_ci}
52288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_try_reset_function);
52298c2ecf20Sopenharmony_ci
52308c2ecf20Sopenharmony_ci/* Do any devices on or below this bus prevent a bus reset? */
52318c2ecf20Sopenharmony_cistatic bool pci_bus_resetable(struct pci_bus *bus)
52328c2ecf20Sopenharmony_ci{
52338c2ecf20Sopenharmony_ci	struct pci_dev *dev;
52348c2ecf20Sopenharmony_ci
52358c2ecf20Sopenharmony_ci
52368c2ecf20Sopenharmony_ci	if (bus->self && (bus->self->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET))
52378c2ecf20Sopenharmony_ci		return false;
52388c2ecf20Sopenharmony_ci
52398c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
52408c2ecf20Sopenharmony_ci		if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
52418c2ecf20Sopenharmony_ci		    (dev->subordinate && !pci_bus_resetable(dev->subordinate)))
52428c2ecf20Sopenharmony_ci			return false;
52438c2ecf20Sopenharmony_ci	}
52448c2ecf20Sopenharmony_ci
52458c2ecf20Sopenharmony_ci	return true;
52468c2ecf20Sopenharmony_ci}
52478c2ecf20Sopenharmony_ci
52488c2ecf20Sopenharmony_ci/* Lock devices from the top of the tree down */
52498c2ecf20Sopenharmony_cistatic void pci_bus_lock(struct pci_bus *bus)
52508c2ecf20Sopenharmony_ci{
52518c2ecf20Sopenharmony_ci	struct pci_dev *dev;
52528c2ecf20Sopenharmony_ci
52538c2ecf20Sopenharmony_ci	pci_dev_lock(bus->self);
52548c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
52558c2ecf20Sopenharmony_ci		if (dev->subordinate)
52568c2ecf20Sopenharmony_ci			pci_bus_lock(dev->subordinate);
52578c2ecf20Sopenharmony_ci		else
52588c2ecf20Sopenharmony_ci			pci_dev_lock(dev);
52598c2ecf20Sopenharmony_ci	}
52608c2ecf20Sopenharmony_ci}
52618c2ecf20Sopenharmony_ci
52628c2ecf20Sopenharmony_ci/* Unlock devices from the bottom of the tree up */
52638c2ecf20Sopenharmony_cistatic void pci_bus_unlock(struct pci_bus *bus)
52648c2ecf20Sopenharmony_ci{
52658c2ecf20Sopenharmony_ci	struct pci_dev *dev;
52668c2ecf20Sopenharmony_ci
52678c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
52688c2ecf20Sopenharmony_ci		if (dev->subordinate)
52698c2ecf20Sopenharmony_ci			pci_bus_unlock(dev->subordinate);
52708c2ecf20Sopenharmony_ci		else
52718c2ecf20Sopenharmony_ci			pci_dev_unlock(dev);
52728c2ecf20Sopenharmony_ci	}
52738c2ecf20Sopenharmony_ci	pci_dev_unlock(bus->self);
52748c2ecf20Sopenharmony_ci}
52758c2ecf20Sopenharmony_ci
52768c2ecf20Sopenharmony_ci/* Return 1 on successful lock, 0 on contention */
52778c2ecf20Sopenharmony_cistatic int pci_bus_trylock(struct pci_bus *bus)
52788c2ecf20Sopenharmony_ci{
52798c2ecf20Sopenharmony_ci	struct pci_dev *dev;
52808c2ecf20Sopenharmony_ci
52818c2ecf20Sopenharmony_ci	if (!pci_dev_trylock(bus->self))
52828c2ecf20Sopenharmony_ci		return 0;
52838c2ecf20Sopenharmony_ci
52848c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
52858c2ecf20Sopenharmony_ci		if (dev->subordinate) {
52868c2ecf20Sopenharmony_ci			if (!pci_bus_trylock(dev->subordinate))
52878c2ecf20Sopenharmony_ci				goto unlock;
52888c2ecf20Sopenharmony_ci		} else if (!pci_dev_trylock(dev))
52898c2ecf20Sopenharmony_ci			goto unlock;
52908c2ecf20Sopenharmony_ci	}
52918c2ecf20Sopenharmony_ci	return 1;
52928c2ecf20Sopenharmony_ci
52938c2ecf20Sopenharmony_ciunlock:
52948c2ecf20Sopenharmony_ci	list_for_each_entry_continue_reverse(dev, &bus->devices, bus_list) {
52958c2ecf20Sopenharmony_ci		if (dev->subordinate)
52968c2ecf20Sopenharmony_ci			pci_bus_unlock(dev->subordinate);
52978c2ecf20Sopenharmony_ci		else
52988c2ecf20Sopenharmony_ci			pci_dev_unlock(dev);
52998c2ecf20Sopenharmony_ci	}
53008c2ecf20Sopenharmony_ci	pci_dev_unlock(bus->self);
53018c2ecf20Sopenharmony_ci	return 0;
53028c2ecf20Sopenharmony_ci}
53038c2ecf20Sopenharmony_ci
53048c2ecf20Sopenharmony_ci/* Do any devices on or below this slot prevent a bus reset? */
53058c2ecf20Sopenharmony_cistatic bool pci_slot_resetable(struct pci_slot *slot)
53068c2ecf20Sopenharmony_ci{
53078c2ecf20Sopenharmony_ci	struct pci_dev *dev;
53088c2ecf20Sopenharmony_ci
53098c2ecf20Sopenharmony_ci	if (slot->bus->self &&
53108c2ecf20Sopenharmony_ci	    (slot->bus->self->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET))
53118c2ecf20Sopenharmony_ci		return false;
53128c2ecf20Sopenharmony_ci
53138c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &slot->bus->devices, bus_list) {
53148c2ecf20Sopenharmony_ci		if (!dev->slot || dev->slot != slot)
53158c2ecf20Sopenharmony_ci			continue;
53168c2ecf20Sopenharmony_ci		if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
53178c2ecf20Sopenharmony_ci		    (dev->subordinate && !pci_bus_resetable(dev->subordinate)))
53188c2ecf20Sopenharmony_ci			return false;
53198c2ecf20Sopenharmony_ci	}
53208c2ecf20Sopenharmony_ci
53218c2ecf20Sopenharmony_ci	return true;
53228c2ecf20Sopenharmony_ci}
53238c2ecf20Sopenharmony_ci
53248c2ecf20Sopenharmony_ci/* Lock devices from the top of the tree down */
53258c2ecf20Sopenharmony_cistatic void pci_slot_lock(struct pci_slot *slot)
53268c2ecf20Sopenharmony_ci{
53278c2ecf20Sopenharmony_ci	struct pci_dev *dev;
53288c2ecf20Sopenharmony_ci
53298c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &slot->bus->devices, bus_list) {
53308c2ecf20Sopenharmony_ci		if (!dev->slot || dev->slot != slot)
53318c2ecf20Sopenharmony_ci			continue;
53328c2ecf20Sopenharmony_ci		if (dev->subordinate)
53338c2ecf20Sopenharmony_ci			pci_bus_lock(dev->subordinate);
53348c2ecf20Sopenharmony_ci		else
53358c2ecf20Sopenharmony_ci			pci_dev_lock(dev);
53368c2ecf20Sopenharmony_ci	}
53378c2ecf20Sopenharmony_ci}
53388c2ecf20Sopenharmony_ci
53398c2ecf20Sopenharmony_ci/* Unlock devices from the bottom of the tree up */
53408c2ecf20Sopenharmony_cistatic void pci_slot_unlock(struct pci_slot *slot)
53418c2ecf20Sopenharmony_ci{
53428c2ecf20Sopenharmony_ci	struct pci_dev *dev;
53438c2ecf20Sopenharmony_ci
53448c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &slot->bus->devices, bus_list) {
53458c2ecf20Sopenharmony_ci		if (!dev->slot || dev->slot != slot)
53468c2ecf20Sopenharmony_ci			continue;
53478c2ecf20Sopenharmony_ci		if (dev->subordinate)
53488c2ecf20Sopenharmony_ci			pci_bus_unlock(dev->subordinate);
53498c2ecf20Sopenharmony_ci		pci_dev_unlock(dev);
53508c2ecf20Sopenharmony_ci	}
53518c2ecf20Sopenharmony_ci}
53528c2ecf20Sopenharmony_ci
53538c2ecf20Sopenharmony_ci/* Return 1 on successful lock, 0 on contention */
53548c2ecf20Sopenharmony_cistatic int pci_slot_trylock(struct pci_slot *slot)
53558c2ecf20Sopenharmony_ci{
53568c2ecf20Sopenharmony_ci	struct pci_dev *dev;
53578c2ecf20Sopenharmony_ci
53588c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &slot->bus->devices, bus_list) {
53598c2ecf20Sopenharmony_ci		if (!dev->slot || dev->slot != slot)
53608c2ecf20Sopenharmony_ci			continue;
53618c2ecf20Sopenharmony_ci		if (dev->subordinate) {
53628c2ecf20Sopenharmony_ci			if (!pci_bus_trylock(dev->subordinate)) {
53638c2ecf20Sopenharmony_ci				pci_dev_unlock(dev);
53648c2ecf20Sopenharmony_ci				goto unlock;
53658c2ecf20Sopenharmony_ci			}
53668c2ecf20Sopenharmony_ci		} else if (!pci_dev_trylock(dev))
53678c2ecf20Sopenharmony_ci			goto unlock;
53688c2ecf20Sopenharmony_ci	}
53698c2ecf20Sopenharmony_ci	return 1;
53708c2ecf20Sopenharmony_ci
53718c2ecf20Sopenharmony_ciunlock:
53728c2ecf20Sopenharmony_ci	list_for_each_entry_continue_reverse(dev,
53738c2ecf20Sopenharmony_ci					     &slot->bus->devices, bus_list) {
53748c2ecf20Sopenharmony_ci		if (!dev->slot || dev->slot != slot)
53758c2ecf20Sopenharmony_ci			continue;
53768c2ecf20Sopenharmony_ci		if (dev->subordinate)
53778c2ecf20Sopenharmony_ci			pci_bus_unlock(dev->subordinate);
53788c2ecf20Sopenharmony_ci		else
53798c2ecf20Sopenharmony_ci			pci_dev_unlock(dev);
53808c2ecf20Sopenharmony_ci	}
53818c2ecf20Sopenharmony_ci	return 0;
53828c2ecf20Sopenharmony_ci}
53838c2ecf20Sopenharmony_ci
53848c2ecf20Sopenharmony_ci/*
53858c2ecf20Sopenharmony_ci * Save and disable devices from the top of the tree down while holding
53868c2ecf20Sopenharmony_ci * the @dev mutex lock for the entire tree.
53878c2ecf20Sopenharmony_ci */
53888c2ecf20Sopenharmony_cistatic void pci_bus_save_and_disable_locked(struct pci_bus *bus)
53898c2ecf20Sopenharmony_ci{
53908c2ecf20Sopenharmony_ci	struct pci_dev *dev;
53918c2ecf20Sopenharmony_ci
53928c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
53938c2ecf20Sopenharmony_ci		pci_dev_save_and_disable(dev);
53948c2ecf20Sopenharmony_ci		if (dev->subordinate)
53958c2ecf20Sopenharmony_ci			pci_bus_save_and_disable_locked(dev->subordinate);
53968c2ecf20Sopenharmony_ci	}
53978c2ecf20Sopenharmony_ci}
53988c2ecf20Sopenharmony_ci
53998c2ecf20Sopenharmony_ci/*
54008c2ecf20Sopenharmony_ci * Restore devices from top of the tree down while holding @dev mutex lock
54018c2ecf20Sopenharmony_ci * for the entire tree.  Parent bridges need to be restored before we can
54028c2ecf20Sopenharmony_ci * get to subordinate devices.
54038c2ecf20Sopenharmony_ci */
54048c2ecf20Sopenharmony_cistatic void pci_bus_restore_locked(struct pci_bus *bus)
54058c2ecf20Sopenharmony_ci{
54068c2ecf20Sopenharmony_ci	struct pci_dev *dev;
54078c2ecf20Sopenharmony_ci
54088c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
54098c2ecf20Sopenharmony_ci		pci_dev_restore(dev);
54108c2ecf20Sopenharmony_ci		if (dev->subordinate)
54118c2ecf20Sopenharmony_ci			pci_bus_restore_locked(dev->subordinate);
54128c2ecf20Sopenharmony_ci	}
54138c2ecf20Sopenharmony_ci}
54148c2ecf20Sopenharmony_ci
54158c2ecf20Sopenharmony_ci/*
54168c2ecf20Sopenharmony_ci * Save and disable devices from the top of the tree down while holding
54178c2ecf20Sopenharmony_ci * the @dev mutex lock for the entire tree.
54188c2ecf20Sopenharmony_ci */
54198c2ecf20Sopenharmony_cistatic void pci_slot_save_and_disable_locked(struct pci_slot *slot)
54208c2ecf20Sopenharmony_ci{
54218c2ecf20Sopenharmony_ci	struct pci_dev *dev;
54228c2ecf20Sopenharmony_ci
54238c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &slot->bus->devices, bus_list) {
54248c2ecf20Sopenharmony_ci		if (!dev->slot || dev->slot != slot)
54258c2ecf20Sopenharmony_ci			continue;
54268c2ecf20Sopenharmony_ci		pci_dev_save_and_disable(dev);
54278c2ecf20Sopenharmony_ci		if (dev->subordinate)
54288c2ecf20Sopenharmony_ci			pci_bus_save_and_disable_locked(dev->subordinate);
54298c2ecf20Sopenharmony_ci	}
54308c2ecf20Sopenharmony_ci}
54318c2ecf20Sopenharmony_ci
54328c2ecf20Sopenharmony_ci/*
54338c2ecf20Sopenharmony_ci * Restore devices from top of the tree down while holding @dev mutex lock
54348c2ecf20Sopenharmony_ci * for the entire tree.  Parent bridges need to be restored before we can
54358c2ecf20Sopenharmony_ci * get to subordinate devices.
54368c2ecf20Sopenharmony_ci */
54378c2ecf20Sopenharmony_cistatic void pci_slot_restore_locked(struct pci_slot *slot)
54388c2ecf20Sopenharmony_ci{
54398c2ecf20Sopenharmony_ci	struct pci_dev *dev;
54408c2ecf20Sopenharmony_ci
54418c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &slot->bus->devices, bus_list) {
54428c2ecf20Sopenharmony_ci		if (!dev->slot || dev->slot != slot)
54438c2ecf20Sopenharmony_ci			continue;
54448c2ecf20Sopenharmony_ci		pci_dev_restore(dev);
54458c2ecf20Sopenharmony_ci		if (dev->subordinate)
54468c2ecf20Sopenharmony_ci			pci_bus_restore_locked(dev->subordinate);
54478c2ecf20Sopenharmony_ci	}
54488c2ecf20Sopenharmony_ci}
54498c2ecf20Sopenharmony_ci
54508c2ecf20Sopenharmony_cistatic int pci_slot_reset(struct pci_slot *slot, int probe)
54518c2ecf20Sopenharmony_ci{
54528c2ecf20Sopenharmony_ci	int rc;
54538c2ecf20Sopenharmony_ci
54548c2ecf20Sopenharmony_ci	if (!slot || !pci_slot_resetable(slot))
54558c2ecf20Sopenharmony_ci		return -ENOTTY;
54568c2ecf20Sopenharmony_ci
54578c2ecf20Sopenharmony_ci	if (!probe)
54588c2ecf20Sopenharmony_ci		pci_slot_lock(slot);
54598c2ecf20Sopenharmony_ci
54608c2ecf20Sopenharmony_ci	might_sleep();
54618c2ecf20Sopenharmony_ci
54628c2ecf20Sopenharmony_ci	rc = pci_reset_hotplug_slot(slot->hotplug, probe);
54638c2ecf20Sopenharmony_ci
54648c2ecf20Sopenharmony_ci	if (!probe)
54658c2ecf20Sopenharmony_ci		pci_slot_unlock(slot);
54668c2ecf20Sopenharmony_ci
54678c2ecf20Sopenharmony_ci	return rc;
54688c2ecf20Sopenharmony_ci}
54698c2ecf20Sopenharmony_ci
54708c2ecf20Sopenharmony_ci/**
54718c2ecf20Sopenharmony_ci * pci_probe_reset_slot - probe whether a PCI slot can be reset
54728c2ecf20Sopenharmony_ci * @slot: PCI slot to probe
54738c2ecf20Sopenharmony_ci *
54748c2ecf20Sopenharmony_ci * Return 0 if slot can be reset, negative if a slot reset is not supported.
54758c2ecf20Sopenharmony_ci */
54768c2ecf20Sopenharmony_ciint pci_probe_reset_slot(struct pci_slot *slot)
54778c2ecf20Sopenharmony_ci{
54788c2ecf20Sopenharmony_ci	return pci_slot_reset(slot, 1);
54798c2ecf20Sopenharmony_ci}
54808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_probe_reset_slot);
54818c2ecf20Sopenharmony_ci
54828c2ecf20Sopenharmony_ci/**
54838c2ecf20Sopenharmony_ci * __pci_reset_slot - Try to reset a PCI slot
54848c2ecf20Sopenharmony_ci * @slot: PCI slot to reset
54858c2ecf20Sopenharmony_ci *
54868c2ecf20Sopenharmony_ci * A PCI bus may host multiple slots, each slot may support a reset mechanism
54878c2ecf20Sopenharmony_ci * independent of other slots.  For instance, some slots may support slot power
54888c2ecf20Sopenharmony_ci * control.  In the case of a 1:1 bus to slot architecture, this function may
54898c2ecf20Sopenharmony_ci * wrap the bus reset to avoid spurious slot related events such as hotplug.
54908c2ecf20Sopenharmony_ci * Generally a slot reset should be attempted before a bus reset.  All of the
54918c2ecf20Sopenharmony_ci * function of the slot and any subordinate buses behind the slot are reset
54928c2ecf20Sopenharmony_ci * through this function.  PCI config space of all devices in the slot and
54938c2ecf20Sopenharmony_ci * behind the slot is saved before and restored after reset.
54948c2ecf20Sopenharmony_ci *
54958c2ecf20Sopenharmony_ci * Same as above except return -EAGAIN if the slot cannot be locked
54968c2ecf20Sopenharmony_ci */
54978c2ecf20Sopenharmony_cistatic int __pci_reset_slot(struct pci_slot *slot)
54988c2ecf20Sopenharmony_ci{
54998c2ecf20Sopenharmony_ci	int rc;
55008c2ecf20Sopenharmony_ci
55018c2ecf20Sopenharmony_ci	rc = pci_slot_reset(slot, 1);
55028c2ecf20Sopenharmony_ci	if (rc)
55038c2ecf20Sopenharmony_ci		return rc;
55048c2ecf20Sopenharmony_ci
55058c2ecf20Sopenharmony_ci	if (pci_slot_trylock(slot)) {
55068c2ecf20Sopenharmony_ci		pci_slot_save_and_disable_locked(slot);
55078c2ecf20Sopenharmony_ci		might_sleep();
55088c2ecf20Sopenharmony_ci		rc = pci_reset_hotplug_slot(slot->hotplug, 0);
55098c2ecf20Sopenharmony_ci		pci_slot_restore_locked(slot);
55108c2ecf20Sopenharmony_ci		pci_slot_unlock(slot);
55118c2ecf20Sopenharmony_ci	} else
55128c2ecf20Sopenharmony_ci		rc = -EAGAIN;
55138c2ecf20Sopenharmony_ci
55148c2ecf20Sopenharmony_ci	return rc;
55158c2ecf20Sopenharmony_ci}
55168c2ecf20Sopenharmony_ci
55178c2ecf20Sopenharmony_cistatic int pci_bus_reset(struct pci_bus *bus, int probe)
55188c2ecf20Sopenharmony_ci{
55198c2ecf20Sopenharmony_ci	int ret;
55208c2ecf20Sopenharmony_ci
55218c2ecf20Sopenharmony_ci	if (!bus->self || !pci_bus_resetable(bus))
55228c2ecf20Sopenharmony_ci		return -ENOTTY;
55238c2ecf20Sopenharmony_ci
55248c2ecf20Sopenharmony_ci	if (probe)
55258c2ecf20Sopenharmony_ci		return 0;
55268c2ecf20Sopenharmony_ci
55278c2ecf20Sopenharmony_ci	pci_bus_lock(bus);
55288c2ecf20Sopenharmony_ci
55298c2ecf20Sopenharmony_ci	might_sleep();
55308c2ecf20Sopenharmony_ci
55318c2ecf20Sopenharmony_ci	ret = pci_bridge_secondary_bus_reset(bus->self);
55328c2ecf20Sopenharmony_ci
55338c2ecf20Sopenharmony_ci	pci_bus_unlock(bus);
55348c2ecf20Sopenharmony_ci
55358c2ecf20Sopenharmony_ci	return ret;
55368c2ecf20Sopenharmony_ci}
55378c2ecf20Sopenharmony_ci
55388c2ecf20Sopenharmony_ci/**
55398c2ecf20Sopenharmony_ci * pci_bus_error_reset - reset the bridge's subordinate bus
55408c2ecf20Sopenharmony_ci * @bridge: The parent device that connects to the bus to reset
55418c2ecf20Sopenharmony_ci *
55428c2ecf20Sopenharmony_ci * This function will first try to reset the slots on this bus if the method is
55438c2ecf20Sopenharmony_ci * available. If slot reset fails or is not available, this will fall back to a
55448c2ecf20Sopenharmony_ci * secondary bus reset.
55458c2ecf20Sopenharmony_ci */
55468c2ecf20Sopenharmony_ciint pci_bus_error_reset(struct pci_dev *bridge)
55478c2ecf20Sopenharmony_ci{
55488c2ecf20Sopenharmony_ci	struct pci_bus *bus = bridge->subordinate;
55498c2ecf20Sopenharmony_ci	struct pci_slot *slot;
55508c2ecf20Sopenharmony_ci
55518c2ecf20Sopenharmony_ci	if (!bus)
55528c2ecf20Sopenharmony_ci		return -ENOTTY;
55538c2ecf20Sopenharmony_ci
55548c2ecf20Sopenharmony_ci	mutex_lock(&pci_slot_mutex);
55558c2ecf20Sopenharmony_ci	if (list_empty(&bus->slots))
55568c2ecf20Sopenharmony_ci		goto bus_reset;
55578c2ecf20Sopenharmony_ci
55588c2ecf20Sopenharmony_ci	list_for_each_entry(slot, &bus->slots, list)
55598c2ecf20Sopenharmony_ci		if (pci_probe_reset_slot(slot))
55608c2ecf20Sopenharmony_ci			goto bus_reset;
55618c2ecf20Sopenharmony_ci
55628c2ecf20Sopenharmony_ci	list_for_each_entry(slot, &bus->slots, list)
55638c2ecf20Sopenharmony_ci		if (pci_slot_reset(slot, 0))
55648c2ecf20Sopenharmony_ci			goto bus_reset;
55658c2ecf20Sopenharmony_ci
55668c2ecf20Sopenharmony_ci	mutex_unlock(&pci_slot_mutex);
55678c2ecf20Sopenharmony_ci	return 0;
55688c2ecf20Sopenharmony_cibus_reset:
55698c2ecf20Sopenharmony_ci	mutex_unlock(&pci_slot_mutex);
55708c2ecf20Sopenharmony_ci	return pci_bus_reset(bridge->subordinate, 0);
55718c2ecf20Sopenharmony_ci}
55728c2ecf20Sopenharmony_ci
55738c2ecf20Sopenharmony_ci/**
55748c2ecf20Sopenharmony_ci * pci_probe_reset_bus - probe whether a PCI bus can be reset
55758c2ecf20Sopenharmony_ci * @bus: PCI bus to probe
55768c2ecf20Sopenharmony_ci *
55778c2ecf20Sopenharmony_ci * Return 0 if bus can be reset, negative if a bus reset is not supported.
55788c2ecf20Sopenharmony_ci */
55798c2ecf20Sopenharmony_ciint pci_probe_reset_bus(struct pci_bus *bus)
55808c2ecf20Sopenharmony_ci{
55818c2ecf20Sopenharmony_ci	return pci_bus_reset(bus, 1);
55828c2ecf20Sopenharmony_ci}
55838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_probe_reset_bus);
55848c2ecf20Sopenharmony_ci
55858c2ecf20Sopenharmony_ci/**
55868c2ecf20Sopenharmony_ci * __pci_reset_bus - Try to reset a PCI bus
55878c2ecf20Sopenharmony_ci * @bus: top level PCI bus to reset
55888c2ecf20Sopenharmony_ci *
55898c2ecf20Sopenharmony_ci * Same as above except return -EAGAIN if the bus cannot be locked
55908c2ecf20Sopenharmony_ci */
55918c2ecf20Sopenharmony_cistatic int __pci_reset_bus(struct pci_bus *bus)
55928c2ecf20Sopenharmony_ci{
55938c2ecf20Sopenharmony_ci	int rc;
55948c2ecf20Sopenharmony_ci
55958c2ecf20Sopenharmony_ci	rc = pci_bus_reset(bus, 1);
55968c2ecf20Sopenharmony_ci	if (rc)
55978c2ecf20Sopenharmony_ci		return rc;
55988c2ecf20Sopenharmony_ci
55998c2ecf20Sopenharmony_ci	if (pci_bus_trylock(bus)) {
56008c2ecf20Sopenharmony_ci		pci_bus_save_and_disable_locked(bus);
56018c2ecf20Sopenharmony_ci		might_sleep();
56028c2ecf20Sopenharmony_ci		rc = pci_bridge_secondary_bus_reset(bus->self);
56038c2ecf20Sopenharmony_ci		pci_bus_restore_locked(bus);
56048c2ecf20Sopenharmony_ci		pci_bus_unlock(bus);
56058c2ecf20Sopenharmony_ci	} else
56068c2ecf20Sopenharmony_ci		rc = -EAGAIN;
56078c2ecf20Sopenharmony_ci
56088c2ecf20Sopenharmony_ci	return rc;
56098c2ecf20Sopenharmony_ci}
56108c2ecf20Sopenharmony_ci
56118c2ecf20Sopenharmony_ci/**
56128c2ecf20Sopenharmony_ci * pci_reset_bus - Try to reset a PCI bus
56138c2ecf20Sopenharmony_ci * @pdev: top level PCI device to reset via slot/bus
56148c2ecf20Sopenharmony_ci *
56158c2ecf20Sopenharmony_ci * Same as above except return -EAGAIN if the bus cannot be locked
56168c2ecf20Sopenharmony_ci */
56178c2ecf20Sopenharmony_ciint pci_reset_bus(struct pci_dev *pdev)
56188c2ecf20Sopenharmony_ci{
56198c2ecf20Sopenharmony_ci	return (!pci_probe_reset_slot(pdev->slot)) ?
56208c2ecf20Sopenharmony_ci	    __pci_reset_slot(pdev->slot) : __pci_reset_bus(pdev->bus);
56218c2ecf20Sopenharmony_ci}
56228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_reset_bus);
56238c2ecf20Sopenharmony_ci
56248c2ecf20Sopenharmony_ci/**
56258c2ecf20Sopenharmony_ci * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
56268c2ecf20Sopenharmony_ci * @dev: PCI device to query
56278c2ecf20Sopenharmony_ci *
56288c2ecf20Sopenharmony_ci * Returns mmrbc: maximum designed memory read count in bytes or
56298c2ecf20Sopenharmony_ci * appropriate error value.
56308c2ecf20Sopenharmony_ci */
56318c2ecf20Sopenharmony_ciint pcix_get_max_mmrbc(struct pci_dev *dev)
56328c2ecf20Sopenharmony_ci{
56338c2ecf20Sopenharmony_ci	int cap;
56348c2ecf20Sopenharmony_ci	u32 stat;
56358c2ecf20Sopenharmony_ci
56368c2ecf20Sopenharmony_ci	cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
56378c2ecf20Sopenharmony_ci	if (!cap)
56388c2ecf20Sopenharmony_ci		return -EINVAL;
56398c2ecf20Sopenharmony_ci
56408c2ecf20Sopenharmony_ci	if (pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat))
56418c2ecf20Sopenharmony_ci		return -EINVAL;
56428c2ecf20Sopenharmony_ci
56438c2ecf20Sopenharmony_ci	return 512 << ((stat & PCI_X_STATUS_MAX_READ) >> 21);
56448c2ecf20Sopenharmony_ci}
56458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcix_get_max_mmrbc);
56468c2ecf20Sopenharmony_ci
56478c2ecf20Sopenharmony_ci/**
56488c2ecf20Sopenharmony_ci * pcix_get_mmrbc - get PCI-X maximum memory read byte count
56498c2ecf20Sopenharmony_ci * @dev: PCI device to query
56508c2ecf20Sopenharmony_ci *
56518c2ecf20Sopenharmony_ci * Returns mmrbc: maximum memory read count in bytes or appropriate error
56528c2ecf20Sopenharmony_ci * value.
56538c2ecf20Sopenharmony_ci */
56548c2ecf20Sopenharmony_ciint pcix_get_mmrbc(struct pci_dev *dev)
56558c2ecf20Sopenharmony_ci{
56568c2ecf20Sopenharmony_ci	int cap;
56578c2ecf20Sopenharmony_ci	u16 cmd;
56588c2ecf20Sopenharmony_ci
56598c2ecf20Sopenharmony_ci	cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
56608c2ecf20Sopenharmony_ci	if (!cap)
56618c2ecf20Sopenharmony_ci		return -EINVAL;
56628c2ecf20Sopenharmony_ci
56638c2ecf20Sopenharmony_ci	if (pci_read_config_word(dev, cap + PCI_X_CMD, &cmd))
56648c2ecf20Sopenharmony_ci		return -EINVAL;
56658c2ecf20Sopenharmony_ci
56668c2ecf20Sopenharmony_ci	return 512 << ((cmd & PCI_X_CMD_MAX_READ) >> 2);
56678c2ecf20Sopenharmony_ci}
56688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcix_get_mmrbc);
56698c2ecf20Sopenharmony_ci
56708c2ecf20Sopenharmony_ci/**
56718c2ecf20Sopenharmony_ci * pcix_set_mmrbc - set PCI-X maximum memory read byte count
56728c2ecf20Sopenharmony_ci * @dev: PCI device to query
56738c2ecf20Sopenharmony_ci * @mmrbc: maximum memory read count in bytes
56748c2ecf20Sopenharmony_ci *    valid values are 512, 1024, 2048, 4096
56758c2ecf20Sopenharmony_ci *
56768c2ecf20Sopenharmony_ci * If possible sets maximum memory read byte count, some bridges have errata
56778c2ecf20Sopenharmony_ci * that prevent this.
56788c2ecf20Sopenharmony_ci */
56798c2ecf20Sopenharmony_ciint pcix_set_mmrbc(struct pci_dev *dev, int mmrbc)
56808c2ecf20Sopenharmony_ci{
56818c2ecf20Sopenharmony_ci	int cap;
56828c2ecf20Sopenharmony_ci	u32 stat, v, o;
56838c2ecf20Sopenharmony_ci	u16 cmd;
56848c2ecf20Sopenharmony_ci
56858c2ecf20Sopenharmony_ci	if (mmrbc < 512 || mmrbc > 4096 || !is_power_of_2(mmrbc))
56868c2ecf20Sopenharmony_ci		return -EINVAL;
56878c2ecf20Sopenharmony_ci
56888c2ecf20Sopenharmony_ci	v = ffs(mmrbc) - 10;
56898c2ecf20Sopenharmony_ci
56908c2ecf20Sopenharmony_ci	cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
56918c2ecf20Sopenharmony_ci	if (!cap)
56928c2ecf20Sopenharmony_ci		return -EINVAL;
56938c2ecf20Sopenharmony_ci
56948c2ecf20Sopenharmony_ci	if (pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat))
56958c2ecf20Sopenharmony_ci		return -EINVAL;
56968c2ecf20Sopenharmony_ci
56978c2ecf20Sopenharmony_ci	if (v > (stat & PCI_X_STATUS_MAX_READ) >> 21)
56988c2ecf20Sopenharmony_ci		return -E2BIG;
56998c2ecf20Sopenharmony_ci
57008c2ecf20Sopenharmony_ci	if (pci_read_config_word(dev, cap + PCI_X_CMD, &cmd))
57018c2ecf20Sopenharmony_ci		return -EINVAL;
57028c2ecf20Sopenharmony_ci
57038c2ecf20Sopenharmony_ci	o = (cmd & PCI_X_CMD_MAX_READ) >> 2;
57048c2ecf20Sopenharmony_ci	if (o != v) {
57058c2ecf20Sopenharmony_ci		if (v > o && (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MMRBC))
57068c2ecf20Sopenharmony_ci			return -EIO;
57078c2ecf20Sopenharmony_ci
57088c2ecf20Sopenharmony_ci		cmd &= ~PCI_X_CMD_MAX_READ;
57098c2ecf20Sopenharmony_ci		cmd |= v << 2;
57108c2ecf20Sopenharmony_ci		if (pci_write_config_word(dev, cap + PCI_X_CMD, cmd))
57118c2ecf20Sopenharmony_ci			return -EIO;
57128c2ecf20Sopenharmony_ci	}
57138c2ecf20Sopenharmony_ci	return 0;
57148c2ecf20Sopenharmony_ci}
57158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcix_set_mmrbc);
57168c2ecf20Sopenharmony_ci
57178c2ecf20Sopenharmony_ci/**
57188c2ecf20Sopenharmony_ci * pcie_get_readrq - get PCI Express read request size
57198c2ecf20Sopenharmony_ci * @dev: PCI device to query
57208c2ecf20Sopenharmony_ci *
57218c2ecf20Sopenharmony_ci * Returns maximum memory read request in bytes or appropriate error value.
57228c2ecf20Sopenharmony_ci */
57238c2ecf20Sopenharmony_ciint pcie_get_readrq(struct pci_dev *dev)
57248c2ecf20Sopenharmony_ci{
57258c2ecf20Sopenharmony_ci	u16 ctl;
57268c2ecf20Sopenharmony_ci
57278c2ecf20Sopenharmony_ci	pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &ctl);
57288c2ecf20Sopenharmony_ci
57298c2ecf20Sopenharmony_ci	return 128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12);
57308c2ecf20Sopenharmony_ci}
57318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcie_get_readrq);
57328c2ecf20Sopenharmony_ci
57338c2ecf20Sopenharmony_ci/**
57348c2ecf20Sopenharmony_ci * pcie_set_readrq - set PCI Express maximum memory read request
57358c2ecf20Sopenharmony_ci * @dev: PCI device to query
57368c2ecf20Sopenharmony_ci * @rq: maximum memory read count in bytes
57378c2ecf20Sopenharmony_ci *    valid values are 128, 256, 512, 1024, 2048, 4096
57388c2ecf20Sopenharmony_ci *
57398c2ecf20Sopenharmony_ci * If possible sets maximum memory read request in bytes
57408c2ecf20Sopenharmony_ci */
57418c2ecf20Sopenharmony_ciint pcie_set_readrq(struct pci_dev *dev, int rq)
57428c2ecf20Sopenharmony_ci{
57438c2ecf20Sopenharmony_ci	u16 v;
57448c2ecf20Sopenharmony_ci	int ret;
57458c2ecf20Sopenharmony_ci	struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus);
57468c2ecf20Sopenharmony_ci
57478c2ecf20Sopenharmony_ci	if (rq < 128 || rq > 4096 || !is_power_of_2(rq))
57488c2ecf20Sopenharmony_ci		return -EINVAL;
57498c2ecf20Sopenharmony_ci
57508c2ecf20Sopenharmony_ci	/*
57518c2ecf20Sopenharmony_ci	 * If using the "performance" PCIe config, we clamp the read rq
57528c2ecf20Sopenharmony_ci	 * size to the max packet size to keep the host bridge from
57538c2ecf20Sopenharmony_ci	 * generating requests larger than we can cope with.
57548c2ecf20Sopenharmony_ci	 */
57558c2ecf20Sopenharmony_ci	if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
57568c2ecf20Sopenharmony_ci		int mps = pcie_get_mps(dev);
57578c2ecf20Sopenharmony_ci
57588c2ecf20Sopenharmony_ci		if (mps < rq)
57598c2ecf20Sopenharmony_ci			rq = mps;
57608c2ecf20Sopenharmony_ci	}
57618c2ecf20Sopenharmony_ci
57628c2ecf20Sopenharmony_ci	v = (ffs(rq) - 8) << 12;
57638c2ecf20Sopenharmony_ci
57648c2ecf20Sopenharmony_ci	if (bridge->no_inc_mrrs) {
57658c2ecf20Sopenharmony_ci		int max_mrrs = pcie_get_readrq(dev);
57668c2ecf20Sopenharmony_ci
57678c2ecf20Sopenharmony_ci		if (rq > max_mrrs) {
57688c2ecf20Sopenharmony_ci			pci_info(dev, "can't set Max_Read_Request_Size to %d; max is %d\n", rq, max_mrrs);
57698c2ecf20Sopenharmony_ci			return -EINVAL;
57708c2ecf20Sopenharmony_ci		}
57718c2ecf20Sopenharmony_ci	}
57728c2ecf20Sopenharmony_ci
57738c2ecf20Sopenharmony_ci	ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
57748c2ecf20Sopenharmony_ci						  PCI_EXP_DEVCTL_READRQ, v);
57758c2ecf20Sopenharmony_ci
57768c2ecf20Sopenharmony_ci	return pcibios_err_to_errno(ret);
57778c2ecf20Sopenharmony_ci}
57788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcie_set_readrq);
57798c2ecf20Sopenharmony_ci
57808c2ecf20Sopenharmony_ci/**
57818c2ecf20Sopenharmony_ci * pcie_get_mps - get PCI Express maximum payload size
57828c2ecf20Sopenharmony_ci * @dev: PCI device to query
57838c2ecf20Sopenharmony_ci *
57848c2ecf20Sopenharmony_ci * Returns maximum payload size in bytes
57858c2ecf20Sopenharmony_ci */
57868c2ecf20Sopenharmony_ciint pcie_get_mps(struct pci_dev *dev)
57878c2ecf20Sopenharmony_ci{
57888c2ecf20Sopenharmony_ci	u16 ctl;
57898c2ecf20Sopenharmony_ci
57908c2ecf20Sopenharmony_ci	pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &ctl);
57918c2ecf20Sopenharmony_ci
57928c2ecf20Sopenharmony_ci	return 128 << ((ctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
57938c2ecf20Sopenharmony_ci}
57948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcie_get_mps);
57958c2ecf20Sopenharmony_ci
57968c2ecf20Sopenharmony_ci/**
57978c2ecf20Sopenharmony_ci * pcie_set_mps - set PCI Express maximum payload size
57988c2ecf20Sopenharmony_ci * @dev: PCI device to query
57998c2ecf20Sopenharmony_ci * @mps: maximum payload size in bytes
58008c2ecf20Sopenharmony_ci *    valid values are 128, 256, 512, 1024, 2048, 4096
58018c2ecf20Sopenharmony_ci *
58028c2ecf20Sopenharmony_ci * If possible sets maximum payload size
58038c2ecf20Sopenharmony_ci */
58048c2ecf20Sopenharmony_ciint pcie_set_mps(struct pci_dev *dev, int mps)
58058c2ecf20Sopenharmony_ci{
58068c2ecf20Sopenharmony_ci	u16 v;
58078c2ecf20Sopenharmony_ci	int ret;
58088c2ecf20Sopenharmony_ci
58098c2ecf20Sopenharmony_ci	if (mps < 128 || mps > 4096 || !is_power_of_2(mps))
58108c2ecf20Sopenharmony_ci		return -EINVAL;
58118c2ecf20Sopenharmony_ci
58128c2ecf20Sopenharmony_ci	v = ffs(mps) - 8;
58138c2ecf20Sopenharmony_ci	if (v > dev->pcie_mpss)
58148c2ecf20Sopenharmony_ci		return -EINVAL;
58158c2ecf20Sopenharmony_ci	v <<= 5;
58168c2ecf20Sopenharmony_ci
58178c2ecf20Sopenharmony_ci	ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
58188c2ecf20Sopenharmony_ci						  PCI_EXP_DEVCTL_PAYLOAD, v);
58198c2ecf20Sopenharmony_ci
58208c2ecf20Sopenharmony_ci	return pcibios_err_to_errno(ret);
58218c2ecf20Sopenharmony_ci}
58228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcie_set_mps);
58238c2ecf20Sopenharmony_ci
58248c2ecf20Sopenharmony_ci/**
58258c2ecf20Sopenharmony_ci * pcie_bandwidth_available - determine minimum link settings of a PCIe
58268c2ecf20Sopenharmony_ci *			      device and its bandwidth limitation
58278c2ecf20Sopenharmony_ci * @dev: PCI device to query
58288c2ecf20Sopenharmony_ci * @limiting_dev: storage for device causing the bandwidth limitation
58298c2ecf20Sopenharmony_ci * @speed: storage for speed of limiting device
58308c2ecf20Sopenharmony_ci * @width: storage for width of limiting device
58318c2ecf20Sopenharmony_ci *
58328c2ecf20Sopenharmony_ci * Walk up the PCI device chain and find the point where the minimum
58338c2ecf20Sopenharmony_ci * bandwidth is available.  Return the bandwidth available there and (if
58348c2ecf20Sopenharmony_ci * limiting_dev, speed, and width pointers are supplied) information about
58358c2ecf20Sopenharmony_ci * that point.  The bandwidth returned is in Mb/s, i.e., megabits/second of
58368c2ecf20Sopenharmony_ci * raw bandwidth.
58378c2ecf20Sopenharmony_ci */
58388c2ecf20Sopenharmony_ciu32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev,
58398c2ecf20Sopenharmony_ci			     enum pci_bus_speed *speed,
58408c2ecf20Sopenharmony_ci			     enum pcie_link_width *width)
58418c2ecf20Sopenharmony_ci{
58428c2ecf20Sopenharmony_ci	u16 lnksta;
58438c2ecf20Sopenharmony_ci	enum pci_bus_speed next_speed;
58448c2ecf20Sopenharmony_ci	enum pcie_link_width next_width;
58458c2ecf20Sopenharmony_ci	u32 bw, next_bw;
58468c2ecf20Sopenharmony_ci
58478c2ecf20Sopenharmony_ci	if (speed)
58488c2ecf20Sopenharmony_ci		*speed = PCI_SPEED_UNKNOWN;
58498c2ecf20Sopenharmony_ci	if (width)
58508c2ecf20Sopenharmony_ci		*width = PCIE_LNK_WIDTH_UNKNOWN;
58518c2ecf20Sopenharmony_ci
58528c2ecf20Sopenharmony_ci	bw = 0;
58538c2ecf20Sopenharmony_ci
58548c2ecf20Sopenharmony_ci	while (dev) {
58558c2ecf20Sopenharmony_ci		pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
58568c2ecf20Sopenharmony_ci
58578c2ecf20Sopenharmony_ci		next_speed = pcie_link_speed[lnksta & PCI_EXP_LNKSTA_CLS];
58588c2ecf20Sopenharmony_ci		next_width = (lnksta & PCI_EXP_LNKSTA_NLW) >>
58598c2ecf20Sopenharmony_ci			PCI_EXP_LNKSTA_NLW_SHIFT;
58608c2ecf20Sopenharmony_ci
58618c2ecf20Sopenharmony_ci		next_bw = next_width * PCIE_SPEED2MBS_ENC(next_speed);
58628c2ecf20Sopenharmony_ci
58638c2ecf20Sopenharmony_ci		/* Check if current device limits the total bandwidth */
58648c2ecf20Sopenharmony_ci		if (!bw || next_bw <= bw) {
58658c2ecf20Sopenharmony_ci			bw = next_bw;
58668c2ecf20Sopenharmony_ci
58678c2ecf20Sopenharmony_ci			if (limiting_dev)
58688c2ecf20Sopenharmony_ci				*limiting_dev = dev;
58698c2ecf20Sopenharmony_ci			if (speed)
58708c2ecf20Sopenharmony_ci				*speed = next_speed;
58718c2ecf20Sopenharmony_ci			if (width)
58728c2ecf20Sopenharmony_ci				*width = next_width;
58738c2ecf20Sopenharmony_ci		}
58748c2ecf20Sopenharmony_ci
58758c2ecf20Sopenharmony_ci		dev = pci_upstream_bridge(dev);
58768c2ecf20Sopenharmony_ci	}
58778c2ecf20Sopenharmony_ci
58788c2ecf20Sopenharmony_ci	return bw;
58798c2ecf20Sopenharmony_ci}
58808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcie_bandwidth_available);
58818c2ecf20Sopenharmony_ci
58828c2ecf20Sopenharmony_ci/**
58838c2ecf20Sopenharmony_ci * pcie_get_speed_cap - query for the PCI device's link speed capability
58848c2ecf20Sopenharmony_ci * @dev: PCI device to query
58858c2ecf20Sopenharmony_ci *
58868c2ecf20Sopenharmony_ci * Query the PCI device speed capability.  Return the maximum link speed
58878c2ecf20Sopenharmony_ci * supported by the device.
58888c2ecf20Sopenharmony_ci */
58898c2ecf20Sopenharmony_cienum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev)
58908c2ecf20Sopenharmony_ci{
58918c2ecf20Sopenharmony_ci	u32 lnkcap2, lnkcap;
58928c2ecf20Sopenharmony_ci
58938c2ecf20Sopenharmony_ci	/*
58948c2ecf20Sopenharmony_ci	 * Link Capabilities 2 was added in PCIe r3.0, sec 7.8.18.  The
58958c2ecf20Sopenharmony_ci	 * implementation note there recommends using the Supported Link
58968c2ecf20Sopenharmony_ci	 * Speeds Vector in Link Capabilities 2 when supported.
58978c2ecf20Sopenharmony_ci	 *
58988c2ecf20Sopenharmony_ci	 * Without Link Capabilities 2, i.e., prior to PCIe r3.0, software
58998c2ecf20Sopenharmony_ci	 * should use the Supported Link Speeds field in Link Capabilities,
59008c2ecf20Sopenharmony_ci	 * where only 2.5 GT/s and 5.0 GT/s speeds were defined.
59018c2ecf20Sopenharmony_ci	 */
59028c2ecf20Sopenharmony_ci	pcie_capability_read_dword(dev, PCI_EXP_LNKCAP2, &lnkcap2);
59038c2ecf20Sopenharmony_ci
59048c2ecf20Sopenharmony_ci	/* PCIe r3.0-compliant */
59058c2ecf20Sopenharmony_ci	if (lnkcap2)
59068c2ecf20Sopenharmony_ci		return PCIE_LNKCAP2_SLS2SPEED(lnkcap2);
59078c2ecf20Sopenharmony_ci
59088c2ecf20Sopenharmony_ci	pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
59098c2ecf20Sopenharmony_ci	if ((lnkcap & PCI_EXP_LNKCAP_SLS) == PCI_EXP_LNKCAP_SLS_5_0GB)
59108c2ecf20Sopenharmony_ci		return PCIE_SPEED_5_0GT;
59118c2ecf20Sopenharmony_ci	else if ((lnkcap & PCI_EXP_LNKCAP_SLS) == PCI_EXP_LNKCAP_SLS_2_5GB)
59128c2ecf20Sopenharmony_ci		return PCIE_SPEED_2_5GT;
59138c2ecf20Sopenharmony_ci
59148c2ecf20Sopenharmony_ci	return PCI_SPEED_UNKNOWN;
59158c2ecf20Sopenharmony_ci}
59168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcie_get_speed_cap);
59178c2ecf20Sopenharmony_ci
59188c2ecf20Sopenharmony_ci/**
59198c2ecf20Sopenharmony_ci * pcie_get_width_cap - query for the PCI device's link width capability
59208c2ecf20Sopenharmony_ci * @dev: PCI device to query
59218c2ecf20Sopenharmony_ci *
59228c2ecf20Sopenharmony_ci * Query the PCI device width capability.  Return the maximum link width
59238c2ecf20Sopenharmony_ci * supported by the device.
59248c2ecf20Sopenharmony_ci */
59258c2ecf20Sopenharmony_cienum pcie_link_width pcie_get_width_cap(struct pci_dev *dev)
59268c2ecf20Sopenharmony_ci{
59278c2ecf20Sopenharmony_ci	u32 lnkcap;
59288c2ecf20Sopenharmony_ci
59298c2ecf20Sopenharmony_ci	pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
59308c2ecf20Sopenharmony_ci	if (lnkcap)
59318c2ecf20Sopenharmony_ci		return (lnkcap & PCI_EXP_LNKCAP_MLW) >> 4;
59328c2ecf20Sopenharmony_ci
59338c2ecf20Sopenharmony_ci	return PCIE_LNK_WIDTH_UNKNOWN;
59348c2ecf20Sopenharmony_ci}
59358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcie_get_width_cap);
59368c2ecf20Sopenharmony_ci
59378c2ecf20Sopenharmony_ci/**
59388c2ecf20Sopenharmony_ci * pcie_bandwidth_capable - calculate a PCI device's link bandwidth capability
59398c2ecf20Sopenharmony_ci * @dev: PCI device
59408c2ecf20Sopenharmony_ci * @speed: storage for link speed
59418c2ecf20Sopenharmony_ci * @width: storage for link width
59428c2ecf20Sopenharmony_ci *
59438c2ecf20Sopenharmony_ci * Calculate a PCI device's link bandwidth by querying for its link speed
59448c2ecf20Sopenharmony_ci * and width, multiplying them, and applying encoding overhead.  The result
59458c2ecf20Sopenharmony_ci * is in Mb/s, i.e., megabits/second of raw bandwidth.
59468c2ecf20Sopenharmony_ci */
59478c2ecf20Sopenharmony_ciu32 pcie_bandwidth_capable(struct pci_dev *dev, enum pci_bus_speed *speed,
59488c2ecf20Sopenharmony_ci			   enum pcie_link_width *width)
59498c2ecf20Sopenharmony_ci{
59508c2ecf20Sopenharmony_ci	*speed = pcie_get_speed_cap(dev);
59518c2ecf20Sopenharmony_ci	*width = pcie_get_width_cap(dev);
59528c2ecf20Sopenharmony_ci
59538c2ecf20Sopenharmony_ci	if (*speed == PCI_SPEED_UNKNOWN || *width == PCIE_LNK_WIDTH_UNKNOWN)
59548c2ecf20Sopenharmony_ci		return 0;
59558c2ecf20Sopenharmony_ci
59568c2ecf20Sopenharmony_ci	return *width * PCIE_SPEED2MBS_ENC(*speed);
59578c2ecf20Sopenharmony_ci}
59588c2ecf20Sopenharmony_ci
59598c2ecf20Sopenharmony_ci/**
59608c2ecf20Sopenharmony_ci * __pcie_print_link_status - Report the PCI device's link speed and width
59618c2ecf20Sopenharmony_ci * @dev: PCI device to query
59628c2ecf20Sopenharmony_ci * @verbose: Print info even when enough bandwidth is available
59638c2ecf20Sopenharmony_ci *
59648c2ecf20Sopenharmony_ci * If the available bandwidth at the device is less than the device is
59658c2ecf20Sopenharmony_ci * capable of, report the device's maximum possible bandwidth and the
59668c2ecf20Sopenharmony_ci * upstream link that limits its performance.  If @verbose, always print
59678c2ecf20Sopenharmony_ci * the available bandwidth, even if the device isn't constrained.
59688c2ecf20Sopenharmony_ci */
59698c2ecf20Sopenharmony_civoid __pcie_print_link_status(struct pci_dev *dev, bool verbose)
59708c2ecf20Sopenharmony_ci{
59718c2ecf20Sopenharmony_ci	enum pcie_link_width width, width_cap;
59728c2ecf20Sopenharmony_ci	enum pci_bus_speed speed, speed_cap;
59738c2ecf20Sopenharmony_ci	struct pci_dev *limiting_dev = NULL;
59748c2ecf20Sopenharmony_ci	u32 bw_avail, bw_cap;
59758c2ecf20Sopenharmony_ci
59768c2ecf20Sopenharmony_ci	bw_cap = pcie_bandwidth_capable(dev, &speed_cap, &width_cap);
59778c2ecf20Sopenharmony_ci	bw_avail = pcie_bandwidth_available(dev, &limiting_dev, &speed, &width);
59788c2ecf20Sopenharmony_ci
59798c2ecf20Sopenharmony_ci	if (bw_avail >= bw_cap && verbose)
59808c2ecf20Sopenharmony_ci		pci_info(dev, "%u.%03u Gb/s available PCIe bandwidth (%s x%d link)\n",
59818c2ecf20Sopenharmony_ci			 bw_cap / 1000, bw_cap % 1000,
59828c2ecf20Sopenharmony_ci			 pci_speed_string(speed_cap), width_cap);
59838c2ecf20Sopenharmony_ci	else if (bw_avail < bw_cap)
59848c2ecf20Sopenharmony_ci		pci_info(dev, "%u.%03u Gb/s available PCIe bandwidth, limited by %s x%d link at %s (capable of %u.%03u Gb/s with %s x%d link)\n",
59858c2ecf20Sopenharmony_ci			 bw_avail / 1000, bw_avail % 1000,
59868c2ecf20Sopenharmony_ci			 pci_speed_string(speed), width,
59878c2ecf20Sopenharmony_ci			 limiting_dev ? pci_name(limiting_dev) : "<unknown>",
59888c2ecf20Sopenharmony_ci			 bw_cap / 1000, bw_cap % 1000,
59898c2ecf20Sopenharmony_ci			 pci_speed_string(speed_cap), width_cap);
59908c2ecf20Sopenharmony_ci}
59918c2ecf20Sopenharmony_ci
59928c2ecf20Sopenharmony_ci/**
59938c2ecf20Sopenharmony_ci * pcie_print_link_status - Report the PCI device's link speed and width
59948c2ecf20Sopenharmony_ci * @dev: PCI device to query
59958c2ecf20Sopenharmony_ci *
59968c2ecf20Sopenharmony_ci * Report the available bandwidth at the device.
59978c2ecf20Sopenharmony_ci */
59988c2ecf20Sopenharmony_civoid pcie_print_link_status(struct pci_dev *dev)
59998c2ecf20Sopenharmony_ci{
60008c2ecf20Sopenharmony_ci	__pcie_print_link_status(dev, true);
60018c2ecf20Sopenharmony_ci}
60028c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcie_print_link_status);
60038c2ecf20Sopenharmony_ci
60048c2ecf20Sopenharmony_ci/**
60058c2ecf20Sopenharmony_ci * pci_select_bars - Make BAR mask from the type of resource
60068c2ecf20Sopenharmony_ci * @dev: the PCI device for which BAR mask is made
60078c2ecf20Sopenharmony_ci * @flags: resource type mask to be selected
60088c2ecf20Sopenharmony_ci *
60098c2ecf20Sopenharmony_ci * This helper routine makes bar mask from the type of resource.
60108c2ecf20Sopenharmony_ci */
60118c2ecf20Sopenharmony_ciint pci_select_bars(struct pci_dev *dev, unsigned long flags)
60128c2ecf20Sopenharmony_ci{
60138c2ecf20Sopenharmony_ci	int i, bars = 0;
60148c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_NUM_RESOURCES; i++)
60158c2ecf20Sopenharmony_ci		if (pci_resource_flags(dev, i) & flags)
60168c2ecf20Sopenharmony_ci			bars |= (1 << i);
60178c2ecf20Sopenharmony_ci	return bars;
60188c2ecf20Sopenharmony_ci}
60198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_select_bars);
60208c2ecf20Sopenharmony_ci
60218c2ecf20Sopenharmony_ci/* Some architectures require additional programming to enable VGA */
60228c2ecf20Sopenharmony_cistatic arch_set_vga_state_t arch_set_vga_state;
60238c2ecf20Sopenharmony_ci
60248c2ecf20Sopenharmony_civoid __init pci_register_set_vga_state(arch_set_vga_state_t func)
60258c2ecf20Sopenharmony_ci{
60268c2ecf20Sopenharmony_ci	arch_set_vga_state = func;	/* NULL disables */
60278c2ecf20Sopenharmony_ci}
60288c2ecf20Sopenharmony_ci
60298c2ecf20Sopenharmony_cistatic int pci_set_vga_state_arch(struct pci_dev *dev, bool decode,
60308c2ecf20Sopenharmony_ci				  unsigned int command_bits, u32 flags)
60318c2ecf20Sopenharmony_ci{
60328c2ecf20Sopenharmony_ci	if (arch_set_vga_state)
60338c2ecf20Sopenharmony_ci		return arch_set_vga_state(dev, decode, command_bits,
60348c2ecf20Sopenharmony_ci						flags);
60358c2ecf20Sopenharmony_ci	return 0;
60368c2ecf20Sopenharmony_ci}
60378c2ecf20Sopenharmony_ci
60388c2ecf20Sopenharmony_ci/**
60398c2ecf20Sopenharmony_ci * pci_set_vga_state - set VGA decode state on device and parents if requested
60408c2ecf20Sopenharmony_ci * @dev: the PCI device
60418c2ecf20Sopenharmony_ci * @decode: true = enable decoding, false = disable decoding
60428c2ecf20Sopenharmony_ci * @command_bits: PCI_COMMAND_IO and/or PCI_COMMAND_MEMORY
60438c2ecf20Sopenharmony_ci * @flags: traverse ancestors and change bridges
60448c2ecf20Sopenharmony_ci * CHANGE_BRIDGE_ONLY / CHANGE_BRIDGE
60458c2ecf20Sopenharmony_ci */
60468c2ecf20Sopenharmony_ciint pci_set_vga_state(struct pci_dev *dev, bool decode,
60478c2ecf20Sopenharmony_ci		      unsigned int command_bits, u32 flags)
60488c2ecf20Sopenharmony_ci{
60498c2ecf20Sopenharmony_ci	struct pci_bus *bus;
60508c2ecf20Sopenharmony_ci	struct pci_dev *bridge;
60518c2ecf20Sopenharmony_ci	u16 cmd;
60528c2ecf20Sopenharmony_ci	int rc;
60538c2ecf20Sopenharmony_ci
60548c2ecf20Sopenharmony_ci	WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) && (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY)));
60558c2ecf20Sopenharmony_ci
60568c2ecf20Sopenharmony_ci	/* ARCH specific VGA enables */
60578c2ecf20Sopenharmony_ci	rc = pci_set_vga_state_arch(dev, decode, command_bits, flags);
60588c2ecf20Sopenharmony_ci	if (rc)
60598c2ecf20Sopenharmony_ci		return rc;
60608c2ecf20Sopenharmony_ci
60618c2ecf20Sopenharmony_ci	if (flags & PCI_VGA_STATE_CHANGE_DECODES) {
60628c2ecf20Sopenharmony_ci		pci_read_config_word(dev, PCI_COMMAND, &cmd);
60638c2ecf20Sopenharmony_ci		if (decode)
60648c2ecf20Sopenharmony_ci			cmd |= command_bits;
60658c2ecf20Sopenharmony_ci		else
60668c2ecf20Sopenharmony_ci			cmd &= ~command_bits;
60678c2ecf20Sopenharmony_ci		pci_write_config_word(dev, PCI_COMMAND, cmd);
60688c2ecf20Sopenharmony_ci	}
60698c2ecf20Sopenharmony_ci
60708c2ecf20Sopenharmony_ci	if (!(flags & PCI_VGA_STATE_CHANGE_BRIDGE))
60718c2ecf20Sopenharmony_ci		return 0;
60728c2ecf20Sopenharmony_ci
60738c2ecf20Sopenharmony_ci	bus = dev->bus;
60748c2ecf20Sopenharmony_ci	while (bus) {
60758c2ecf20Sopenharmony_ci		bridge = bus->self;
60768c2ecf20Sopenharmony_ci		if (bridge) {
60778c2ecf20Sopenharmony_ci			pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
60788c2ecf20Sopenharmony_ci					     &cmd);
60798c2ecf20Sopenharmony_ci			if (decode)
60808c2ecf20Sopenharmony_ci				cmd |= PCI_BRIDGE_CTL_VGA;
60818c2ecf20Sopenharmony_ci			else
60828c2ecf20Sopenharmony_ci				cmd &= ~PCI_BRIDGE_CTL_VGA;
60838c2ecf20Sopenharmony_ci			pci_write_config_word(bridge, PCI_BRIDGE_CONTROL,
60848c2ecf20Sopenharmony_ci					      cmd);
60858c2ecf20Sopenharmony_ci		}
60868c2ecf20Sopenharmony_ci		bus = bus->parent;
60878c2ecf20Sopenharmony_ci	}
60888c2ecf20Sopenharmony_ci	return 0;
60898c2ecf20Sopenharmony_ci}
60908c2ecf20Sopenharmony_ci
60918c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
60928c2ecf20Sopenharmony_cibool pci_pr3_present(struct pci_dev *pdev)
60938c2ecf20Sopenharmony_ci{
60948c2ecf20Sopenharmony_ci	struct acpi_device *adev;
60958c2ecf20Sopenharmony_ci
60968c2ecf20Sopenharmony_ci	if (acpi_disabled)
60978c2ecf20Sopenharmony_ci		return false;
60988c2ecf20Sopenharmony_ci
60998c2ecf20Sopenharmony_ci	adev = ACPI_COMPANION(&pdev->dev);
61008c2ecf20Sopenharmony_ci	if (!adev)
61018c2ecf20Sopenharmony_ci		return false;
61028c2ecf20Sopenharmony_ci
61038c2ecf20Sopenharmony_ci	return adev->power.flags.power_resources &&
61048c2ecf20Sopenharmony_ci		acpi_has_method(adev->handle, "_PR3");
61058c2ecf20Sopenharmony_ci}
61068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_pr3_present);
61078c2ecf20Sopenharmony_ci#endif
61088c2ecf20Sopenharmony_ci
61098c2ecf20Sopenharmony_ci/**
61108c2ecf20Sopenharmony_ci * pci_add_dma_alias - Add a DMA devfn alias for a device
61118c2ecf20Sopenharmony_ci * @dev: the PCI device for which alias is added
61128c2ecf20Sopenharmony_ci * @devfn_from: alias slot and function
61138c2ecf20Sopenharmony_ci * @nr_devfns: number of subsequent devfns to alias
61148c2ecf20Sopenharmony_ci *
61158c2ecf20Sopenharmony_ci * This helper encodes an 8-bit devfn as a bit number in dma_alias_mask
61168c2ecf20Sopenharmony_ci * which is used to program permissible bus-devfn source addresses for DMA
61178c2ecf20Sopenharmony_ci * requests in an IOMMU.  These aliases factor into IOMMU group creation
61188c2ecf20Sopenharmony_ci * and are useful for devices generating DMA requests beyond or different
61198c2ecf20Sopenharmony_ci * from their logical bus-devfn.  Examples include device quirks where the
61208c2ecf20Sopenharmony_ci * device simply uses the wrong devfn, as well as non-transparent bridges
61218c2ecf20Sopenharmony_ci * where the alias may be a proxy for devices in another domain.
61228c2ecf20Sopenharmony_ci *
61238c2ecf20Sopenharmony_ci * IOMMU group creation is performed during device discovery or addition,
61248c2ecf20Sopenharmony_ci * prior to any potential DMA mapping and therefore prior to driver probing
61258c2ecf20Sopenharmony_ci * (especially for userspace assigned devices where IOMMU group definition
61268c2ecf20Sopenharmony_ci * cannot be left as a userspace activity).  DMA aliases should therefore
61278c2ecf20Sopenharmony_ci * be configured via quirks, such as the PCI fixup header quirk.
61288c2ecf20Sopenharmony_ci */
61298c2ecf20Sopenharmony_civoid pci_add_dma_alias(struct pci_dev *dev, u8 devfn_from, unsigned nr_devfns)
61308c2ecf20Sopenharmony_ci{
61318c2ecf20Sopenharmony_ci	int devfn_to;
61328c2ecf20Sopenharmony_ci
61338c2ecf20Sopenharmony_ci	nr_devfns = min(nr_devfns, (unsigned) MAX_NR_DEVFNS - devfn_from);
61348c2ecf20Sopenharmony_ci	devfn_to = devfn_from + nr_devfns - 1;
61358c2ecf20Sopenharmony_ci
61368c2ecf20Sopenharmony_ci	if (!dev->dma_alias_mask)
61378c2ecf20Sopenharmony_ci		dev->dma_alias_mask = bitmap_zalloc(MAX_NR_DEVFNS, GFP_KERNEL);
61388c2ecf20Sopenharmony_ci	if (!dev->dma_alias_mask) {
61398c2ecf20Sopenharmony_ci		pci_warn(dev, "Unable to allocate DMA alias mask\n");
61408c2ecf20Sopenharmony_ci		return;
61418c2ecf20Sopenharmony_ci	}
61428c2ecf20Sopenharmony_ci
61438c2ecf20Sopenharmony_ci	bitmap_set(dev->dma_alias_mask, devfn_from, nr_devfns);
61448c2ecf20Sopenharmony_ci
61458c2ecf20Sopenharmony_ci	if (nr_devfns == 1)
61468c2ecf20Sopenharmony_ci		pci_info(dev, "Enabling fixed DMA alias to %02x.%d\n",
61478c2ecf20Sopenharmony_ci				PCI_SLOT(devfn_from), PCI_FUNC(devfn_from));
61488c2ecf20Sopenharmony_ci	else if (nr_devfns > 1)
61498c2ecf20Sopenharmony_ci		pci_info(dev, "Enabling fixed DMA alias for devfn range from %02x.%d to %02x.%d\n",
61508c2ecf20Sopenharmony_ci				PCI_SLOT(devfn_from), PCI_FUNC(devfn_from),
61518c2ecf20Sopenharmony_ci				PCI_SLOT(devfn_to), PCI_FUNC(devfn_to));
61528c2ecf20Sopenharmony_ci}
61538c2ecf20Sopenharmony_ci
61548c2ecf20Sopenharmony_cibool pci_devs_are_dma_aliases(struct pci_dev *dev1, struct pci_dev *dev2)
61558c2ecf20Sopenharmony_ci{
61568c2ecf20Sopenharmony_ci	return (dev1->dma_alias_mask &&
61578c2ecf20Sopenharmony_ci		test_bit(dev2->devfn, dev1->dma_alias_mask)) ||
61588c2ecf20Sopenharmony_ci	       (dev2->dma_alias_mask &&
61598c2ecf20Sopenharmony_ci		test_bit(dev1->devfn, dev2->dma_alias_mask)) ||
61608c2ecf20Sopenharmony_ci	       pci_real_dma_dev(dev1) == dev2 ||
61618c2ecf20Sopenharmony_ci	       pci_real_dma_dev(dev2) == dev1;
61628c2ecf20Sopenharmony_ci}
61638c2ecf20Sopenharmony_ci
61648c2ecf20Sopenharmony_cibool pci_device_is_present(struct pci_dev *pdev)
61658c2ecf20Sopenharmony_ci{
61668c2ecf20Sopenharmony_ci	u32 v;
61678c2ecf20Sopenharmony_ci
61688c2ecf20Sopenharmony_ci	/* Check PF if pdev is a VF, since VF Vendor/Device IDs are 0xffff */
61698c2ecf20Sopenharmony_ci	pdev = pci_physfn(pdev);
61708c2ecf20Sopenharmony_ci	if (pci_dev_is_disconnected(pdev))
61718c2ecf20Sopenharmony_ci		return false;
61728c2ecf20Sopenharmony_ci	return pci_bus_read_dev_vendor_id(pdev->bus, pdev->devfn, &v, 0);
61738c2ecf20Sopenharmony_ci}
61748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_device_is_present);
61758c2ecf20Sopenharmony_ci
61768c2ecf20Sopenharmony_civoid pci_ignore_hotplug(struct pci_dev *dev)
61778c2ecf20Sopenharmony_ci{
61788c2ecf20Sopenharmony_ci	struct pci_dev *bridge = dev->bus->self;
61798c2ecf20Sopenharmony_ci
61808c2ecf20Sopenharmony_ci	dev->ignore_hotplug = 1;
61818c2ecf20Sopenharmony_ci	/* Propagate the "ignore hotplug" setting to the parent bridge. */
61828c2ecf20Sopenharmony_ci	if (bridge)
61838c2ecf20Sopenharmony_ci		bridge->ignore_hotplug = 1;
61848c2ecf20Sopenharmony_ci}
61858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_ignore_hotplug);
61868c2ecf20Sopenharmony_ci
61878c2ecf20Sopenharmony_ci/**
61888c2ecf20Sopenharmony_ci * pci_real_dma_dev - Get PCI DMA device for PCI device
61898c2ecf20Sopenharmony_ci * @dev: the PCI device that may have a PCI DMA alias
61908c2ecf20Sopenharmony_ci *
61918c2ecf20Sopenharmony_ci * Permits the platform to provide architecture-specific functionality to
61928c2ecf20Sopenharmony_ci * devices needing to alias DMA to another PCI device on another PCI bus. If
61938c2ecf20Sopenharmony_ci * the PCI device is on the same bus, it is recommended to use
61948c2ecf20Sopenharmony_ci * pci_add_dma_alias(). This is the default implementation. Architecture
61958c2ecf20Sopenharmony_ci * implementations can override this.
61968c2ecf20Sopenharmony_ci */
61978c2ecf20Sopenharmony_cistruct pci_dev __weak *pci_real_dma_dev(struct pci_dev *dev)
61988c2ecf20Sopenharmony_ci{
61998c2ecf20Sopenharmony_ci	return dev;
62008c2ecf20Sopenharmony_ci}
62018c2ecf20Sopenharmony_ci
62028c2ecf20Sopenharmony_ciresource_size_t __weak pcibios_default_alignment(void)
62038c2ecf20Sopenharmony_ci{
62048c2ecf20Sopenharmony_ci	return 0;
62058c2ecf20Sopenharmony_ci}
62068c2ecf20Sopenharmony_ci
62078c2ecf20Sopenharmony_ci/*
62088c2ecf20Sopenharmony_ci * Arches that don't want to expose struct resource to userland as-is in
62098c2ecf20Sopenharmony_ci * sysfs and /proc can implement their own pci_resource_to_user().
62108c2ecf20Sopenharmony_ci */
62118c2ecf20Sopenharmony_civoid __weak pci_resource_to_user(const struct pci_dev *dev, int bar,
62128c2ecf20Sopenharmony_ci				 const struct resource *rsrc,
62138c2ecf20Sopenharmony_ci				 resource_size_t *start, resource_size_t *end)
62148c2ecf20Sopenharmony_ci{
62158c2ecf20Sopenharmony_ci	*start = rsrc->start;
62168c2ecf20Sopenharmony_ci	*end = rsrc->end;
62178c2ecf20Sopenharmony_ci}
62188c2ecf20Sopenharmony_ci
62198c2ecf20Sopenharmony_cistatic char *resource_alignment_param;
62208c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(resource_alignment_lock);
62218c2ecf20Sopenharmony_ci
62228c2ecf20Sopenharmony_ci/**
62238c2ecf20Sopenharmony_ci * pci_specified_resource_alignment - get resource alignment specified by user.
62248c2ecf20Sopenharmony_ci * @dev: the PCI device to get
62258c2ecf20Sopenharmony_ci * @resize: whether or not to change resources' size when reassigning alignment
62268c2ecf20Sopenharmony_ci *
62278c2ecf20Sopenharmony_ci * RETURNS: Resource alignment if it is specified.
62288c2ecf20Sopenharmony_ci *          Zero if it is not specified.
62298c2ecf20Sopenharmony_ci */
62308c2ecf20Sopenharmony_cistatic resource_size_t pci_specified_resource_alignment(struct pci_dev *dev,
62318c2ecf20Sopenharmony_ci							bool *resize)
62328c2ecf20Sopenharmony_ci{
62338c2ecf20Sopenharmony_ci	int align_order, count;
62348c2ecf20Sopenharmony_ci	resource_size_t align = pcibios_default_alignment();
62358c2ecf20Sopenharmony_ci	const char *p;
62368c2ecf20Sopenharmony_ci	int ret;
62378c2ecf20Sopenharmony_ci
62388c2ecf20Sopenharmony_ci	spin_lock(&resource_alignment_lock);
62398c2ecf20Sopenharmony_ci	p = resource_alignment_param;
62408c2ecf20Sopenharmony_ci	if (!p || !*p)
62418c2ecf20Sopenharmony_ci		goto out;
62428c2ecf20Sopenharmony_ci	if (pci_has_flag(PCI_PROBE_ONLY)) {
62438c2ecf20Sopenharmony_ci		align = 0;
62448c2ecf20Sopenharmony_ci		pr_info_once("PCI: Ignoring requested alignments (PCI_PROBE_ONLY)\n");
62458c2ecf20Sopenharmony_ci		goto out;
62468c2ecf20Sopenharmony_ci	}
62478c2ecf20Sopenharmony_ci
62488c2ecf20Sopenharmony_ci	while (*p) {
62498c2ecf20Sopenharmony_ci		count = 0;
62508c2ecf20Sopenharmony_ci		if (sscanf(p, "%d%n", &align_order, &count) == 1 &&
62518c2ecf20Sopenharmony_ci		    p[count] == '@') {
62528c2ecf20Sopenharmony_ci			p += count + 1;
62538c2ecf20Sopenharmony_ci			if (align_order > 63) {
62548c2ecf20Sopenharmony_ci				pr_err("PCI: Invalid requested alignment (order %d)\n",
62558c2ecf20Sopenharmony_ci				       align_order);
62568c2ecf20Sopenharmony_ci				align_order = PAGE_SHIFT;
62578c2ecf20Sopenharmony_ci			}
62588c2ecf20Sopenharmony_ci		} else {
62598c2ecf20Sopenharmony_ci			align_order = PAGE_SHIFT;
62608c2ecf20Sopenharmony_ci		}
62618c2ecf20Sopenharmony_ci
62628c2ecf20Sopenharmony_ci		ret = pci_dev_str_match(dev, p, &p);
62638c2ecf20Sopenharmony_ci		if (ret == 1) {
62648c2ecf20Sopenharmony_ci			*resize = true;
62658c2ecf20Sopenharmony_ci			align = 1ULL << align_order;
62668c2ecf20Sopenharmony_ci			break;
62678c2ecf20Sopenharmony_ci		} else if (ret < 0) {
62688c2ecf20Sopenharmony_ci			pr_err("PCI: Can't parse resource_alignment parameter: %s\n",
62698c2ecf20Sopenharmony_ci			       p);
62708c2ecf20Sopenharmony_ci			break;
62718c2ecf20Sopenharmony_ci		}
62728c2ecf20Sopenharmony_ci
62738c2ecf20Sopenharmony_ci		if (*p != ';' && *p != ',') {
62748c2ecf20Sopenharmony_ci			/* End of param or invalid format */
62758c2ecf20Sopenharmony_ci			break;
62768c2ecf20Sopenharmony_ci		}
62778c2ecf20Sopenharmony_ci		p++;
62788c2ecf20Sopenharmony_ci	}
62798c2ecf20Sopenharmony_ciout:
62808c2ecf20Sopenharmony_ci	spin_unlock(&resource_alignment_lock);
62818c2ecf20Sopenharmony_ci	return align;
62828c2ecf20Sopenharmony_ci}
62838c2ecf20Sopenharmony_ci
62848c2ecf20Sopenharmony_cistatic void pci_request_resource_alignment(struct pci_dev *dev, int bar,
62858c2ecf20Sopenharmony_ci					   resource_size_t align, bool resize)
62868c2ecf20Sopenharmony_ci{
62878c2ecf20Sopenharmony_ci	struct resource *r = &dev->resource[bar];
62888c2ecf20Sopenharmony_ci	resource_size_t size;
62898c2ecf20Sopenharmony_ci
62908c2ecf20Sopenharmony_ci	if (!(r->flags & IORESOURCE_MEM))
62918c2ecf20Sopenharmony_ci		return;
62928c2ecf20Sopenharmony_ci
62938c2ecf20Sopenharmony_ci	if (r->flags & IORESOURCE_PCI_FIXED) {
62948c2ecf20Sopenharmony_ci		pci_info(dev, "BAR%d %pR: ignoring requested alignment %#llx\n",
62958c2ecf20Sopenharmony_ci			 bar, r, (unsigned long long)align);
62968c2ecf20Sopenharmony_ci		return;
62978c2ecf20Sopenharmony_ci	}
62988c2ecf20Sopenharmony_ci
62998c2ecf20Sopenharmony_ci	size = resource_size(r);
63008c2ecf20Sopenharmony_ci	if (size >= align)
63018c2ecf20Sopenharmony_ci		return;
63028c2ecf20Sopenharmony_ci
63038c2ecf20Sopenharmony_ci	/*
63048c2ecf20Sopenharmony_ci	 * Increase the alignment of the resource.  There are two ways we
63058c2ecf20Sopenharmony_ci	 * can do this:
63068c2ecf20Sopenharmony_ci	 *
63078c2ecf20Sopenharmony_ci	 * 1) Increase the size of the resource.  BARs are aligned on their
63088c2ecf20Sopenharmony_ci	 *    size, so when we reallocate space for this resource, we'll
63098c2ecf20Sopenharmony_ci	 *    allocate it with the larger alignment.  This also prevents
63108c2ecf20Sopenharmony_ci	 *    assignment of any other BARs inside the alignment region, so
63118c2ecf20Sopenharmony_ci	 *    if we're requesting page alignment, this means no other BARs
63128c2ecf20Sopenharmony_ci	 *    will share the page.
63138c2ecf20Sopenharmony_ci	 *
63148c2ecf20Sopenharmony_ci	 *    The disadvantage is that this makes the resource larger than
63158c2ecf20Sopenharmony_ci	 *    the hardware BAR, which may break drivers that compute things
63168c2ecf20Sopenharmony_ci	 *    based on the resource size, e.g., to find registers at a
63178c2ecf20Sopenharmony_ci	 *    fixed offset before the end of the BAR.
63188c2ecf20Sopenharmony_ci	 *
63198c2ecf20Sopenharmony_ci	 * 2) Retain the resource size, but use IORESOURCE_STARTALIGN and
63208c2ecf20Sopenharmony_ci	 *    set r->start to the desired alignment.  By itself this
63218c2ecf20Sopenharmony_ci	 *    doesn't prevent other BARs being put inside the alignment
63228c2ecf20Sopenharmony_ci	 *    region, but if we realign *every* resource of every device in
63238c2ecf20Sopenharmony_ci	 *    the system, none of them will share an alignment region.
63248c2ecf20Sopenharmony_ci	 *
63258c2ecf20Sopenharmony_ci	 * When the user has requested alignment for only some devices via
63268c2ecf20Sopenharmony_ci	 * the "pci=resource_alignment" argument, "resize" is true and we
63278c2ecf20Sopenharmony_ci	 * use the first method.  Otherwise we assume we're aligning all
63288c2ecf20Sopenharmony_ci	 * devices and we use the second.
63298c2ecf20Sopenharmony_ci	 */
63308c2ecf20Sopenharmony_ci
63318c2ecf20Sopenharmony_ci	pci_info(dev, "BAR%d %pR: requesting alignment to %#llx\n",
63328c2ecf20Sopenharmony_ci		 bar, r, (unsigned long long)align);
63338c2ecf20Sopenharmony_ci
63348c2ecf20Sopenharmony_ci	if (resize) {
63358c2ecf20Sopenharmony_ci		r->start = 0;
63368c2ecf20Sopenharmony_ci		r->end = align - 1;
63378c2ecf20Sopenharmony_ci	} else {
63388c2ecf20Sopenharmony_ci		r->flags &= ~IORESOURCE_SIZEALIGN;
63398c2ecf20Sopenharmony_ci		r->flags |= IORESOURCE_STARTALIGN;
63408c2ecf20Sopenharmony_ci		r->start = align;
63418c2ecf20Sopenharmony_ci		r->end = r->start + size - 1;
63428c2ecf20Sopenharmony_ci	}
63438c2ecf20Sopenharmony_ci	r->flags |= IORESOURCE_UNSET;
63448c2ecf20Sopenharmony_ci}
63458c2ecf20Sopenharmony_ci
63468c2ecf20Sopenharmony_ci/*
63478c2ecf20Sopenharmony_ci * This function disables memory decoding and releases memory resources
63488c2ecf20Sopenharmony_ci * of the device specified by kernel's boot parameter 'pci=resource_alignment='.
63498c2ecf20Sopenharmony_ci * It also rounds up size to specified alignment.
63508c2ecf20Sopenharmony_ci * Later on, the kernel will assign page-aligned memory resource back
63518c2ecf20Sopenharmony_ci * to the device.
63528c2ecf20Sopenharmony_ci */
63538c2ecf20Sopenharmony_civoid pci_reassigndev_resource_alignment(struct pci_dev *dev)
63548c2ecf20Sopenharmony_ci{
63558c2ecf20Sopenharmony_ci	int i;
63568c2ecf20Sopenharmony_ci	struct resource *r;
63578c2ecf20Sopenharmony_ci	resource_size_t align;
63588c2ecf20Sopenharmony_ci	u16 command;
63598c2ecf20Sopenharmony_ci	bool resize = false;
63608c2ecf20Sopenharmony_ci
63618c2ecf20Sopenharmony_ci	/*
63628c2ecf20Sopenharmony_ci	 * VF BARs are read-only zero according to SR-IOV spec r1.1, sec
63638c2ecf20Sopenharmony_ci	 * 3.4.1.11.  Their resources are allocated from the space
63648c2ecf20Sopenharmony_ci	 * described by the VF BARx register in the PF's SR-IOV capability.
63658c2ecf20Sopenharmony_ci	 * We can't influence their alignment here.
63668c2ecf20Sopenharmony_ci	 */
63678c2ecf20Sopenharmony_ci	if (dev->is_virtfn)
63688c2ecf20Sopenharmony_ci		return;
63698c2ecf20Sopenharmony_ci
63708c2ecf20Sopenharmony_ci	/* check if specified PCI is target device to reassign */
63718c2ecf20Sopenharmony_ci	align = pci_specified_resource_alignment(dev, &resize);
63728c2ecf20Sopenharmony_ci	if (!align)
63738c2ecf20Sopenharmony_ci		return;
63748c2ecf20Sopenharmony_ci
63758c2ecf20Sopenharmony_ci	if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL &&
63768c2ecf20Sopenharmony_ci	    (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
63778c2ecf20Sopenharmony_ci		pci_warn(dev, "Can't reassign resources to host bridge\n");
63788c2ecf20Sopenharmony_ci		return;
63798c2ecf20Sopenharmony_ci	}
63808c2ecf20Sopenharmony_ci
63818c2ecf20Sopenharmony_ci	pci_read_config_word(dev, PCI_COMMAND, &command);
63828c2ecf20Sopenharmony_ci	command &= ~PCI_COMMAND_MEMORY;
63838c2ecf20Sopenharmony_ci	pci_write_config_word(dev, PCI_COMMAND, command);
63848c2ecf20Sopenharmony_ci
63858c2ecf20Sopenharmony_ci	for (i = 0; i <= PCI_ROM_RESOURCE; i++)
63868c2ecf20Sopenharmony_ci		pci_request_resource_alignment(dev, i, align, resize);
63878c2ecf20Sopenharmony_ci
63888c2ecf20Sopenharmony_ci	/*
63898c2ecf20Sopenharmony_ci	 * Need to disable bridge's resource window,
63908c2ecf20Sopenharmony_ci	 * to enable the kernel to reassign new resource
63918c2ecf20Sopenharmony_ci	 * window later on.
63928c2ecf20Sopenharmony_ci	 */
63938c2ecf20Sopenharmony_ci	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
63948c2ecf20Sopenharmony_ci		for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
63958c2ecf20Sopenharmony_ci			r = &dev->resource[i];
63968c2ecf20Sopenharmony_ci			if (!(r->flags & IORESOURCE_MEM))
63978c2ecf20Sopenharmony_ci				continue;
63988c2ecf20Sopenharmony_ci			r->flags |= IORESOURCE_UNSET;
63998c2ecf20Sopenharmony_ci			r->end = resource_size(r) - 1;
64008c2ecf20Sopenharmony_ci			r->start = 0;
64018c2ecf20Sopenharmony_ci		}
64028c2ecf20Sopenharmony_ci		pci_disable_bridge_window(dev);
64038c2ecf20Sopenharmony_ci	}
64048c2ecf20Sopenharmony_ci}
64058c2ecf20Sopenharmony_ci
64068c2ecf20Sopenharmony_cistatic ssize_t resource_alignment_show(struct bus_type *bus, char *buf)
64078c2ecf20Sopenharmony_ci{
64088c2ecf20Sopenharmony_ci	size_t count = 0;
64098c2ecf20Sopenharmony_ci
64108c2ecf20Sopenharmony_ci	spin_lock(&resource_alignment_lock);
64118c2ecf20Sopenharmony_ci	if (resource_alignment_param)
64128c2ecf20Sopenharmony_ci		count = scnprintf(buf, PAGE_SIZE, "%s", resource_alignment_param);
64138c2ecf20Sopenharmony_ci	spin_unlock(&resource_alignment_lock);
64148c2ecf20Sopenharmony_ci
64158c2ecf20Sopenharmony_ci	/*
64168c2ecf20Sopenharmony_ci	 * When set by the command line, resource_alignment_param will not
64178c2ecf20Sopenharmony_ci	 * have a trailing line feed, which is ugly. So conditionally add
64188c2ecf20Sopenharmony_ci	 * it here.
64198c2ecf20Sopenharmony_ci	 */
64208c2ecf20Sopenharmony_ci	if (count >= 2 && buf[count - 2] != '\n' && count < PAGE_SIZE - 1) {
64218c2ecf20Sopenharmony_ci		buf[count - 1] = '\n';
64228c2ecf20Sopenharmony_ci		buf[count++] = 0;
64238c2ecf20Sopenharmony_ci	}
64248c2ecf20Sopenharmony_ci
64258c2ecf20Sopenharmony_ci	return count;
64268c2ecf20Sopenharmony_ci}
64278c2ecf20Sopenharmony_ci
64288c2ecf20Sopenharmony_cistatic ssize_t resource_alignment_store(struct bus_type *bus,
64298c2ecf20Sopenharmony_ci					const char *buf, size_t count)
64308c2ecf20Sopenharmony_ci{
64318c2ecf20Sopenharmony_ci	char *param = kstrndup(buf, count, GFP_KERNEL);
64328c2ecf20Sopenharmony_ci
64338c2ecf20Sopenharmony_ci	if (!param)
64348c2ecf20Sopenharmony_ci		return -ENOMEM;
64358c2ecf20Sopenharmony_ci
64368c2ecf20Sopenharmony_ci	spin_lock(&resource_alignment_lock);
64378c2ecf20Sopenharmony_ci	kfree(resource_alignment_param);
64388c2ecf20Sopenharmony_ci	resource_alignment_param = param;
64398c2ecf20Sopenharmony_ci	spin_unlock(&resource_alignment_lock);
64408c2ecf20Sopenharmony_ci	return count;
64418c2ecf20Sopenharmony_ci}
64428c2ecf20Sopenharmony_ci
64438c2ecf20Sopenharmony_cistatic BUS_ATTR_RW(resource_alignment);
64448c2ecf20Sopenharmony_ci
64458c2ecf20Sopenharmony_cistatic int __init pci_resource_alignment_sysfs_init(void)
64468c2ecf20Sopenharmony_ci{
64478c2ecf20Sopenharmony_ci	return bus_create_file(&pci_bus_type,
64488c2ecf20Sopenharmony_ci					&bus_attr_resource_alignment);
64498c2ecf20Sopenharmony_ci}
64508c2ecf20Sopenharmony_cilate_initcall(pci_resource_alignment_sysfs_init);
64518c2ecf20Sopenharmony_ci
64528c2ecf20Sopenharmony_cistatic void pci_no_domains(void)
64538c2ecf20Sopenharmony_ci{
64548c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_DOMAINS
64558c2ecf20Sopenharmony_ci	pci_domains_supported = 0;
64568c2ecf20Sopenharmony_ci#endif
64578c2ecf20Sopenharmony_ci}
64588c2ecf20Sopenharmony_ci
64598c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_DOMAINS_GENERIC
64608c2ecf20Sopenharmony_cistatic atomic_t __domain_nr = ATOMIC_INIT(-1);
64618c2ecf20Sopenharmony_ci
64628c2ecf20Sopenharmony_cistatic int pci_get_new_domain_nr(void)
64638c2ecf20Sopenharmony_ci{
64648c2ecf20Sopenharmony_ci	return atomic_inc_return(&__domain_nr);
64658c2ecf20Sopenharmony_ci}
64668c2ecf20Sopenharmony_ci
64678c2ecf20Sopenharmony_cistatic int of_pci_bus_find_domain_nr(struct device *parent)
64688c2ecf20Sopenharmony_ci{
64698c2ecf20Sopenharmony_ci	static int use_dt_domains = -1;
64708c2ecf20Sopenharmony_ci	int domain = -1;
64718c2ecf20Sopenharmony_ci
64728c2ecf20Sopenharmony_ci	if (parent)
64738c2ecf20Sopenharmony_ci		domain = of_get_pci_domain_nr(parent->of_node);
64748c2ecf20Sopenharmony_ci
64758c2ecf20Sopenharmony_ci	/*
64768c2ecf20Sopenharmony_ci	 * Check DT domain and use_dt_domains values.
64778c2ecf20Sopenharmony_ci	 *
64788c2ecf20Sopenharmony_ci	 * If DT domain property is valid (domain >= 0) and
64798c2ecf20Sopenharmony_ci	 * use_dt_domains != 0, the DT assignment is valid since this means
64808c2ecf20Sopenharmony_ci	 * we have not previously allocated a domain number by using
64818c2ecf20Sopenharmony_ci	 * pci_get_new_domain_nr(); we should also update use_dt_domains to
64828c2ecf20Sopenharmony_ci	 * 1, to indicate that we have just assigned a domain number from
64838c2ecf20Sopenharmony_ci	 * DT.
64848c2ecf20Sopenharmony_ci	 *
64858c2ecf20Sopenharmony_ci	 * If DT domain property value is not valid (ie domain < 0), and we
64868c2ecf20Sopenharmony_ci	 * have not previously assigned a domain number from DT
64878c2ecf20Sopenharmony_ci	 * (use_dt_domains != 1) we should assign a domain number by
64888c2ecf20Sopenharmony_ci	 * using the:
64898c2ecf20Sopenharmony_ci	 *
64908c2ecf20Sopenharmony_ci	 * pci_get_new_domain_nr()
64918c2ecf20Sopenharmony_ci	 *
64928c2ecf20Sopenharmony_ci	 * API and update the use_dt_domains value to keep track of method we
64938c2ecf20Sopenharmony_ci	 * are using to assign domain numbers (use_dt_domains = 0).
64948c2ecf20Sopenharmony_ci	 *
64958c2ecf20Sopenharmony_ci	 * All other combinations imply we have a platform that is trying
64968c2ecf20Sopenharmony_ci	 * to mix domain numbers obtained from DT and pci_get_new_domain_nr(),
64978c2ecf20Sopenharmony_ci	 * which is a recipe for domain mishandling and it is prevented by
64988c2ecf20Sopenharmony_ci	 * invalidating the domain value (domain = -1) and printing a
64998c2ecf20Sopenharmony_ci	 * corresponding error.
65008c2ecf20Sopenharmony_ci	 */
65018c2ecf20Sopenharmony_ci	if (domain >= 0 && use_dt_domains) {
65028c2ecf20Sopenharmony_ci		use_dt_domains = 1;
65038c2ecf20Sopenharmony_ci	} else if (domain < 0 && use_dt_domains != 1) {
65048c2ecf20Sopenharmony_ci		use_dt_domains = 0;
65058c2ecf20Sopenharmony_ci		domain = pci_get_new_domain_nr();
65068c2ecf20Sopenharmony_ci	} else {
65078c2ecf20Sopenharmony_ci		if (parent)
65088c2ecf20Sopenharmony_ci			pr_err("Node %pOF has ", parent->of_node);
65098c2ecf20Sopenharmony_ci		pr_err("Inconsistent \"linux,pci-domain\" property in DT\n");
65108c2ecf20Sopenharmony_ci		domain = -1;
65118c2ecf20Sopenharmony_ci	}
65128c2ecf20Sopenharmony_ci
65138c2ecf20Sopenharmony_ci	return domain;
65148c2ecf20Sopenharmony_ci}
65158c2ecf20Sopenharmony_ci
65168c2ecf20Sopenharmony_ciint pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
65178c2ecf20Sopenharmony_ci{
65188c2ecf20Sopenharmony_ci	return acpi_disabled ? of_pci_bus_find_domain_nr(parent) :
65198c2ecf20Sopenharmony_ci			       acpi_pci_bus_find_domain_nr(bus);
65208c2ecf20Sopenharmony_ci}
65218c2ecf20Sopenharmony_ci#endif
65228c2ecf20Sopenharmony_ci
65238c2ecf20Sopenharmony_ci/**
65248c2ecf20Sopenharmony_ci * pci_ext_cfg_avail - can we access extended PCI config space?
65258c2ecf20Sopenharmony_ci *
65268c2ecf20Sopenharmony_ci * Returns 1 if we can access PCI extended config space (offsets
65278c2ecf20Sopenharmony_ci * greater than 0xff). This is the default implementation. Architecture
65288c2ecf20Sopenharmony_ci * implementations can override this.
65298c2ecf20Sopenharmony_ci */
65308c2ecf20Sopenharmony_ciint __weak pci_ext_cfg_avail(void)
65318c2ecf20Sopenharmony_ci{
65328c2ecf20Sopenharmony_ci	return 1;
65338c2ecf20Sopenharmony_ci}
65348c2ecf20Sopenharmony_ci
65358c2ecf20Sopenharmony_civoid __weak pci_fixup_cardbus(struct pci_bus *bus)
65368c2ecf20Sopenharmony_ci{
65378c2ecf20Sopenharmony_ci}
65388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_fixup_cardbus);
65398c2ecf20Sopenharmony_ci
65408c2ecf20Sopenharmony_cistatic int __init pci_setup(char *str)
65418c2ecf20Sopenharmony_ci{
65428c2ecf20Sopenharmony_ci	while (str) {
65438c2ecf20Sopenharmony_ci		char *k = strchr(str, ',');
65448c2ecf20Sopenharmony_ci		if (k)
65458c2ecf20Sopenharmony_ci			*k++ = 0;
65468c2ecf20Sopenharmony_ci		if (*str && (str = pcibios_setup(str)) && *str) {
65478c2ecf20Sopenharmony_ci			if (!strcmp(str, "nomsi")) {
65488c2ecf20Sopenharmony_ci				pci_no_msi();
65498c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "noats", 5)) {
65508c2ecf20Sopenharmony_ci				pr_info("PCIe: ATS is disabled\n");
65518c2ecf20Sopenharmony_ci				pcie_ats_disabled = true;
65528c2ecf20Sopenharmony_ci			} else if (!strcmp(str, "noaer")) {
65538c2ecf20Sopenharmony_ci				pci_no_aer();
65548c2ecf20Sopenharmony_ci			} else if (!strcmp(str, "earlydump")) {
65558c2ecf20Sopenharmony_ci				pci_early_dump = true;
65568c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "realloc=", 8)) {
65578c2ecf20Sopenharmony_ci				pci_realloc_get_opt(str + 8);
65588c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "realloc", 7)) {
65598c2ecf20Sopenharmony_ci				pci_realloc_get_opt("on");
65608c2ecf20Sopenharmony_ci			} else if (!strcmp(str, "nodomains")) {
65618c2ecf20Sopenharmony_ci				pci_no_domains();
65628c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "noari", 5)) {
65638c2ecf20Sopenharmony_ci				pcie_ari_disabled = true;
65648c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "cbiosize=", 9)) {
65658c2ecf20Sopenharmony_ci				pci_cardbus_io_size = memparse(str + 9, &str);
65668c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "cbmemsize=", 10)) {
65678c2ecf20Sopenharmony_ci				pci_cardbus_mem_size = memparse(str + 10, &str);
65688c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "resource_alignment=", 19)) {
65698c2ecf20Sopenharmony_ci				resource_alignment_param = str + 19;
65708c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "ecrc=", 5)) {
65718c2ecf20Sopenharmony_ci				pcie_ecrc_get_policy(str + 5);
65728c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "hpiosize=", 9)) {
65738c2ecf20Sopenharmony_ci				pci_hotplug_io_size = memparse(str + 9, &str);
65748c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "hpmmiosize=", 11)) {
65758c2ecf20Sopenharmony_ci				pci_hotplug_mmio_size = memparse(str + 11, &str);
65768c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "hpmmioprefsize=", 15)) {
65778c2ecf20Sopenharmony_ci				pci_hotplug_mmio_pref_size = memparse(str + 15, &str);
65788c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "hpmemsize=", 10)) {
65798c2ecf20Sopenharmony_ci				pci_hotplug_mmio_size = memparse(str + 10, &str);
65808c2ecf20Sopenharmony_ci				pci_hotplug_mmio_pref_size = pci_hotplug_mmio_size;
65818c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "hpbussize=", 10)) {
65828c2ecf20Sopenharmony_ci				pci_hotplug_bus_size =
65838c2ecf20Sopenharmony_ci					simple_strtoul(str + 10, &str, 0);
65848c2ecf20Sopenharmony_ci				if (pci_hotplug_bus_size > 0xff)
65858c2ecf20Sopenharmony_ci					pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE;
65868c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "pcie_bus_tune_off", 17)) {
65878c2ecf20Sopenharmony_ci				pcie_bus_config = PCIE_BUS_TUNE_OFF;
65888c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "pcie_bus_safe", 13)) {
65898c2ecf20Sopenharmony_ci				pcie_bus_config = PCIE_BUS_SAFE;
65908c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "pcie_bus_perf", 13)) {
65918c2ecf20Sopenharmony_ci				pcie_bus_config = PCIE_BUS_PERFORMANCE;
65928c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "pcie_bus_peer2peer", 18)) {
65938c2ecf20Sopenharmony_ci				pcie_bus_config = PCIE_BUS_PEER2PEER;
65948c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "pcie_scan_all", 13)) {
65958c2ecf20Sopenharmony_ci				pci_add_flags(PCI_SCAN_ALL_PCIE_DEVS);
65968c2ecf20Sopenharmony_ci			} else if (!strncmp(str, "disable_acs_redir=", 18)) {
65978c2ecf20Sopenharmony_ci				disable_acs_redir_param = str + 18;
65988c2ecf20Sopenharmony_ci			} else {
65998c2ecf20Sopenharmony_ci				pr_err("PCI: Unknown option `%s'\n", str);
66008c2ecf20Sopenharmony_ci			}
66018c2ecf20Sopenharmony_ci		}
66028c2ecf20Sopenharmony_ci		str = k;
66038c2ecf20Sopenharmony_ci	}
66048c2ecf20Sopenharmony_ci	return 0;
66058c2ecf20Sopenharmony_ci}
66068c2ecf20Sopenharmony_ciearly_param("pci", pci_setup);
66078c2ecf20Sopenharmony_ci
66088c2ecf20Sopenharmony_ci/*
66098c2ecf20Sopenharmony_ci * 'resource_alignment_param' and 'disable_acs_redir_param' are initialized
66108c2ecf20Sopenharmony_ci * in pci_setup(), above, to point to data in the __initdata section which
66118c2ecf20Sopenharmony_ci * will be freed after the init sequence is complete. We can't allocate memory
66128c2ecf20Sopenharmony_ci * in pci_setup() because some architectures do not have any memory allocation
66138c2ecf20Sopenharmony_ci * service available during an early_param() call. So we allocate memory and
66148c2ecf20Sopenharmony_ci * copy the variable here before the init section is freed.
66158c2ecf20Sopenharmony_ci *
66168c2ecf20Sopenharmony_ci */
66178c2ecf20Sopenharmony_cistatic int __init pci_realloc_setup_params(void)
66188c2ecf20Sopenharmony_ci{
66198c2ecf20Sopenharmony_ci	resource_alignment_param = kstrdup(resource_alignment_param,
66208c2ecf20Sopenharmony_ci					   GFP_KERNEL);
66218c2ecf20Sopenharmony_ci	disable_acs_redir_param = kstrdup(disable_acs_redir_param, GFP_KERNEL);
66228c2ecf20Sopenharmony_ci
66238c2ecf20Sopenharmony_ci	return 0;
66248c2ecf20Sopenharmony_ci}
66258c2ecf20Sopenharmony_cipure_initcall(pci_realloc_setup_params);
6626