diff options
author | Gavin Shan <gwshan@linux.vnet.ibm.com> | 2015-03-17 01:15:02 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2015-03-23 22:15:49 -0400 |
commit | cca87d303c85b257a7b0fd34f9d6fce1c59880a2 (patch) | |
tree | 4145eab3e328314e60b9dcc3590616a93aa7bb90 /arch/powerpc | |
parent | 12a89dbac7914c58b0d207ef608e1c02534708bc (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.h | 6 | ||||
-rw-r--r-- | arch/powerpc/include/asm/pci-bridge.h | 11 | ||||
-rw-r--r-- | arch/powerpc/kernel/pci_dn.c | 130 |
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 | ||
9 | struct dma_map_ops; | 9 | struct dma_map_ops; |
10 | struct device_node; | 10 | struct device_node; |
11 | #ifdef CONFIG_PPC64 | ||
12 | struct 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) | |||
154 | struct iommu_table; | 155 | struct iommu_table; |
155 | 156 | ||
156 | struct pci_dn { | 157 | struct 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 | ||
185 | extern struct pci_dn *pci_get_pdn_by_devfn(struct pci_bus *bus, | ||
186 | int devfn); | ||
179 | extern struct pci_dn *pci_get_pdn(struct pci_dev *pdev); | 187 | extern struct pci_dn *pci_get_pdn(struct pci_dev *pdev); |
180 | 188 | extern void *update_dn_pci_info(struct device_node *dn, void *data); | |
181 | extern void * update_dn_pci_info(struct device_node *dn, void *data); | ||
182 | 189 | ||
183 | static inline int pci_device_from_OF_node(struct device_node *np, | 190 | static 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 | */ | ||
42 | static 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 | |||
70 | struct 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 | |||
35 | struct pci_dn *pci_get_pdn(struct pci_dev *pdev) | 107 | struct 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 | |||
284 | static 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 | } | ||
295 | DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, pci_dev_pdn_setup); | ||