diff options
author | David Daney <ddaney@caviumnetworks.com> | 2010-10-07 19:03:53 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2010-10-29 14:08:43 -0400 |
commit | c9941158fd8a539a56b0e8a4740ec1f6beb23ea3 (patch) | |
tree | 73e3868737061e1d5b0b61c182ea443e3ccd94e3 /arch/mips | |
parent | 468ffde46d429fbd291b0ef43a06afe9c837629f (diff) |
MIPS: Octeon: Apply CN63XXP1 errata workarounds.
The CN63XXP1 needs a couple of workarounds to ensure memory is not written
in unexpected ways.
All PREF with hints in the range 0-4,6-24 are replaced with PREF 28. We
pass a flag to the assembler to cover compiler generated code, and patch
uasm for the dynamically generated code.
The write buffer threshold is reduced to 4.
Signed-off-by: David Daney <ddaney@caviumnetworks.com>
Patchwork: http://patchwork.linux-mips.org/patch/1672/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/cavium-octeon/Kconfig | 11 | ||||
-rw-r--r-- | arch/mips/cavium-octeon/setup.c | 42 | ||||
-rw-r--r-- | arch/mips/mm/uasm.c | 20 |
4 files changed, 69 insertions, 5 deletions
diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 1a81240102c5..7c1102e41fe2 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile | |||
@@ -156,6 +156,7 @@ cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += $(call cc-option,-march=octeon) -Wa,--trap | |||
156 | ifeq (,$(findstring march=octeon, $(cflags-$(CONFIG_CPU_CAVIUM_OCTEON)))) | 156 | ifeq (,$(findstring march=octeon, $(cflags-$(CONFIG_CPU_CAVIUM_OCTEON)))) |
157 | cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += -Wa,-march=octeon | 157 | cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += -Wa,-march=octeon |
158 | endif | 158 | endif |
159 | cflags-$(CONFIG_CAVIUM_CN63XXP1) += -Wa,-mfix-cn63xxp1 | ||
159 | 160 | ||
160 | cflags-$(CONFIG_CPU_R4000_WORKAROUNDS) += $(call cc-option,-mfix-r4000,) | 161 | cflags-$(CONFIG_CPU_R4000_WORKAROUNDS) += $(call cc-option,-mfix-r4000,) |
161 | cflags-$(CONFIG_CPU_R4400_WORKAROUNDS) += $(call cc-option,-mfix-r4400,) | 162 | cflags-$(CONFIG_CPU_R4400_WORKAROUNDS) += $(call cc-option,-mfix-r4400,) |
diff --git a/arch/mips/cavium-octeon/Kconfig b/arch/mips/cavium-octeon/Kconfig index 475156b0c807..caae22858163 100644 --- a/arch/mips/cavium-octeon/Kconfig +++ b/arch/mips/cavium-octeon/Kconfig | |||
@@ -3,6 +3,17 @@ config CAVIUM_OCTEON_SPECIFIC_OPTIONS | |||
3 | depends on CPU_CAVIUM_OCTEON | 3 | depends on CPU_CAVIUM_OCTEON |
4 | default "y" | 4 | default "y" |
5 | 5 | ||
6 | config CAVIUM_CN63XXP1 | ||
7 | bool "Enable CN63XXP1 errata worarounds" | ||
8 | depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS | ||
9 | default "n" | ||
10 | help | ||
11 | The CN63XXP1 chip requires build time workarounds to | ||
12 | function reliably, select this option to enable them. These | ||
13 | workarounds will cause a slight decrease in performance on | ||
14 | non-CN63XXP1 hardware, so it is recommended to select "n" | ||
15 | unless it is known the workarounds are needed. | ||
16 | |||
6 | config CAVIUM_OCTEON_2ND_KERNEL | 17 | config CAVIUM_OCTEON_2ND_KERNEL |
7 | bool "Build the kernel to be used as a 2nd kernel on the same chip" | 18 | bool "Build the kernel to be used as a 2nd kernel on the same chip" |
8 | depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS | 19 | depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS |
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index c072b24f4853..b0c3686c96dd 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c | |||
@@ -356,8 +356,18 @@ void octeon_user_io_init(void) | |||
356 | cvmmemctl.s.wbfltime = 0; | 356 | cvmmemctl.s.wbfltime = 0; |
357 | /* R/W If set, do not put Istream in the L2 cache. */ | 357 | /* R/W If set, do not put Istream in the L2 cache. */ |
358 | cvmmemctl.s.istrnol2 = 0; | 358 | cvmmemctl.s.istrnol2 = 0; |
359 | /* R/W The write buffer threshold. */ | 359 | |
360 | cvmmemctl.s.wbthresh = 10; | 360 | /* |
361 | * R/W The write buffer threshold. As per erratum Core-14752 | ||
362 | * for CN63XX, a sc/scd might fail if the write buffer is | ||
363 | * full. Lowering WBTHRESH greatly lowers the chances of the | ||
364 | * write buffer ever being full and triggering the erratum. | ||
365 | */ | ||
366 | if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X)) | ||
367 | cvmmemctl.s.wbthresh = 4; | ||
368 | else | ||
369 | cvmmemctl.s.wbthresh = 10; | ||
370 | |||
361 | /* R/W If set, CVMSEG is available for loads/stores in | 371 | /* R/W If set, CVMSEG is available for loads/stores in |
362 | * kernel/debug mode. */ | 372 | * kernel/debug mode. */ |
363 | #if CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 | 373 | #if CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 |
@@ -375,14 +385,13 @@ void octeon_user_io_init(void) | |||
375 | * is max legal value. */ | 385 | * is max legal value. */ |
376 | cvmmemctl.s.lmemsz = CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE; | 386 | cvmmemctl.s.lmemsz = CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE; |
377 | 387 | ||
388 | write_c0_cvmmemctl(cvmmemctl.u64); | ||
378 | 389 | ||
379 | if (smp_processor_id() == 0) | 390 | if (smp_processor_id() == 0) |
380 | pr_notice("CVMSEG size: %d cache lines (%d bytes)\n", | 391 | pr_notice("CVMSEG size: %d cache lines (%d bytes)\n", |
381 | CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE, | 392 | CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE, |
382 | CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128); | 393 | CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128); |
383 | 394 | ||
384 | write_c0_cvmmemctl(cvmmemctl.u64); | ||
385 | |||
386 | /* Move the performance counter interrupts to IRQ 6 */ | 395 | /* Move the performance counter interrupts to IRQ 6 */ |
387 | cvmctl = read_c0_cvmctl(); | 396 | cvmctl = read_c0_cvmctl(); |
388 | cvmctl &= ~(7 << 7); | 397 | cvmctl &= ~(7 << 7); |
@@ -758,6 +767,31 @@ EXPORT_SYMBOL(prom_putchar); | |||
758 | 767 | ||
759 | void prom_free_prom_memory(void) | 768 | void prom_free_prom_memory(void) |
760 | { | 769 | { |
770 | if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X)) { | ||
771 | /* Check for presence of Core-14449 fix. */ | ||
772 | u32 insn; | ||
773 | u32 *foo; | ||
774 | |||
775 | foo = &insn; | ||
776 | |||
777 | asm volatile("# before" : : : "memory"); | ||
778 | prefetch(foo); | ||
779 | asm volatile( | ||
780 | ".set push\n\t" | ||
781 | ".set noreorder\n\t" | ||
782 | "bal 1f\n\t" | ||
783 | "nop\n" | ||
784 | "1:\tlw %0,-12($31)\n\t" | ||
785 | ".set pop\n\t" | ||
786 | : "=r" (insn) : : "$31", "memory"); | ||
787 | |||
788 | if ((insn >> 26) != 0x33) | ||
789 | panic("No PREF instruction at Core-14449 probe point.\n"); | ||
790 | |||
791 | if (((insn >> 16) & 0x1f) != 28) | ||
792 | panic("Core-14449 WAR not in place (%04x).\n" | ||
793 | "Please build kernel with proper options (CONFIG_CAVIUM_CN63XXP1).\n", insn); | ||
794 | } | ||
761 | #ifdef CONFIG_CAVIUM_DECODE_RSL | 795 | #ifdef CONFIG_CAVIUM_DECODE_RSL |
762 | cvmx_interrupt_rsl_enable(); | 796 | cvmx_interrupt_rsl_enable(); |
763 | 797 | ||
diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index d2647a4e012b..23afdebc8e5c 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c | |||
@@ -405,7 +405,6 @@ I_u1u2u3(_mfc0) | |||
405 | I_u1u2u3(_mtc0) | 405 | I_u1u2u3(_mtc0) |
406 | I_u2u1u3(_ori) | 406 | I_u2u1u3(_ori) |
407 | I_u3u1u2(_or) | 407 | I_u3u1u2(_or) |
408 | I_u2s3u1(_pref) | ||
409 | I_0(_rfe) | 408 | I_0(_rfe) |
410 | I_u2s3u1(_sc) | 409 | I_u2s3u1(_sc) |
411 | I_u2s3u1(_scd) | 410 | I_u2s3u1(_scd) |
@@ -427,6 +426,25 @@ I_u1(_syscall); | |||
427 | I_u1u2s3(_bbit0); | 426 | I_u1u2s3(_bbit0); |
428 | I_u1u2s3(_bbit1); | 427 | I_u1u2s3(_bbit1); |
429 | 428 | ||
429 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | ||
430 | #include <asm/octeon/octeon.h> | ||
431 | void __uasminit uasm_i_pref(u32 **buf, unsigned int a, signed int b, | ||
432 | unsigned int c) | ||
433 | { | ||
434 | if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) && a <= 24 && a != 5) | ||
435 | /* | ||
436 | * As per erratum Core-14449, replace prefetches 0-4, | ||
437 | * 6-24 with 'pref 28'. | ||
438 | */ | ||
439 | build_insn(buf, insn_pref, c, 28, b); | ||
440 | else | ||
441 | build_insn(buf, insn_pref, c, a, b); | ||
442 | } | ||
443 | UASM_EXPORT_SYMBOL(uasm_i_pref); | ||
444 | #else | ||
445 | I_u2s3u1(_pref) | ||
446 | #endif | ||
447 | |||
430 | /* Handle labels. */ | 448 | /* Handle labels. */ |
431 | void __uasminit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid) | 449 | void __uasminit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid) |
432 | { | 450 | { |