[v2] ARC: IOC: panic if kernel was started with previously enabled IOC

Message ID 20181030085421.7657-1-Eugeniy.Paltsev@synopsys.com
State New
Headers show
Series
  • [v2] ARC: IOC: panic if kernel was started with previously enabled IOC
Related show

Commit Message

Eugeniy Paltsev Oct. 30, 2018, 8:54 a.m.
If IOC was already enabled (due to bootloader) it technically needs to
be reconfigured with aperture base,size corresponding to Linux memory
map which will certainly be different than uboot's. But disabling and
reenabling IOC when DMA might be potentially active is tricky business.
To avoid random memory issues later, just panic here and ask user to
upgrade bootloader to one which doesn't enable IOC.

This was actually seen as issue on some of the HSDK board with a version
of uboot which enabled IOC. There were random issues later with starting
of X or peripherals etc.

Also while I'm at it, replace hardcoded bits in ARC_REG_IO_COH_PARTIAL
and ARC_REG_IO_COH_ENABLE registers by definitions.

Inspired by: https://lkml.org/lkml/2018/1/19/557
Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
---
Changes v1->v2:
 * Fix regression: check for IOC existence before accessing to any IOC
   register.

 arch/arc/include/asm/cache.h |  2 ++
 arch/arc/mm/cache.c          | 25 ++++++++++++++++++++++---
 2 files changed, 24 insertions(+), 3 deletions(-)

Comments

Vineet Gupta Oct. 30, 2018, 4:05 p.m. | #1
On 10/30/18 1:54 AM, Eugeniy Paltsev wrote:
> If IOC was already enabled (due to bootloader) it technically needs to
> be reconfigured with aperture base,size corresponding to Linux memory
> map which will certainly be different than uboot's. But disabling and
> reenabling IOC when DMA might be potentially active is tricky business.
> To avoid random memory issues later, just panic here and ask user to
> upgrade bootloader to one which doesn't enable IOC.
>
> This was actually seen as issue on some of the HSDK board with a version
> of uboot which enabled IOC. There were random issues later with starting
> of X or peripherals etc.
>
> Also while I'm at it, replace hardcoded bits in ARC_REG_IO_COH_PARTIAL
> and ARC_REG_IO_COH_ENABLE registers by definitions.
>
> Inspired by: https://lkml.org/lkml/2018/1/19/557
> Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
> ---
> Changes v1->v2:
>  * Fix regression: check for IOC existence before accessing to any IOC
>    register.
>
...
...
>  		arc_slc_disable();
>  
> -	if (is_isa_arcv2() && ioc_enable)
> +	if (is_isa_arcv2() && ioc_exists)
>  		arc_ioc_setup();

Folded this hunk into existing patch in for-curr.

Thx,
-Vineet

Patch

diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h
index ff7d3232764a..f393b663413e 100644
--- a/arch/arc/include/asm/cache.h
+++ b/arch/arc/include/asm/cache.h
@@ -113,7 +113,9 @@  extern unsigned long perip_base, perip_end;
 
 /* IO coherency related Auxiliary registers */
 #define ARC_REG_IO_COH_ENABLE	0x500
+#define ARC_IO_COH_ENABLE_BIT	BIT(0)
 #define ARC_REG_IO_COH_PARTIAL	0x501
+#define ARC_IO_COH_PARTIAL_BIT	BIT(0)
 #define ARC_REG_IO_COH_AP0_BASE	0x508
 #define ARC_REG_IO_COH_AP0_SIZE	0x509
 
diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c
index f2701c13a66b..1b913c90676a 100644
--- a/arch/arc/mm/cache.c
+++ b/arch/arc/mm/cache.c
@@ -1144,6 +1144,25 @@  noinline void __init arc_ioc_setup(void)
 {
 	unsigned int ioc_base, mem_sz;
 
+	/*
+	 * Disabling and reconfiguring of IOC are quite a tricky actions because
+	 * nobody knows what happens if there're IOC-ahndled tarnsactions in
+	 * flight when we're disabling IOC.
+	 *
+	 * And the problem is external DMA masters [that were initialized and
+	 * set in a bootlaoder that was executed before we got here] might
+	 * continue to send data to memory even at this point and we have
+	 * no way to prevent that.
+	 *
+	 * That said it's much safer to not enable IOC at all anywhere before
+	 * Linux kernel.
+	 */
+	if (read_aux_reg(ARC_REG_IO_COH_ENABLE) & ARC_IO_COH_ENABLE_BIT)
+		panic("kernel was started with previously enabled IOC!\n");
+
+	if (!ioc_enable)
+		return;
+
 	/*
 	 * As for today we don't support both IOC and ZONE_HIGHMEM enabled
 	 * simultaneously. This happens because as of today IOC aperture covers
@@ -1187,8 +1206,8 @@  noinline void __init arc_ioc_setup(void)
 		panic("IOC Aperture start must be aligned to the size of the aperture");
 
 	write_aux_reg(ARC_REG_IO_COH_AP0_BASE, ioc_base >> 12);
-	write_aux_reg(ARC_REG_IO_COH_PARTIAL, 1);
-	write_aux_reg(ARC_REG_IO_COH_ENABLE, 1);
+	write_aux_reg(ARC_REG_IO_COH_PARTIAL, ARC_IO_COH_PARTIAL_BIT);
+	write_aux_reg(ARC_REG_IO_COH_ENABLE, ARC_IO_COH_ENABLE_BIT);
 
 	/* Re-enable L1 dcache */
 	__dc_enable();
@@ -1265,7 +1284,7 @@  void __init arc_cache_init_master(void)
 	if (is_isa_arcv2() && l2_line_sz && !slc_enable)
 		arc_slc_disable();
 
-	if (is_isa_arcv2() && ioc_enable)
+	if (is_isa_arcv2() && ioc_exists)
 		arc_ioc_setup();
 
 	if (is_isa_arcv2() && l2_line_sz && slc_enable) {