summaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorAlexey Kardashevskiy <aik@ozlabs.ru>2016-04-29 04:55:24 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2016-05-11 07:54:31 -0400
commitb5cb9ab1a00b112fcb96164c814f1f111deeafba (patch)
tree22196f630c24217b3a5d23d8c999831a50157e5f /arch/powerpc
parent85674868cecebdf6eb7239ecf9c32b6273208d03 (diff)
powerpc/powernv/npu: Enable NVLink pass through
IBM POWER8 NVlink systems come with Tesla K40-ish GPUs each of which also has a couple of fast speed links (NVLink). The interface to links is exposed as an emulated PCI bridge which is included into the same IOMMU group as the corresponding GPU. In the kernel, NPUs get a separate PHB of the PNV_PHB_NPU type and a PE which behave pretty much as the standard IODA2 PHB except NPU PHB has just a single TVE in the hardware which means it can have either 32bit window or 64bit window or DMA bypass but never two of these. In order to make these links work when GPU is passed to the guest, these bridges need to be passed as well; otherwise performance will degrade. This implements and exports API to manage NPU state in regard to VFIO; it replicates iommu_table_group_ops. This defines a new pnv_pci_ioda2_npu_ops which is assigned to the IODA2 bridge if there are NPUs for a GPU on the bridge. The new callbacks call the default IODA2 callbacks plus new NPU API. This adds a gpe_table_group_to_npe() helper to find NPU PE for the IODA2 table_group, it is not expected to fail as the helper is only called from the pnv_pci_ioda2_npu_ops. This does not define NPU-specific .release_ownership() so after VFIO is finished, DMA on NPU is disabled which is ok as the nvidia driver sets DMA mask when probing which enable 32 or 64bit DMA on NPU. This adds a pnv_pci_npu_setup_iommu() helper which adds NPUs to the GPU group if any found. The helper uses helpers to look for the "ibm,gpu" property in the device tree which is a phandle of the corresponding GPU. This adds an additional loop over PEs in pnv_ioda_setup_dma() as the main loop skips NPU PEs as they do not have 32bit DMA segments. As pnv_npu_set_window() and pnv_npu_unset_window() are started being used by the new IODA2-NPU IOMMU group, this makes the helpers public and adds the DMA window number parameter. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Reviewed-By: Alistair Popple <alistair@popple.id.au> [mpe: Add pnv_pci_ioda_setup_iommu_api() to fix build with IOMMU_API=n] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/platforms/powernv/npu-dma.c64
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c112
-rw-r--r--arch/powerpc/platforms/powernv/pci.h6
3 files changed, 176 insertions, 6 deletions
diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c
index cb2d1dad38a8..0459e100b4e7 100644
--- a/arch/powerpc/platforms/powernv/npu-dma.c
+++ b/arch/powerpc/platforms/powernv/npu-dma.c
@@ -12,6 +12,7 @@
12#include <linux/export.h> 12#include <linux/export.h>
13#include <linux/pci.h> 13#include <linux/pci.h>
14#include <linux/memblock.h> 14#include <linux/memblock.h>
15#include <linux/iommu.h>
15 16
16#include <asm/iommu.h> 17#include <asm/iommu.h>
17#include <asm/pnv-pci.h> 18#include <asm/pnv-pci.h>
@@ -154,7 +155,7 @@ static struct pnv_ioda_pe *get_gpu_pci_dev_and_pe(struct pnv_ioda_pe *npe,
154 return pe; 155 return pe;
155} 156}
156 157
157static long pnv_npu_set_window(struct pnv_ioda_pe *npe, 158long pnv_npu_set_window(struct pnv_ioda_pe *npe, int num,
158 struct iommu_table *tbl) 159 struct iommu_table *tbl)
159{ 160{
160 struct pnv_phb *phb = npe->phb; 161 struct pnv_phb *phb = npe->phb;
@@ -182,13 +183,13 @@ static long pnv_npu_set_window(struct pnv_ioda_pe *npe,
182 pnv_pci_ioda2_tce_invalidate_entire(phb, false); 183 pnv_pci_ioda2_tce_invalidate_entire(phb, false);
183 184
184 /* Add the table to the list so its TCE cache will get invalidated */ 185 /* Add the table to the list so its TCE cache will get invalidated */
185 pnv_pci_link_table_and_group(phb->hose->node, 0, 186 pnv_pci_link_table_and_group(phb->hose->node, num,
186 tbl, &npe->table_group); 187 tbl, &npe->table_group);
187 188
188 return 0; 189 return 0;
189} 190}
190 191
191static long pnv_npu_unset_window(struct pnv_ioda_pe *npe) 192long pnv_npu_unset_window(struct pnv_ioda_pe *npe, int num)
192{ 193{
193 struct pnv_phb *phb = npe->phb; 194 struct pnv_phb *phb = npe->phb;
194 int64_t rc; 195 int64_t rc;
@@ -205,7 +206,7 @@ static long pnv_npu_unset_window(struct pnv_ioda_pe *npe)
205 } 206 }
206 pnv_pci_ioda2_tce_invalidate_entire(phb, false); 207 pnv_pci_ioda2_tce_invalidate_entire(phb, false);
207 208
208 pnv_pci_unlink_table_and_group(npe->table_group.tables[0], 209 pnv_pci_unlink_table_and_group(npe->table_group.tables[num],
209 &npe->table_group); 210 &npe->table_group);
210 211
211 return 0; 212 return 0;
@@ -231,7 +232,7 @@ static void pnv_npu_dma_set_32(struct pnv_ioda_pe *npe)
231 if (!gpe) 232 if (!gpe)
232 return; 233 return;
233 234
234 rc = pnv_npu_set_window(npe, gpe->table_group.tables[0]); 235 rc = pnv_npu_set_window(npe, 0, gpe->table_group.tables[0]);
235 236
236 /* 237 /*
237 * We don't initialise npu_pe->tce32_table as we always use 238 * We don't initialise npu_pe->tce32_table as we always use
@@ -255,7 +256,7 @@ static int pnv_npu_dma_set_bypass(struct pnv_ioda_pe *npe)
255 if (phb->type != PNV_PHB_NPU || !npe->pdev) 256 if (phb->type != PNV_PHB_NPU || !npe->pdev)
256 return -EINVAL; 257 return -EINVAL;
257 258
258 rc = pnv_npu_unset_window(npe); 259 rc = pnv_npu_unset_window(npe, 0);
259 if (rc != OPAL_SUCCESS) 260 if (rc != OPAL_SUCCESS)
260 return rc; 261 return rc;
261 262
@@ -307,3 +308,54 @@ void pnv_npu_try_dma_set_bypass(struct pci_dev *gpdev, bool bypass)
307 } 308 }
308 } 309 }
309} 310}
311
312/* Switch ownership from platform code to external user (e.g. VFIO) */
313void pnv_npu_take_ownership(struct pnv_ioda_pe *npe)
314{
315 struct pnv_phb *phb = npe->phb;
316 int64_t rc;
317
318 /*
319 * Note: NPU has just a single TVE in the hardware which means that
320 * while used by the kernel, it can have either 32bit window or
321 * DMA bypass but never both. So we deconfigure 32bit window only
322 * if it was enabled at the moment of ownership change.
323 */
324 if (npe->table_group.tables[0]) {
325 pnv_npu_unset_window(npe, 0);
326 return;
327 }
328
329 /* Disable bypass */
330 rc = opal_pci_map_pe_dma_window_real(phb->opal_id,
331 npe->pe_number, npe->pe_number,
332 0 /* bypass base */, 0);
333 if (rc) {
334 pe_err(npe, "Failed to disable bypass, err %lld\n", rc);
335 return;
336 }
337 pnv_pci_ioda2_tce_invalidate_entire(npe->phb, false);
338}
339
340struct pnv_ioda_pe *pnv_pci_npu_setup_iommu(struct pnv_ioda_pe *npe)
341{
342 struct pnv_phb *phb = npe->phb;
343 struct pci_bus *pbus = phb->hose->bus;
344 struct pci_dev *npdev, *gpdev = NULL, *gptmp;
345 struct pnv_ioda_pe *gpe = get_gpu_pci_dev_and_pe(npe, &gpdev);
346
347 if (!gpe || !gpdev)
348 return NULL;
349
350 list_for_each_entry(npdev, &pbus->devices, bus_list) {
351 gptmp = pnv_pci_get_gpu_dev(npdev);
352
353 if (gptmp != gpdev)
354 continue;
355
356 pe_info(gpe, "Attached NPU %s\n", dev_name(&npdev->dev));
357 iommu_group_add_device(gpe->table_group.group, &npdev->dev);
358 }
359
360 return gpe;
361}
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index ef31218f4e83..4cfe704106da 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -2389,6 +2389,116 @@ static struct iommu_table_group_ops pnv_pci_ioda2_ops = {
2389 .take_ownership = pnv_ioda2_take_ownership, 2389 .take_ownership = pnv_ioda2_take_ownership,
2390 .release_ownership = pnv_ioda2_release_ownership, 2390 .release_ownership = pnv_ioda2_release_ownership,
2391}; 2391};
2392
2393static int gpe_table_group_to_npe_cb(struct device *dev, void *opaque)
2394{
2395 struct pci_controller *hose;
2396 struct pnv_phb *phb;
2397 struct pnv_ioda_pe **ptmppe = opaque;
2398 struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
2399 struct pci_dn *pdn = pci_get_pdn(pdev);
2400
2401 if (!pdn || pdn->pe_number == IODA_INVALID_PE)
2402 return 0;
2403
2404 hose = pci_bus_to_host(pdev->bus);
2405 phb = hose->private_data;
2406 if (phb->type != PNV_PHB_NPU)
2407 return 0;
2408
2409 *ptmppe = &phb->ioda.pe_array[pdn->pe_number];
2410
2411 return 1;
2412}
2413
2414/*
2415 * This returns PE of associated NPU.
2416 * This assumes that NPU is in the same IOMMU group with GPU and there is
2417 * no other PEs.
2418 */
2419static struct pnv_ioda_pe *gpe_table_group_to_npe(
2420 struct iommu_table_group *table_group)
2421{
2422 struct pnv_ioda_pe *npe = NULL;
2423 int ret = iommu_group_for_each_dev(table_group->group, &npe,
2424 gpe_table_group_to_npe_cb);
2425
2426 BUG_ON(!ret || !npe);
2427
2428 return npe;
2429}
2430
2431static long pnv_pci_ioda2_npu_set_window(struct iommu_table_group *table_group,
2432 int num, struct iommu_table *tbl)
2433{
2434 long ret = pnv_pci_ioda2_set_window(table_group, num, tbl);
2435
2436 if (ret)
2437 return ret;
2438
2439 ret = pnv_npu_set_window(gpe_table_group_to_npe(table_group), num, tbl);
2440 if (ret)
2441 pnv_pci_ioda2_unset_window(table_group, num);
2442
2443 return ret;
2444}
2445
2446static long pnv_pci_ioda2_npu_unset_window(
2447 struct iommu_table_group *table_group,
2448 int num)
2449{
2450 long ret = pnv_pci_ioda2_unset_window(table_group, num);
2451
2452 if (ret)
2453 return ret;
2454
2455 return pnv_npu_unset_window(gpe_table_group_to_npe(table_group), num);
2456}
2457
2458static void pnv_ioda2_npu_take_ownership(struct iommu_table_group *table_group)
2459{
2460 /*
2461 * Detach NPU first as pnv_ioda2_take_ownership() will destroy
2462 * the iommu_table if 32bit DMA is enabled.
2463 */
2464 pnv_npu_take_ownership(gpe_table_group_to_npe(table_group));
2465 pnv_ioda2_take_ownership(table_group);
2466}
2467
2468static struct iommu_table_group_ops pnv_pci_ioda2_npu_ops = {
2469 .get_table_size = pnv_pci_ioda2_get_table_size,
2470 .create_table = pnv_pci_ioda2_create_table,
2471 .set_window = pnv_pci_ioda2_npu_set_window,
2472 .unset_window = pnv_pci_ioda2_npu_unset_window,
2473 .take_ownership = pnv_ioda2_npu_take_ownership,
2474 .release_ownership = pnv_ioda2_release_ownership,
2475};
2476
2477static void pnv_pci_ioda_setup_iommu_api(void)
2478{
2479 struct pci_controller *hose, *tmp;
2480 struct pnv_phb *phb;
2481 struct pnv_ioda_pe *pe, *gpe;
2482
2483 /*
2484 * Now we have all PHBs discovered, time to add NPU devices to
2485 * the corresponding IOMMU groups.
2486 */
2487 list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
2488 phb = hose->private_data;
2489
2490 if (phb->type != PNV_PHB_NPU)
2491 continue;
2492
2493 list_for_each_entry(pe, &phb->ioda.pe_list, list) {
2494 gpe = pnv_pci_npu_setup_iommu(pe);
2495 if (gpe)
2496 gpe->table_group.ops = &pnv_pci_ioda2_npu_ops;
2497 }
2498 }
2499}
2500#else /* !CONFIG_IOMMU_API */
2501static void pnv_pci_ioda_setup_iommu_api(void) { };
2392#endif 2502#endif
2393 2503
2394static void pnv_pci_ioda_setup_opal_tce_kill(struct pnv_phb *phb) 2504static void pnv_pci_ioda_setup_opal_tce_kill(struct pnv_phb *phb)
@@ -3115,6 +3225,8 @@ static void pnv_pci_ioda_setup_DMA(void)
3115 phb = hose->private_data; 3225 phb = hose->private_data;
3116 phb->initialized = 1; 3226 phb->initialized = 1;
3117 } 3227 }
3228
3229 pnv_pci_ioda_setup_iommu_api();
3118} 3230}
3119 3231
3120static void pnv_pci_ioda_create_dbgfs(void) 3232static void pnv_pci_ioda_create_dbgfs(void)
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index 2b35606a0a56..7dee25e304db 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -225,5 +225,11 @@ extern void pe_level_printk(const struct pnv_ioda_pe *pe, const char *level,
225/* Nvlink functions */ 225/* Nvlink functions */
226extern void pnv_npu_try_dma_set_bypass(struct pci_dev *gpdev, bool bypass); 226extern void pnv_npu_try_dma_set_bypass(struct pci_dev *gpdev, bool bypass);
227extern void pnv_pci_ioda2_tce_invalidate_entire(struct pnv_phb *phb, bool rm); 227extern void pnv_pci_ioda2_tce_invalidate_entire(struct pnv_phb *phb, bool rm);
228extern struct pnv_ioda_pe *pnv_pci_npu_setup_iommu(struct pnv_ioda_pe *npe);
229extern long pnv_npu_set_window(struct pnv_ioda_pe *npe, int num,
230 struct iommu_table *tbl);
231extern long pnv_npu_unset_window(struct pnv_ioda_pe *npe, int num);
232extern void pnv_npu_take_ownership(struct pnv_ioda_pe *npe);
233extern void pnv_npu_release_ownership(struct pnv_ioda_pe *npe);
228 234
229#endif /* __POWERNV_PCI_H */ 235#endif /* __POWERNV_PCI_H */