+++ /dev/null
-/*
- * arch/ubicom32/mach-common/cachectl.c
- * Architecture cache control support
- *
- * (C) Copyright 2009, Ubicom, Inc.
- *
- * This file is part of the Ubicom32 Linux Kernel Port.
- *
- * The Ubicom32 Linux Kernel Port is free software: you can redistribute
- * it and/or modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 2 of the
- * License, or (at your option) any later version.
- *
- * The Ubicom32 Linux Kernel Port is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Ubicom32 Linux Kernel Port. If not,
- * see <http://www.gnu.org/licenses/>.
- *
- * Ubicom32 implementation derived from (with many thanks):
- * arch/m68knommu
- * arch/blackfin
- * arch/parisc
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <asm/cachectl.h>
-
-/*
- * The write queue flush procedure in mem_cache_control needs to make
- * DCACHE_WRITE_QUEUE_LENGTH writes to DDR (not OCM). Here we reserve some
- * memory for this operation.
- * Allocate array of cache lines of least DCACHE_WRITE_QUEUE_LENGTH + 1 words in
- * length rounded up to the nearest cache line.
- */
-#define CACHE_WRITE_QUEUE_FLUSH_AREA_SIZE \
- ALIGN(sizeof(int) * (DCACHE_WRITE_QUEUE_LENGTH + 1), CACHE_LINE_SIZE)
-
-static char cache_write_queue_flush_area[CACHE_WRITE_QUEUE_FLUSH_AREA_SIZE]
- __attribute__((aligned(CACHE_LINE_SIZE)));
-
-/*
- * ONE_CCR_ADDR_OP is a helper macro that executes a single CCR operation.
- */
-#define ONE_CCR_ADDR_OP(cc, op_addr, op) \
- do { \
- asm volatile ( \
- " btst "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_VALID)" \n\t" \
- " jmpne.f .-4 \n\t" \
- " move.4 "D(CCR_ADDR)"(%0), %1 \n\t" \
- " move.1 "D(CCR_CTRL+3)"(%0), %2 \n\t" \
- " bset "D(CCR_CTRL)"(%0), "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_VALID)" \n\t" \
- " cycles 2 \n\t" \
- " btst "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_DONE)" \n\t" \
- " jmpeq.f .-4 \n\t" \
- : \
- : "a"(cc), "r"(op_addr), "r"(op & 0xff) \
- : "cc" \
- ); \
- } while (0)
-
-/*
- * mem_cache_control()
- * Special cache control operation
- */
-void mem_cache_control(unsigned long cc, unsigned long begin_addr,
- unsigned long end_addr, unsigned long op)
-{
- unsigned long op_addr;
- int dccr = cc == DCCR_BASE;
- if (dccr && op == CCR_CTRL_FLUSH_ADDR) {
- /*
- * We ensure all previous writes have left the data cache write
- * queue by sending DCACHE_WRITE_QUEUE_LENGTH writes (to
- * different words) down the queue. If this is not done it's
- * possible that the data we are trying to flush hasn't even
- * entered the data cache.
- * The +1 ensure that the final 'flush' is actually a flush.
- */
- int *flush_area = (int *)cache_write_queue_flush_area;
- asm volatile(
- " .rept "D(DCACHE_WRITE_QUEUE_LENGTH + 1)" \n\t"
- " move.4 (%0)4++, d0 \n\t"
- " .endr \n\t"
- : "+a"(flush_area)
- );
- }
-
- if (dccr)
- UBICOM32_LOCK(DCCR_LOCK_BIT);
- else
- UBICOM32_LOCK(ICCR_LOCK_BIT);
-
- /*
- * Calculate the cache lines we need to operate on that include
- * begin_addr though end_addr.
- */
- begin_addr = begin_addr & ~(CACHE_LINE_SIZE - 1);
- end_addr = (end_addr + CACHE_LINE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1);
- op_addr = begin_addr;
-
- do {
- ONE_CCR_ADDR_OP(cc, op_addr, op);
- op_addr += CACHE_LINE_SIZE;
- } while (likely(op_addr < end_addr));
-
- if (dccr && op == CCR_CTRL_FLUSH_ADDR) {
- /*
- * It turns out that when flushing the data cache the last flush
- * isn't actually complete at this point. This is because there
- * is another write buffer on the DDR side of the cache that is
- * arbitrated with the I-Cache.
- *
- * The only foolproof method that ensures that the last data
- * cache flush *actually* completed is to do another flush on a
- * dirty cache line. This flush will block until the DDR write
- * buffer is empty.
- *
- * Rather than creating a another dirty cache line, we use the
- * flush_area above as we know that it is dirty from previous
- * writes.
- */
- ONE_CCR_ADDR_OP(cc, cache_write_queue_flush_area, op);
- }
-
- if (dccr)
- UBICOM32_UNLOCK(DCCR_LOCK_BIT);
- else
- UBICOM32_UNLOCK(ICCR_LOCK_BIT);
-
-}
-EXPORT_SYMBOL(mem_cache_control);