aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Kardashevskiy <aik@ozlabs.ru>2013-08-28 04:37:43 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-10-11 02:24:40 -0400
commit8e0a1611cb891e72a9affc4a8ee4795c634896a6 (patch)
tree05c7376a7be9a41de27ac60a6b412807c0f09adb
parent8e0861fa3c4edfc2f30dd4cf4d58d3929f7c1b23 (diff)
powerpc: add real mode support for dma operations on powernv
The existing TCE machine calls (tce_build and tce_free) only support virtual mode as they call __raw_writeq for TCE invalidation what fails in real mode. This introduces tce_build_rm and tce_free_rm real mode versions which do mostly the same but use "Store Doubleword Caching Inhibited Indexed" instruction for TCE invalidation. This new feature is going to be utilized by real mode support of VFIO. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-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 */