aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2015-03-25 04:23:52 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2015-03-30 22:02:37 -0400
commita8b2f8288a3fdef8d93efef2b1ead7563004275e (patch)
tree40f3d68896c56cb4e67b48d006f367eb28cf1b34 /arch/powerpc/kernel
parentd74b9027a4dafa44d3a3c2a44ce135e50a13ec10 (diff)
powerpc/pci: Create pci_dn for VFs
pci_dn is the extension of PCI device node and is created from device node. Unfortunately, VFs are enabled dynamically by PF's driver and they don't have corresponding device nodes and pci_dn, which is required to access VFs' config spaces. The patch creates pci_dn for VFs in pcibios_sriov_enable() on their PF, and removes pci_dn for VFs in pcibios_sriov_disable() on their PF. When VF's pci_dn is created, it's put to the child list of the pci_dn of PF's upstream bridge. The pci_dn is linked to pci_dev during early fixup time to setup the fast path. [bhelgaas: add ifdef around add_one_dev_pci_info(), use dev_printk()] Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/pci_dn.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
index 65b98367005c..e5f1d78ef7cf 100644
--- a/arch/powerpc/kernel/pci_dn.c
+++ b/arch/powerpc/kernel/pci_dn.c
@@ -136,6 +136,122 @@ struct pci_dn *pci_get_pdn(struct pci_dev *pdev)
136 return NULL; 136 return NULL;
137} 137}
138 138
139#ifdef CONFIG_PCI_IOV
140static struct pci_dn *add_one_dev_pci_data(struct pci_dn *parent,
141 struct pci_dev *pdev,
142 int busno, int devfn)
143{
144 struct pci_dn *pdn;
145
146 /* Except PHB, we always have the parent */
147 if (!parent)
148 return NULL;
149
150 pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
151 if (!pdn) {
152 dev_warn(&pdev->dev, "%s: Out of memory!\n", __func__);
153 return NULL;
154 }
155
156 pdn->phb = parent->phb;
157 pdn->parent = parent;
158 pdn->busno = busno;
159 pdn->devfn = devfn;
160#ifdef CONFIG_PPC_POWERNV
161 pdn->pe_number = IODA_INVALID_PE;
162#endif
163 INIT_LIST_HEAD(&pdn->child_list);
164 INIT_LIST_HEAD(&pdn->list);
165 list_add_tail(&pdn->list, &parent->child_list);
166
167 /*
168 * If we already have PCI device instance, lets
169 * bind them.
170 */
171 if (pdev)
172 pdev->dev.archdata.pci_data = pdn;
173
174 return pdn;
175}
176#endif
177
178struct pci_dn *add_dev_pci_data(struct pci_dev *pdev)
179{
180#ifdef CONFIG_PCI_IOV
181 struct pci_dn *parent, *pdn;
182 int i;
183
184 /* Only support IOV for now */
185 if (!pdev->is_physfn)
186 return pci_get_pdn(pdev);
187
188 /* Check if VFs have been populated */
189 pdn = pci_get_pdn(pdev);
190 if (!pdn || (pdn->flags & PCI_DN_FLAG_IOV_VF))
191 return NULL;
192
193 pdn->flags |= PCI_DN_FLAG_IOV_VF;
194 parent = pci_bus_to_pdn(pdev->bus);
195 if (!parent)
196 return NULL;
197
198 for (i = 0; i < pci_sriov_get_totalvfs(pdev); i++) {
199 pdn = add_one_dev_pci_data(parent, NULL,
200 pci_iov_virtfn_bus(pdev, i),
201 pci_iov_virtfn_devfn(pdev, i));
202 if (!pdn) {
203 dev_warn(&pdev->dev, "%s: Cannot create firmware data for VF#%d\n",
204 __func__, i);
205 return NULL;
206 }
207 }
208#endif /* CONFIG_PCI_IOV */
209
210 return pci_get_pdn(pdev);
211}
212
213void remove_dev_pci_data(struct pci_dev *pdev)
214{
215#ifdef CONFIG_PCI_IOV
216 struct pci_dn *parent;
217 struct pci_dn *pdn, *tmp;
218 int i;
219
220 /* Only support IOV PF for now */
221 if (!pdev->is_physfn)
222 return;
223
224 /* Check if VFs have been populated */
225 pdn = pci_get_pdn(pdev);
226 if (!pdn || !(pdn->flags & PCI_DN_FLAG_IOV_VF))
227 return;
228
229 pdn->flags &= ~PCI_DN_FLAG_IOV_VF;
230 parent = pci_bus_to_pdn(pdev->bus);
231 if (!parent)
232 return;
233
234 /*
235 * We might introduce flag to pci_dn in future
236 * so that we can release VF's firmware data in
237 * a batch mode.
238 */
239 for (i = 0; i < pci_sriov_get_totalvfs(pdev); i++) {
240 list_for_each_entry_safe(pdn, tmp,
241 &parent->child_list, list) {
242 if (pdn->busno != pci_iov_virtfn_bus(pdev, i) ||
243 pdn->devfn != pci_iov_virtfn_devfn(pdev, i))
244 continue;
245
246 if (!list_empty(&pdn->list))
247 list_del(&pdn->list);
248
249 kfree(pdn);
250 }
251 }
252#endif /* CONFIG_PCI_IOV */
253}
254
139/* 255/*
140 * Traverse_func that inits the PCI fields of the device node. 256 * Traverse_func that inits the PCI fields of the device node.
141 * NOTE: this *must* be done before read/write config to the device. 257 * NOTE: this *must* be done before read/write config to the device.