aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/pci-bridge.h3
-rw-r--r--arch/powerpc/kernel/pci_dn.c116
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c16
3 files changed, 135 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 2c6dc2a3d14a..ece30f589398 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -156,6 +156,7 @@ struct iommu_table;
156 156
157struct pci_dn { 157struct pci_dn {
158 int flags; 158 int flags;
159#define PCI_DN_FLAG_IOV_VF 0x01
159 160
160 int busno; /* pci bus number */ 161 int busno; /* pci bus number */
161 int devfn; /* pci device and function number */ 162 int devfn; /* pci device and function number */
@@ -188,6 +189,8 @@ struct pci_dn {
188extern struct pci_dn *pci_get_pdn_by_devfn(struct pci_bus *bus, 189extern struct pci_dn *pci_get_pdn_by_devfn(struct pci_bus *bus,
189 int devfn); 190 int devfn);
190extern struct pci_dn *pci_get_pdn(struct pci_dev *pdev); 191extern struct pci_dn *pci_get_pdn(struct pci_dev *pdev);
192extern struct pci_dn *add_dev_pci_data(struct pci_dev *pdev);
193extern void remove_dev_pci_data(struct pci_dev *pdev);
191extern void *update_dn_pci_info(struct device_node *dn, void *data); 194extern void *update_dn_pci_info(struct device_node *dn, void *data);
192 195
193static inline int pci_device_from_OF_node(struct device_node *np, 196static inline int pci_device_from_OF_node(struct device_node *np,
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.
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 26fe09936935..7f58f199f2c1 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -974,6 +974,22 @@ static void pnv_pci_ioda_setup_PEs(void)
974 } 974 }
975} 975}
976 976
977#ifdef CONFIG_PCI_IOV
978int pcibios_sriov_disable(struct pci_dev *pdev)
979{
980 /* Release PCI data */
981 remove_dev_pci_data(pdev);
982 return 0;
983}
984
985int pcibios_sriov_enable(struct pci_dev *pdev, u16 num_vfs)
986{
987 /* Allocate PCI data */
988 add_dev_pci_data(pdev);
989 return 0;
990}
991#endif /* CONFIG_PCI_IOV */
992
977static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev) 993static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev)
978{ 994{
979 struct pci_dn *pdn = pci_get_pdn(pdev); 995 struct pci_dn *pdn = pci_get_pdn(pdev);