aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/machdep.h12
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c49
-rw-r--r--arch/powerpc/platforms/powernv/pci.c42
-rw-r--r--arch/powerpc/platforms/powernv/pci.h3
4 files changed, 87 insertions, 19 deletions
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 8b480901165a..07dd3b1312e5 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -78,6 +78,18 @@ struct machdep_calls {
78 long index); 78 long index);
79 void (*tce_flush)(struct iommu_table *tbl); 79 void (*tce_flush)(struct iommu_table *tbl);
80 80
81 /* _rm versions are for real mode use only */
82 int (*tce_build_rm)(struct iommu_table *tbl,
83 long index,
84 long npages,
85 unsigned long uaddr,
86 enum dma_data_direction direction,
87 struct dma_attrs *attrs);
88 void (*tce_free_rm)(struct iommu_table *tbl,
89 long index,
90 long npages);
91 void (*tce_flush_rm)(struct iommu_table *tbl);
92
81 void __iomem * (*ioremap)(phys_addr_t addr, unsigned long size, 93 void __iomem * (*ioremap)(phys_addr_t addr, unsigned long size,
82 unsigned long flags, void *caller); 94 unsigned long flags, void *caller);
83 void (*iounmap)(volatile void __iomem *token); 95 void (*iounmap)(volatile void __iomem *token);
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 74a5a5773b1f..307015d9cd99 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -70,6 +70,16 @@ define_pe_printk_level(pe_err, KERN_ERR);
70define_pe_printk_level(pe_warn, KERN_WARNING); 70define_pe_printk_level(pe_warn, KERN_WARNING);
71define_pe_printk_level(pe_info, KERN_INFO); 71define_pe_printk_level(pe_info, KERN_INFO);
72 72
73/*
74 * stdcix is only supposed to be used in hypervisor real mode as per
75 * the architecture spec
76 */
77static inline void __raw_rm_writeq(u64 val, volatile void __iomem *paddr)
78{
79 __asm__ __volatile__("stdcix %0,0,%1"
80 : : "r" (val), "r" (paddr) : "memory");
81}
82
73static int pnv_ioda_alloc_pe(struct pnv_phb *phb) 83static int pnv_ioda_alloc_pe(struct pnv_phb *phb)
74{ 84{
75 unsigned long pe; 85 unsigned long pe;
@@ -454,10 +464,13 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus)
454 } 464 }
455} 465}
456 466
457static void pnv_pci_ioda1_tce_invalidate(struct iommu_table *tbl, 467static void pnv_pci_ioda1_tce_invalidate(struct pnv_ioda_pe *pe,
458 u64 *startp, u64 *endp) 468 struct iommu_table *tbl,
469 u64 *startp, u64 *endp, bool rm)
459{ 470{
460 u64 __iomem *invalidate = (u64 __iomem *)tbl->it_index; 471 u64 __iomem *invalidate = rm ?
472 (u64 __iomem *)pe->tce_inval_reg_phys :
473 (u64 __iomem *)tbl->it_index;
461 unsigned long start, end, inc; 474 unsigned long start, end, inc;
462 475
463 start = __pa(startp); 476 start = __pa(startp);
@@ -484,7 +497,10 @@ static void pnv_pci_ioda1_tce_invalidate(struct iommu_table *tbl,
484 497
485 mb(); /* Ensure above stores are visible */ 498 mb(); /* Ensure above stores are visible */
486 while (start <= end) { 499 while (start <= end) {
487 __raw_writeq(start, invalidate); 500 if (rm)
501 __raw_rm_writeq(start, invalidate);
502 else
503 __raw_writeq(start, invalidate);
488 start += inc; 504 start += inc;
489 } 505 }
490 506
@@ -496,10 +512,12 @@ static void pnv_pci_ioda1_tce_invalidate(struct iommu_table *tbl,
496 512
497static void pnv_pci_ioda2_tce_invalidate(struct pnv_ioda_pe *pe, 513static void pnv_pci_ioda2_tce_invalidate(struct pnv_ioda_pe *pe,
498 struct iommu_table *tbl, 514 struct iommu_table *tbl,
499 u64 *startp, u64 *endp) 515 u64 *startp, u64 *endp, bool rm)
500{ 516{
501 unsigned long start, end, inc; 517 unsigned long start, end, inc;
502 u64 __iomem *invalidate = (u64 __iomem *)tbl->it_index; 518 u64 __iomem *invalidate = rm ?
519 (u64 __iomem *)pe->tce_inval_reg_phys :
520 (u64 __iomem *)tbl->it_index;
503 521
504 /* We'll invalidate DMA address in PE scope */ 522 /* We'll invalidate DMA address in PE scope */
505 start = 0x2ul << 60; 523 start = 0x2ul << 60;
@@ -515,22 +533,25 @@ static void pnv_pci_ioda2_tce_invalidate(struct pnv_ioda_pe *pe,
515 mb(); 533 mb();
516 534
517 while (start <= end) { 535 while (start <= end) {
518 __raw_writeq(start, invalidate); 536 if (rm)
537 __raw_rm_writeq(start, invalidate);
538 else
539 __raw_writeq(start, invalidate);
519 start += inc; 540 start += inc;
520 } 541 }
521} 542}
522 543
523void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl, 544void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl,
524 u64 *startp, u64 *endp) 545 u64 *startp, u64 *endp, bool rm)
525{ 546{
526 struct pnv_ioda_pe *pe = container_of(tbl, struct pnv_ioda_pe, 547 struct pnv_ioda_pe *pe = container_of(tbl, struct pnv_ioda_pe,
527 tce32_table); 548 tce32_table);
528 struct pnv_phb *phb = pe->phb; 549 struct pnv_phb *phb = pe->phb;
529 550
530 if (phb->type == PNV_PHB_IODA1) 551 if (phb->type == PNV_PHB_IODA1)
531 pnv_pci_ioda1_tce_invalidate(tbl, startp, endp); 552 pnv_pci_ioda1_tce_invalidate(pe, tbl, startp, endp, rm);
532 else 553 else
533 pnv_pci_ioda2_tce_invalidate(pe, tbl, startp, endp); 554 pnv_pci_ioda2_tce_invalidate(pe, tbl, startp, endp, rm);
534} 555}
535 556
536static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb, 557static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
@@ -603,7 +624,9 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
603 * bus number, print that out instead. 624 * bus number, print that out instead.
604 */ 625 */
605 tbl->it_busno = 0; 626 tbl->it_busno = 0;
606 tbl->it_index = (unsigned long)ioremap(be64_to_cpup(swinvp), 8); 627 pe->tce_inval_reg_phys = be64_to_cpup(swinvp);
628 tbl->it_index = (unsigned long)ioremap(pe->tce_inval_reg_phys,
629 8);
607 tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE | 630 tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE |
608 TCE_PCI_SWINV_PAIR; 631 TCE_PCI_SWINV_PAIR;
609 } 632 }
@@ -681,7 +704,9 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
681 * bus number, print that out instead. 704 * bus number, print that out instead.
682 */ 705 */
683 tbl->it_busno = 0; 706 tbl->it_busno = 0;
684 tbl->it_index = (unsigned long)ioremap(be64_to_cpup(swinvp), 8); 707 pe->tce_inval_reg_phys = be64_to_cpup(swinvp);
708 tbl->it_index = (unsigned long)ioremap(pe->tce_inval_reg_phys,
709 8);
685 tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE; 710 tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE;
686 } 711 }
687 iommu_init_table(tbl, phb->hose->node); 712 iommu_init_table(tbl, phb->hose->node);
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index a28d3b5e6393..420abe3baab9 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -401,7 +401,7 @@ struct pci_ops pnv_pci_ops = {
401 401
402static int pnv_tce_build(struct iommu_table *tbl, long index, long npages, 402static int pnv_tce_build(struct iommu_table *tbl, long index, long npages,
403 unsigned long uaddr, enum dma_data_direction direction, 403 unsigned long uaddr, enum dma_data_direction direction,
404 struct dma_attrs *attrs) 404 struct dma_attrs *attrs, bool rm)
405{ 405{
406 u64 proto_tce; 406 u64 proto_tce;
407 u64 *tcep, *tces; 407 u64 *tcep, *tces;
@@ -423,12 +423,22 @@ static int pnv_tce_build(struct iommu_table *tbl, long index, long npages,
423 * of flags if that becomes the case 423 * of flags if that becomes the case
424 */ 424 */
425 if (tbl->it_type & TCE_PCI_SWINV_CREATE) 425 if (tbl->it_type & TCE_PCI_SWINV_CREATE)
426 pnv_pci_ioda_tce_invalidate(tbl, tces, tcep - 1); 426 pnv_pci_ioda_tce_invalidate(tbl, tces, tcep - 1, rm);
427 427
428 return 0; 428 return 0;
429} 429}
430 430
431static void pnv_tce_free(struct iommu_table *tbl, long index, long npages) 431static int pnv_tce_build_vm(struct iommu_table *tbl, long index, long npages,
432 unsigned long uaddr,
433 enum dma_data_direction direction,
434 struct dma_attrs *attrs)
435{
436 return pnv_tce_build(tbl, index, npages, uaddr, direction, attrs,
437 false);
438}
439
440static void pnv_tce_free(struct iommu_table *tbl, long index, long npages,
441 bool rm)
432{ 442{
433 u64 *tcep, *tces; 443 u64 *tcep, *tces;
434 444
@@ -438,7 +448,12 @@ static void pnv_tce_free(struct iommu_table *tbl, long index, long npages)
438 *(tcep++) = 0; 448 *(tcep++) = 0;
439 449
440 if (tbl->it_type & TCE_PCI_SWINV_FREE) 450 if (tbl->it_type & TCE_PCI_SWINV_FREE)
441 pnv_pci_ioda_tce_invalidate(tbl, tces, tcep - 1); 451 pnv_pci_ioda_tce_invalidate(tbl, tces, tcep - 1, rm);
452}
453
454static void pnv_tce_free_vm(struct iommu_table *tbl, long index, long npages)
455{
456 pnv_tce_free(tbl, index, npages, false);
442} 457}
443 458
444static unsigned long pnv_tce_get(struct iommu_table *tbl, long index) 459static unsigned long pnv_tce_get(struct iommu_table *tbl, long index)
@@ -446,6 +461,19 @@ static unsigned long pnv_tce_get(struct iommu_table *tbl, long index)
446 return ((u64 *)tbl->it_base)[index - tbl->it_offset]; 461 return ((u64 *)tbl->it_base)[index - tbl->it_offset];
447} 462}
448 463
464static int pnv_tce_build_rm(struct iommu_table *tbl, long index, long npages,
465 unsigned long uaddr,
466 enum dma_data_direction direction,
467 struct dma_attrs *attrs)
468{
469 return pnv_tce_build(tbl, index, npages, uaddr, direction, attrs, true);
470}
471
472static void pnv_tce_free_rm(struct iommu_table *tbl, long index, long npages)
473{
474 pnv_tce_free(tbl, index, npages, true);
475}
476
449void pnv_pci_setup_iommu_table(struct iommu_table *tbl, 477void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
450 void *tce_mem, u64 tce_size, 478 void *tce_mem, u64 tce_size,
451 u64 dma_offset) 479 u64 dma_offset)
@@ -610,8 +638,10 @@ void __init pnv_pci_init(void)
610 638
611 /* Configure IOMMU DMA hooks */ 639 /* Configure IOMMU DMA hooks */
612 ppc_md.pci_dma_dev_setup = pnv_pci_dma_dev_setup; 640 ppc_md.pci_dma_dev_setup = pnv_pci_dma_dev_setup;
613 ppc_md.tce_build = pnv_tce_build; 641 ppc_md.tce_build = pnv_tce_build_vm;
614 ppc_md.tce_free = pnv_tce_free; 642 ppc_md.tce_free = pnv_tce_free_vm;
643 ppc_md.tce_build_rm = pnv_tce_build_rm;
644 ppc_md.tce_free_rm = pnv_tce_free_rm;
615 ppc_md.tce_get = pnv_tce_get; 645 ppc_md.tce_get = pnv_tce_get;
616 ppc_md.pci_probe_mode = pnv_pci_probe_mode; 646 ppc_md.pci_probe_mode = pnv_pci_probe_mode;
617 set_pci_dma_ops(&dma_iommu_ops); 647 set_pci_dma_ops(&dma_iommu_ops);
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index d633c64e05a1..170dd98629d7 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -52,6 +52,7 @@ struct pnv_ioda_pe {
52 int tce32_seg; 52 int tce32_seg;
53 int tce32_segcount; 53 int tce32_segcount;
54 struct iommu_table tce32_table; 54 struct iommu_table tce32_table;
55 phys_addr_t tce_inval_reg_phys;
55 56
56 /* XXX TODO: Add support for additional 64-bit iommus */ 57 /* XXX TODO: Add support for additional 64-bit iommus */
57 58
@@ -193,6 +194,6 @@ extern void pnv_pci_init_p5ioc2_hub(struct device_node *np);
193extern void pnv_pci_init_ioda_hub(struct device_node *np); 194extern void pnv_pci_init_ioda_hub(struct device_node *np);
194extern void pnv_pci_init_ioda2_phb(struct device_node *np); 195extern void pnv_pci_init_ioda2_phb(struct device_node *np);
195extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl, 196extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl,
196 u64 *startp, u64 *endp); 197 u64 *startp, u64 *endp, bool rm);
197 198
198#endif /* __POWERNV_PCI_H */ 199#endif /* __POWERNV_PCI_H */