diff options
author | Gavin Shan <shangw@linux.vnet.ibm.com> | 2013-04-25 15:21:01 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-04-26 02:10:00 -0400 |
commit | 373f565741a3636954cd87034d9ebb1dc7bfd716 (patch) | |
tree | 6c51ef6736305eb478be626028f8eecb1f95f0cf /arch | |
parent | 4cce95508bfeaa1cab74b08558993c81436dcbe0 (diff) |
powerpc/powernv: Build DMA space for PE on PHB3
The patch intends to build 32-bits DMA space for individual PEs on
PHB3. The TVE# is recognized by the combo of PE# and fixed bits
from DMA address, which is zero for 32-bits DMA space.
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/platforms/powernv/pci-ioda.c | 99 |
1 files changed, 93 insertions, 6 deletions
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 1c7e808a1302..04a37dc06a77 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c | |||
@@ -600,9 +600,8 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb, | |||
600 | */ | 600 | */ |
601 | tbl->it_busno = 0; | 601 | tbl->it_busno = 0; |
602 | tbl->it_index = (unsigned long)ioremap(be64_to_cpup(swinvp), 8); | 602 | tbl->it_index = (unsigned long)ioremap(be64_to_cpup(swinvp), 8); |
603 | tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE; | 603 | tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE | |
604 | if (phb->type == PNV_PHB_IODA1) | 604 | TCE_PCI_SWINV_PAIR; |
605 | tbl->it_type |= TCE_PCI_SWINV_PAIR; | ||
606 | } | 605 | } |
607 | iommu_init_table(tbl, phb->hose->node); | 606 | iommu_init_table(tbl, phb->hose->node); |
608 | 607 | ||
@@ -620,6 +619,81 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb, | |||
620 | __free_pages(tce_mem, get_order(TCE32_TABLE_SIZE * segs)); | 619 | __free_pages(tce_mem, get_order(TCE32_TABLE_SIZE * segs)); |
621 | } | 620 | } |
622 | 621 | ||
622 | static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb, | ||
623 | struct pnv_ioda_pe *pe) | ||
624 | { | ||
625 | struct page *tce_mem = NULL; | ||
626 | void *addr; | ||
627 | const __be64 *swinvp; | ||
628 | struct iommu_table *tbl; | ||
629 | unsigned int tce_table_size, end; | ||
630 | int64_t rc; | ||
631 | |||
632 | /* We shouldn't already have a 32-bit DMA associated */ | ||
633 | if (WARN_ON(pe->tce32_seg >= 0)) | ||
634 | return; | ||
635 | |||
636 | /* The PE will reserve all possible 32-bits space */ | ||
637 | pe->tce32_seg = 0; | ||
638 | end = (1 << ilog2(phb->ioda.m32_pci_base)); | ||
639 | tce_table_size = (end / 0x1000) * 8; | ||
640 | pe_info(pe, "Setting up 32-bit TCE table at 0..%08x\n", | ||
641 | end); | ||
642 | |||
643 | /* Allocate TCE table */ | ||
644 | tce_mem = alloc_pages_node(phb->hose->node, GFP_KERNEL, | ||
645 | get_order(tce_table_size)); | ||
646 | if (!tce_mem) { | ||
647 | pe_err(pe, "Failed to allocate a 32-bit TCE memory\n"); | ||
648 | goto fail; | ||
649 | } | ||
650 | addr = page_address(tce_mem); | ||
651 | memset(addr, 0, tce_table_size); | ||
652 | |||
653 | /* | ||
654 | * Map TCE table through TVT. The TVE index is the PE number | ||
655 | * shifted by 1 bit for 32-bits DMA space. | ||
656 | */ | ||
657 | rc = opal_pci_map_pe_dma_window(phb->opal_id, pe->pe_number, | ||
658 | pe->pe_number << 1, 1, __pa(addr), | ||
659 | tce_table_size, 0x1000); | ||
660 | if (rc) { | ||
661 | pe_err(pe, "Failed to configure 32-bit TCE table," | ||
662 | " err %ld\n", rc); | ||
663 | goto fail; | ||
664 | } | ||
665 | |||
666 | /* Setup linux iommu table */ | ||
667 | tbl = &pe->tce32_table; | ||
668 | pnv_pci_setup_iommu_table(tbl, addr, tce_table_size, 0); | ||
669 | |||
670 | /* OPAL variant of PHB3 invalidated TCEs */ | ||
671 | swinvp = of_get_property(phb->hose->dn, "ibm,opal-tce-kill", NULL); | ||
672 | if (swinvp) { | ||
673 | /* We need a couple more fields -- an address and a data | ||
674 | * to or. Since the bus is only printed out on table free | ||
675 | * errors, and on the first pass the data will be a relative | ||
676 | * bus number, print that out instead. | ||
677 | */ | ||
678 | tbl->it_busno = 0; | ||
679 | tbl->it_index = (unsigned long)ioremap(be64_to_cpup(swinvp), 8); | ||
680 | tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE; | ||
681 | } | ||
682 | iommu_init_table(tbl, phb->hose->node); | ||
683 | |||
684 | if (pe->pdev) | ||
685 | set_iommu_table_base(&pe->pdev->dev, tbl); | ||
686 | else | ||
687 | pnv_ioda_setup_bus_dma(pe, pe->pbus); | ||
688 | |||
689 | return; | ||
690 | fail: | ||
691 | if (pe->tce32_seg >= 0) | ||
692 | pe->tce32_seg = -1; | ||
693 | if (tce_mem) | ||
694 | __free_pages(tce_mem, get_order(tce_table_size)); | ||
695 | } | ||
696 | |||
623 | static void pnv_ioda_setup_dma(struct pnv_phb *phb) | 697 | static void pnv_ioda_setup_dma(struct pnv_phb *phb) |
624 | { | 698 | { |
625 | struct pci_controller *hose = phb->hose; | 699 | struct pci_controller *hose = phb->hose; |
@@ -662,9 +736,22 @@ static void pnv_ioda_setup_dma(struct pnv_phb *phb) | |||
662 | if (segs > remaining) | 736 | if (segs > remaining) |
663 | segs = remaining; | 737 | segs = remaining; |
664 | } | 738 | } |
665 | pe_info(pe, "DMA weight %d, assigned %d DMA32 segments\n", | 739 | |
666 | pe->dma_weight, segs); | 740 | /* |
667 | pnv_pci_ioda_setup_dma_pe(phb, pe, base, segs); | 741 | * For IODA2 compliant PHB3, we needn't care about the weight. |
742 | * The all available 32-bits DMA space will be assigned to | ||
743 | * the specific PE. | ||
744 | */ | ||
745 | if (phb->type == PNV_PHB_IODA1) { | ||
746 | pe_info(pe, "DMA weight %d, assigned %d DMA32 segments\n", | ||
747 | pe->dma_weight, segs); | ||
748 | pnv_pci_ioda_setup_dma_pe(phb, pe, base, segs); | ||
749 | } else { | ||
750 | pe_info(pe, "Assign DMA32 space\n"); | ||
751 | segs = 0; | ||
752 | pnv_pci_ioda2_setup_dma_pe(phb, pe); | ||
753 | } | ||
754 | |||
668 | remaining -= segs; | 755 | remaining -= segs; |
669 | base += segs; | 756 | base += segs; |
670 | } | 757 | } |