Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/arch/microblaze/kernel/cpu/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 16 kB image not shown  

Quelle  cache.c   Sprache: C

 
/*
 * Cache control for MicroBlaze cache memories
 *
 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
 * Copyright (C) 2007-2009 PetaLogix
 * Copyright (C) 2007-2009 John Williams <john.williams@petalogix.com>
 *
 * This file is subject to the terms and conditions of the GNU General
 * Public License. See the file COPYING in the main directory of this
 * archive for more details.
 */


#include <asm/cacheflush.h>
#include <linux/cache.h>
#include <asm/cpuinfo.h>
#include <asm/pvr.h>

static inline void __enable_icache_msr(void)
{
 __asm__ __volatile__ (" msrset r0, %0;" \
    "nop;"   \
   : : "i" (MSR_ICE) : "memory");
}

static inline void __disable_icache_msr(void)
{
 __asm__ __volatile__ (" msrclr r0, %0;" \
    "nop;"   \
   : : "i" (MSR_ICE) : "memory");
}

static inline void __enable_dcache_msr(void)
{
 __asm__ __volatile__ (" msrset r0, %0;" \
    "nop;"   \
   : : "i" (MSR_DCE) : "memory");
}

static inline void __disable_dcache_msr(void)
{
 __asm__ __volatile__ (" msrclr r0, %0;" \
    "nop; "   \
   : : "i" (MSR_DCE) : "memory");
}

static inline void __enable_icache_nomsr(void)
{
 __asm__ __volatile__ (" mfs r12, rmsr;" \
    "nop;"   \
    "ori r12, r12, %0;" \
    "mts rmsr, r12;" \
    "nop;"   \
   : : "i" (MSR_ICE) : "memory""r12");
}

static inline void __disable_icache_nomsr(void)
{
 __asm__ __volatile__ (" mfs r12, rmsr;" \
    "nop;"   \
    "andi r12, r12, ~%0;" \
    "mts rmsr, r12;" \
    "nop;"   \
   : : "i" (MSR_ICE) : "memory""r12");
}

static inline void __enable_dcache_nomsr(void)
{
 __asm__ __volatile__ (" mfs r12, rmsr;" \
    "nop;"   \
    "ori r12, r12, %0;" \
    "mts rmsr, r12;" \
    "nop;"   \
   : : "i" (MSR_DCE) : "memory""r12");
}

static inline void __disable_dcache_nomsr(void)
{
 __asm__ __volatile__ (" mfs r12, rmsr;" \
    "nop;"   \
    "andi r12, r12, ~%0;" \
    "mts rmsr, r12;" \
    "nop;"   \
   : : "i" (MSR_DCE) : "memory""r12");
}


/* Helper macro for computing the limits of cache range loops
 *
 * End address can be unaligned which is OK for C implementation.
 * ASM implementation align it in ASM macros
 */

#define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size) \
do {         \
 int align = ~(cache_line_length - 1);    \
 if (start <  UINT_MAX - cache_size)    \
  end = min(start + cache_size, end);   \
 start &= align;       \
while (0)

/*
 * Helper macro to loop over the specified cache_size/line_length and
 * execute 'op' on that cacheline
 */

#define CACHE_ALL_LOOP(cache_size, line_length, op)   \
do {         \
 unsigned int len = cache_size - line_length;   \
 int step = -line_length;     \
 WARN_ON(step >= 0);      \
         \
 __asm__ __volatile__ (" 1: " #op " %0, r0;"  \
     "bgtid %0, 1b;"  \
     "addk %0, %0, %1;"  \
     : : "r" (len), "r" (step) \
     : "memory");   \
while (0)

/* Used for wdc.flush/clear which can use rB for offset which is not possible
 * to use for simple wdc or wic.
 *
 * start address is cache aligned
 * end address is not aligned, if end is aligned then I have to subtract
 * cacheline length because I can't flush/invalidate the next cacheline.
 * If is not, I align it because I will flush/invalidate whole line.
 */

#define CACHE_RANGE_LOOP_2(start, end, line_length, op)   \
do {         \
 int step = -line_length;     \
 int align = ~(line_length - 1);     \
 int count;       \
 end = ((end & align) == end) ? end - line_length : end & align; \
 count = end - start;      \
 WARN_ON(count < 0);      \
         \
 __asm__ __volatile__ (" 1: " #op " %0, %1;"  \
     "bgtid %1, 1b;"  \
     "addk %1, %1, %2;"  \
     : : "r" (start), "r" (count), \
     "r" (step) : "memory");  \
while (0)

/* It is used only first parameter for OP - for wic, wdc */
#define CACHE_RANGE_LOOP_1(start, end, line_length, op)   \
do {         \
 unsigned int volatile temp = 0;      \
 unsigned int align = ~(line_length - 1);     \
 end = ((end & align) == end) ? end - line_length : end & align; \
 WARN_ON(end < start);     \
         \
 __asm__ __volatile__ (" 1: " #op " %1, r0;"  \
     "cmpu %0, %1, %2;"  \
     "bgtid %0, 1b;"  \
     "addk %1, %1, %3;"  \
    : : "r" (temp), "r" (start), "r" (end), \
     "r" (line_length) : "memory"); \
while (0)

#define ASM_LOOP

static void __flush_icache_range_msr_irq(unsigned long start, unsigned long end)
{
 unsigned long flags;
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
    (unsigned int)start, (unsigned int) end);

 CACHE_LOOP_LIMITS(start, end,
   cpuinfo.icache_line_length, cpuinfo.icache_size);

 local_irq_save(flags);
 __disable_icache_msr();

#ifdef ASM_LOOP
 CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
#else
 for (i = start; i < end; i += cpuinfo.icache_line_length)
  __asm__ __volatile__ ("wic %0, r0;" \
    : : "r" (i));
#endif
 __enable_icache_msr();
 local_irq_restore(flags);
}

static void __flush_icache_range_nomsr_irq(unsigned long start,
    unsigned long end)
{
 unsigned long flags;
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
    (unsigned int)start, (unsigned int) end);

 CACHE_LOOP_LIMITS(start, end,
   cpuinfo.icache_line_length, cpuinfo.icache_size);

 local_irq_save(flags);
 __disable_icache_nomsr();

#ifdef ASM_LOOP
 CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
#else
 for (i = start; i < end; i += cpuinfo.icache_line_length)
  __asm__ __volatile__ ("wic %0, r0;" \
    : : "r" (i));
#endif

 __enable_icache_nomsr();
 local_irq_restore(flags);
}

static void __flush_icache_range_noirq(unsigned long start,
    unsigned long end)
{
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
    (unsigned int)start, (unsigned int) end);

 CACHE_LOOP_LIMITS(start, end,
   cpuinfo.icache_line_length, cpuinfo.icache_size);
#ifdef ASM_LOOP
 CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
#else
 for (i = start; i < end; i += cpuinfo.icache_line_length)
  __asm__ __volatile__ ("wic %0, r0;" \
    : : "r" (i));
#endif
}

static void __flush_icache_all_msr_irq(void)
{
 unsigned long flags;
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s\n", __func__);

 local_irq_save(flags);
 __disable_icache_msr();
#ifdef ASM_LOOP
 CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
#else
 for (i = 0; i < cpuinfo.icache_size;
   i += cpuinfo.icache_line_length)
   __asm__ __volatile__ ("wic %0, r0;" \
     : : "r" (i));
#endif
 __enable_icache_msr();
 local_irq_restore(flags);
}

static void __flush_icache_all_nomsr_irq(void)
{
 unsigned long flags;
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s\n", __func__);

 local_irq_save(flags);
 __disable_icache_nomsr();
#ifdef ASM_LOOP
 CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
#else
 for (i = 0; i < cpuinfo.icache_size;
   i += cpuinfo.icache_line_length)
   __asm__ __volatile__ ("wic %0, r0;" \
     : : "r" (i));
#endif
 __enable_icache_nomsr();
 local_irq_restore(flags);
}

static void __flush_icache_all_noirq(void)
{
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s\n", __func__);
#ifdef ASM_LOOP
 CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
#else
 for (i = 0; i < cpuinfo.icache_size;
   i += cpuinfo.icache_line_length)
   __asm__ __volatile__ ("wic %0, r0;" \
     : : "r" (i));
#endif
}

static void __invalidate_dcache_all_msr_irq(void)
{
 unsigned long flags;
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s\n", __func__);

 local_irq_save(flags);
 __disable_dcache_msr();
#ifdef ASM_LOOP
 CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
#else
 for (i = 0; i < cpuinfo.dcache_size;
   i += cpuinfo.dcache_line_length)
   __asm__ __volatile__ ("wdc %0, r0;" \
     : : "r" (i));
#endif
 __enable_dcache_msr();
 local_irq_restore(flags);
}

static void __invalidate_dcache_all_nomsr_irq(void)
{
 unsigned long flags;
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s\n", __func__);

 local_irq_save(flags);
 __disable_dcache_nomsr();
#ifdef ASM_LOOP
 CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
#else
 for (i = 0; i < cpuinfo.dcache_size;
   i += cpuinfo.dcache_line_length)
   __asm__ __volatile__ ("wdc %0, r0;" \
     : : "r" (i));
#endif
 __enable_dcache_nomsr();
 local_irq_restore(flags);
}

static void __invalidate_dcache_all_noirq_wt(void)
{
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s\n", __func__);
#ifdef ASM_LOOP
 CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
#else
 for (i = 0; i < cpuinfo.dcache_size;
   i += cpuinfo.dcache_line_length)
   __asm__ __volatile__ ("wdc %0, r0;" \
     : : "r" (i));
#endif
}

/*
 * FIXME It is blindly invalidation as is expected
 * but can't be called on noMMU in microblaze_cache_init below
 *
 * MS: noMMU kernel won't boot if simple wdc is used
 * The reason should be that there are discared data which kernel needs
 */

static void __invalidate_dcache_all_wb(void)
{
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s\n", __func__);
#ifdef ASM_LOOP
 CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
     wdc);
#else
 for (i = 0; i < cpuinfo.dcache_size;
   i += cpuinfo.dcache_line_length)
   __asm__ __volatile__ ("wdc %0, r0;" \
     : : "r" (i));
#endif
}

static void __invalidate_dcache_range_wb(unsigned long start,
      unsigned long end)
{
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
    (unsigned int)start, (unsigned int) end);

 CACHE_LOOP_LIMITS(start, end,
   cpuinfo.dcache_line_length, cpuinfo.dcache_size);
#ifdef ASM_LOOP
 CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear);
#else
 for (i = start; i < end; i += cpuinfo.dcache_line_length)
  __asm__ __volatile__ ("wdc.clear %0, r0;" \
    : : "r" (i));
#endif
}

static void __invalidate_dcache_range_nomsr_wt(unsigned long start,
       unsigned long end)
{
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
    (unsigned int)start, (unsigned int) end);
 CACHE_LOOP_LIMITS(start, end,
   cpuinfo.dcache_line_length, cpuinfo.dcache_size);

#ifdef ASM_LOOP
 CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
#else
 for (i = start; i < end; i += cpuinfo.dcache_line_length)
  __asm__ __volatile__ ("wdc %0, r0;" \
    : : "r" (i));
#endif
}

static void __invalidate_dcache_range_msr_irq_wt(unsigned long start,
       unsigned long end)
{
 unsigned long flags;
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
    (unsigned int)start, (unsigned int) end);
 CACHE_LOOP_LIMITS(start, end,
   cpuinfo.dcache_line_length, cpuinfo.dcache_size);

 local_irq_save(flags);
 __disable_dcache_msr();

#ifdef ASM_LOOP
 CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
#else
 for (i = start; i < end; i += cpuinfo.dcache_line_length)
  __asm__ __volatile__ ("wdc %0, r0;" \
    : : "r" (i));
#endif

 __enable_dcache_msr();
 local_irq_restore(flags);
}

static void __invalidate_dcache_range_nomsr_irq(unsigned long start,
       unsigned long end)
{
 unsigned long flags;
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
    (unsigned int)start, (unsigned int) end);

 CACHE_LOOP_LIMITS(start, end,
   cpuinfo.dcache_line_length, cpuinfo.dcache_size);

 local_irq_save(flags);
 __disable_dcache_nomsr();

#ifdef ASM_LOOP
 CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
#else
 for (i = start; i < end; i += cpuinfo.dcache_line_length)
  __asm__ __volatile__ ("wdc %0, r0;" \
    : : "r" (i));
#endif

 __enable_dcache_nomsr();
 local_irq_restore(flags);
}

static void __flush_dcache_all_wb(void)
{
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s\n", __func__);
#ifdef ASM_LOOP
 CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
    wdc.flush);
#else
 for (i = 0; i < cpuinfo.dcache_size;
   i += cpuinfo.dcache_line_length)
   __asm__ __volatile__ ("wdc.flush %0, r0;" \
     : : "r" (i));
#endif
}

static void __flush_dcache_range_wb(unsigned long start, unsigned long end)
{
#ifndef ASM_LOOP
 int i;
#endif
 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
    (unsigned int)start, (unsigned int) end);

 CACHE_LOOP_LIMITS(start, end,
   cpuinfo.dcache_line_length, cpuinfo.dcache_size);
#ifdef ASM_LOOP
 CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.flush);
#else
 for (i = start; i < end; i += cpuinfo.dcache_line_length)
  __asm__ __volatile__ ("wdc.flush %0, r0;" \
    : : "r" (i));
#endif
}

/* struct for wb caches and for wt caches */
struct scache *mbc;

/* new wb cache model */
static const struct scache wb_msr = {
 .ie = __enable_icache_msr,
 .id = __disable_icache_msr,
 .ifl = __flush_icache_all_noirq,
 .iflr = __flush_icache_range_noirq,
 .iin = __flush_icache_all_noirq,
 .iinr = __flush_icache_range_noirq,
 .de = __enable_dcache_msr,
 .dd = __disable_dcache_msr,
 .dfl = __flush_dcache_all_wb,
 .dflr = __flush_dcache_range_wb,
 .din = __invalidate_dcache_all_wb,
 .dinr = __invalidate_dcache_range_wb,
};

/* There is only difference in ie, id, de, dd functions */
static const struct scache wb_nomsr = {
 .ie = __enable_icache_nomsr,
 .id = __disable_icache_nomsr,
 .ifl = __flush_icache_all_noirq,
 .iflr = __flush_icache_range_noirq,
 .iin = __flush_icache_all_noirq,
 .iinr = __flush_icache_range_noirq,
 .de = __enable_dcache_nomsr,
 .dd = __disable_dcache_nomsr,
 .dfl = __flush_dcache_all_wb,
 .dflr = __flush_dcache_range_wb,
 .din = __invalidate_dcache_all_wb,
 .dinr = __invalidate_dcache_range_wb,
};

/* Old wt cache model with disabling irq and turn off cache */
static const struct scache wt_msr = {
 .ie = __enable_icache_msr,
 .id = __disable_icache_msr,
 .ifl = __flush_icache_all_msr_irq,
 .iflr = __flush_icache_range_msr_irq,
 .iin = __flush_icache_all_msr_irq,
 .iinr = __flush_icache_range_msr_irq,
 .de = __enable_dcache_msr,
 .dd = __disable_dcache_msr,
 .dfl = __invalidate_dcache_all_msr_irq,
 .dflr = __invalidate_dcache_range_msr_irq_wt,
 .din = __invalidate_dcache_all_msr_irq,
 .dinr = __invalidate_dcache_range_msr_irq_wt,
};

static const struct scache wt_nomsr = {
 .ie = __enable_icache_nomsr,
 .id = __disable_icache_nomsr,
 .ifl = __flush_icache_all_nomsr_irq,
 .iflr = __flush_icache_range_nomsr_irq,
 .iin = __flush_icache_all_nomsr_irq,
 .iinr = __flush_icache_range_nomsr_irq,
 .de = __enable_dcache_nomsr,
 .dd = __disable_dcache_nomsr,
 .dfl = __invalidate_dcache_all_nomsr_irq,
 .dflr = __invalidate_dcache_range_nomsr_irq,
 .din = __invalidate_dcache_all_nomsr_irq,
 .dinr = __invalidate_dcache_range_nomsr_irq,
};

/* New wt cache model for newer Microblaze versions */
static const struct scache wt_msr_noirq = {
 .ie = __enable_icache_msr,
 .id = __disable_icache_msr,
 .ifl = __flush_icache_all_noirq,
 .iflr = __flush_icache_range_noirq,
 .iin = __flush_icache_all_noirq,
 .iinr = __flush_icache_range_noirq,
 .de = __enable_dcache_msr,
 .dd = __disable_dcache_msr,
 .dfl = __invalidate_dcache_all_noirq_wt,
 .dflr = __invalidate_dcache_range_nomsr_wt,
 .din = __invalidate_dcache_all_noirq_wt,
 .dinr = __invalidate_dcache_range_nomsr_wt,
};

static const struct scache wt_nomsr_noirq = {
 .ie = __enable_icache_nomsr,
 .id = __disable_icache_nomsr,
 .ifl = __flush_icache_all_noirq,
 .iflr = __flush_icache_range_noirq,
 .iin = __flush_icache_all_noirq,
 .iinr = __flush_icache_range_noirq,
 .de = __enable_dcache_nomsr,
 .dd = __disable_dcache_nomsr,
 .dfl = __invalidate_dcache_all_noirq_wt,
 .dflr = __invalidate_dcache_range_nomsr_wt,
 .din = __invalidate_dcache_all_noirq_wt,
 .dinr = __invalidate_dcache_range_nomsr_wt,
};

/* CPU version code for 7.20.c - see arch/microblaze/kernel/cpu/cpuinfo.c */
#define CPUVER_7_20_A 0x0c
#define CPUVER_7_20_D 0x0f

void microblaze_cache_init(void)
{
 if (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) {
  if (cpuinfo.dcache_wb) {
   pr_info("wb_msr\n");
   mbc = (struct scache *)&wb_msr;
   if (cpuinfo.ver_code <= CPUVER_7_20_D) {
    /* MS: problem with signal handling - hw bug */
    pr_info("WB won't work properly\n");
   }
  } else {
   if (cpuinfo.ver_code >= CPUVER_7_20_A) {
    pr_info("wt_msr_noirq\n");
    mbc = (struct scache *)&wt_msr_noirq;
   } else {
    pr_info("wt_msr\n");
    mbc = (struct scache *)&wt_msr;
   }
  }
 } else {
  if (cpuinfo.dcache_wb) {
   pr_info("wb_nomsr\n");
   mbc = (struct scache *)&wb_nomsr;
   if (cpuinfo.ver_code <= CPUVER_7_20_D) {
    /* MS: problem with signal handling - hw bug */
    pr_info("WB won't work properly\n");
   }
  } else {
   if (cpuinfo.ver_code >= CPUVER_7_20_A) {
    pr_info("wt_nomsr_noirq\n");
    mbc = (struct scache *)&wt_nomsr_noirq;
   } else {
    pr_info("wt_nomsr\n");
    mbc = (struct scache *)&wt_nomsr;
   }
  }
 }
 /*
 * FIXME Invalidation is done in U-BOOT
 * WT cache: Data is already written to main memory
 * WB cache: Discard data on noMMU which caused that kernel doesn't boot
 */

 /* invalidate_dcache(); */
 enable_dcache();

 invalidate_icache();
 enable_icache();
}

Messung V0.5
C=98 H=79 G=88

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.