diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-15 00:02:18 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-15 00:02:18 -0500 |
commit | 91838e2dab460ba589fb90db0fe1f504f5c04f12 (patch) | |
tree | 53974ed7a32ddd63d75e2da63f00d8308eb8d08a /drivers/iommu/arm-smmu.c | |
parent | f080480488028bcc25357f85e8ae54ccc3bb7173 (diff) | |
parent | bb51eeee5a947f61eeefaa55221c26460542654d (diff) |
Merge tag 'iommu-updates-v3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
Pull IOMMU updates from Joerg Roedel:
"This time the updates contain:
- Tracepoints for certain IOMMU-API functions to make their use
easier to debug
- A tracepoint for IOMMU page faults to make it easier to get them in
user space
- Updates and fixes for the new ARM SMMU driver after the first
hardware showed up
- Various other fixes and cleanups in other IOMMU drivers"
* tag 'iommu-updates-v3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: (26 commits)
iommu/shmobile: Enable the driver on all ARM platforms
iommu/tegra-smmu: Staticize tegra_smmu_pm_ops
iommu/tegra-gart: Staticize tegra_gart_pm_ops
iommu/vt-d: Use list_for_each_entry_safe() for dmar_domain->devices traversal
iommu/vt-d: Use for_each_drhd_unit() instead of list_for_each_entry()
iommu/vt-d: Fixed interaction of VFIO_IOMMU_MAP_DMA with IOMMU address limits
iommu/arm-smmu: Clear global and context bank fault status registers
iommu/arm-smmu: Print context fault information
iommu/arm-smmu: Check for num_context_irqs > 0 to avoid divide by zero exception
iommu/arm-smmu: Refine check for proper size of mapped region
iommu/arm-smmu: Switch to subsys_initcall for driver registration
iommu/arm-smmu: use relaxed accessors where possible
iommu/arm-smmu: replace devm_request_and_ioremap by devm_ioremap_resource
iommu: Remove stack trace from broken irq remapping warning
iommu: Change iommu driver to call io_page_fault trace event
iommu: Add iommu_error class event to iommu trace
iommu/tegra: gart: cleanup devm_* functions usage
iommu/tegra: Print phys_addr_t using %pa
iommu: No need to pass '0x' when '%pa' is used
iommu: Change iommu driver to call unmap trace event
...
Diffstat (limited to 'drivers/iommu/arm-smmu.c')
-rw-r--r-- | drivers/iommu/arm-smmu.c | 69 |
1 files changed, 37 insertions, 32 deletions
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"); |