aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2015-03-17 01:15:02 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2015-03-23 22:15:49 -0400
commitcca87d303c85b257a7b0fd34f9d6fce1c59880a2 (patch)
tree4145eab3e328314e60b9dcc3590616a93aa7bb90 /arch/powerpc
parent12a89dbac7914c58b0d207ef608e1c02534708bc (diff)
powerpc/pci: Refactor pci_dn
Currently, the PCI config accessors are implemented based on device node. Unfortunately, SRIOV VFs won't have the corresponding device nodes. pci_dn will be used in replacement with device node for SRIOV VFs. So we have to use pci_dn in PCI config accessors. The patch refactors pci_dn in following aspects to make it ready to be used in PCI config accessors as we do in subsequent patch: * pci_dn is organized as a hierarchy tree. PCI device's pci_dn is put to the child list of pci_dn of its upstream bridge or PHB. VF's pci_dn will be put to the child list of pci_dn of PF's bridge. * For one particular PCI device (VF or not), its pci_dn can be found from pdev->dev.archdata.pci_data, PCI_DN(devnode), or parent's list. The fast path (fetching pci_dn through PCI device instance) is populated during early fixup time. [bhelgaas: changelog] Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/device.h6
-rw-r--r--arch/powerpc/include/asm/pci-bridge.h11
-rw-r--r--arch/powerpc/kernel/pci_dn.c130
3 files changed, 141 insertions, 6 deletions
diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h
index 38faeded7d59..9f1371bab5fc 100644
--- a/arch/powerpc/include/asm/device.h
+++ b/arch/powerpc/include/asm/device.h
@@ -8,6 +8,9 @@
8 8
9struct dma_map_ops; 9struct dma_map_ops;
10struct device_node; 10struct device_node;
11#ifdef CONFIG_PPC64
12struct pci_dn;
13#endif
11 14
12/* 15/*
13 * Arch extensions to struct device. 16 * Arch extensions to struct device.
@@ -34,6 +37,9 @@ struct dev_archdata {
34#ifdef CONFIG_SWIOTLB 37#ifdef CONFIG_SWIOTLB
35 dma_addr_t max_direct_dma_addr; 38 dma_addr_t max_direct_dma_addr;
36#endif 39#endif
40#ifdef CONFIG_PPC64
41 struct pci_dn *pci_data;
42#endif
37#ifdef CONFIG_EEH 43#ifdef CONFIG_EEH
38 struct eeh_dev *edev; 44 struct eeh_dev *edev;
39#endif 45#endif
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 546d036fe925..706710b571c3 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -89,6 +89,7 @@ struct pci_controller {
89 89
90#ifdef CONFIG_PPC64 90#ifdef CONFIG_PPC64
91 unsigned long buid; 91 unsigned long buid;
92 struct pci_dn *pci_data;
92#endif /* CONFIG_PPC64 */ 93#endif /* CONFIG_PPC64 */
93 94
94 void *private_data; 95 void *private_data;
@@ -154,9 +155,12 @@ static inline int isa_vaddr_is_ioport(void __iomem *address)
154struct iommu_table; 155struct iommu_table;
155 156
156struct pci_dn { 157struct pci_dn {
158 int flags;
159
157 int busno; /* pci bus number */ 160 int busno; /* pci bus number */
158 int devfn; /* pci device and function number */ 161 int devfn; /* pci device and function number */
159 162
163 struct pci_dn *parent;
160 struct pci_controller *phb; /* for pci devices */ 164 struct pci_controller *phb; /* for pci devices */
161 struct iommu_table *iommu_table; /* for phb's or bridges */ 165 struct iommu_table *iommu_table; /* for phb's or bridges */
162 struct device_node *node; /* back-pointer to the device_node */ 166 struct device_node *node; /* back-pointer to the device_node */
@@ -171,14 +175,17 @@ struct pci_dn {
171#ifdef CONFIG_PPC_POWERNV 175#ifdef CONFIG_PPC_POWERNV
172 int pe_number; 176 int pe_number;
173#endif 177#endif
178 struct list_head child_list;
179 struct list_head list;
174}; 180};
175 181
176/* Get the pointer to a device_node's pci_dn */ 182/* Get the pointer to a device_node's pci_dn */
177#define PCI_DN(dn) ((struct pci_dn *) (dn)->data) 183#define PCI_DN(dn) ((struct pci_dn *) (dn)->data)
178 184
185extern struct pci_dn *pci_get_pdn_by_devfn(struct pci_bus *bus,
186 int devfn);
179extern struct pci_dn *pci_get_pdn(struct pci_dev *pdev); 187extern struct pci_dn *pci_get_pdn(struct pci_dev *pdev);
180 188extern void *update_dn_pci_info(struct device_node *dn, void *data);
181extern void * update_dn_pci_info(struct device_node *dn, void *data);
182 189
183static inline int pci_device_from_OF_node(struct device_node *np, 190static inline int pci_device_from_OF_node(struct device_node *np,
184 u8 *bus, u8 *devfn) 191 u8 *bus, u8 *devfn)
diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
index 83df3075d3df..0ab2dadaf842 100644
--- a/arch/powerpc/kernel/pci_dn.c
+++ b/arch/powerpc/kernel/pci_dn.c
@@ -32,12 +32,108 @@
32#include <asm/ppc-pci.h> 32#include <asm/ppc-pci.h>
33#include <asm/firmware.h> 33#include <asm/firmware.h>
34 34
35/*
36 * The function is used to find the firmware data of one
37 * specific PCI device, which is attached to the indicated
38 * PCI bus. For VFs, their firmware data is linked to that
39 * one of PF's bridge. For other devices, their firmware
40 * data is linked to that of their bridge.
41 */
42static struct pci_dn *pci_bus_to_pdn(struct pci_bus *bus)
43{
44 struct pci_bus *pbus;
45 struct device_node *dn;
46 struct pci_dn *pdn;
47
48 /*
49 * We probably have virtual bus which doesn't
50 * have associated bridge.
51 */
52 pbus = bus;
53 while (pbus) {
54 if (pci_is_root_bus(pbus) || pbus->self)
55 break;
56
57 pbus = pbus->parent;
58 }
59
60 /*
61 * Except virtual bus, all PCI buses should
62 * have device nodes.
63 */
64 dn = pci_bus_to_OF_node(pbus);
65 pdn = dn ? PCI_DN(dn) : NULL;
66
67 return pdn;
68}
69
70struct pci_dn *pci_get_pdn_by_devfn(struct pci_bus *bus,
71 int devfn)
72{
73 struct device_node *dn = NULL;
74 struct pci_dn *parent, *pdn;
75 struct pci_dev *pdev = NULL;
76
77 /* Fast path: fetch from PCI device */
78 list_for_each_entry(pdev, &bus->devices, bus_list) {
79 if (pdev->devfn == devfn) {
80 if (pdev->dev.archdata.pci_data)
81 return pdev->dev.archdata.pci_data;
82
83 dn = pci_device_to_OF_node(pdev);
84 break;
85 }
86 }
87
88 /* Fast path: fetch from device node */
89 pdn = dn ? PCI_DN(dn) : NULL;
90 if (pdn)
91 return pdn;
92
93 /* Slow path: fetch from firmware data hierarchy */
94 parent = pci_bus_to_pdn(bus);
95 if (!parent)
96 return NULL;
97
98 list_for_each_entry(pdn, &parent->child_list, list) {
99 if (pdn->busno == bus->number &&
100 pdn->devfn == devfn)
101 return pdn;
102 }
103
104 return NULL;
105}
106
35struct pci_dn *pci_get_pdn(struct pci_dev *pdev) 107struct pci_dn *pci_get_pdn(struct pci_dev *pdev)
36{ 108{
37 struct device_node *dn = pci_device_to_OF_node(pdev); 109 struct device_node *dn;
38 if (!dn) 110 struct pci_dn *parent, *pdn;
111
112 /* Search device directly */
113 if (pdev->dev.archdata.pci_data)
114 return pdev->dev.archdata.pci_data;
115
116 /* Check device node */
117 dn = pci_device_to_OF_node(pdev);
118 pdn = dn ? PCI_DN(dn) : NULL;
119 if (pdn)
120 return pdn;
121
122 /*
123 * VFs don't have device nodes. We hook their
124 * firmware data to PF's bridge.
125 */
126 parent = pci_bus_to_pdn(pdev->bus);
127 if (!parent)
39 return NULL; 128 return NULL;
40 return PCI_DN(dn); 129
130 list_for_each_entry(pdn, &parent->child_list, list) {
131 if (pdn->busno == pdev->bus->number &&
132 pdn->devfn == pdev->devfn)
133 return pdn;
134 }
135
136 return NULL;
41} 137}
42 138
43/* 139/*
@@ -49,6 +145,7 @@ void *update_dn_pci_info(struct device_node *dn, void *data)
49 struct pci_controller *phb = data; 145 struct pci_controller *phb = data;
50 const __be32 *type = of_get_property(dn, "ibm,pci-config-space-type", NULL); 146 const __be32 *type = of_get_property(dn, "ibm,pci-config-space-type", NULL);
51 const __be32 *regs; 147 const __be32 *regs;
148 struct device_node *parent;
52 struct pci_dn *pdn; 149 struct pci_dn *pdn;
53 150
54 pdn = zalloc_maybe_bootmem(sizeof(*pdn), GFP_KERNEL); 151 pdn = zalloc_maybe_bootmem(sizeof(*pdn), GFP_KERNEL);
@@ -70,6 +167,15 @@ void *update_dn_pci_info(struct device_node *dn, void *data)
70 } 167 }
71 168
72 pdn->pci_ext_config_space = (type && of_read_number(type, 1) == 1); 169 pdn->pci_ext_config_space = (type && of_read_number(type, 1) == 1);
170
171 /* Attach to parent node */
172 INIT_LIST_HEAD(&pdn->child_list);
173 INIT_LIST_HEAD(&pdn->list);
174 parent = of_get_parent(dn);
175 pdn->parent = parent ? PCI_DN(parent) : NULL;
176 if (pdn->parent)
177 list_add_tail(&pdn->list, &pdn->parent->child_list);
178
73 return NULL; 179 return NULL;
74} 180}
75 181
@@ -147,8 +253,11 @@ void pci_devs_phb_init_dynamic(struct pci_controller *phb)
147 /* PHB nodes themselves must not match */ 253 /* PHB nodes themselves must not match */
148 update_dn_pci_info(dn, phb); 254 update_dn_pci_info(dn, phb);
149 pdn = dn->data; 255 pdn = dn->data;
150 if (pdn) 256 if (pdn) {
151 pdn->devfn = pdn->busno = -1; 257 pdn->devfn = pdn->busno = -1;
258 pdn->phb = phb;
259 phb->pci_data = pdn;
260 }
152 261
153 /* Update dn->phb ptrs for new phb and children devices */ 262 /* Update dn->phb ptrs for new phb and children devices */
154 traverse_pci_devices(dn, update_dn_pci_info, phb); 263 traverse_pci_devices(dn, update_dn_pci_info, phb);
@@ -171,3 +280,16 @@ void __init pci_devs_phb_init(void)
171 list_for_each_entry_safe(phb, tmp, &hose_list, list_node) 280 list_for_each_entry_safe(phb, tmp, &hose_list, list_node)
172 pci_devs_phb_init_dynamic(phb); 281 pci_devs_phb_init_dynamic(phb);
173} 282}
283
284static void pci_dev_pdn_setup(struct pci_dev *pdev)
285{
286 struct pci_dn *pdn;
287
288 if (pdev->dev.archdata.pci_data)
289 return;
290
291 /* Setup the fast path */
292 pdn = pci_get_pdn(pdev);
293 pdev->dev.archdata.pci_data = pdn;
294}
295DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, pci_dev_pdn_setup);