From 3846a3b9511c5166082a93536d919a9c42abcd91 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 7 Aug 2019 11:26:45 +0300 Subject: iommu/omap: fix boot issue on remoteprocs with AMMU/Unicache Support has been added to the OMAP IOMMU driver to fix a boot hang issue on OMAP remoteprocs with AMMU/Unicache, caused by an improper AMMU/Unicache state upon initial deassertion of the processor reset. The issue is described in detail in the next three paragraphs. All the Cortex M3/M4 IPU processor subsystems in OMAP SoCs have a AMMU/Unicache IP that dictates the memory attributes for addresses seen by the processor cores. The AMMU/Unicache is configured/enabled by the SCACHE_CONFIG.BYPASS bit - a value of 1 enables the cache and mandates all addresses accessed by M3/M4 be defined in the AMMU. This bit is not programmable from the host processor. The M3/M4 boot sequence starts out with the AMMU/Unicache in disabled state, and SYS/BIOS programs the AMMU regions and enables the Unicache during one of its initial boot steps. This SCACHE_CONFIG.BYPASS bit is however enabled by default whenever a RET reset is applied to the IP, irrespective of whether it was previously enabled or not. The AMMU registers lose their context whenever this reset is applied. The reset is effective as long as the MMU portion of the subsystem is enabled and clocked. This behavior is common to all the IPU and DSP subsystems that have an AMMU/Unicache. The IPU boot sequence involves enabling and programming the MMU, and loading the processor and releasing the reset(s) for the processor. The PM setup code currently sets the target state for most of the power domains to RET. The L2 MMU can be enabled, programmed and accessed properly just fine with the domain in hardware supervised mode, while the power domain goes through a RET->ON->RET transition during the programming sequence. However, the ON->RET transition asserts a RET reset, and the SCACHE_CONFIG.BYPASS bit gets auto-set. An AMMU fault is thrown immediately when the M3/M4 core's reset is released since the first instruction address itself will not be defined in any valid AMMU regions. The ON->RET transition happens automatically on the power domain after enabling the iommu due to the hardware supervised mode. This patch adds and invokes the .set_pwrdm_constraint pdata ops, if present, during the OMAP IOMMU enable and disable functions to resolve the above boot hang issue. The ops will allow to invoke a mach-omap2 layer API pwrdm_set_next_pwrst() in a multi-arch kernel environment. The ops also returns the current power domain state while enforcing the constraint so that the driver can store it and use it to set back the power domain state while releasing the constraint. The pdata ops implementation restricts the target power domain to ON during enable, and back to the original power domain state during disable, and thereby eliminating the conditions for the boot issue. The implementation is effective only when the original power domain state is either RET or OFF, and is a no-op when it is ON or INACTIVE. The .set_pwrdm_constraint ops need to be plugged in pdata-quirks for the affected remote processors to be able to boot properly. Note that the current issue is seen only on kernels with the affected power domains programmed to enter RET. For eg., IPU1 on DRA7xx is in a separate domain and is susceptible to this bug, while the IPU2 subsystem is within CORE power domain, and CORE RET is not supported on this SoC. IPUs on OMAP4 and OMAP5 are also susceptible since they are in CORE power domain, and CORE RET is a valid power target on these SoCs. Signed-off-by: Suman Anna Signed-off-by: Joerg Roedel --- arch/arm/mach-omap2/Makefile | 2 ++ arch/arm/mach-omap2/omap-iommu.c | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 arch/arm/mach-omap2/omap-iommu.c (limited to 'arch') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 600650551621..d4f11c5070ae 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -229,3 +229,5 @@ include/generated/ti-pm-asm-offsets.h: arch/arm/mach-omap2/pm-asm-offsets.s FORC $(obj)/sleep33xx.o $(obj)/sleep43xx.o: include/generated/ti-pm-asm-offsets.h targets += pm-asm-offsets.s + +obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c new file mode 100644 index 000000000000..f1a6ece8108e --- /dev/null +++ b/arch/arm/mach-omap2/omap-iommu.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * OMAP IOMMU quirks for various TI SoCs + * + * Copyright (C) 2015-2019 Texas Instruments Incorporated - http://www.ti.com/ + * Suman Anna + */ + +#include +#include + +#include "omap_hwmod.h" +#include "omap_device.h" +#include "powerdomain.h" + +int omap_iommu_set_pwrdm_constraint(struct platform_device *pdev, bool request, + u8 *pwrst) +{ + struct powerdomain *pwrdm; + struct omap_device *od; + u8 next_pwrst; + + od = to_omap_device(pdev); + if (!od) + return -ENODEV; + + if (od->hwmods_cnt != 1) + return -EINVAL; + + pwrdm = omap_hwmod_get_pwrdm(od->hwmods[0]); + if (!pwrdm) + return -EINVAL; + + if (request) + *pwrst = pwrdm_read_next_pwrst(pwrdm); + + if (*pwrst > PWRDM_POWER_RET) + return 0; + + next_pwrst = request ? PWRDM_POWER_ON : *pwrst; + + return pwrdm_set_next_pwrst(pwrdm, next_pwrst); +} -- cgit v1.2.3 From c53c47aac4ff9509e7e1a32666baefbd9793c5a0 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 19 Aug 2019 15:22:51 +0200 Subject: x86/dma: Get rid of iommu_pass_through This variable has no users anymore. Remove it and tell the IOMMU code via its new functions about requested DMA modes. Reviewed-by: Borislav Petkov Signed-off-by: Joerg Roedel --- arch/x86/include/asm/iommu.h | 1 - arch/x86/kernel/pci-dma.c | 20 +++----------------- 2 files changed, 3 insertions(+), 18 deletions(-) (limited to 'arch') diff --git a/arch/x86/include/asm/iommu.h b/arch/x86/include/asm/iommu.h index baedab8ac538..b91623d521d9 100644 --- a/arch/x86/include/asm/iommu.h +++ b/arch/x86/include/asm/iommu.h @@ -4,7 +4,6 @@ extern int force_iommu, no_iommu; extern int iommu_detected; -extern int iommu_pass_through; /* 10 seconds */ #define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index f62b498b18fb..fa4352dce491 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include #include +#include #include #include #include @@ -34,21 +35,6 @@ int no_iommu __read_mostly; /* Set this to 1 if there is a HW IOMMU in the system */ int iommu_detected __read_mostly = 0; -/* - * This variable becomes 1 if iommu=pt is passed on the kernel command line. - * If this variable is 1, IOMMU implementations do no DMA translation for - * devices and allow every device to access to whole physical memory. This is - * useful if a user wants to use an IOMMU only for KVM device assignment to - * guests and not for driver dma translation. - * It is also possible to disable by default in kernel config, and enable with - * iommu=nopt at boot time. - */ -#ifdef CONFIG_IOMMU_DEFAULT_PASSTHROUGH -int iommu_pass_through __read_mostly = 1; -#else -int iommu_pass_through __read_mostly; -#endif - extern struct iommu_table_entry __iommu_table[], __iommu_table_end[]; void __init pci_iommu_alloc(void) @@ -120,9 +106,9 @@ static __init int iommu_setup(char *p) swiotlb = 1; #endif if (!strncmp(p, "pt", 2)) - iommu_pass_through = 1; + iommu_set_default_passthrough(true); if (!strncmp(p, "nopt", 4)) - iommu_pass_through = 0; + iommu_set_default_translated(true); gart_parse_options(p); -- cgit v1.2.3 From 74bc0f6b22fd1a3c839f61d8475335a98af53c7a Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 19 Aug 2019 15:22:52 +0200 Subject: ia64: Get rid of iommu_pass_through This variable has no users anymore so it can be removed. Signed-off-by: Joerg Roedel --- arch/ia64/include/asm/iommu.h | 2 -- arch/ia64/kernel/pci-dma.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'arch') diff --git a/arch/ia64/include/asm/iommu.h b/arch/ia64/include/asm/iommu.h index 7429a72f3f92..92aceef63710 100644 --- a/arch/ia64/include/asm/iommu.h +++ b/arch/ia64/include/asm/iommu.h @@ -8,10 +8,8 @@ extern void no_iommu_init(void); #ifdef CONFIG_INTEL_IOMMU extern int force_iommu, no_iommu; -extern int iommu_pass_through; extern int iommu_detected; #else -#define iommu_pass_through (0) #define no_iommu (1) #define iommu_detected (0) #endif diff --git a/arch/ia64/kernel/pci-dma.c b/arch/ia64/kernel/pci-dma.c index fe988c49f01c..f5d49cd3fbb0 100644 --- a/arch/ia64/kernel/pci-dma.c +++ b/arch/ia64/kernel/pci-dma.c @@ -22,8 +22,6 @@ int force_iommu __read_mostly = 1; int force_iommu __read_mostly; #endif -int iommu_pass_through; - static int __init pci_iommu_init(void) { if (iommu_detected) -- cgit v1.2.3