aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorGavin Shan <shangw@linux.vnet.ibm.com>2013-04-25 15:21:00 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-04-26 02:09:59 -0400
commit4cce95508bfeaa1cab74b08558993c81436dcbe0 (patch)
treee7c8e24087a508c7288954a8d4da2d65f9f62d19 /arch/powerpc
parent137436c9a6ee385c883db09e41af763888ee7642 (diff)
powerpc/powernv: TCE invalidation for PHB3
The TCE should be invalidated while it's created or free'd. The approach to do that for IODA1 and IODA2 compliant PHBs are different. So the patch differentiate them with different functions called to do that for IODA1 and IODA2 compliant PHBs. It's notable that the PCI address is used to invalidate the corresponding TCE on IODA2 compliant PHB3. Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-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 */