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