Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932799AbdLRP31 (ORCPT ); Mon, 18 Dec 2017 10:29:27 -0500 Received: from smtprelay.synopsys.com ([198.182.47.9]:42800 "EHLO smtprelay.synopsys.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758577AbdLRP3Z (ORCPT ); Mon, 18 Dec 2017 10:29:25 -0500 From: Alexey Brodkin To: linux-snps-arc@lists.infradead.org Cc: linux-kernel@vger.kernel.org, Vineet Gupta , Alexey Brodkin Subject: [PATCH v2] ARC: Force disable IOC if we don't want to use it Date: Mon, 18 Dec 2017 18:29:20 +0300 Message-Id: <20171218152920.4696-1-abrodkin@synopsys.com> X-Mailer: git-send-email 2.14.3 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 2698 Lines: 85 If software that was executed before Linux kernel [like boot-ROM or bootloader] enabled IOC but we'd like to not use it [mostly for debugging of weird DMA issues] we essentially need to disable IOC. So we do here. Note we will only disable IOC if "ioc_enable" variable is force set to 0. As of today that's only possible either before building right in arch/arc/mm/cache.c or via debugger on target reght before execution of the kernel starts. We may make "ioc_enable" a boot-parameter later though. Signed-off-by: Alexey Brodkin --- Chnages in v2: * Now disabling really works as in v1 we never entered disabling code if ioc_enable=0. * Do nothing if IOC was not enabled arch/arc/mm/cache.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c index 69f77c113875..9cadf7b779ed 100644 --- a/arch/arc/mm/cache.c +++ b/arch/arc/mm/cache.c @@ -1186,6 +1186,40 @@ noinline void __init arc_ioc_setup(void) __dc_enable(); } +/* + * Disabling of IOC is quite a tricky action 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 + * in boot-ROM, bootloader etc but if we do need to disable it in Linux kernel + * it should be done as early as possible and made by master core while all + * slaves aren't active. + * + */ +noinline void __init arc_ioc_disable(void) +{ + /* Exit if IOC was never enabled */ + if (!read_aux_reg(ARC_REG_IO_COH_ENABLE)) + return; + + /* Flush + invalidate + disable L1 dcache */ + __dc_disable(); + + /* Flush + invalidate SLC */ + if (read_aux_reg(ARC_REG_SLC_BCR)) + slc_entire_op(OP_FLUSH_N_INV); + + write_aux_reg(ARC_REG_IO_COH_ENABLE, 0); + + /* Re-enable L1 dcache */ + __dc_enable(); +} + /* * Cache related boot time checks/setups only needed on master CPU: * - Geometry checks (kernel build and hardware agree: e.g. L1_CACHE_BYTES) @@ -1247,8 +1281,12 @@ 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) - arc_ioc_setup(); + if (is_isa_arcv2()) { + if (ioc_enable) + arc_ioc_setup(); + else if (ioc_exists) + arc_ioc_disable(); + } if (is_isa_arcv2() && ioc_enable) { __dma_cache_wback_inv = __dma_cache_wback_inv_ioc; -- 2.14.3