18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PCI <-> OF mapping helpers 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2011 IBM Corp. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "PCI: OF: " fmt 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/pci.h> 128c2ecf20Sopenharmony_ci#include <linux/of.h> 138c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 148c2ecf20Sopenharmony_ci#include <linux/of_address.h> 158c2ecf20Sopenharmony_ci#include <linux/of_pci.h> 168c2ecf20Sopenharmony_ci#include "pci.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 198c2ecf20Sopenharmony_civoid pci_set_of_node(struct pci_dev *dev) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci if (!dev->bus->dev.of_node) 228c2ecf20Sopenharmony_ci return; 238c2ecf20Sopenharmony_ci dev->dev.of_node = of_pci_find_child_device(dev->bus->dev.of_node, 248c2ecf20Sopenharmony_ci dev->devfn); 258c2ecf20Sopenharmony_ci if (dev->dev.of_node) 268c2ecf20Sopenharmony_ci dev->dev.fwnode = &dev->dev.of_node->fwnode; 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_civoid pci_release_of_node(struct pci_dev *dev) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci of_node_put(dev->dev.of_node); 328c2ecf20Sopenharmony_ci dev->dev.of_node = NULL; 338c2ecf20Sopenharmony_ci dev->dev.fwnode = NULL; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_civoid pci_set_bus_of_node(struct pci_bus *bus) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct device_node *node; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (bus->self == NULL) { 418c2ecf20Sopenharmony_ci node = pcibios_get_phb_of_node(bus); 428c2ecf20Sopenharmony_ci } else { 438c2ecf20Sopenharmony_ci node = of_node_get(bus->self->dev.of_node); 448c2ecf20Sopenharmony_ci if (node && of_property_read_bool(node, "external-facing")) 458c2ecf20Sopenharmony_ci bus->self->external_facing = true; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci bus->dev.of_node = node; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (bus->dev.of_node) 518c2ecf20Sopenharmony_ci bus->dev.fwnode = &bus->dev.of_node->fwnode; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_civoid pci_release_bus_of_node(struct pci_bus *bus) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci of_node_put(bus->dev.of_node); 578c2ecf20Sopenharmony_ci bus->dev.of_node = NULL; 588c2ecf20Sopenharmony_ci bus->dev.fwnode = NULL; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistruct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci /* This should only be called for PHBs */ 648c2ecf20Sopenharmony_ci if (WARN_ON(bus->self || bus->parent)) 658c2ecf20Sopenharmony_ci return NULL; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* 688c2ecf20Sopenharmony_ci * Look for a node pointer in either the intermediary device we 698c2ecf20Sopenharmony_ci * create above the root bus or its own parent. Normally only 708c2ecf20Sopenharmony_ci * the later is populated. 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_ci if (bus->bridge->of_node) 738c2ecf20Sopenharmony_ci return of_node_get(bus->bridge->of_node); 748c2ecf20Sopenharmony_ci if (bus->bridge->parent && bus->bridge->parent->of_node) 758c2ecf20Sopenharmony_ci return of_node_get(bus->bridge->parent->of_node); 768c2ecf20Sopenharmony_ci return NULL; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistruct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci#ifdef CONFIG_IRQ_DOMAIN 828c2ecf20Sopenharmony_ci struct irq_domain *d; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (!bus->dev.of_node) 858c2ecf20Sopenharmony_ci return NULL; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* Start looking for a phandle to an MSI controller. */ 888c2ecf20Sopenharmony_ci d = of_msi_get_domain(&bus->dev, bus->dev.of_node, DOMAIN_BUS_PCI_MSI); 898c2ecf20Sopenharmony_ci if (d) 908c2ecf20Sopenharmony_ci return d; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci /* 938c2ecf20Sopenharmony_ci * If we don't have an msi-parent property, look for a domain 948c2ecf20Sopenharmony_ci * directly attached to the host bridge. 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci d = irq_find_matching_host(bus->dev.of_node, DOMAIN_BUS_PCI_MSI); 978c2ecf20Sopenharmony_ci if (d) 988c2ecf20Sopenharmony_ci return d; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return irq_find_host(bus->dev.of_node); 1018c2ecf20Sopenharmony_ci#else 1028c2ecf20Sopenharmony_ci return NULL; 1038c2ecf20Sopenharmony_ci#endif 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic inline int __of_pci_pci_compare(struct device_node *node, 1078c2ecf20Sopenharmony_ci unsigned int data) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci int devfn; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci devfn = of_pci_get_devfn(node); 1128c2ecf20Sopenharmony_ci if (devfn < 0) 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return devfn == data; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistruct device_node *of_pci_find_child_device(struct device_node *parent, 1198c2ecf20Sopenharmony_ci unsigned int devfn) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct device_node *node, *node2; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci for_each_child_of_node(parent, node) { 1248c2ecf20Sopenharmony_ci if (__of_pci_pci_compare(node, devfn)) 1258c2ecf20Sopenharmony_ci return node; 1268c2ecf20Sopenharmony_ci /* 1278c2ecf20Sopenharmony_ci * Some OFs create a parent node "multifunc-device" as 1288c2ecf20Sopenharmony_ci * a fake root for all functions of a multi-function 1298c2ecf20Sopenharmony_ci * device we go down them as well. 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ci if (of_node_name_eq(node, "multifunc-device")) { 1328c2ecf20Sopenharmony_ci for_each_child_of_node(node, node2) { 1338c2ecf20Sopenharmony_ci if (__of_pci_pci_compare(node2, devfn)) { 1348c2ecf20Sopenharmony_ci of_node_put(node); 1358c2ecf20Sopenharmony_ci return node2; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci return NULL; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_pci_find_child_device); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/** 1458c2ecf20Sopenharmony_ci * of_pci_get_devfn() - Get device and function numbers for a device node 1468c2ecf20Sopenharmony_ci * @np: device node 1478c2ecf20Sopenharmony_ci * 1488c2ecf20Sopenharmony_ci * Parses a standard 5-cell PCI resource and returns an 8-bit value that can 1498c2ecf20Sopenharmony_ci * be passed to the PCI_SLOT() and PCI_FUNC() macros to extract the device 1508c2ecf20Sopenharmony_ci * and function numbers respectively. On error a negative error code is 1518c2ecf20Sopenharmony_ci * returned. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ciint of_pci_get_devfn(struct device_node *np) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci u32 reg[5]; 1568c2ecf20Sopenharmony_ci int error; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci error = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg)); 1598c2ecf20Sopenharmony_ci if (error) 1608c2ecf20Sopenharmony_ci return error; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return (reg[0] >> 8) & 0xff; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_pci_get_devfn); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/** 1678c2ecf20Sopenharmony_ci * of_pci_parse_bus_range() - parse the bus-range property of a PCI device 1688c2ecf20Sopenharmony_ci * @node: device node 1698c2ecf20Sopenharmony_ci * @res: address to a struct resource to return the bus-range 1708c2ecf20Sopenharmony_ci * 1718c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error-code on failure. 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ciint of_pci_parse_bus_range(struct device_node *node, struct resource *res) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci u32 bus_range[2]; 1768c2ecf20Sopenharmony_ci int error; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci error = of_property_read_u32_array(node, "bus-range", bus_range, 1798c2ecf20Sopenharmony_ci ARRAY_SIZE(bus_range)); 1808c2ecf20Sopenharmony_ci if (error) 1818c2ecf20Sopenharmony_ci return error; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci res->name = node->name; 1848c2ecf20Sopenharmony_ci res->start = bus_range[0]; 1858c2ecf20Sopenharmony_ci res->end = bus_range[1]; 1868c2ecf20Sopenharmony_ci res->flags = IORESOURCE_BUS; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return 0; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_pci_parse_bus_range); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/** 1938c2ecf20Sopenharmony_ci * This function will try to obtain the host bridge domain number by 1948c2ecf20Sopenharmony_ci * finding a property called "linux,pci-domain" of the given device node. 1958c2ecf20Sopenharmony_ci * 1968c2ecf20Sopenharmony_ci * @node: device tree node with the domain information 1978c2ecf20Sopenharmony_ci * 1988c2ecf20Sopenharmony_ci * Returns the associated domain number from DT in the range [0-0xffff], or 1998c2ecf20Sopenharmony_ci * a negative value if the required property is not found. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ciint of_get_pci_domain_nr(struct device_node *node) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci u32 domain; 2048c2ecf20Sopenharmony_ci int error; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci error = of_property_read_u32(node, "linux,pci-domain", &domain); 2078c2ecf20Sopenharmony_ci if (error) 2088c2ecf20Sopenharmony_ci return error; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return (u16)domain; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_get_pci_domain_nr); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/** 2158c2ecf20Sopenharmony_ci * of_pci_check_probe_only - Setup probe only mode if linux,pci-probe-only 2168c2ecf20Sopenharmony_ci * is present and valid 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_civoid of_pci_check_probe_only(void) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci u32 val; 2218c2ecf20Sopenharmony_ci int ret; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci ret = of_property_read_u32(of_chosen, "linux,pci-probe-only", &val); 2248c2ecf20Sopenharmony_ci if (ret) { 2258c2ecf20Sopenharmony_ci if (ret == -ENODATA || ret == -EOVERFLOW) 2268c2ecf20Sopenharmony_ci pr_warn("linux,pci-probe-only without valid value, ignoring\n"); 2278c2ecf20Sopenharmony_ci return; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (val) 2318c2ecf20Sopenharmony_ci pci_add_flags(PCI_PROBE_ONLY); 2328c2ecf20Sopenharmony_ci else 2338c2ecf20Sopenharmony_ci pci_clear_flags(PCI_PROBE_ONLY); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci pr_info("PROBE_ONLY %sabled\n", val ? "en" : "dis"); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_pci_check_probe_only); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/** 2408c2ecf20Sopenharmony_ci * devm_of_pci_get_host_bridge_resources() - Resource-managed parsing of PCI 2418c2ecf20Sopenharmony_ci * host bridge resources from DT 2428c2ecf20Sopenharmony_ci * @dev: host bridge device 2438c2ecf20Sopenharmony_ci * @busno: bus number associated with the bridge root bus 2448c2ecf20Sopenharmony_ci * @bus_max: maximum number of buses for this bridge 2458c2ecf20Sopenharmony_ci * @resources: list where the range of resources will be added after DT parsing 2468c2ecf20Sopenharmony_ci * @ib_resources: list where the range of inbound resources (with addresses 2478c2ecf20Sopenharmony_ci * from 'dma-ranges') will be added after DT parsing 2488c2ecf20Sopenharmony_ci * @io_base: pointer to a variable that will contain on return the physical 2498c2ecf20Sopenharmony_ci * address for the start of the I/O range. Can be NULL if the caller doesn't 2508c2ecf20Sopenharmony_ci * expect I/O ranges to be present in the device tree. 2518c2ecf20Sopenharmony_ci * 2528c2ecf20Sopenharmony_ci * This function will parse the "ranges" property of a PCI host bridge device 2538c2ecf20Sopenharmony_ci * node and setup the resource mapping based on its content. It is expected 2548c2ecf20Sopenharmony_ci * that the property conforms with the Power ePAPR document. 2558c2ecf20Sopenharmony_ci * 2568c2ecf20Sopenharmony_ci * It returns zero if the range parsing has been successful or a standard error 2578c2ecf20Sopenharmony_ci * value if it failed. 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_cistatic int devm_of_pci_get_host_bridge_resources(struct device *dev, 2608c2ecf20Sopenharmony_ci unsigned char busno, unsigned char bus_max, 2618c2ecf20Sopenharmony_ci struct list_head *resources, 2628c2ecf20Sopenharmony_ci struct list_head *ib_resources, 2638c2ecf20Sopenharmony_ci resource_size_t *io_base) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct device_node *dev_node = dev->of_node; 2668c2ecf20Sopenharmony_ci struct resource *res, tmp_res; 2678c2ecf20Sopenharmony_ci struct resource *bus_range; 2688c2ecf20Sopenharmony_ci struct of_pci_range range; 2698c2ecf20Sopenharmony_ci struct of_pci_range_parser parser; 2708c2ecf20Sopenharmony_ci const char *range_type; 2718c2ecf20Sopenharmony_ci int err; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (io_base) 2748c2ecf20Sopenharmony_ci *io_base = (resource_size_t)OF_BAD_ADDR; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci bus_range = devm_kzalloc(dev, sizeof(*bus_range), GFP_KERNEL); 2778c2ecf20Sopenharmony_ci if (!bus_range) 2788c2ecf20Sopenharmony_ci return -ENOMEM; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci dev_info(dev, "host bridge %pOF ranges:\n", dev_node); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci err = of_pci_parse_bus_range(dev_node, bus_range); 2838c2ecf20Sopenharmony_ci if (err) { 2848c2ecf20Sopenharmony_ci bus_range->start = busno; 2858c2ecf20Sopenharmony_ci bus_range->end = bus_max; 2868c2ecf20Sopenharmony_ci bus_range->flags = IORESOURCE_BUS; 2878c2ecf20Sopenharmony_ci dev_info(dev, " No bus range found for %pOF, using %pR\n", 2888c2ecf20Sopenharmony_ci dev_node, bus_range); 2898c2ecf20Sopenharmony_ci } else { 2908c2ecf20Sopenharmony_ci if (bus_range->end > bus_range->start + bus_max) 2918c2ecf20Sopenharmony_ci bus_range->end = bus_range->start + bus_max; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci pci_add_resource(resources, bus_range); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* Check for ranges property */ 2968c2ecf20Sopenharmony_ci err = of_pci_range_parser_init(&parser, dev_node); 2978c2ecf20Sopenharmony_ci if (err) 2988c2ecf20Sopenharmony_ci return 0; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci dev_dbg(dev, "Parsing ranges property...\n"); 3018c2ecf20Sopenharmony_ci for_each_of_pci_range(&parser, &range) { 3028c2ecf20Sopenharmony_ci /* Read next ranges element */ 3038c2ecf20Sopenharmony_ci if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO) 3048c2ecf20Sopenharmony_ci range_type = "IO"; 3058c2ecf20Sopenharmony_ci else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) 3068c2ecf20Sopenharmony_ci range_type = "MEM"; 3078c2ecf20Sopenharmony_ci else 3088c2ecf20Sopenharmony_ci range_type = "err"; 3098c2ecf20Sopenharmony_ci dev_info(dev, " %6s %#012llx..%#012llx -> %#012llx\n", 3108c2ecf20Sopenharmony_ci range_type, range.cpu_addr, 3118c2ecf20Sopenharmony_ci range.cpu_addr + range.size - 1, range.pci_addr); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* 3148c2ecf20Sopenharmony_ci * If we failed translation or got a zero-sized region 3158c2ecf20Sopenharmony_ci * then skip this range 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci if (range.cpu_addr == OF_BAD_ADDR || range.size == 0) 3188c2ecf20Sopenharmony_ci continue; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci err = of_pci_range_to_resource(&range, dev_node, &tmp_res); 3218c2ecf20Sopenharmony_ci if (err) 3228c2ecf20Sopenharmony_ci continue; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci res = devm_kmemdup(dev, &tmp_res, sizeof(tmp_res), GFP_KERNEL); 3258c2ecf20Sopenharmony_ci if (!res) { 3268c2ecf20Sopenharmony_ci err = -ENOMEM; 3278c2ecf20Sopenharmony_ci goto failed; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (resource_type(res) == IORESOURCE_IO) { 3318c2ecf20Sopenharmony_ci if (!io_base) { 3328c2ecf20Sopenharmony_ci dev_err(dev, "I/O range found for %pOF. Please provide an io_base pointer to save CPU base address\n", 3338c2ecf20Sopenharmony_ci dev_node); 3348c2ecf20Sopenharmony_ci err = -EINVAL; 3358c2ecf20Sopenharmony_ci goto failed; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci if (*io_base != (resource_size_t)OF_BAD_ADDR) 3388c2ecf20Sopenharmony_ci dev_warn(dev, "More than one I/O resource converted for %pOF. CPU base address for old range lost!\n", 3398c2ecf20Sopenharmony_ci dev_node); 3408c2ecf20Sopenharmony_ci *io_base = range.cpu_addr; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci pci_add_resource_offset(resources, res, res->start - range.pci_addr); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* Check for dma-ranges property */ 3478c2ecf20Sopenharmony_ci if (!ib_resources) 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci err = of_pci_dma_range_parser_init(&parser, dev_node); 3508c2ecf20Sopenharmony_ci if (err) 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci dev_dbg(dev, "Parsing dma-ranges property...\n"); 3548c2ecf20Sopenharmony_ci for_each_of_pci_range(&parser, &range) { 3558c2ecf20Sopenharmony_ci struct resource_entry *entry; 3568c2ecf20Sopenharmony_ci /* 3578c2ecf20Sopenharmony_ci * If we failed translation or got a zero-sized region 3588c2ecf20Sopenharmony_ci * then skip this range 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_ci if (((range.flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM) || 3618c2ecf20Sopenharmony_ci range.cpu_addr == OF_BAD_ADDR || range.size == 0) 3628c2ecf20Sopenharmony_ci continue; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci dev_info(dev, " %6s %#012llx..%#012llx -> %#012llx\n", 3658c2ecf20Sopenharmony_ci "IB MEM", range.cpu_addr, 3668c2ecf20Sopenharmony_ci range.cpu_addr + range.size - 1, range.pci_addr); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci err = of_pci_range_to_resource(&range, dev_node, &tmp_res); 3708c2ecf20Sopenharmony_ci if (err) 3718c2ecf20Sopenharmony_ci continue; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci res = devm_kmemdup(dev, &tmp_res, sizeof(tmp_res), GFP_KERNEL); 3748c2ecf20Sopenharmony_ci if (!res) { 3758c2ecf20Sopenharmony_ci err = -ENOMEM; 3768c2ecf20Sopenharmony_ci goto failed; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* Keep the resource list sorted */ 3808c2ecf20Sopenharmony_ci resource_list_for_each_entry(entry, ib_resources) 3818c2ecf20Sopenharmony_ci if (entry->res->start > res->start) 3828c2ecf20Sopenharmony_ci break; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci pci_add_resource_offset(&entry->node, res, 3858c2ecf20Sopenharmony_ci res->start - range.pci_addr); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci return 0; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cifailed: 3918c2ecf20Sopenharmony_ci pci_free_resource_list(resources); 3928c2ecf20Sopenharmony_ci return err; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_OF_IRQ) 3968c2ecf20Sopenharmony_ci/** 3978c2ecf20Sopenharmony_ci * of_irq_parse_pci - Resolve the interrupt for a PCI device 3988c2ecf20Sopenharmony_ci * @pdev: the device whose interrupt is to be resolved 3998c2ecf20Sopenharmony_ci * @out_irq: structure of_phandle_args filled by this function 4008c2ecf20Sopenharmony_ci * 4018c2ecf20Sopenharmony_ci * This function resolves the PCI interrupt for a given PCI device. If a 4028c2ecf20Sopenharmony_ci * device-node exists for a given pci_dev, it will use normal OF tree 4038c2ecf20Sopenharmony_ci * walking. If not, it will implement standard swizzling and walk up the 4048c2ecf20Sopenharmony_ci * PCI tree until an device-node is found, at which point it will finish 4058c2ecf20Sopenharmony_ci * resolving using the OF tree walking. 4068c2ecf20Sopenharmony_ci */ 4078c2ecf20Sopenharmony_cistatic int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct device_node *dn, *ppnode; 4108c2ecf20Sopenharmony_ci struct pci_dev *ppdev; 4118c2ecf20Sopenharmony_ci __be32 laddr[3]; 4128c2ecf20Sopenharmony_ci u8 pin; 4138c2ecf20Sopenharmony_ci int rc; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* 4168c2ecf20Sopenharmony_ci * Check if we have a device node, if yes, fallback to standard 4178c2ecf20Sopenharmony_ci * device tree parsing 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_ci dn = pci_device_to_OF_node(pdev); 4208c2ecf20Sopenharmony_ci if (dn) { 4218c2ecf20Sopenharmony_ci rc = of_irq_parse_one(dn, 0, out_irq); 4228c2ecf20Sopenharmony_ci if (!rc) 4238c2ecf20Sopenharmony_ci return rc; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* 4278c2ecf20Sopenharmony_ci * Ok, we don't, time to have fun. Let's start by building up an 4288c2ecf20Sopenharmony_ci * interrupt spec. we assume #interrupt-cells is 1, which is standard 4298c2ecf20Sopenharmony_ci * for PCI. If you do different, then don't use that routine. 4308c2ecf20Sopenharmony_ci */ 4318c2ecf20Sopenharmony_ci rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); 4328c2ecf20Sopenharmony_ci if (rc != 0) 4338c2ecf20Sopenharmony_ci goto err; 4348c2ecf20Sopenharmony_ci /* No pin, exit with no error message. */ 4358c2ecf20Sopenharmony_ci if (pin == 0) 4368c2ecf20Sopenharmony_ci return -ENODEV; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Now we walk up the PCI tree */ 4398c2ecf20Sopenharmony_ci for (;;) { 4408c2ecf20Sopenharmony_ci /* Get the pci_dev of our parent */ 4418c2ecf20Sopenharmony_ci ppdev = pdev->bus->self; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* Ouch, it's a host bridge... */ 4448c2ecf20Sopenharmony_ci if (ppdev == NULL) { 4458c2ecf20Sopenharmony_ci ppnode = pci_bus_to_OF_node(pdev->bus); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* No node for host bridge ? give up */ 4488c2ecf20Sopenharmony_ci if (ppnode == NULL) { 4498c2ecf20Sopenharmony_ci rc = -EINVAL; 4508c2ecf20Sopenharmony_ci goto err; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci } else { 4538c2ecf20Sopenharmony_ci /* We found a P2P bridge, check if it has a node */ 4548c2ecf20Sopenharmony_ci ppnode = pci_device_to_OF_node(ppdev); 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* 4588c2ecf20Sopenharmony_ci * Ok, we have found a parent with a device-node, hand over to 4598c2ecf20Sopenharmony_ci * the OF parsing code. 4608c2ecf20Sopenharmony_ci * We build a unit address from the linux device to be used for 4618c2ecf20Sopenharmony_ci * resolution. Note that we use the linux bus number which may 4628c2ecf20Sopenharmony_ci * not match your firmware bus numbering. 4638c2ecf20Sopenharmony_ci * Fortunately, in most cases, interrupt-map-mask doesn't 4648c2ecf20Sopenharmony_ci * include the bus number as part of the matching. 4658c2ecf20Sopenharmony_ci * You should still be careful about that though if you intend 4668c2ecf20Sopenharmony_ci * to rely on this function (you ship a firmware that doesn't 4678c2ecf20Sopenharmony_ci * create device nodes for all PCI devices). 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_ci if (ppnode) 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* 4738c2ecf20Sopenharmony_ci * We can only get here if we hit a P2P bridge with no node; 4748c2ecf20Sopenharmony_ci * let's do standard swizzling and try again 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_ci pin = pci_swizzle_interrupt_pin(pdev, pin); 4778c2ecf20Sopenharmony_ci pdev = ppdev; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci out_irq->np = ppnode; 4818c2ecf20Sopenharmony_ci out_irq->args_count = 1; 4828c2ecf20Sopenharmony_ci out_irq->args[0] = pin; 4838c2ecf20Sopenharmony_ci laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8)); 4848c2ecf20Sopenharmony_ci laddr[1] = laddr[2] = cpu_to_be32(0); 4858c2ecf20Sopenharmony_ci rc = of_irq_parse_raw(laddr, out_irq); 4868c2ecf20Sopenharmony_ci if (rc) 4878c2ecf20Sopenharmony_ci goto err; 4888c2ecf20Sopenharmony_ci return 0; 4898c2ecf20Sopenharmony_cierr: 4908c2ecf20Sopenharmony_ci if (rc == -ENOENT) { 4918c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 4928c2ecf20Sopenharmony_ci "%s: no interrupt-map found, INTx interrupts not available\n", 4938c2ecf20Sopenharmony_ci __func__); 4948c2ecf20Sopenharmony_ci pr_warn_once("%s: possibly some PCI slots don't have level triggered interrupts capability\n", 4958c2ecf20Sopenharmony_ci __func__); 4968c2ecf20Sopenharmony_ci } else { 4978c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "%s: failed with rc=%d\n", __func__, rc); 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci return rc; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci/** 5038c2ecf20Sopenharmony_ci * of_irq_parse_and_map_pci() - Decode a PCI IRQ from the device tree and map to a VIRQ 5048c2ecf20Sopenharmony_ci * @dev: The PCI device needing an IRQ 5058c2ecf20Sopenharmony_ci * @slot: PCI slot number; passed when used as map_irq callback. Unused 5068c2ecf20Sopenharmony_ci * @pin: PCI IRQ pin number; passed when used as map_irq callback. Unused 5078c2ecf20Sopenharmony_ci * 5088c2ecf20Sopenharmony_ci * @slot and @pin are unused, but included in the function so that this 5098c2ecf20Sopenharmony_ci * function can be used directly as the map_irq callback to 5108c2ecf20Sopenharmony_ci * pci_assign_irq() and struct pci_host_bridge.map_irq pointer 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_ciint of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci struct of_phandle_args oirq; 5158c2ecf20Sopenharmony_ci int ret; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci ret = of_irq_parse_pci(dev, &oirq); 5188c2ecf20Sopenharmony_ci if (ret) 5198c2ecf20Sopenharmony_ci return 0; /* Proper return code 0 == NO_IRQ */ 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return irq_create_of_mapping(&oirq); 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_irq_parse_and_map_pci); 5248c2ecf20Sopenharmony_ci#endif /* CONFIG_OF_IRQ */ 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic int pci_parse_request_of_pci_ranges(struct device *dev, 5278c2ecf20Sopenharmony_ci struct pci_host_bridge *bridge) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci int err, res_valid = 0; 5308c2ecf20Sopenharmony_ci resource_size_t iobase; 5318c2ecf20Sopenharmony_ci struct resource_entry *win, *tmp; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bridge->windows); 5348c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bridge->dma_ranges); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &bridge->windows, 5378c2ecf20Sopenharmony_ci &bridge->dma_ranges, &iobase); 5388c2ecf20Sopenharmony_ci if (err) 5398c2ecf20Sopenharmony_ci return err; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci err = devm_request_pci_bus_resources(dev, &bridge->windows); 5428c2ecf20Sopenharmony_ci if (err) 5438c2ecf20Sopenharmony_ci return err; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci resource_list_for_each_entry_safe(win, tmp, &bridge->windows) { 5468c2ecf20Sopenharmony_ci struct resource *res = win->res; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci switch (resource_type(res)) { 5498c2ecf20Sopenharmony_ci case IORESOURCE_IO: 5508c2ecf20Sopenharmony_ci err = devm_pci_remap_iospace(dev, res, iobase); 5518c2ecf20Sopenharmony_ci if (err) { 5528c2ecf20Sopenharmony_ci dev_warn(dev, "error %d: failed to map resource %pR\n", 5538c2ecf20Sopenharmony_ci err, res); 5548c2ecf20Sopenharmony_ci resource_list_destroy_entry(win); 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci break; 5578c2ecf20Sopenharmony_ci case IORESOURCE_MEM: 5588c2ecf20Sopenharmony_ci res_valid |= !(res->flags & IORESOURCE_PREFETCH); 5598c2ecf20Sopenharmony_ci break; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (!res_valid) 5648c2ecf20Sopenharmony_ci dev_warn(dev, "non-prefetchable memory resource required\n"); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci return 0; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ciint devm_of_pci_bridge_init(struct device *dev, struct pci_host_bridge *bridge) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci if (!dev->of_node) 5728c2ecf20Sopenharmony_ci return 0; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci bridge->swizzle_irq = pci_common_swizzle; 5758c2ecf20Sopenharmony_ci bridge->map_irq = of_irq_parse_and_map_pci; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return pci_parse_request_of_pci_ranges(dev, bridge); 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci/** 5838c2ecf20Sopenharmony_ci * This function will try to find the limitation of link speed by finding 5848c2ecf20Sopenharmony_ci * a property called "max-link-speed" of the given device node. 5858c2ecf20Sopenharmony_ci * 5868c2ecf20Sopenharmony_ci * @node: device tree node with the max link speed information 5878c2ecf20Sopenharmony_ci * 5888c2ecf20Sopenharmony_ci * Returns the associated max link speed from DT, or a negative value if the 5898c2ecf20Sopenharmony_ci * required property is not found or is invalid. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ciint of_pci_get_max_link_speed(struct device_node *node) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci u32 max_link_speed; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (of_property_read_u32(node, "max-link-speed", &max_link_speed) || 5968c2ecf20Sopenharmony_ci max_link_speed == 0 || max_link_speed > 4) 5978c2ecf20Sopenharmony_ci return -EINVAL; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci return max_link_speed; 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_pci_get_max_link_speed); 602