linux/arch/microblaze/kernel/cpu/cache.c
<<
>>
Prefs
   1/*
   2 * Cache control for MicroBlaze cache memories
   3 *
   4 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
   5 * Copyright (C) 2007-2009 PetaLogix
   6 * Copyright (C) 2007-2009 John Williams <john.williams@petalogix.com>
   7 *
   8 * This file is subject to the terms and conditions of the GNU General
   9 * Public License. See the file COPYING in the main directory of this
  10 * archive for more details.
  11 */
  12
  13#include <asm/cacheflush.h>
  14#include <linux/cache.h>
  15#include <asm/cpuinfo.h>
  16#include <asm/pvr.h>
  17
  18static inline void __enable_icache_msr(void)
  19{
  20        __asm__ __volatile__ ("  msrset r0, %0;"        \
  21                                "nop;"                  \
  22                        : : "i" (MSR_ICE) : "memory");
  23}
  24
  25static inline void __disable_icache_msr(void)
  26{
  27        __asm__ __volatile__ ("  msrclr r0, %0;"        \
  28                                "nop;"                  \
  29                        : : "i" (MSR_ICE) : "memory");
  30}
  31
  32static inline void __enable_dcache_msr(void)
  33{
  34        __asm__ __volatile__ ("  msrset r0, %0;"        \
  35                                "nop;"                  \
  36                        : : "i" (MSR_DCE) : "memory");
  37}
  38
  39static inline void __disable_dcache_msr(void)
  40{
  41        __asm__ __volatile__ ("  msrclr r0, %0;"        \
  42                                "nop; "                 \
  43                        : : "i" (MSR_DCE) : "memory");
  44}
  45
  46static inline void __enable_icache_nomsr(void)
  47{
  48        __asm__ __volatile__ ("  mfs    r12, rmsr;"     \
  49                                "nop;"                  \
  50                                "ori    r12, r12, %0;"  \
  51                                "mts    rmsr, r12;"     \
  52                                "nop;"                  \
  53                        : : "i" (MSR_ICE) : "memory", "r12");
  54}
  55
  56static inline void __disable_icache_nomsr(void)
  57{
  58        __asm__ __volatile__ ("  mfs    r12, rmsr;"     \
  59                                "nop;"                  \
  60                                "andi   r12, r12, ~%0;" \
  61                                "mts    rmsr, r12;"     \
  62                                "nop;"                  \
  63                        : : "i" (MSR_ICE) : "memory", "r12");
  64}
  65
  66static inline void __enable_dcache_nomsr(void)
  67{
  68        __asm__ __volatile__ ("  mfs    r12, rmsr;"     \
  69                                "nop;"                  \
  70                                "ori    r12, r12, %0;"  \
  71                                "mts    rmsr, r12;"     \
  72                                "nop;"                  \
  73                        : : "i" (MSR_DCE) : "memory", "r12");
  74}
  75
  76static inline void __disable_dcache_nomsr(void)
  77{
  78        __asm__ __volatile__ ("  mfs    r12, rmsr;"     \
  79                                "nop;"                  \
  80                                "andi   r12, r12, ~%0;" \
  81                                "mts    rmsr, r12;"     \
  82                                "nop;"                  \
  83                        : : "i" (MSR_DCE) : "memory", "r12");
  84}
  85
  86
  87/* Helper macro for computing the limits of cache range loops
  88 *
  89 * End address can be unaligned which is OK for C implementation.
  90 * ASM implementation align it in ASM macros
  91 */
  92#define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size)    \
  93do {                                                                    \
  94        int align = ~(cache_line_length - 1);                           \
  95        if (start <  UINT_MAX - cache_size)                             \
  96                end = min(start + cache_size, end);                     \
  97        start &= align;                                                 \
  98} while (0)
  99
 100/*
 101 * Helper macro to loop over the specified cache_size/line_length and
 102 * execute 'op' on that cacheline
 103 */
 104#define CACHE_ALL_LOOP(cache_size, line_length, op)                     \
 105do {                                                                    \
 106        unsigned int len = cache_size - line_length;                    \
 107        int step = -line_length;                                        \
 108        WARN_ON(step >= 0);                                             \
 109                                                                        \
 110        __asm__ __volatile__ (" 1:      " #op " %0, r0;"                \
 111                                        "bgtid   %0, 1b;"               \
 112                                        "addk    %0, %0, %1;"           \
 113                                        : : "r" (len), "r" (step)       \
 114                                        : "memory");                    \
 115} while (0)
 116
 117/* Used for wdc.flush/clear which can use rB for offset which is not possible
 118 * to use for simple wdc or wic.
 119 *
 120 * start address is cache aligned
 121 * end address is not aligned, if end is aligned then I have to subtract
 122 * cacheline length because I can't flush/invalidate the next cacheline.
 123 * If is not, I align it because I will flush/invalidate whole line.
 124 */
 125#define CACHE_RANGE_LOOP_2(start, end, line_length, op)                 \
 126do {                                                                    \
 127        int step = -line_length;                                        \
 128        int align = ~(line_length - 1);                                 \
 129        int count;                                                      \
 130        end = ((end & align) == end) ? end - line_length : end & align; \
 131        count = end - start;                                            \
 132        WARN_ON(count < 0);                                             \
 133                                                                        \
 134        __asm__ __volatile__ (" 1:      " #op " %0, %1;"                \
 135                                        "bgtid  %1, 1b;"                \
 136                                        "addk   %1, %1, %2;"            \
 137                                        : : "r" (start), "r" (count),   \
 138                                        "r" (step) : "memory");         \
 139} while (0)
 140
 141/* It is used only first parameter for OP - for wic, wdc */
 142#define CACHE_RANGE_LOOP_1(start, end, line_length, op)                 \
 143do {                                                                    \
 144        unsigned int volatile temp = 0;                                         \
 145        unsigned int align = ~(line_length - 1);                                        \
 146        end = ((end & align) == end) ? end - line_length : end & align; \
 147        WARN_ON(end < start);                                   \
 148                                                                        \
 149        __asm__ __volatile__ (" 1:      " #op " %1, r0;"                \
 150                                        "cmpu   %0, %1, %2;"            \
 151                                        "bgtid  %0, 1b;"                \
 152                                        "addk   %1, %1, %3;"            \
 153                                : : "r" (temp), "r" (start), "r" (end), \
 154                                        "r" (line_length) : "memory");  \
 155} while (0)
 156
 157#define ASM_LOOP
 158
 159static void __flush_icache_range_msr_irq(unsigned long start, unsigned long end)
 160{
 161        unsigned long flags;
 162#ifndef ASM_LOOP
 163        int i;
 164#endif
 165        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
 166                                (unsigned int)start, (unsigned int) end);
 167
 168        CACHE_LOOP_LIMITS(start, end,
 169                        cpuinfo.icache_line_length, cpuinfo.icache_size);
 170
 171        local_irq_save(flags);
 172        __disable_icache_msr();
 173
 174#ifdef ASM_LOOP
 175        CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
 176#else
 177        for (i = start; i < end; i += cpuinfo.icache_line_length)
 178                __asm__ __volatile__ ("wic      %0, r0;"        \
 179                                : : "r" (i));
 180#endif
 181        __enable_icache_msr();
 182        local_irq_restore(flags);
 183}
 184
 185static void __flush_icache_range_nomsr_irq(unsigned long start,
 186                                unsigned long end)
 187{
 188        unsigned long flags;
 189#ifndef ASM_LOOP
 190        int i;
 191#endif
 192        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
 193                                (unsigned int)start, (unsigned int) end);
 194
 195        CACHE_LOOP_LIMITS(start, end,
 196                        cpuinfo.icache_line_length, cpuinfo.icache_size);
 197
 198        local_irq_save(flags);
 199        __disable_icache_nomsr();
 200
 201#ifdef ASM_LOOP
 202        CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
 203#else
 204        for (i = start; i < end; i += cpuinfo.icache_line_length)
 205                __asm__ __volatile__ ("wic      %0, r0;"        \
 206                                : : "r" (i));
 207#endif
 208
 209        __enable_icache_nomsr();
 210        local_irq_restore(flags);
 211}
 212
 213static void __flush_icache_range_noirq(unsigned long start,
 214                                unsigned long end)
 215{
 216#ifndef ASM_LOOP
 217        int i;
 218#endif
 219        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
 220                                (unsigned int)start, (unsigned int) end);
 221
 222        CACHE_LOOP_LIMITS(start, end,
 223                        cpuinfo.icache_line_length, cpuinfo.icache_size);
 224#ifdef ASM_LOOP
 225        CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
 226#else
 227        for (i = start; i < end; i += cpuinfo.icache_line_length)
 228                __asm__ __volatile__ ("wic      %0, r0;"        \
 229                                : : "r" (i));
 230#endif
 231}
 232
 233static void __flush_icache_all_msr_irq(void)
 234{
 235        unsigned long flags;
 236#ifndef ASM_LOOP
 237        int i;
 238#endif
 239        pr_debug("%s\n", __func__);
 240
 241        local_irq_save(flags);
 242        __disable_icache_msr();
 243#ifdef ASM_LOOP
 244        CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
 245#else
 246        for (i = 0; i < cpuinfo.icache_size;
 247                 i += cpuinfo.icache_line_length)
 248                        __asm__ __volatile__ ("wic      %0, r0;" \
 249                                        : : "r" (i));
 250#endif
 251        __enable_icache_msr();
 252        local_irq_restore(flags);
 253}
 254
 255static void __flush_icache_all_nomsr_irq(void)
 256{
 257        unsigned long flags;
 258#ifndef ASM_LOOP
 259        int i;
 260#endif
 261        pr_debug("%s\n", __func__);
 262
 263        local_irq_save(flags);
 264        __disable_icache_nomsr();
 265#ifdef ASM_LOOP
 266        CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
 267#else
 268        for (i = 0; i < cpuinfo.icache_size;
 269                 i += cpuinfo.icache_line_length)
 270                        __asm__ __volatile__ ("wic      %0, r0;" \
 271                                        : : "r" (i));
 272#endif
 273        __enable_icache_nomsr();
 274        local_irq_restore(flags);
 275}
 276
 277static void __flush_icache_all_noirq(void)
 278{
 279#ifndef ASM_LOOP
 280        int i;
 281#endif
 282        pr_debug("%s\n", __func__);
 283#ifdef ASM_LOOP
 284        CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
 285#else
 286        for (i = 0; i < cpuinfo.icache_size;
 287                 i += cpuinfo.icache_line_length)
 288                        __asm__ __volatile__ ("wic      %0, r0;" \
 289                                        : : "r" (i));
 290#endif
 291}
 292
 293static void __invalidate_dcache_all_msr_irq(void)
 294{
 295        unsigned long flags;
 296#ifndef ASM_LOOP
 297        int i;
 298#endif
 299        pr_debug("%s\n", __func__);
 300
 301        local_irq_save(flags);
 302        __disable_dcache_msr();
 303#ifdef ASM_LOOP
 304        CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
 305#else
 306        for (i = 0; i < cpuinfo.dcache_size;
 307                 i += cpuinfo.dcache_line_length)
 308                        __asm__ __volatile__ ("wdc      %0, r0;" \
 309                                        : : "r" (i));
 310#endif
 311        __enable_dcache_msr();
 312        local_irq_restore(flags);
 313}
 314
 315static void __invalidate_dcache_all_nomsr_irq(void)
 316{
 317        unsigned long flags;
 318#ifndef ASM_LOOP
 319        int i;
 320#endif
 321        pr_debug("%s\n", __func__);
 322
 323        local_irq_save(flags);
 324        __disable_dcache_nomsr();
 325#ifdef ASM_LOOP
 326        CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
 327#else
 328        for (i = 0; i < cpuinfo.dcache_size;
 329                 i += cpuinfo.dcache_line_length)
 330                        __asm__ __volatile__ ("wdc      %0, r0;" \
 331                                        : : "r" (i));
 332#endif
 333        __enable_dcache_nomsr();
 334        local_irq_restore(flags);
 335}
 336
 337static void __invalidate_dcache_all_noirq_wt(void)
 338{
 339#ifndef ASM_LOOP
 340        int i;
 341#endif
 342        pr_debug("%s\n", __func__);
 343#ifdef ASM_LOOP
 344        CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
 345#else
 346        for (i = 0; i < cpuinfo.dcache_size;
 347                 i += cpuinfo.dcache_line_length)
 348                        __asm__ __volatile__ ("wdc      %0, r0;" \
 349                                        : : "r" (i));
 350#endif
 351}
 352
 353/*
 354 * FIXME It is blindly invalidation as is expected
 355 * but can't be called on noMMU in microblaze_cache_init below
 356 *
 357 * MS: noMMU kernel won't boot if simple wdc is used
 358 * The reason should be that there are discared data which kernel needs
 359 */
 360static void __invalidate_dcache_all_wb(void)
 361{
 362#ifndef ASM_LOOP
 363        int i;
 364#endif
 365        pr_debug("%s\n", __func__);
 366#ifdef ASM_LOOP
 367        CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
 368                                        wdc);
 369#else
 370        for (i = 0; i < cpuinfo.dcache_size;
 371                 i += cpuinfo.dcache_line_length)
 372                        __asm__ __volatile__ ("wdc      %0, r0;" \
 373                                        : : "r" (i));
 374#endif
 375}
 376
 377static void __invalidate_dcache_range_wb(unsigned long start,
 378                                                unsigned long end)
 379{
 380#ifndef ASM_LOOP
 381        int i;
 382#endif
 383        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
 384                                (unsigned int)start, (unsigned int) end);
 385
 386        CACHE_LOOP_LIMITS(start, end,
 387                        cpuinfo.dcache_line_length, cpuinfo.dcache_size);
 388#ifdef ASM_LOOP
 389        CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear);
 390#else
 391        for (i = start; i < end; i += cpuinfo.dcache_line_length)
 392                __asm__ __volatile__ ("wdc.clear        %0, r0;"        \
 393                                : : "r" (i));
 394#endif
 395}
 396
 397static void __invalidate_dcache_range_nomsr_wt(unsigned long start,
 398                                                        unsigned long end)
 399{
 400#ifndef ASM_LOOP
 401        int i;
 402#endif
 403        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
 404                                (unsigned int)start, (unsigned int) end);
 405        CACHE_LOOP_LIMITS(start, end,
 406                        cpuinfo.dcache_line_length, cpuinfo.dcache_size);
 407
 408#ifdef ASM_LOOP
 409        CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
 410#else
 411        for (i = start; i < end; i += cpuinfo.dcache_line_length)
 412                __asm__ __volatile__ ("wdc      %0, r0;"        \
 413                                : : "r" (i));
 414#endif
 415}
 416
 417static void __invalidate_dcache_range_msr_irq_wt(unsigned long start,
 418                                                        unsigned long end)
 419{
 420        unsigned long flags;
 421#ifndef ASM_LOOP
 422        int i;
 423#endif
 424        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
 425                                (unsigned int)start, (unsigned int) end);
 426        CACHE_LOOP_LIMITS(start, end,
 427                        cpuinfo.dcache_line_length, cpuinfo.dcache_size);
 428
 429        local_irq_save(flags);
 430        __disable_dcache_msr();
 431
 432#ifdef ASM_LOOP
 433        CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
 434#else
 435        for (i = start; i < end; i += cpuinfo.dcache_line_length)
 436                __asm__ __volatile__ ("wdc      %0, r0;"        \
 437                                : : "r" (i));
 438#endif
 439
 440        __enable_dcache_msr();
 441        local_irq_restore(flags);
 442}
 443
 444static void __invalidate_dcache_range_nomsr_irq(unsigned long start,
 445                                                        unsigned long end)
 446{
 447        unsigned long flags;
 448#ifndef ASM_LOOP
 449        int i;
 450#endif
 451        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
 452                                (unsigned int)start, (unsigned int) end);
 453
 454        CACHE_LOOP_LIMITS(start, end,
 455                        cpuinfo.dcache_line_length, cpuinfo.dcache_size);
 456
 457        local_irq_save(flags);
 458        __disable_dcache_nomsr();
 459
 460#ifdef ASM_LOOP
 461        CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
 462#else
 463        for (i = start; i < end; i += cpuinfo.dcache_line_length)
 464                __asm__ __volatile__ ("wdc      %0, r0;"        \
 465                                : : "r" (i));
 466#endif
 467
 468        __enable_dcache_nomsr();
 469        local_irq_restore(flags);
 470}
 471
 472static void __flush_dcache_all_wb(void)
 473{
 474#ifndef ASM_LOOP
 475        int i;
 476#endif
 477        pr_debug("%s\n", __func__);
 478#ifdef ASM_LOOP
 479        CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
 480                                wdc.flush);
 481#else
 482        for (i = 0; i < cpuinfo.dcache_size;
 483                 i += cpuinfo.dcache_line_length)
 484                        __asm__ __volatile__ ("wdc.flush        %0, r0;" \
 485                                        : : "r" (i));
 486#endif
 487}
 488
 489static void __flush_dcache_range_wb(unsigned long start, unsigned long end)
 490{
 491#ifndef ASM_LOOP
 492        int i;
 493#endif
 494        pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
 495                                (unsigned int)start, (unsigned int) end);
 496
 497        CACHE_LOOP_LIMITS(start, end,
 498                        cpuinfo.dcache_line_length, cpuinfo.dcache_size);
 499#ifdef ASM_LOOP
 500        CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.flush);
 501#else
 502        for (i = start; i < end; i += cpuinfo.dcache_line_length)
 503                __asm__ __volatile__ ("wdc.flush        %0, r0;"        \
 504                                : : "r" (i));
 505#endif
 506}
 507
 508/* struct for wb caches and for wt caches */
 509struct scache *mbc;
 510
 511/* new wb cache model */
 512static const struct scache wb_msr = {
 513        .ie = __enable_icache_msr,
 514        .id = __disable_icache_msr,
 515        .ifl = __flush_icache_all_noirq,
 516        .iflr = __flush_icache_range_noirq,
 517        .iin = __flush_icache_all_noirq,
 518        .iinr = __flush_icache_range_noirq,
 519        .de = __enable_dcache_msr,
 520        .dd = __disable_dcache_msr,
 521        .dfl = __flush_dcache_all_wb,
 522        .dflr = __flush_dcache_range_wb,
 523        .din = __invalidate_dcache_all_wb,
 524        .dinr = __invalidate_dcache_range_wb,
 525};
 526
 527/* There is only difference in ie, id, de, dd functions */
 528static const struct scache wb_nomsr = {
 529        .ie = __enable_icache_nomsr,
 530        .id = __disable_icache_nomsr,
 531        .ifl = __flush_icache_all_noirq,
 532        .iflr = __flush_icache_range_noirq,
 533        .iin = __flush_icache_all_noirq,
 534        .iinr = __flush_icache_range_noirq,
 535        .de = __enable_dcache_nomsr,
 536        .dd = __disable_dcache_nomsr,
 537        .dfl = __flush_dcache_all_wb,
 538        .dflr = __flush_dcache_range_wb,
 539        .din = __invalidate_dcache_all_wb,
 540        .dinr = __invalidate_dcache_range_wb,
 541};
 542
 543/* Old wt cache model with disabling irq and turn off cache */
 544static const struct scache wt_msr = {
 545        .ie = __enable_icache_msr,
 546        .id = __disable_icache_msr,
 547        .ifl = __flush_icache_all_msr_irq,
 548        .iflr = __flush_icache_range_msr_irq,
 549        .iin = __flush_icache_all_msr_irq,
 550        .iinr = __flush_icache_range_msr_irq,
 551        .de = __enable_dcache_msr,
 552        .dd = __disable_dcache_msr,
 553        .dfl = __invalidate_dcache_all_msr_irq,
 554        .dflr = __invalidate_dcache_range_msr_irq_wt,
 555        .din = __invalidate_dcache_all_msr_irq,
 556        .dinr = __invalidate_dcache_range_msr_irq_wt,
 557};
 558
 559static const struct scache wt_nomsr = {
 560        .ie = __enable_icache_nomsr,
 561        .id = __disable_icache_nomsr,
 562        .ifl = __flush_icache_all_nomsr_irq,
 563        .iflr = __flush_icache_range_nomsr_irq,
 564        .iin = __flush_icache_all_nomsr_irq,
 565        .iinr = __flush_icache_range_nomsr_irq,
 566        .de = __enable_dcache_nomsr,
 567        .dd = __disable_dcache_nomsr,
 568        .dfl = __invalidate_dcache_all_nomsr_irq,
 569        .dflr = __invalidate_dcache_range_nomsr_irq,
 570        .din = __invalidate_dcache_all_nomsr_irq,
 571        .dinr = __invalidate_dcache_range_nomsr_irq,
 572};
 573
 574/* New wt cache model for newer Microblaze versions */
 575static const struct scache wt_msr_noirq = {
 576        .ie = __enable_icache_msr,
 577        .id = __disable_icache_msr,
 578        .ifl = __flush_icache_all_noirq,
 579        .iflr = __flush_icache_range_noirq,
 580        .iin = __flush_icache_all_noirq,
 581        .iinr = __flush_icache_range_noirq,
 582        .de = __enable_dcache_msr,
 583        .dd = __disable_dcache_msr,
 584        .dfl = __invalidate_dcache_all_noirq_wt,
 585        .dflr = __invalidate_dcache_range_nomsr_wt,
 586        .din = __invalidate_dcache_all_noirq_wt,
 587        .dinr = __invalidate_dcache_range_nomsr_wt,
 588};
 589
 590static const struct scache wt_nomsr_noirq = {
 591        .ie = __enable_icache_nomsr,
 592        .id = __disable_icache_nomsr,
 593        .ifl = __flush_icache_all_noirq,
 594        .iflr = __flush_icache_range_noirq,
 595        .iin = __flush_icache_all_noirq,
 596        .iinr = __flush_icache_range_noirq,
 597        .de = __enable_dcache_nomsr,
 598        .dd = __disable_dcache_nomsr,
 599        .dfl = __invalidate_dcache_all_noirq_wt,
 600        .dflr = __invalidate_dcache_range_nomsr_wt,
 601        .din = __invalidate_dcache_all_noirq_wt,
 602        .dinr = __invalidate_dcache_range_nomsr_wt,
 603};
 604
 605/* CPU version code for 7.20.c - see arch/microblaze/kernel/cpu/cpuinfo.c */
 606#define CPUVER_7_20_A   0x0c
 607#define CPUVER_7_20_D   0x0f
 608
 609void microblaze_cache_init(void)
 610{
 611        if (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) {
 612                if (cpuinfo.dcache_wb) {
 613                        pr_info("wb_msr\n");
 614                        mbc = (struct scache *)&wb_msr;
 615                        if (cpuinfo.ver_code <= CPUVER_7_20_D) {
 616                                /* MS: problem with signal handling - hw bug */
 617                                pr_info("WB won't work properly\n");
 618                        }
 619                } else {
 620                        if (cpuinfo.ver_code >= CPUVER_7_20_A) {
 621                                pr_info("wt_msr_noirq\n");
 622                                mbc = (struct scache *)&wt_msr_noirq;
 623                        } else {
 624                                pr_info("wt_msr\n");
 625                                mbc = (struct scache *)&wt_msr;
 626                        }
 627                }
 628        } else {
 629                if (cpuinfo.dcache_wb) {
 630                        pr_info("wb_nomsr\n");
 631                        mbc = (struct scache *)&wb_nomsr;
 632                        if (cpuinfo.ver_code <= CPUVER_7_20_D) {
 633                                /* MS: problem with signal handling - hw bug */
 634                                pr_info("WB won't work properly\n");
 635                        }
 636                } else {
 637                        if (cpuinfo.ver_code >= CPUVER_7_20_A) {
 638                                pr_info("wt_nomsr_noirq\n");
 639                                mbc = (struct scache *)&wt_nomsr_noirq;
 640                        } else {
 641                                pr_info("wt_nomsr\n");
 642                                mbc = (struct scache *)&wt_nomsr;
 643                        }
 644                }
 645        }
 646        /*
 647         * FIXME Invalidation is done in U-BOOT
 648         * WT cache: Data is already written to main memory
 649         * WB cache: Discard data on noMMU which caused that kernel doesn't boot
 650         */
 651        /* invalidate_dcache(); */
 652        enable_dcache();
 653
 654        invalidate_icache();
 655        enable_icache();
 656}
 657