diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/iommu/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/iommu/Makefile | 1 | ||||
| -rw-r--r-- | drivers/iommu/arm-smmu.c | 69 | ||||
| -rw-r--r-- | drivers/iommu/dmar.c | 2 | ||||
| -rw-r--r-- | drivers/iommu/intel-iommu.c | 12 | ||||
| -rw-r--r-- | drivers/iommu/intel_irq_remapping.c | 13 | ||||
| -rw-r--r-- | drivers/iommu/iommu-traces.c | 27 | ||||
| -rw-r--r-- | drivers/iommu/iommu.c | 21 | ||||
| -rw-r--r-- | drivers/iommu/tegra-gart.c | 27 | ||||
| -rw-r--r-- | drivers/iommu/tegra-smmu.c | 4 |
10 files changed, 106 insertions, 72 deletions
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index c880ebaf1553..9fd51e51e78b 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig | |||
| @@ -206,7 +206,7 @@ config SHMOBILE_IPMMU_TLB | |||
| 206 | config SHMOBILE_IOMMU | 206 | config SHMOBILE_IOMMU |
| 207 | bool "IOMMU for Renesas IPMMU/IPMMUI" | 207 | bool "IOMMU for Renesas IPMMU/IPMMUI" |
| 208 | default n | 208 | default n |
| 209 | depends on (ARM && ARCH_SHMOBILE) | 209 | depends on ARM || COMPILE_TEST |
| 210 | select IOMMU_API | 210 | select IOMMU_API |
| 211 | select ARM_DMA_USE_IOMMU | 211 | select ARM_DMA_USE_IOMMU |
| 212 | select SHMOBILE_IPMMU | 212 | select SHMOBILE_IPMMU |
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 14c1f474cf11..5d58bf16e9e3 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | obj-$(CONFIG_IOMMU_API) += iommu.o | 1 | obj-$(CONFIG_IOMMU_API) += iommu.o |
| 2 | obj-$(CONFIG_IOMMU_API) += iommu-traces.o | ||
| 2 | obj-$(CONFIG_OF_IOMMU) += of_iommu.o | 3 | obj-$(CONFIG_OF_IOMMU) += of_iommu.o |
| 3 | obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o | 4 | obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o |
| 4 | obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o | 5 | obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o |
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 2349d6272aef..1abfb5684ab7 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c | |||
| @@ -590,6 +590,9 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev) | |||
| 590 | ret = IRQ_HANDLED; | 590 | ret = IRQ_HANDLED; |
| 591 | resume = RESUME_RETRY; | 591 | resume = RESUME_RETRY; |
| 592 | } else { | 592 | } else { |
| 593 | dev_err_ratelimited(smmu->dev, | ||
| 594 | "Unhandled context fault: iova=0x%08lx, fsynr=0x%x, cb=%d\n", | ||
| 595 | iova, fsynr, root_cfg->cbndx); | ||
| 593 | ret = IRQ_NONE; | 596 | ret = IRQ_NONE; |
| 594 | resume = RESUME_TERMINATE; | 597 | resume = RESUME_TERMINATE; |
| 595 | } | 598 | } |
| @@ -778,7 +781,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain) | |||
| 778 | #ifdef __BIG_ENDIAN | 781 | #ifdef __BIG_ENDIAN |
| 779 | reg |= SCTLR_E; | 782 | reg |= SCTLR_E; |
| 780 | #endif | 783 | #endif |
| 781 | writel(reg, cb_base + ARM_SMMU_CB_SCTLR); | 784 | writel_relaxed(reg, cb_base + ARM_SMMU_CB_SCTLR); |
| 782 | } | 785 | } |
| 783 | 786 | ||
| 784 | static int arm_smmu_init_domain_context(struct iommu_domain *domain, | 787 | static int arm_smmu_init_domain_context(struct iommu_domain *domain, |
| @@ -1562,9 +1565,13 @@ static struct iommu_ops arm_smmu_ops = { | |||
| 1562 | static void arm_smmu_device_reset(struct arm_smmu_device *smmu) | 1565 | static void arm_smmu_device_reset(struct arm_smmu_device *smmu) |
| 1563 | { | 1566 | { |
| 1564 | void __iomem *gr0_base = ARM_SMMU_GR0(smmu); | 1567 | void __iomem *gr0_base = ARM_SMMU_GR0(smmu); |
| 1565 | void __iomem *sctlr_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB_SCTLR; | 1568 | void __iomem *cb_base; |
| 1566 | int i = 0; | 1569 | int i = 0; |
| 1567 | u32 scr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sCR0); | 1570 | u32 reg; |
| 1571 | |||
| 1572 | /* Clear Global FSR */ | ||
| 1573 | reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR); | ||
| 1574 | writel(reg, gr0_base + ARM_SMMU_GR0_sGFSR); | ||
| 1568 | 1575 | ||
| 1569 | /* Mark all SMRn as invalid and all S2CRn as bypass */ | 1576 | /* Mark all SMRn as invalid and all S2CRn as bypass */ |
| 1570 | for (i = 0; i < smmu->num_mapping_groups; ++i) { | 1577 | for (i = 0; i < smmu->num_mapping_groups; ++i) { |
| @@ -1572,33 +1579,38 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) | |||
| 1572 | writel_relaxed(S2CR_TYPE_BYPASS, gr0_base + ARM_SMMU_GR0_S2CR(i)); | 1579 | writel_relaxed(S2CR_TYPE_BYPASS, gr0_base + ARM_SMMU_GR0_S2CR(i)); |
| 1573 | } | 1580 | } |
| 1574 | 1581 | ||
| 1575 | /* Make sure all context banks are disabled */ | 1582 | /* Make sure all context banks are disabled and clear CB_FSR */ |
| 1576 | for (i = 0; i < smmu->num_context_banks; ++i) | 1583 | for (i = 0; i < smmu->num_context_banks; ++i) { |
| 1577 | writel_relaxed(0, sctlr_base + ARM_SMMU_CB(smmu, i)); | 1584 | cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, i); |
| 1585 | writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR); | ||
| 1586 | writel_relaxed(FSR_FAULT, cb_base + ARM_SMMU_CB_FSR); | ||
| 1587 | } | ||
| 1578 | 1588 | ||
| 1579 | /* Invalidate the TLB, just in case */ | 1589 | /* Invalidate the TLB, just in case */ |
| 1580 | writel_relaxed(0, gr0_base + ARM_SMMU_GR0_STLBIALL); | 1590 | writel_relaxed(0, gr0_base + ARM_SMMU_GR0_STLBIALL); |
| 1581 | writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLH); | 1591 | writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLH); |
| 1582 | writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLNSNH); | 1592 | writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLNSNH); |
| 1583 | 1593 | ||
| 1594 | reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_sCR0); | ||
| 1595 | |||
| 1584 | /* Enable fault reporting */ | 1596 | /* Enable fault reporting */ |
| 1585 | scr0 |= (sCR0_GFRE | sCR0_GFIE | sCR0_GCFGFRE | sCR0_GCFGFIE); | 1597 | reg |= (sCR0_GFRE | sCR0_GFIE | sCR0_GCFGFRE | sCR0_GCFGFIE); |
| 1586 | 1598 | ||
| 1587 | /* Disable TLB broadcasting. */ | 1599 | /* Disable TLB broadcasting. */ |
| 1588 | scr0 |= (sCR0_VMIDPNE | sCR0_PTM); | 1600 | reg |= (sCR0_VMIDPNE | sCR0_PTM); |
| 1589 | 1601 | ||
| 1590 | /* Enable client access, but bypass when no mapping is found */ | 1602 | /* Enable client access, but bypass when no mapping is found */ |
| 1591 | scr0 &= ~(sCR0_CLIENTPD | sCR0_USFCFG); | 1603 | reg &= ~(sCR0_CLIENTPD | sCR0_USFCFG); |
| 1592 | 1604 | ||
| 1593 | /* Disable forced broadcasting */ | 1605 | /* Disable forced broadcasting */ |
| 1594 | scr0 &= ~sCR0_FB; | 1606 | reg &= ~sCR0_FB; |
| 1595 | 1607 | ||
| 1596 | /* Don't upgrade barriers */ | 1608 | /* Don't upgrade barriers */ |
| 1597 | scr0 &= ~(sCR0_BSU_MASK << sCR0_BSU_SHIFT); | 1609 | reg &= ~(sCR0_BSU_MASK << sCR0_BSU_SHIFT); |
| 1598 | 1610 | ||
| 1599 | /* Push the button */ | 1611 | /* Push the button */ |
| 1600 | arm_smmu_tlb_sync(smmu); | 1612 | arm_smmu_tlb_sync(smmu); |
| 1601 | writel(scr0, gr0_base + ARM_SMMU_GR0_sCR0); | 1613 | writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_sCR0); |
| 1602 | } | 1614 | } |
| 1603 | 1615 | ||
| 1604 | static int arm_smmu_id_size_to_bits(int size) | 1616 | static int arm_smmu_id_size_to_bits(int size) |
| @@ -1703,13 +1715,12 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) | |||
| 1703 | id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID1); | 1715 | id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID1); |
| 1704 | smmu->pagesize = (id & ID1_PAGESIZE) ? SZ_64K : SZ_4K; | 1716 | smmu->pagesize = (id & ID1_PAGESIZE) ? SZ_64K : SZ_4K; |
| 1705 | 1717 | ||
| 1706 | /* Check that we ioremapped enough */ | 1718 | /* Check for size mismatch of SMMU address space from mapped region */ |
| 1707 | size = 1 << (((id >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1); | 1719 | size = 1 << (((id >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1); |
| 1708 | size *= (smmu->pagesize << 1); | 1720 | size *= (smmu->pagesize << 1); |
| 1709 | if (smmu->size < size) | 1721 | if (smmu->size != size) |
| 1710 | dev_warn(smmu->dev, | 1722 | dev_warn(smmu->dev, "SMMU address space size (0x%lx) differs " |
| 1711 | "device is 0x%lx bytes but only mapped 0x%lx!\n", | 1723 | "from mapped region size (0x%lx)!\n", size, smmu->size); |
| 1712 | size, smmu->size); | ||
| 1713 | 1724 | ||
| 1714 | smmu->num_s2_context_banks = (id >> ID1_NUMS2CB_SHIFT) & | 1725 | smmu->num_s2_context_banks = (id >> ID1_NUMS2CB_SHIFT) & |
| 1715 | ID1_NUMS2CB_MASK; | 1726 | ID1_NUMS2CB_MASK; |
| @@ -1784,15 +1795,10 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) | |||
| 1784 | smmu->dev = dev; | 1795 | smmu->dev = dev; |
| 1785 | 1796 | ||
| 1786 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1797 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 1787 | if (!res) { | 1798 | smmu->base = devm_ioremap_resource(dev, res); |
| 1788 | dev_err(dev, "missing base address/size\n"); | 1799 | if (IS_ERR(smmu->base)) |
| 1789 | return -ENODEV; | 1800 | return PTR_ERR(smmu->base); |
| 1790 | } | ||
| 1791 | |||
| 1792 | smmu->size = resource_size(res); | 1801 | smmu->size = resource_size(res); |
| 1793 | smmu->base = devm_request_and_ioremap(dev, res); | ||
| 1794 | if (!smmu->base) | ||
| 1795 | return -EADDRNOTAVAIL; | ||
| 1796 | 1802 | ||
| 1797 | if (of_property_read_u32(dev->of_node, "#global-interrupts", | 1803 | if (of_property_read_u32(dev->of_node, "#global-interrupts", |
| 1798 | &smmu->num_global_irqs)) { | 1804 | &smmu->num_global_irqs)) { |
| @@ -1807,12 +1813,11 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) | |||
| 1807 | smmu->num_context_irqs++; | 1813 | smmu->num_context_irqs++; |
| 1808 | } | 1814 | } |
| 1809 | 1815 | ||
| 1810 | if (num_irqs < smmu->num_global_irqs) { | 1816 | if (!smmu->num_context_irqs) { |
| 1811 | dev_warn(dev, "found %d interrupts but expected at least %d\n", | 1817 | dev_err(dev, "found %d interrupts but expected at least %d\n", |
| 1812 | num_irqs, smmu->num_global_irqs); | 1818 | num_irqs, smmu->num_global_irqs + 1); |
| 1813 | smmu->num_global_irqs = num_irqs; | 1819 | return -ENODEV; |
| 1814 | } | 1820 | } |
| 1815 | smmu->num_context_irqs = num_irqs - smmu->num_global_irqs; | ||
| 1816 | 1821 | ||
| 1817 | smmu->irqs = devm_kzalloc(dev, sizeof(*smmu->irqs) * num_irqs, | 1822 | smmu->irqs = devm_kzalloc(dev, sizeof(*smmu->irqs) * num_irqs, |
| 1818 | GFP_KERNEL); | 1823 | GFP_KERNEL); |
| @@ -1936,7 +1941,7 @@ static int arm_smmu_device_remove(struct platform_device *pdev) | |||
| 1936 | free_irq(smmu->irqs[i], smmu); | 1941 | free_irq(smmu->irqs[i], smmu); |
| 1937 | 1942 | ||
| 1938 | /* Turn the thing off */ | 1943 | /* Turn the thing off */ |
| 1939 | writel(sCR0_CLIENTPD, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_sCR0); | 1944 | writel_relaxed(sCR0_CLIENTPD, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_sCR0); |
| 1940 | return 0; | 1945 | return 0; |
| 1941 | } | 1946 | } |
| 1942 | 1947 | ||
| @@ -1984,7 +1989,7 @@ static void __exit arm_smmu_exit(void) | |||
| 1984 | return platform_driver_unregister(&arm_smmu_driver); | 1989 | return platform_driver_unregister(&arm_smmu_driver); |
| 1985 | } | 1990 | } |
| 1986 | 1991 | ||
| 1987 | module_init(arm_smmu_init); | 1992 | subsys_initcall(arm_smmu_init); |
| 1988 | module_exit(arm_smmu_exit); | 1993 | module_exit(arm_smmu_exit); |
| 1989 | 1994 | ||
| 1990 | MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations"); | 1995 | MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations"); |
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 900946950230..8b452c9676d9 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c | |||
| @@ -403,7 +403,7 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev) | |||
| 403 | 403 | ||
| 404 | dev = pci_physfn(dev); | 404 | dev = pci_physfn(dev); |
| 405 | 405 | ||
| 406 | list_for_each_entry(dmaru, &dmar_drhd_units, list) { | 406 | for_each_drhd_unit(dmaru) { |
| 407 | drhd = container_of(dmaru->hdr, | 407 | drhd = container_of(dmaru->hdr, |
| 408 | struct acpi_dmar_hardware_unit, | 408 | struct acpi_dmar_hardware_unit, |
| 409 | header); | 409 | header); |
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 15e9b57e9cf0..43b9bfea48fa 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c | |||
| @@ -782,7 +782,11 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain, | |||
| 782 | int offset; | 782 | int offset; |
| 783 | 783 | ||
| 784 | BUG_ON(!domain->pgd); | 784 | BUG_ON(!domain->pgd); |
| 785 | BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width); | 785 | |
| 786 | if (addr_width < BITS_PER_LONG && pfn >> addr_width) | ||
| 787 | /* Address beyond IOMMU's addressing capabilities. */ | ||
| 788 | return NULL; | ||
| 789 | |||
| 786 | parent = domain->pgd; | 790 | parent = domain->pgd; |
| 787 | 791 | ||
| 788 | while (level > 0) { | 792 | while (level > 0) { |
| @@ -3777,11 +3781,10 @@ static void iommu_detach_dependent_devices(struct intel_iommu *iommu, | |||
| 3777 | static void domain_remove_one_dev_info(struct dmar_domain *domain, | 3781 | static void domain_remove_one_dev_info(struct dmar_domain *domain, |
| 3778 | struct pci_dev *pdev) | 3782 | struct pci_dev *pdev) |
| 3779 | { | 3783 | { |
| 3780 | struct device_domain_info *info; | 3784 | struct device_domain_info *info, *tmp; |
| 3781 | struct intel_iommu *iommu; | 3785 | struct intel_iommu *iommu; |
| 3782 | unsigned long flags; | 3786 | unsigned long flags; |
| 3783 | int found = 0; | 3787 | int found = 0; |
| 3784 | struct list_head *entry, *tmp; | ||
| 3785 | 3788 | ||
| 3786 | iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number, | 3789 | iommu = device_to_iommu(pci_domain_nr(pdev->bus), pdev->bus->number, |
| 3787 | pdev->devfn); | 3790 | pdev->devfn); |
| @@ -3789,8 +3792,7 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain, | |||
| 3789 | return; | 3792 | return; |
| 3790 | 3793 | ||
| 3791 | spin_lock_irqsave(&device_domain_lock, flags); | 3794 | spin_lock_irqsave(&device_domain_lock, flags); |
| 3792 | list_for_each_safe(entry, tmp, &domain->devices) { | 3795 | list_for_each_entry_safe(info, tmp, &domain->devices, link) { |
| 3793 | info = list_entry(entry, struct device_domain_info, link); | ||
| 3794 | if (info->segment == pci_domain_nr(pdev->bus) && | 3796 | if (info->segment == pci_domain_nr(pdev->bus) && |
| 3795 | info->bus == pdev->bus->number && | 3797 | info->bus == pdev->bus->number && |
| 3796 | info->devfn == pdev->devfn) { | 3798 | info->devfn == pdev->devfn) { |
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index ab86902fd9ff..bab10b1002fb 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c | |||
| @@ -525,12 +525,13 @@ static int __init intel_irq_remapping_supported(void) | |||
| 525 | if (disable_irq_remap) | 525 | if (disable_irq_remap) |
| 526 | return 0; | 526 | return 0; |
| 527 | if (irq_remap_broken) { | 527 | if (irq_remap_broken) { |
| 528 | WARN_TAINT(1, TAINT_FIRMWARE_WORKAROUND, | 528 | printk(KERN_WARNING |
| 529 | "This system BIOS has enabled interrupt remapping\n" | 529 | "This system BIOS has enabled interrupt remapping\n" |
| 530 | "on a chipset that contains an erratum making that\n" | 530 | "on a chipset that contains an erratum making that\n" |
| 531 | "feature unstable. To maintain system stability\n" | 531 | "feature unstable. To maintain system stability\n" |
| 532 | "interrupt remapping is being disabled. Please\n" | 532 | "interrupt remapping is being disabled. Please\n" |
| 533 | "contact your BIOS vendor for an update\n"); | 533 | "contact your BIOS vendor for an update\n"); |
| 534 | add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); | ||
| 534 | disable_irq_remap = 1; | 535 | disable_irq_remap = 1; |
| 535 | return 0; | 536 | return 0; |
| 536 | } | 537 | } |
diff --git a/drivers/iommu/iommu-traces.c b/drivers/iommu/iommu-traces.c new file mode 100644 index 000000000000..bf3b317ff0c1 --- /dev/null +++ b/drivers/iommu/iommu-traces.c | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | /* | ||
| 2 | * iommu trace points | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013 Shuah Khan <shuah.kh@samsung.com> | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/string.h> | ||
| 9 | #include <linux/types.h> | ||
| 10 | |||
| 11 | #define CREATE_TRACE_POINTS | ||
| 12 | #include <trace/events/iommu.h> | ||
| 13 | |||
| 14 | /* iommu_group_event */ | ||
| 15 | EXPORT_TRACEPOINT_SYMBOL_GPL(add_device_to_group); | ||
| 16 | EXPORT_TRACEPOINT_SYMBOL_GPL(remove_device_from_group); | ||
| 17 | |||
| 18 | /* iommu_device_event */ | ||
| 19 | EXPORT_TRACEPOINT_SYMBOL_GPL(attach_device_to_domain); | ||
| 20 | EXPORT_TRACEPOINT_SYMBOL_GPL(detach_device_from_domain); | ||
| 21 | |||
| 22 | /* iommu_map_unmap */ | ||
| 23 | EXPORT_TRACEPOINT_SYMBOL_GPL(map); | ||
| 24 | EXPORT_TRACEPOINT_SYMBOL_GPL(unmap); | ||
| 25 | |||
| 26 | /* iommu_error */ | ||
| 27 | EXPORT_TRACEPOINT_SYMBOL_GPL(io_page_fault); | ||
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index fbe9ca734f8f..e5555fcfe703 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/idr.h> | 29 | #include <linux/idr.h> |
| 30 | #include <linux/notifier.h> | 30 | #include <linux/notifier.h> |
| 31 | #include <linux/err.h> | 31 | #include <linux/err.h> |
| 32 | #include <trace/events/iommu.h> | ||
| 32 | 33 | ||
| 33 | static struct kset *iommu_group_kset; | 34 | static struct kset *iommu_group_kset; |
| 34 | static struct ida iommu_group_ida; | 35 | static struct ida iommu_group_ida; |
| @@ -363,6 +364,8 @@ rename: | |||
| 363 | /* Notify any listeners about change to group. */ | 364 | /* Notify any listeners about change to group. */ |
| 364 | blocking_notifier_call_chain(&group->notifier, | 365 | blocking_notifier_call_chain(&group->notifier, |
| 365 | IOMMU_GROUP_NOTIFY_ADD_DEVICE, dev); | 366 | IOMMU_GROUP_NOTIFY_ADD_DEVICE, dev); |
| 367 | |||
| 368 | trace_add_device_to_group(group->id, dev); | ||
| 366 | return 0; | 369 | return 0; |
| 367 | } | 370 | } |
| 368 | EXPORT_SYMBOL_GPL(iommu_group_add_device); | 371 | EXPORT_SYMBOL_GPL(iommu_group_add_device); |
| @@ -399,6 +402,8 @@ void iommu_group_remove_device(struct device *dev) | |||
| 399 | sysfs_remove_link(group->devices_kobj, device->name); | 402 | sysfs_remove_link(group->devices_kobj, device->name); |
| 400 | sysfs_remove_link(&dev->kobj, "iommu_group"); | 403 | sysfs_remove_link(&dev->kobj, "iommu_group"); |
| 401 | 404 | ||
| 405 | trace_remove_device_from_group(group->id, dev); | ||
| 406 | |||
| 402 | kfree(device->name); | 407 | kfree(device->name); |
| 403 | kfree(device); | 408 | kfree(device); |
| 404 | dev->iommu_group = NULL; | 409 | dev->iommu_group = NULL; |
| @@ -680,10 +685,14 @@ EXPORT_SYMBOL_GPL(iommu_domain_free); | |||
| 680 | 685 | ||
| 681 | int iommu_attach_device(struct iommu_domain *domain, struct device *dev) | 686 | int iommu_attach_device(struct iommu_domain *domain, struct device *dev) |
| 682 | { | 687 | { |
| 688 | int ret; | ||
| 683 | if (unlikely(domain->ops->attach_dev == NULL)) | 689 | if (unlikely(domain->ops->attach_dev == NULL)) |
| 684 | return -ENODEV; | 690 | return -ENODEV; |
| 685 | 691 | ||
| 686 | return domain->ops->attach_dev(domain, dev); | 692 | ret = domain->ops->attach_dev(domain, dev); |
| 693 | if (!ret) | ||
| 694 | trace_attach_device_to_domain(dev); | ||
| 695 | return ret; | ||
| 687 | } | 696 | } |
| 688 | EXPORT_SYMBOL_GPL(iommu_attach_device); | 697 | EXPORT_SYMBOL_GPL(iommu_attach_device); |
| 689 | 698 | ||
| @@ -693,6 +702,7 @@ void iommu_detach_device(struct iommu_domain *domain, struct device *dev) | |||
| 693 | return; | 702 | return; |
| 694 | 703 | ||
| 695 | domain->ops->detach_dev(domain, dev); | 704 | domain->ops->detach_dev(domain, dev); |
| 705 | trace_detach_device_from_domain(dev); | ||
| 696 | } | 706 | } |
| 697 | EXPORT_SYMBOL_GPL(iommu_detach_device); | 707 | EXPORT_SYMBOL_GPL(iommu_detach_device); |
| 698 | 708 | ||
| @@ -807,17 +817,17 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, | |||
| 807 | * size of the smallest page supported by the hardware | 817 | * size of the smallest page supported by the hardware |
| 808 | */ | 818 | */ |
| 809 | if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) { | 819 | if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) { |
| 810 | pr_err("unaligned: iova 0x%lx pa 0x%pa size 0x%zx min_pagesz 0x%x\n", | 820 | pr_err("unaligned: iova 0x%lx pa %pa size 0x%zx min_pagesz 0x%x\n", |
| 811 | iova, &paddr, size, min_pagesz); | 821 | iova, &paddr, size, min_pagesz); |
| 812 | return -EINVAL; | 822 | return -EINVAL; |
| 813 | } | 823 | } |
| 814 | 824 | ||
| 815 | pr_debug("map: iova 0x%lx pa 0x%pa size 0x%zx\n", iova, &paddr, size); | 825 | pr_debug("map: iova 0x%lx pa %pa size 0x%zx\n", iova, &paddr, size); |
| 816 | 826 | ||
| 817 | while (size) { | 827 | while (size) { |
| 818 | size_t pgsize = iommu_pgsize(domain, iova | paddr, size); | 828 | size_t pgsize = iommu_pgsize(domain, iova | paddr, size); |
| 819 | 829 | ||
| 820 | pr_debug("mapping: iova 0x%lx pa 0x%pa pgsize 0x%zx\n", | 830 | pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx\n", |
| 821 | iova, &paddr, pgsize); | 831 | iova, &paddr, pgsize); |
| 822 | 832 | ||
| 823 | ret = domain->ops->map(domain, iova, paddr, pgsize, prot); | 833 | ret = domain->ops->map(domain, iova, paddr, pgsize, prot); |
| @@ -832,6 +842,8 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, | |||
| 832 | /* unroll mapping in case something went wrong */ | 842 | /* unroll mapping in case something went wrong */ |
| 833 | if (ret) | 843 | if (ret) |
| 834 | iommu_unmap(domain, orig_iova, orig_size - size); | 844 | iommu_unmap(domain, orig_iova, orig_size - size); |
| 845 | else | ||
| 846 | trace_map(iova, paddr, size); | ||
| 835 | 847 | ||
| 836 | return ret; | 848 | return ret; |
| 837 | } | 849 | } |
| @@ -880,6 +892,7 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) | |||
| 880 | unmapped += unmapped_page; | 892 | unmapped += unmapped_page; |
| 881 | } | 893 | } |
| 882 | 894 | ||
| 895 | trace_unmap(iova, 0, size); | ||
| 883 | return unmapped; | 896 | return unmapped; |
| 884 | } | 897 | } |
| 885 | EXPORT_SYMBOL_GPL(iommu_unmap); | 898 | EXPORT_SYMBOL_GPL(iommu_unmap); |
diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index 108c0e9c24d9..dba1a9fd5070 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c | |||
| @@ -252,7 +252,7 @@ static int gart_iommu_map(struct iommu_domain *domain, unsigned long iova, | |||
| 252 | spin_lock_irqsave(&gart->pte_lock, flags); | 252 | spin_lock_irqsave(&gart->pte_lock, flags); |
| 253 | pfn = __phys_to_pfn(pa); | 253 | pfn = __phys_to_pfn(pa); |
| 254 | if (!pfn_valid(pfn)) { | 254 | if (!pfn_valid(pfn)) { |
| 255 | dev_err(gart->dev, "Invalid page: %08x\n", pa); | 255 | dev_err(gart->dev, "Invalid page: %pa\n", &pa); |
| 256 | spin_unlock_irqrestore(&gart->pte_lock, flags); | 256 | spin_unlock_irqrestore(&gart->pte_lock, flags); |
| 257 | return -EINVAL; | 257 | return -EINVAL; |
| 258 | } | 258 | } |
| @@ -295,8 +295,8 @@ static phys_addr_t gart_iommu_iova_to_phys(struct iommu_domain *domain, | |||
| 295 | 295 | ||
| 296 | pa = (pte & GART_PAGE_MASK); | 296 | pa = (pte & GART_PAGE_MASK); |
| 297 | if (!pfn_valid(__phys_to_pfn(pa))) { | 297 | if (!pfn_valid(__phys_to_pfn(pa))) { |
| 298 | dev_err(gart->dev, "No entry for %08llx:%08x\n", | 298 | dev_err(gart->dev, "No entry for %08llx:%pa\n", |
| 299 | (unsigned long long)iova, pa); | 299 | (unsigned long long)iova, &pa); |
| 300 | gart_dump_table(gart); | 300 | gart_dump_table(gart); |
| 301 | return -EINVAL; | 301 | return -EINVAL; |
| 302 | } | 302 | } |
| @@ -351,7 +351,6 @@ static int tegra_gart_probe(struct platform_device *pdev) | |||
| 351 | struct gart_device *gart; | 351 | struct gart_device *gart; |
| 352 | struct resource *res, *res_remap; | 352 | struct resource *res, *res_remap; |
| 353 | void __iomem *gart_regs; | 353 | void __iomem *gart_regs; |
| 354 | int err; | ||
| 355 | struct device *dev = &pdev->dev; | 354 | struct device *dev = &pdev->dev; |
| 356 | 355 | ||
| 357 | if (gart_handle) | 356 | if (gart_handle) |
| @@ -376,8 +375,7 @@ static int tegra_gart_probe(struct platform_device *pdev) | |||
| 376 | gart_regs = devm_ioremap(dev, res->start, resource_size(res)); | 375 | gart_regs = devm_ioremap(dev, res->start, resource_size(res)); |
| 377 | if (!gart_regs) { | 376 | if (!gart_regs) { |
| 378 | dev_err(dev, "failed to remap GART registers\n"); | 377 | dev_err(dev, "failed to remap GART registers\n"); |
| 379 | err = -ENXIO; | 378 | return -ENXIO; |
| 380 | goto fail; | ||
| 381 | } | 379 | } |
| 382 | 380 | ||
| 383 | gart->dev = &pdev->dev; | 381 | gart->dev = &pdev->dev; |
| @@ -391,8 +389,7 @@ static int tegra_gart_probe(struct platform_device *pdev) | |||
| 391 | gart->savedata = vmalloc(sizeof(u32) * gart->page_count); | 389 | gart->savedata = vmalloc(sizeof(u32) * gart->page_count); |
| 392 | if (!gart->savedata) { | 390 | if (!gart->savedata) { |
| 393 | dev_err(dev, "failed to allocate context save area\n"); | 391 | dev_err(dev, "failed to allocate context save area\n"); |
| 394 | err = -ENOMEM; | 392 | return -ENOMEM; |
| 395 | goto fail; | ||
| 396 | } | 393 | } |
| 397 | 394 | ||
| 398 | platform_set_drvdata(pdev, gart); | 395 | platform_set_drvdata(pdev, gart); |
| @@ -401,32 +398,20 @@ static int tegra_gart_probe(struct platform_device *pdev) | |||
| 401 | gart_handle = gart; | 398 | gart_handle = gart; |
| 402 | bus_set_iommu(&platform_bus_type, &gart_iommu_ops); | 399 | bus_set_iommu(&platform_bus_type, &gart_iommu_ops); |
| 403 | return 0; | 400 | return 0; |
| 404 | |||
| 405 | fail: | ||
| 406 | if (gart_regs) | ||
| 407 | devm_iounmap(dev, gart_regs); | ||
| 408 | if (gart && gart->savedata) | ||
| 409 | vfree(gart->savedata); | ||
| 410 | devm_kfree(dev, gart); | ||
| 411 | return err; | ||
| 412 | } | 401 | } |
| 413 | 402 | ||
| 414 | static int tegra_gart_remove(struct platform_device *pdev) | 403 | static int tegra_gart_remove(struct platform_device *pdev) |
| 415 | { | 404 | { |
| 416 | struct gart_device *gart = platform_get_drvdata(pdev); | 405 | struct gart_device *gart = platform_get_drvdata(pdev); |
| 417 | struct device *dev = gart->dev; | ||
| 418 | 406 | ||
| 419 | writel(0, gart->regs + GART_CONFIG); | 407 | writel(0, gart->regs + GART_CONFIG); |
| 420 | if (gart->savedata) | 408 | if (gart->savedata) |
| 421 | vfree(gart->savedata); | 409 | vfree(gart->savedata); |
| 422 | if (gart->regs) | ||
| 423 | devm_iounmap(dev, gart->regs); | ||
| 424 | devm_kfree(dev, gart); | ||
| 425 | gart_handle = NULL; | 410 | gart_handle = NULL; |
| 426 | return 0; | 411 | return 0; |
| 427 | } | 412 | } |
| 428 | 413 | ||
| 429 | const struct dev_pm_ops tegra_gart_pm_ops = { | 414 | static const struct dev_pm_ops tegra_gart_pm_ops = { |
| 430 | .suspend = tegra_gart_suspend, | 415 | .suspend = tegra_gart_suspend, |
| 431 | .resume = tegra_gart_resume, | 416 | .resume = tegra_gart_resume, |
| 432 | }; | 417 | }; |
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index e0665603afd9..605b5b46a903 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c | |||
| @@ -731,7 +731,7 @@ static int smmu_iommu_map(struct iommu_domain *domain, unsigned long iova, | |||
| 731 | unsigned long pfn = __phys_to_pfn(pa); | 731 | unsigned long pfn = __phys_to_pfn(pa); |
| 732 | unsigned long flags; | 732 | unsigned long flags; |
| 733 | 733 | ||
| 734 | dev_dbg(as->smmu->dev, "[%d] %08lx:%08x\n", as->asid, iova, pa); | 734 | dev_dbg(as->smmu->dev, "[%d] %08lx:%pa\n", as->asid, iova, &pa); |
| 735 | 735 | ||
| 736 | if (!pfn_valid(pfn)) | 736 | if (!pfn_valid(pfn)) |
| 737 | return -ENOMEM; | 737 | return -ENOMEM; |
| @@ -1254,7 +1254,7 @@ static int tegra_smmu_remove(struct platform_device *pdev) | |||
| 1254 | return 0; | 1254 | return 0; |
| 1255 | } | 1255 | } |
| 1256 | 1256 | ||
| 1257 | const struct dev_pm_ops tegra_smmu_pm_ops = { | 1257 | static const struct dev_pm_ops tegra_smmu_pm_ops = { |
| 1258 | .suspend = tegra_smmu_suspend, | 1258 | .suspend = tegra_smmu_suspend, |
| 1259 | .resume = tegra_smmu_resume, | 1259 | .resume = tegra_smmu_resume, |
| 1260 | }; | 1260 | }; |
