From patchwork Tue Jan 16 16:20:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eugeniy Paltsev X-Patchwork-Id: 861747 X-Patchwork-Delegate: alexey.brodkin@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 3zLb8F72xdz9ryk for ; Wed, 17 Jan 2018 03:21:49 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id 9EA7BC21D5D; Tue, 16 Jan 2018 16:21:13 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.0 required=5.0 tests=RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 3912AC21E4A; Tue, 16 Jan 2018 16:20:54 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id B8B38C21D5D; Tue, 16 Jan 2018 16:20:50 +0000 (UTC) Received: from smtprelay.synopsys.com (smtprelay.synopsys.com [198.182.60.111]) by lists.denx.de (Postfix) with ESMTPS id 199C8C21C2F for ; Tue, 16 Jan 2018 16:20:50 +0000 (UTC) Received: from mailhost.synopsys.com (mailhost1.synopsys.com [10.12.238.239]) by smtprelay.synopsys.com (Postfix) with ESMTP id 7E17410C01A5 for ; Tue, 16 Jan 2018 08:20:48 -0800 (PST) Received: from mailhost.synopsys.com (localhost [127.0.0.1]) by mailhost.synopsys.com (Postfix) with ESMTP id D8603739; Tue, 16 Jan 2018 08:20:47 -0800 (PST) Received: from localhost.internal.synopsys.com (unknown [10.121.3.12]) by mailhost.synopsys.com (Postfix) with ESMTP id 553FE706; Tue, 16 Jan 2018 08:20:46 -0800 (PST) From: Eugeniy Paltsev To: uboot-snps-arc@synopsys.com Date: Tue, 16 Jan 2018 19:20:27 +0300 Message-Id: <20180116162029.9258-2-Eugeniy.Paltsev@synopsys.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20180116162029.9258-1-Eugeniy.Paltsev@synopsys.com> References: <20180116162029.9258-1-Eugeniy.Paltsev@synopsys.com> Cc: u-boot@lists.denx.de, Alexey Brodkin , Eugeniy Paltsev Subject: [U-Boot] [PATCH 2/4] ARC: ARCv2: CACHE: fix work without IOC X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Previous slc_line_op implementation is broken. It was never tested/used as we use u-boot with IOC enabled. So if we disable IOC we will get a lot of errors while using DMA peripherals. Fix it by replacingi broken slc_line_op with slc region operations (which are used in linux kernel) Main changes: * Replace __slc_line_op (per line operations) by __slc_rgn_op (region operations) Implementation from 4.14 linux kernel. * Rework __slc_entire_op to get rid of __after_slc_op and __before_slc_op functions. Implementation from 4.14 linux kernel with flush fix (flush only instead of flush-n-inv when OP_FLUSH is used) * Add SLC invalidation to invalidate_icache_all function. * Add (start >= end) check to invalidate_dcache_range and flush_dcache_range as some buggy drivers pass region start == end. Signed-off-by: Eugeniy Paltsev --- arch/arc/include/asm/arcregs.h | 4 + arch/arc/lib/cache.c | 167 +++++++++++++++++++++++------------------ 2 files changed, 97 insertions(+), 74 deletions(-) diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index 53e83c7..67f4163 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -63,6 +63,10 @@ #define ARC_AUX_SLC_INVALIDATE 0x905 #define ARC_AUX_SLC_IVDL 0x910 #define ARC_AUX_SLC_FLDL 0x912 +#define ARC_AUX_SLC_RGN_START 0x914 +#define ARC_AUX_SLC_RGN_START1 0x915 +#define ARC_AUX_SLC_RGN_END 0x916 +#define ARC_AUX_SLC_RGN_END1 0x917 #define ARC_BCR_CLUSTER 0xcf /* MMU Management regs */ diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c index 0a41dc4..a6bbe3c 100644 --- a/arch/arc/lib/cache.c +++ b/arch/arc/lib/cache.c @@ -20,12 +20,17 @@ #define DC_CTRL_INV_MODE_FLUSH (1 << 6) #define DC_CTRL_FLUSH_STATUS (1 << 8) #define CACHE_VER_NUM_MASK 0xF -#define SLC_CTRL_SB (1 << 2) #define OP_INV 0x1 #define OP_FLUSH 0x2 #define OP_INV_IC 0x3 +/* Bit val in SLC_CONTROL */ +#define SLC_CTRL_DIS 0x001 +#define SLC_CTRL_IM 0x040 +#define SLC_CTRL_BUSY 0x100 +#define SLC_CTRL_RGN_OP_INV 0x200 + /* * By default that variable will fall into .bss section. * But .bss section is not relocated and so it will be initilized before @@ -68,87 +73,88 @@ void read_decode_mmu_bcr(void) #endif /* (CONFIG_ARC_MMU_VER >= 4) */ } -static unsigned int __before_slc_op(const int op) +static void __slc_entire_op(const int op) { - unsigned int reg = reg; + unsigned int ctrl; - if (op == OP_INV) { - /* - * IM is set by default and implies Flush-n-inv - * Clear it here for vanilla inv - */ - reg = read_aux_reg(ARC_AUX_SLC_CTRL); - write_aux_reg(ARC_AUX_SLC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); - } + ctrl = read_aux_reg(ARC_AUX_SLC_CTRL); - return reg; -} - -static void __after_slc_op(const int op, unsigned int reg) -{ - if (op & OP_FLUSH) { /* flush / flush-n-inv both wait */ - /* - * Make sure "busy" bit reports correct status, - * see STAR 9001165532 - */ - read_aux_reg(ARC_AUX_SLC_CTRL); - while (read_aux_reg(ARC_AUX_SLC_CTRL) & - DC_CTRL_FLUSH_STATUS) - ; - } - - /* Switch back to default Invalidate mode */ - if (op == OP_INV) - write_aux_reg(ARC_AUX_SLC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); -} - -static inline void __slc_line_loop(unsigned long paddr, unsigned long sz, - const int op) -{ - unsigned int aux_cmd; - int num_lines; + if (!(op & OP_FLUSH)) /* i.e. OP_INV */ + ctrl &= ~SLC_CTRL_IM; /* clear IM: Disable flush before Inv */ + else + ctrl |= SLC_CTRL_IM; -#define SLC_LINE_MASK (~(slc_line_sz - 1)) + write_aux_reg(ARC_AUX_SLC_CTRL, ctrl); - aux_cmd = op & OP_INV ? ARC_AUX_SLC_IVDL : ARC_AUX_SLC_FLDL; + if (op & OP_INV) /* Inv or flush-n-inv use same cmd reg */ + write_aux_reg(ARC_AUX_SLC_INVALIDATE, 0x1); + else + write_aux_reg(ARC_AUX_SLC_FLUSH, 0x1); - sz += paddr & ~SLC_LINE_MASK; - paddr &= SLC_LINE_MASK; + /* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */ + read_aux_reg(ARC_AUX_SLC_CTRL); - num_lines = DIV_ROUND_UP(sz, slc_line_sz); + /* Important to wait for flush to complete */ + while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY); +} - while (num_lines-- > 0) { - write_aux_reg(aux_cmd, paddr); - paddr += slc_line_sz; - } +static void slc_upper_region_init(void) +{ + /* + * ARC_AUX_SLC_RGN_END1 and ARC_AUX_SLC_RGN_START1 are always == 0 + * as we don't use PAE40. + */ + write_aux_reg(ARC_AUX_SLC_RGN_END1, 0); + write_aux_reg(ARC_AUX_SLC_RGN_START1, 0); } -static inline void __slc_entire_op(const int cacheop) +static void __slc_rgn_op(unsigned long paddr, unsigned long sz, const int op) { - int aux; - unsigned int ctrl_reg = __before_slc_op(cacheop); + unsigned int ctrl; + unsigned long end; + + /* + * The Region Flush operation is specified by CTRL.RGN_OP[11..9] + * - b'000 (default) is Flush, + * - b'001 is Invalidate if CTRL.IM == 0 + * - b'001 is Flush-n-Invalidate if CTRL.IM == 1 + */ + ctrl = read_aux_reg(ARC_AUX_SLC_CTRL); + + /* Don't rely on default value of IM bit */ + if (!(op & OP_FLUSH)) /* i.e. OP_INV */ + ctrl &= ~SLC_CTRL_IM; /* clear IM: Disable flush before Inv */ + else + ctrl |= SLC_CTRL_IM; - if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ - aux = ARC_AUX_SLC_INVALIDATE; + if (op & OP_INV) + ctrl |= SLC_CTRL_RGN_OP_INV; /* Inv or flush-n-inv */ else - aux = ARC_AUX_SLC_FLUSH; + ctrl &= ~SLC_CTRL_RGN_OP_INV; - write_aux_reg(aux, 0x1); + write_aux_reg(ARC_AUX_SLC_CTRL, ctrl); - __after_slc_op(cacheop, ctrl_reg); -} + /* + * Lower bits are ignored, no need to clip + * END needs to be setup before START (latter triggers the operation) + * END can't be same as START, so add (l2_line_sz - 1) to sz + */ + end = paddr + sz + slc_line_sz - 1; -static inline void __slc_line_op(unsigned long paddr, unsigned long sz, - const int cacheop) -{ - unsigned int ctrl_reg = __before_slc_op(cacheop); - __slc_line_loop(paddr, sz, cacheop); - __after_slc_op(cacheop, ctrl_reg); + /* + * Upper addresses (ARC_AUX_SLC_RGN_END1 and ARC_AUX_SLC_RGN_START1) + * are always == 0 as we don't use PAE40, so we only setup lower ones + * (ARC_AUX_SLC_RGN_END and ARC_AUX_SLC_RGN_START) + */ + write_aux_reg(ARC_AUX_SLC_RGN_END, end); + write_aux_reg(ARC_AUX_SLC_RGN_START, paddr); + + /* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */ + read_aux_reg(ARC_AUX_SLC_CTRL); + + while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY); } -#else -#define __slc_entire_op(cacheop) -#define __slc_line_op(paddr, sz, cacheop) -#endif +#endif /* CONFIG_ISA_ARCV2 */ #ifdef CONFIG_ISA_ARCV2 static void read_decode_cache_bcr_arcv2(void) @@ -272,7 +278,15 @@ void cache_init(void) } read_decode_mmu_bcr(); -#endif + + /* + * ARC_AUX_SLC_RGN_START1 and ARC_AUX_SLC_RGN_END1 register exist + * only if PAE exists in current HW. So we had to check pae_exist + * before using them. + */ + if (slc_exists && pae_exists) + slc_upper_region_init(); +#endif /* CONFIG_ISA_ARCV2 */ } int icache_status(void) @@ -300,7 +314,6 @@ void icache_disable(void) IC_CTRL_CACHE_DISABLE); } -#ifndef CONFIG_SYS_DCACHE_OFF void invalidate_icache_all(void) { /* Any write to IC_IVIC register triggers invalidation of entire I$ */ @@ -315,12 +328,12 @@ void invalidate_icache_all(void) __builtin_arc_nop(); read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */ } -} -#else -void invalidate_icache_all(void) -{ -} + +#ifdef CONFIG_ISA_ARCV2 + if (slc_exists) + __slc_entire_op(OP_INV); #endif +} int dcache_status(void) { @@ -447,6 +460,9 @@ static inline void __dc_line_op(unsigned long paddr, unsigned long sz, void invalidate_dcache_range(unsigned long start, unsigned long end) { + if (start >= end) + return; + #ifdef CONFIG_ISA_ARCV2 if (!ioc_exists) #endif @@ -454,12 +470,15 @@ void invalidate_dcache_range(unsigned long start, unsigned long end) #ifdef CONFIG_ISA_ARCV2 if (slc_exists && !ioc_exists) - __slc_line_op(start, end - start, OP_INV); + __slc_rgn_op(start, end - start, OP_INV); #endif } void flush_dcache_range(unsigned long start, unsigned long end) { + if (start >= end) + return; + #ifdef CONFIG_ISA_ARCV2 if (!ioc_exists) #endif @@ -467,7 +486,7 @@ void flush_dcache_range(unsigned long start, unsigned long end) #ifdef CONFIG_ISA_ARCV2 if (slc_exists && !ioc_exists) - __slc_line_op(start, end - start, OP_FLUSH); + __slc_rgn_op(start, end - start, OP_FLUSH); #endif }