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