aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c85
-rw-r--r--arch/powerpc/platforms/powernv/pci.c48
-rw-r--r--arch/powerpc/platforms/powernv/pci.h6
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
453static 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
493static 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
519void 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
452static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb, 532static 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
333static 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
374static int pnv_tce_build(struct iommu_table *tbl, long index, long npages, 332static 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
416static unsigned long pnv_tce_get(struct iommu_table *tbl, long index) 374static 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.. */
26struct pnv_phb;
26struct pnv_ioda_pe { 27struct 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,
154extern void pnv_pci_init_p5ioc2_hub(struct device_node *np); 156extern void pnv_pci_init_p5ioc2_hub(struct device_node *np);
155extern void pnv_pci_init_ioda_hub(struct device_node *np); 157extern void pnv_pci_init_ioda_hub(struct device_node *np);
156extern void pnv_pci_init_ioda2_phb(struct device_node *np); 158extern void pnv_pci_init_ioda2_phb(struct device_node *np);
157 159extern 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 */