diff options
-rw-r--r-- | arch/powerpc/include/asm/machdep.h | 12 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci-ioda.c | 49 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci.c | 42 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci.h | 3 |
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); | |||
70 | define_pe_printk_level(pe_warn, KERN_WARNING); | 70 | define_pe_printk_level(pe_warn, KERN_WARNING); |
71 | define_pe_printk_level(pe_info, KERN_INFO); | 71 | define_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 | */ | ||
77 | static 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 | |||
73 | static int pnv_ioda_alloc_pe(struct pnv_phb *phb) | 83 | static 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 | ||
457 | static void pnv_pci_ioda1_tce_invalidate(struct iommu_table *tbl, | 467 | static 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 | ||
497 | static void pnv_pci_ioda2_tce_invalidate(struct pnv_ioda_pe *pe, | 513 | static 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 | ||
523 | void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl, | 544 | void 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 | ||
536 | static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb, | 557 | static 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 | ||
402 | static int pnv_tce_build(struct iommu_table *tbl, long index, long npages, | 402 | static 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 | ||
431 | static void pnv_tce_free(struct iommu_table *tbl, long index, long npages) | 431 | static 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 | |||
440 | static 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 | |||
454 | static 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 | ||
444 | static unsigned long pnv_tce_get(struct iommu_table *tbl, long index) | 459 | static 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 | ||
464 | static 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 | |||
472 | static void pnv_tce_free_rm(struct iommu_table *tbl, long index, long npages) | ||
473 | { | ||
474 | pnv_tce_free(tbl, index, npages, true); | ||
475 | } | ||
476 | |||
449 | void pnv_pci_setup_iommu_table(struct iommu_table *tbl, | 477 | void 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); | |||
193 | extern void pnv_pci_init_ioda_hub(struct device_node *np); | 194 | extern void pnv_pci_init_ioda_hub(struct device_node *np); |
194 | extern void pnv_pci_init_ioda2_phb(struct device_node *np); | 195 | extern void pnv_pci_init_ioda2_phb(struct device_node *np); |
195 | extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl, | 196 | extern 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 */ |