1 /* 2 * PCI <-> OF mapping helpers 3 * 4 * Copyright 2011 IBM Corp. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12 #include <linux/irqdomain.h> 13 #include <linux/kernel.h> 14 #include <linux/pci.h> 15 #include <linux/of.h> 16 #include <linux/of_pci.h> 17 #include "pci.h" 18 19 void pci_set_of_node(struct pci_dev *dev) 20 { 21 if (!dev->bus->dev.of_node) 22 return; 23 dev->dev.of_node = of_pci_find_child_device(dev->bus->dev.of_node, 24 dev->devfn); 25 } 26 27 void pci_release_of_node(struct pci_dev *dev) 28 { 29 of_node_put(dev->dev.of_node); 30 dev->dev.of_node = NULL; 31 } 32 33 void pci_set_bus_of_node(struct pci_bus *bus) 34 { 35 if (bus->self == NULL) 36 bus->dev.of_node = pcibios_get_phb_of_node(bus); 37 else 38 bus->dev.of_node = of_node_get(bus->self->dev.of_node); 39 } 40 41 void pci_release_bus_of_node(struct pci_bus *bus) 42 { 43 of_node_put(bus->dev.of_node); 44 bus->dev.of_node = NULL; 45 } 46 47 struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus) 48 { 49 /* This should only be called for PHBs */ 50 if (WARN_ON(bus->self || bus->parent)) 51 return NULL; 52 53 /* Look for a node pointer in either the intermediary device we 54 * create above the root bus or it's own parent. Normally only 55 * the later is populated. 56 */ 57 if (bus->bridge->of_node) 58 return of_node_get(bus->bridge->of_node); 59 if (bus->bridge->parent && bus->bridge->parent->of_node) 60 return of_node_get(bus->bridge->parent->of_node); 61 return NULL; 62 } 63 64 struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus) 65 { 66 #ifdef CONFIG_IRQ_DOMAIN 67 struct device_node *np; 68 struct irq_domain *d; 69 70 if (!bus->dev.of_node) 71 return NULL; 72 73 /* Start looking for a phandle to an MSI controller. */ 74 np = of_parse_phandle(bus->dev.of_node, "msi-parent", 0); 75 76 /* 77 * If we don't have an msi-parent property, look for a domain 78 * directly attached to the host bridge. 79 */ 80 if (!np) 81 np = bus->dev.of_node; 82 83 d = irq_find_matching_host(np, DOMAIN_BUS_PCI_MSI); 84 if (d) 85 return d; 86 87 return irq_find_host(np); 88 #else 89 return NULL; 90 #endif 91 } 92