/* * PCI <-> OF mapping helpers * * Copyright 2011 IBM Corp. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include #include #include #include #include #include #include "pci.h" void pci_set_of_node(struct pci_dev *dev) { if (!dev->bus->dev.of_node) return; dev->dev.of_node = of_pci_find_child_device(dev->bus->dev.of_node, dev->devfn); } void pci_release_of_node(struct pci_dev *dev) { of_node_put(dev->dev.of_node); dev->dev.of_node = NULL; } void pci_set_bus_of_node(struct pci_bus *bus) { if (bus->self == NULL) bus->dev.of_node = pcibios_get_phb_of_node(bus); else bus->dev.of_node = of_node_get(bus->self->dev.of_node); } void pci_release_bus_of_node(struct pci_bus *bus) { of_node_put(bus->dev.of_node); bus->dev.of_node = NULL; } struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus) { /* This should only be called for PHBs */ if (WARN_ON(bus->self || bus->parent)) return NULL; /* Look for a node pointer in either the intermediary device we * create above the root bus or it's own parent. Normally only * the later is populated. */ if (bus->bridge->of_node) return of_node_get(bus->bridge->of_node); if (bus->bridge->parent && bus->bridge->parent->of_node) return of_node_get(bus->bridge->parent->of_node); return NULL; } struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus) { #ifdef CONFIG_IRQ_DOMAIN struct irq_domain *d; if (!bus->dev.of_node) return NULL; /* Start looking for a phandle to an MSI controller. */ d = of_msi_get_domain(&bus->dev, bus->dev.of_node, DOMAIN_BUS_PCI_MSI); if (d) return d; /* * If we don't have an msi-parent property, look for a domain * directly attached to the host bridge. */ d = irq_find_matching_host(bus->dev.of_node, DOMAIN_BUS_PCI_MSI); if (d) return d; return irq_find_host(bus->dev.of_node); #else return NULL; #endif } int pci_parse_request_of_pci_ranges(struct device *dev, struct list_head *resources, struct resource **bus_range) { int err, res_valid = 0; struct device_node *np = dev->of_node; resource_size_t iobase; struct resource_entry *win, *tmp; INIT_LIST_HEAD(resources); err = of_pci_get_host_bridge_resources(np, 0, 0xff, resources, &iobase); if (err) return err; err = devm_request_pci_bus_resources(dev, resources); if (err) goto out_release_res; resource_list_for_each_entry_safe(win, tmp, resources) { struct resource *res = win->res; switch (resource_type(res)) { case IORESOURCE_IO: err = pci_remap_iospace(res, iobase); if (err) { dev_warn(dev, "error %d: failed to map resource %pR\n", err, res); resource_list_destroy_entry(win); } break; case IORESOURCE_MEM: res_valid |= !(res->flags & IORESOURCE_PREFETCH); break; case IORESOURCE_BUS: if (bus_range) *bus_range = res; break; } } if (res_valid) return 0; dev_err(dev, "non-prefetchable memory resource required\n"); err = -EINVAL; out_release_res: pci_free_resource_list(resources); return err; }