diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/platforms/powernv/pci-ioda.c | 85 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci.c | 48 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci.h | 6 |
3 files changed, 90 insertions, 49 deletions
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 3f88c51cb95b..1c7e808a1302 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c | |||
@@ -89,6 +89,7 @@ static int pnv_ioda_alloc_pe(struct pnv_phb *phb) | |||
89 | return IODA_INVALID_PE; | 89 | return IODA_INVALID_PE; |
90 | } while(test_and_set_bit(pe, phb->ioda.pe_alloc)); | 90 | } while(test_and_set_bit(pe, phb->ioda.pe_alloc)); |
91 | 91 | ||
92 | phb->ioda.pe_array[pe].phb = phb; | ||
92 | phb->ioda.pe_array[pe].pe_number = pe; | 93 | phb->ioda.pe_array[pe].pe_number = pe; |
93 | return pe; | 94 | return pe; |
94 | } | 95 | } |
@@ -449,6 +450,85 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus) | |||
449 | } | 450 | } |
450 | } | 451 | } |
451 | 452 | ||
453 | static void pnv_pci_ioda1_tce_invalidate(struct iommu_table *tbl, | ||
454 | u64 *startp, u64 *endp) | ||
455 | { | ||
456 | u64 __iomem *invalidate = (u64 __iomem *)tbl->it_index; | ||
457 | unsigned long start, end, inc; | ||
458 | |||
459 | start = __pa(startp); | ||
460 | end = __pa(endp); | ||
461 | |||
462 | /* BML uses this case for p6/p7/galaxy2: Shift addr and put in node */ | ||
463 | if (tbl->it_busno) { | ||
464 | start <<= 12; | ||
465 | end <<= 12; | ||
466 | inc = 128 << 12; | ||
467 | start |= tbl->it_busno; | ||
468 | end |= tbl->it_busno; | ||
469 | } else if (tbl->it_type & TCE_PCI_SWINV_PAIR) { | ||
470 | /* p7ioc-style invalidation, 2 TCEs per write */ | ||
471 | start |= (1ull << 63); | ||
472 | end |= (1ull << 63); | ||
473 | inc = 16; | ||
474 | } else { | ||
475 | /* Default (older HW) */ | ||
476 | inc = 128; | ||
477 | } | ||
478 | |||
479 | end |= inc - 1; /* round up end to be different than start */ | ||
480 | |||
481 | mb(); /* Ensure above stores are visible */ | ||
482 | while (start <= end) { | ||
483 | __raw_writeq(start, invalidate); | ||
484 | start += inc; | ||
485 | } | ||
486 | |||
487 | /* | ||
488 | * The iommu layer will do another mb() for us on build() | ||
489 | * and we don't care on free() | ||
490 | */ | ||
491 | } | ||
492 | |||
493 | static void pnv_pci_ioda2_tce_invalidate(struct pnv_ioda_pe *pe, | ||
494 | struct iommu_table *tbl, | ||
495 | u64 *startp, u64 *endp) | ||
496 | { | ||
497 | unsigned long start, end, inc; | ||
498 | u64 __iomem *invalidate = (u64 __iomem *)tbl->it_index; | ||
499 | |||
500 | /* We'll invalidate DMA address in PE scope */ | ||
501 | start = 0x2ul << 60; | ||
502 | start |= (pe->pe_number & 0xFF); | ||
503 | end = start; | ||
504 | |||
505 | /* Figure out the start, end and step */ | ||
506 | inc = tbl->it_offset + (((u64)startp - tbl->it_base) / sizeof(u64)); | ||
507 | start |= (inc << 12); | ||
508 | inc = tbl->it_offset + (((u64)endp - tbl->it_base) / sizeof(u64)); | ||
509 | end |= (inc << 12); | ||
510 | inc = (0x1ul << 12); | ||
511 | mb(); | ||
512 | |||
513 | while (start <= end) { | ||
514 | __raw_writeq(start, invalidate); | ||
515 | start += inc; | ||
516 | } | ||
517 | } | ||
518 | |||
519 | void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl, | ||
520 | u64 *startp, u64 *endp) | ||
521 | { | ||
522 | struct pnv_ioda_pe *pe = container_of(tbl, struct pnv_ioda_pe, | ||
523 | tce32_table); | ||
524 | struct pnv_phb *phb = pe->phb; | ||
525 | |||
526 | if (phb->type == PNV_PHB_IODA1) | ||
527 | pnv_pci_ioda1_tce_invalidate(tbl, startp, endp); | ||
528 | else | ||
529 | pnv_pci_ioda2_tce_invalidate(pe, tbl, startp, endp); | ||
530 | } | ||
531 | |||
452 | static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb, | 532 | static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb, |
453 | struct pnv_ioda_pe *pe, unsigned int base, | 533 | struct pnv_ioda_pe *pe, unsigned int base, |
454 | unsigned int segs) | 534 | unsigned int segs) |
@@ -520,8 +600,9 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb, | |||
520 | */ | 600 | */ |
521 | tbl->it_busno = 0; | 601 | tbl->it_busno = 0; |
522 | tbl->it_index = (unsigned long)ioremap(be64_to_cpup(swinvp), 8); | 602 | tbl->it_index = (unsigned long)ioremap(be64_to_cpup(swinvp), 8); |
523 | tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE | 603 | tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE; |
524 | | TCE_PCI_SWINV_PAIR; | 604 | if (phb->type == PNV_PHB_IODA1) |
605 | tbl->it_type |= TCE_PCI_SWINV_PAIR; | ||
525 | } | 606 | } |
526 | iommu_init_table(tbl, phb->hose->node); | 607 | iommu_init_table(tbl, phb->hose->node); |
527 | 608 | ||
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 861e185483fe..55dfca844ddf 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c | |||
@@ -329,48 +329,6 @@ struct pci_ops pnv_pci_ops = { | |||
329 | .write = pnv_pci_write_config, | 329 | .write = pnv_pci_write_config, |
330 | }; | 330 | }; |
331 | 331 | ||
332 | |||
333 | static void pnv_tce_invalidate(struct iommu_table *tbl, | ||
334 | u64 *startp, u64 *endp) | ||
335 | { | ||
336 | u64 __iomem *invalidate = (u64 __iomem *)tbl->it_index; | ||
337 | unsigned long start, end, inc; | ||
338 | |||
339 | start = __pa(startp); | ||
340 | end = __pa(endp); | ||
341 | |||
342 | |||
343 | /* BML uses this case for p6/p7/galaxy2: Shift addr and put in node */ | ||
344 | if (tbl->it_busno) { | ||
345 | start <<= 12; | ||
346 | end <<= 12; | ||
347 | inc = 128 << 12; | ||
348 | start |= tbl->it_busno; | ||
349 | end |= tbl->it_busno; | ||
350 | } | ||
351 | /* p7ioc-style invalidation, 2 TCEs per write */ | ||
352 | else if (tbl->it_type & TCE_PCI_SWINV_PAIR) { | ||
353 | start |= (1ull << 63); | ||
354 | end |= (1ull << 63); | ||
355 | inc = 16; | ||
356 | } | ||
357 | /* Default (older HW) */ | ||
358 | else | ||
359 | inc = 128; | ||
360 | |||
361 | end |= inc - 1; /* round up end to be different than start */ | ||
362 | |||
363 | mb(); /* Ensure above stores are visible */ | ||
364 | while (start <= end) { | ||
365 | __raw_writeq(start, invalidate); | ||
366 | start += inc; | ||
367 | } | ||
368 | /* The iommu layer will do another mb() for us on build() and | ||
369 | * we don't care on free() | ||
370 | */ | ||
371 | } | ||
372 | |||
373 | |||
374 | static int pnv_tce_build(struct iommu_table *tbl, long index, long npages, | 332 | static int pnv_tce_build(struct iommu_table *tbl, long index, long npages, |
375 | unsigned long uaddr, enum dma_data_direction direction, | 333 | unsigned long uaddr, enum dma_data_direction direction, |
376 | struct dma_attrs *attrs) | 334 | struct dma_attrs *attrs) |
@@ -395,7 +353,7 @@ static int pnv_tce_build(struct iommu_table *tbl, long index, long npages, | |||
395 | * of flags if that becomes the case | 353 | * of flags if that becomes the case |
396 | */ | 354 | */ |
397 | if (tbl->it_type & TCE_PCI_SWINV_CREATE) | 355 | if (tbl->it_type & TCE_PCI_SWINV_CREATE) |
398 | pnv_tce_invalidate(tbl, tces, tcep - 1); | 356 | pnv_pci_ioda_tce_invalidate(tbl, tces, tcep - 1); |
399 | 357 | ||
400 | return 0; | 358 | return 0; |
401 | } | 359 | } |
@@ -409,8 +367,8 @@ static void pnv_tce_free(struct iommu_table *tbl, long index, long npages) | |||
409 | while (npages--) | 367 | while (npages--) |
410 | *(tcep++) = 0; | 368 | *(tcep++) = 0; |
411 | 369 | ||
412 | if (tbl->it_type & TCE_PCI_SWINV_FREE) | 370 | if (tbl->it_type & TCE_PCI_SWINV_CREATE) |
413 | pnv_tce_invalidate(tbl, tces, tcep - 1); | 371 | pnv_pci_ioda_tce_invalidate(tbl, tces, tcep - 1); |
414 | } | 372 | } |
415 | 373 | ||
416 | static unsigned long pnv_tce_get(struct iommu_table *tbl, long index) | 374 | static unsigned long pnv_tce_get(struct iommu_table *tbl, long index) |
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 3c552b3dd0c6..48dc4bb856a1 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h | |||
@@ -23,8 +23,10 @@ enum pnv_phb_model { | |||
23 | #define PNV_IODA_PE_BUS_ALL (1 << 2) /* PE has subordinate buses */ | 23 | #define PNV_IODA_PE_BUS_ALL (1 << 2) /* PE has subordinate buses */ |
24 | 24 | ||
25 | /* Data associated with a PE, including IOMMU tracking etc.. */ | 25 | /* Data associated with a PE, including IOMMU tracking etc.. */ |
26 | struct pnv_phb; | ||
26 | struct pnv_ioda_pe { | 27 | struct pnv_ioda_pe { |
27 | unsigned long flags; | 28 | unsigned long flags; |
29 | struct pnv_phb *phb; | ||
28 | 30 | ||
29 | /* A PE can be associated with a single device or an | 31 | /* A PE can be associated with a single device or an |
30 | * entire bus (& children). In the former case, pdev | 32 | * entire bus (& children). In the former case, pdev |
@@ -154,6 +156,6 @@ extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl, | |||
154 | extern void pnv_pci_init_p5ioc2_hub(struct device_node *np); | 156 | extern void pnv_pci_init_p5ioc2_hub(struct device_node *np); |
155 | extern void pnv_pci_init_ioda_hub(struct device_node *np); | 157 | extern void pnv_pci_init_ioda_hub(struct device_node *np); |
156 | extern void pnv_pci_init_ioda2_phb(struct device_node *np); | 158 | extern void pnv_pci_init_ioda2_phb(struct device_node *np); |
157 | 159 | extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl, | |
158 | 160 | u64 *startp, u64 *endp); | |
159 | #endif /* __POWERNV_PCI_H */ | 161 | #endif /* __POWERNV_PCI_H */ |