Re: [PATCH 15/24] C6X: cache control
From: Arnd Bergmann <arnd@arndb.de>
Date: 2011-08-09 16:53:57
On Monday 08 August 2011, Mark Salter wrote:
+/* + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter [off-list ref] + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/io.h> + +#include <asm/cache.h> +#include <asm/machdep.h> +#include <asm/soc.h> + +#define IMCR_BASE 0x01840000
Please don't hardcode MMIO regions like this. You should have the base address in the device tree and use of_iomap() like you do in some other cases. If you need this really early, you might need to
+static void cache_block_operation_wait(unsigned int wc_reg)
+{
+ /* Wait for completion */
+ while (imcr_get(wc_reg))
+ ;
+}When you have blocking loops like this one, better use cpu_relax() in the loop body. I realize that that is currently a nop, but it's better style to use it anyway.
+/*
+ * Generic function to perform a block cache operation as
+ * invalidate or writeback/invalidate
+ */
+static void cache_block_operation(unsigned int *start,
+ unsigned int *end,
+ unsigned int bar_reg,
+ unsigned int wc_reg)
+{
+ unsigned long flags;
+ unsigned int wcnt =
+ (L2_CACHE_ALIGN_CNT((unsigned int) end)
+ - L2_CACHE_ALIGN_LOW((unsigned int) start)) >> 2;
+ unsigned int wc = 0;
+
+ for (; wcnt; wcnt -= wc, start += wc) {
+loop:
+ local_irq_save(flags);
+
+ /*
+ * If another cache operation is occuring
+ */
+ if (unlikely(imcr_get(wc_reg))) {
+ local_irq_restore(flags);
+
+ /* Wait for previous operation completion */
+ cache_block_operation_wait(wc_reg);
+
+ /* Try again */
+ goto loop;
+ }
+
+ imcr_set(bar_reg, L2_CACHE_ALIGN_LOW((unsigned int) start));
+
+ if (wcnt > 0xffff)
+ wc = 0xffff;
+ else
+ wc = wcnt;
+
+ /* Set word count value in the WC register */
+ imcr_set(wc_reg, wc & 0xffff);
+
+ local_irq_restore(flags);
+
+ /* Wait for completion */
+ cache_block_operation_wait(wc_reg);
+ }
+}Doesn't this need a proper spinlock instead of a local_irq_save? You should try to write code with SMP in mind, even if the current usage is UP only. The resulting object code is the same on UP.
+ * L1P global-invalidate all
+ */
+void L1P_cache_global_invalidate(void)
+{
+ unsigned int set = 1;
+ imcr_set(IMCR_L1PINV, set);
+ while (imcr_get(IMCR_L1PINV) & 1)
+ ;
+}
+
+/*
+ * L1D global-invalidate all
+ *
+ * Warning: this operation causes all updated data in L1D to
+ * be discarded rather than written back to the lower levels of
+ * memory
+ */
+void L1D_cache_global_invalidate(void)
+{
+ unsigned int set = 1;
+ imcr_set(IMCR_L1DINV, set);
+ while (imcr_get(IMCR_L1DINV) & 1)
+ ;
+}
+
+void L1D_cache_global_writeback(void)
+{
+ unsigned int set = 1;
+ imcr_set(IMCR_L1DWB, set);
+ while (imcr_get(IMCR_L1DWB) & 1)
+ ;
+}
+
+void L1D_cache_global_writeback_invalidate(void)
+{
+ unsigned int set = 1;
+ imcr_set(IMCR_L1DWBINV, set);
+ while (imcr_get(IMCR_L1DWBINV) & 1)
+ ;
+}cpu_relax() again. Arnd