Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[MIPS] R4000/R4400 daddiu erratum workaround

This complements the generic R4000/R4400 errata workaround code and adds
bits for the daddiu problem. In most places it just modifies handwritten
assembly code so that the assembler is allowed to use a temporary register
as daddiu may now be treated as a macro that expands to a sequence of li
and daddu. It is the AT register or, where AT is unavailable or used
explicitly for another purpose, an explicitly-named register is selected,
using the .set at=<reg> feature added recently to gas. This feature is
only used if CONFIG_CPU_DADDI_WORKAROUNDS has been set, so if the
workaround remains disabled, the required version of binutils stays
unchanged.

Similarly, daddiu instructions put in branch delay slots in noreorder
fragments are now taken out of them and the assembler is allowed to
reorder them itself as possible (which it does making the whole idea of
scheduling them into delay slots manually questionable).

Also in the very few places where such a simple conversion was not
possible, a handcoded longer sequence is implemented.

Other than that there are changes to code responsible for building the
TLB fault and page clear/copy handlers to avoid daddiu as appropriate.
These are only effective if the erratum is verified to be present at the
run time.

Finally there is a trivial update to __delay(), because it uses daddiu in
a branch delay slot.

Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Maciej W. Rozycki and committed by
Ralf Baechle
619b6e18 20d60d99

+227 -83
+7 -1
arch/mips/kernel/genex.S
··· 6 6 * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle 7 7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 8 8 * Copyright (C) 2001 MIPS Technologies, Inc. 9 - * Copyright (C) 2002 Maciej W. Rozycki 9 + * Copyright (C) 2002, 2007 Maciej W. Rozycki 10 10 */ 11 11 #include <linux/init.h> 12 12 ··· 471 471 jr k0 472 472 rfe 473 473 #else 474 + #ifndef CONFIG_CPU_DADDI_WORKAROUNDS 474 475 LONG_ADDIU k0, 4 /* stall on $k0 */ 476 + #else 477 + .set at=v1 478 + LONG_ADDIU k0, 4 479 + .set noat 480 + #endif 475 481 MTC0 k0, CP0_EPC 476 482 /* I hope three instructions between MTC0 and ERET are enough... */ 477 483 ori k1, _THREAD_MASK
+51 -10
arch/mips/lib/csum_partial.S
··· 7 7 * 8 8 * Copyright (C) 1998, 1999 Ralf Baechle 9 9 * Copyright (C) 1999 Silicon Graphics, Inc. 10 + * Copyright (C) 2007 Maciej W. Rozycki 10 11 */ 11 12 #include <linux/errno.h> 12 13 #include <asm/asm.h> ··· 53 52 #define UNIT(unit) ((unit)*NBYTES) 54 53 55 54 #define ADDC(sum,reg) \ 55 + .set push; \ 56 + .set noat; \ 56 57 ADD sum, reg; \ 57 58 sltu v1, sum, reg; \ 58 - ADD sum, v1 59 + ADD sum, v1; \ 60 + .set pop 59 61 60 62 #define CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3) \ 61 63 LOAD _t0, (offset + UNIT(0))(src); \ ··· 182 178 CSUM_BIGCHUNK(src, 0x40, sum, t0, t1, t3, t4) 183 179 CSUM_BIGCHUNK(src, 0x60, sum, t0, t1, t3, t4) 184 180 LONG_SUBU t8, t8, 0x01 181 + .set reorder /* DADDI_WAR */ 182 + PTR_ADDU src, src, 0x80 185 183 bnez t8, move_128bytes 186 - PTR_ADDU src, src, 0x80 184 + .set noreorder 187 185 188 186 1: 189 187 beqz t2, 1f ··· 214 208 lw t0, (src) 215 209 LONG_SUBU t8, t8, 0x1 216 210 ADDC(sum, t0) 211 + .set reorder /* DADDI_WAR */ 212 + PTR_ADDU src, src, 0x4 217 213 bnez t8, end_words 218 - PTR_ADDU src, src, 0x4 214 + .set noreorder 219 215 220 216 /* unknown src alignment and < 8 bytes to go */ 221 217 small_csumcpy: ··· 254 246 1: ADDC(sum, t1) 255 247 256 248 /* fold checksum */ 249 + .set push 250 + .set noat 257 251 #ifdef USE_DOUBLE 258 252 dsll32 v1, sum, 0 259 253 daddu sum, v1 ··· 276 266 srl sum, sum, 8 277 267 or sum, v1 278 268 andi sum, 0xffff 269 + .set pop 279 270 1: 280 271 .set reorder 281 272 /* Add the passed partial csum. */ ··· 384 373 385 374 #define ADDRMASK (NBYTES-1) 386 375 376 + #ifndef CONFIG_CPU_DADDI_WORKAROUNDS 387 377 .set noat 378 + #else 379 + .set at=v1 380 + #endif 388 381 389 382 LEAF(__csum_partial_copy_user) 390 383 PTR_ADDU AT, src, len /* See (1) above. */ ··· 456 441 ADDC(sum, t6) 457 442 EXC( STORE t7, UNIT(7)(dst), s_exc) 458 443 ADDC(sum, t7) 444 + .set reorder /* DADDI_WAR */ 445 + ADD dst, dst, 8*NBYTES 459 446 bgez len, 1b 460 - ADD dst, dst, 8*NBYTES 447 + .set noreorder 461 448 ADD len, 8*NBYTES # revert len (see above) 462 449 463 450 /* ··· 488 471 ADDC(sum, t2) 489 472 EXC( STORE t3, UNIT(3)(dst), s_exc) 490 473 ADDC(sum, t3) 474 + .set reorder /* DADDI_WAR */ 475 + ADD dst, dst, 4*NBYTES 491 476 beqz len, done 492 - ADD dst, dst, 4*NBYTES 477 + .set noreorder 493 478 less_than_4units: 494 479 /* 495 480 * rem = len % NBYTES ··· 504 485 SUB len, len, NBYTES 505 486 EXC( STORE t0, 0(dst), s_exc) 506 487 ADDC(sum, t0) 488 + .set reorder /* DADDI_WAR */ 489 + ADD dst, dst, NBYTES 507 490 bne rem, len, 1b 508 - ADD dst, dst, NBYTES 491 + .set noreorder 509 492 510 493 /* 511 494 * src and dst are aligned, need to copy rem bytes (rem < NBYTES) ··· 593 572 ADDC(sum, t2) 594 573 EXC( STORE t3, UNIT(3)(dst), s_exc) 595 574 ADDC(sum, t3) 575 + .set reorder /* DADDI_WAR */ 576 + ADD dst, dst, 4*NBYTES 596 577 bne len, rem, 1b 597 - ADD dst, dst, 4*NBYTES 578 + .set noreorder 598 579 599 580 cleanup_src_unaligned: 600 581 beqz len, done ··· 610 587 SUB len, len, NBYTES 611 588 EXC( STORE t0, 0(dst), s_exc) 612 589 ADDC(sum, t0) 590 + .set reorder /* DADDI_WAR */ 591 + ADD dst, dst, NBYTES 613 592 bne len, rem, 1b 614 - ADD dst, dst, NBYTES 593 + .set noreorder 615 594 616 595 copy_bytes_checklen: 617 596 beqz len, done ··· 656 631 ADDC(sum, t2) 657 632 done: 658 633 /* fold checksum */ 634 + .set push 635 + .set noat 659 636 #ifdef USE_DOUBLE 660 637 dsll32 v1, sum, 0 661 638 daddu sum, v1 ··· 678 651 srl sum, sum, 8 679 652 or sum, v1 680 653 andi sum, 0xffff 654 + .set pop 681 655 1: 682 656 .set reorder 683 657 ADDC(sum, psum) ··· 706 678 SLLV t1, t1, t2 707 679 addu t2, SHIFT_INC 708 680 ADDC(sum, t1) 681 + .set reorder /* DADDI_WAR */ 682 + ADD dst, dst, 1 709 683 bne src, t0, 1b 710 - ADD dst, dst, 1 684 + .set noreorder 711 685 l_exc: 712 686 LOAD t0, TI_TASK($28) 713 687 nop ··· 727 697 * Clear len bytes starting at dst. Can't call __bzero because it 728 698 * might modify len. An inefficient loop for these rare times... 729 699 */ 700 + .set reorder /* DADDI_WAR */ 701 + SUB src, len, 1 730 702 beqz len, done 731 - SUB src, len, 1 703 + .set noreorder 732 704 1: sb zero, 0(dst) 733 705 ADD dst, dst, 1 706 + .set push 707 + .set noat 708 + #ifndef CONFIG_CPU_DADDI_WORKAROUNDS 734 709 bnez src, 1b 735 710 SUB src, src, 1 711 + #else 712 + li v1, 1 713 + bnez src, 1b 714 + SUB src, src, v1 715 + #endif 736 716 li v1, -EFAULT 737 717 b done 738 718 sw v1, (errptr) ··· 752 712 li v1, -EFAULT 753 713 jr ra 754 714 sw v1, (errptr) 715 + .set pop 755 716 END(__csum_partial_copy_user)
+20 -5
arch/mips/lib/memcpy-inatomic.S
··· 9 9 * Copyright (C) 1999, 2000, 01, 2002 Silicon Graphics, Inc. 10 10 * Copyright (C) 2002 Broadcom, Inc. 11 11 * memcpy/copy_user author: Mark Vandevoorde 12 + * Copyright (C) 2007 Maciej W. Rozycki 12 13 * 13 14 * Mnemonic names for arguments to memcpy/__copy_user 14 15 */ ··· 176 175 177 176 .text 178 177 .set noreorder 178 + #ifndef CONFIG_CPU_DADDI_WORKAROUNDS 179 179 .set noat 180 + #else 181 + .set at=v1 182 + #endif 180 183 181 184 /* 182 185 * A combined memcpy/__copy_user ··· 273 268 STORE t1, UNIT(1)(dst) 274 269 STORE t2, UNIT(2)(dst) 275 270 STORE t3, UNIT(3)(dst) 271 + .set reorder /* DADDI_WAR */ 272 + ADD dst, dst, 4*NBYTES 276 273 beqz len, done 277 - ADD dst, dst, 4*NBYTES 274 + .set noreorder 278 275 less_than_4units: 279 276 /* 280 277 * rem = len % NBYTES ··· 288 281 ADD src, src, NBYTES 289 282 SUB len, len, NBYTES 290 283 STORE t0, 0(dst) 284 + .set reorder /* DADDI_WAR */ 285 + ADD dst, dst, NBYTES 291 286 bne rem, len, 1b 292 - ADD dst, dst, NBYTES 287 + .set noreorder 293 288 294 289 /* 295 290 * src and dst are aligned, need to copy rem bytes (rem < NBYTES) ··· 370 361 STORE t2, UNIT(2)(dst) 371 362 STORE t3, UNIT(3)(dst) 372 363 PREF( 1, 9*32(dst) ) # 1 is PREF_STORE (not streamed) 364 + .set reorder /* DADDI_WAR */ 365 + ADD dst, dst, 4*NBYTES 373 366 bne len, rem, 1b 374 - ADD dst, dst, 4*NBYTES 367 + .set noreorder 375 368 376 369 cleanup_src_unaligned: 377 370 beqz len, done ··· 386 375 ADD src, src, NBYTES 387 376 SUB len, len, NBYTES 388 377 STORE t0, 0(dst) 378 + .set reorder /* DADDI_WAR */ 379 + ADD dst, dst, NBYTES 389 380 bne len, rem, 1b 390 - ADD dst, dst, NBYTES 381 + .set noreorder 391 382 392 383 copy_bytes_checklen: 393 384 beqz len, done ··· 437 424 EXC( lb t1, 0(src), l_exc) 438 425 ADD src, src, 1 439 426 sb t1, 0(dst) # can't fault -- we're copy_from_user 427 + .set reorder /* DADDI_WAR */ 428 + ADD dst, dst, 1 440 429 bne src, t0, 1b 441 - ADD dst, dst, 1 430 + .set noreorder 442 431 l_exc: 443 432 LOAD t0, TI_TASK($28) 444 433 nop
+47 -13
arch/mips/lib/memcpy.S
··· 9 9 * Copyright (C) 1999, 2000, 01, 2002 Silicon Graphics, Inc. 10 10 * Copyright (C) 2002 Broadcom, Inc. 11 11 * memcpy/copy_user author: Mark Vandevoorde 12 + * Copyright (C) 2007 Maciej W. Rozycki 12 13 * 13 14 * Mnemonic names for arguments to memcpy/__copy_user 14 15 */ ··· 176 175 177 176 .text 178 177 .set noreorder 178 + #ifndef CONFIG_CPU_DADDI_WORKAROUNDS 179 179 .set noat 180 + #else 181 + .set at=v1 182 + #endif 180 183 181 184 /* 182 185 * A combined memcpy/__copy_user ··· 276 271 EXC( STORE t1, UNIT(1)(dst), s_exc_p3u) 277 272 EXC( STORE t2, UNIT(2)(dst), s_exc_p2u) 278 273 EXC( STORE t3, UNIT(3)(dst), s_exc_p1u) 274 + .set reorder /* DADDI_WAR */ 275 + ADD dst, dst, 4*NBYTES 279 276 beqz len, done 280 - ADD dst, dst, 4*NBYTES 277 + .set noreorder 281 278 less_than_4units: 282 279 /* 283 280 * rem = len % NBYTES ··· 291 284 ADD src, src, NBYTES 292 285 SUB len, len, NBYTES 293 286 EXC( STORE t0, 0(dst), s_exc_p1u) 287 + .set reorder /* DADDI_WAR */ 288 + ADD dst, dst, NBYTES 294 289 bne rem, len, 1b 295 - ADD dst, dst, NBYTES 290 + .set noreorder 296 291 297 292 /* 298 293 * src and dst are aligned, need to copy rem bytes (rem < NBYTES) ··· 373 364 EXC( STORE t2, UNIT(2)(dst), s_exc_p2u) 374 365 EXC( STORE t3, UNIT(3)(dst), s_exc_p1u) 375 366 PREF( 1, 9*32(dst) ) # 1 is PREF_STORE (not streamed) 367 + .set reorder /* DADDI_WAR */ 368 + ADD dst, dst, 4*NBYTES 376 369 bne len, rem, 1b 377 - ADD dst, dst, 4*NBYTES 370 + .set noreorder 378 371 379 372 cleanup_src_unaligned: 380 373 beqz len, done ··· 389 378 ADD src, src, NBYTES 390 379 SUB len, len, NBYTES 391 380 EXC( STORE t0, 0(dst), s_exc_p1u) 381 + .set reorder /* DADDI_WAR */ 382 + ADD dst, dst, NBYTES 392 383 bne len, rem, 1b 393 - ADD dst, dst, NBYTES 384 + .set noreorder 394 385 395 386 copy_bytes_checklen: 396 387 beqz len, done ··· 440 427 EXC( lb t1, 0(src), l_exc) 441 428 ADD src, src, 1 442 429 sb t1, 0(dst) # can't fault -- we're copy_from_user 430 + .set reorder /* DADDI_WAR */ 431 + ADD dst, dst, 1 443 432 bne src, t0, 1b 444 - ADD dst, dst, 1 433 + .set noreorder 445 434 l_exc: 446 435 LOAD t0, TI_TASK($28) 447 436 nop ··· 461 446 * Clear len bytes starting at dst. Can't call __bzero because it 462 447 * might modify len. An inefficient loop for these rare times... 463 448 */ 449 + .set reorder /* DADDI_WAR */ 450 + SUB src, len, 1 464 451 beqz len, done 465 - SUB src, len, 1 452 + .set noreorder 466 453 1: sb zero, 0(dst) 467 454 ADD dst, dst, 1 455 + #ifndef CONFIG_CPU_DADDI_WORKAROUNDS 468 456 bnez src, 1b 469 457 SUB src, src, 1 458 + #else 459 + .set push 460 + .set noat 461 + li v1, 1 462 + bnez src, 1b 463 + SUB src, src, v1 464 + .set pop 465 + #endif 470 466 jr ra 471 467 nop 472 468 473 469 474 - #define SEXC(n) \ 475 - s_exc_p ## n ## u: \ 476 - jr ra; \ 477 - ADD len, len, n*NBYTES 470 + #define SEXC(n) \ 471 + .set reorder; /* DADDI_WAR */ \ 472 + s_exc_p ## n ## u: \ 473 + ADD len, len, n*NBYTES; \ 474 + jr ra; \ 475 + .set noreorder 478 476 479 477 SEXC(8) 480 478 SEXC(7) ··· 499 471 SEXC(1) 500 472 501 473 s_exc_p1: 474 + .set reorder /* DADDI_WAR */ 475 + ADD len, len, 1 502 476 jr ra 503 - ADD len, len, 1 477 + .set noreorder 504 478 s_exc: 505 479 jr ra 506 480 nop ··· 532 502 SUB a2, a2, 0x1 533 503 sb t0, -1(a0) 534 504 SUB a1, a1, 0x1 505 + .set reorder /* DADDI_WAR */ 506 + SUB a0, a0, 0x1 535 507 bnez a2, r_end_bytes 536 - SUB a0, a0, 0x1 508 + .set noreorder 537 509 538 510 r_out: 539 511 jr ra ··· 546 514 SUB a2, a2, 0x1 547 515 sb t0, (a0) 548 516 ADD a1, a1, 0x1 517 + .set reorder /* DADDI_WAR */ 518 + ADD a0, a0, 0x1 549 519 bnez a2, r_end_bytes_up 550 - ADD a0, a0, 0x1 520 + .set noreorder 551 521 552 522 jr ra 553 523 move a2, zero
+10 -1
arch/mips/lib/memset.S
··· 5 5 * 6 6 * Copyright (C) 1998, 1999, 2000 by Ralf Baechle 7 7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 8 + * Copyright (C) 2007 Maciej W. Rozycki 8 9 */ 9 10 #include <asm/asm.h> 10 11 #include <asm/asm-offsets.h> ··· 75 74 bnez t0, small_memset 76 75 andi t0, a0, LONGMASK /* aligned? */ 77 76 77 + #ifndef CONFIG_CPU_DADDI_WORKAROUNDS 78 78 beqz t0, 1f 79 79 PTR_SUBU t0, LONGSIZE /* alignment in bytes */ 80 + #else 81 + .set noat 82 + li AT, LONGSIZE 83 + beqz t0, 1f 84 + PTR_SUBU t0, AT /* alignment in bytes */ 85 + .set at 86 + #endif 80 87 81 88 #ifdef __MIPSEB__ 82 89 EX(LONG_S_L, a1, (a0), first_fixup) /* make word/dword aligned */ ··· 115 106 .set noat 116 107 LONG_SRL AT, t0, 1 117 108 PTR_SUBU t1, AT 118 - .set noat 109 + .set at 119 110 #endif 120 111 jr t1 121 112 PTR_ADDU a0, t0 /* dest ptr */
+2 -2
arch/mips/lib/strncpy_user.S
··· 41 41 beqz t0, 2f 42 42 sb t0, (a0) 43 43 PTR_ADDIU v0, 1 44 - bne v0, a2, 1b 45 - PTR_ADDIU a0, 1 46 44 .set reorder 45 + PTR_ADDIU a0, 1 46 + bne v0, a2, 1b 47 47 2: PTR_ADDU t0, a1, v0 48 48 xor t0, a1 49 49 bltz t0, fault
+31 -35
arch/mips/mm/pg-r4k.c
··· 4 4 * for more details. 5 5 * 6 6 * Copyright (C) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org) 7 + * Copyright (C) 2007 Maciej W. Rozycki 7 8 */ 8 9 #include <linux/init.h> 9 10 #include <linux/kernel.h> ··· 13 12 #include <linux/module.h> 14 13 #include <linux/proc_fs.h> 15 14 15 + #include <asm/bugs.h> 16 16 #include <asm/cacheops.h> 17 17 #include <asm/inst.h> 18 18 #include <asm/io.h> ··· 257 255 __build_store_reg(reg); 258 256 } 259 257 260 - static inline void build_addiu_a2_a0(unsigned long offset) 258 + static inline void build_addiu_rt_rs(unsigned int rt, unsigned int rs, 259 + unsigned long offset) 261 260 { 262 261 union mips_instruction mi; 263 262 264 263 BUG_ON(offset > 0x7fff); 265 264 266 - mi.i_format.opcode = cpu_has_64bit_gp_regs ? daddiu_op : addiu_op; 267 - mi.i_format.rs = 4; /* $a0 */ 268 - mi.i_format.rt = 6; /* $a2 */ 269 - mi.i_format.simmediate = offset; 265 + if (cpu_has_64bit_gp_regs && DADDI_WAR && r4k_daddiu_bug()) { 266 + mi.i_format.opcode = addiu_op; 267 + mi.i_format.rs = 0; /* $zero */ 268 + mi.i_format.rt = 25; /* $t9 */ 269 + mi.i_format.simmediate = offset; 270 + emit_instruction(mi); 270 271 272 + mi.r_format.opcode = spec_op; 273 + mi.r_format.rs = rs; 274 + mi.r_format.rt = 25; /* $t9 */ 275 + mi.r_format.rd = rt; 276 + mi.r_format.re = 0; 277 + mi.r_format.func = daddu_op; 278 + } else { 279 + mi.i_format.opcode = cpu_has_64bit_gp_regs ? 280 + daddiu_op : addiu_op; 281 + mi.i_format.rs = rs; 282 + mi.i_format.rt = rt; 283 + mi.i_format.simmediate = offset; 284 + } 271 285 emit_instruction(mi); 286 + } 287 + 288 + static inline void build_addiu_a2_a0(unsigned long offset) 289 + { 290 + build_addiu_rt_rs(6, 4, offset); /* $a2, $a0, offset */ 272 291 } 273 292 274 293 static inline void build_addiu_a2(unsigned long offset) 275 294 { 276 - union mips_instruction mi; 277 - 278 - BUG_ON(offset > 0x7fff); 279 - 280 - mi.i_format.opcode = cpu_has_64bit_gp_regs ? daddiu_op : addiu_op; 281 - mi.i_format.rs = 6; /* $a2 */ 282 - mi.i_format.rt = 6; /* $a2 */ 283 - mi.i_format.simmediate = offset; 284 - 285 - emit_instruction(mi); 295 + build_addiu_rt_rs(6, 6, offset); /* $a2, $a2, offset */ 286 296 } 287 297 288 298 static inline void build_addiu_a1(unsigned long offset) 289 299 { 290 - union mips_instruction mi; 291 - 292 - BUG_ON(offset > 0x7fff); 293 - 294 - mi.i_format.opcode = cpu_has_64bit_gp_regs ? daddiu_op : addiu_op; 295 - mi.i_format.rs = 5; /* $a1 */ 296 - mi.i_format.rt = 5; /* $a1 */ 297 - mi.i_format.simmediate = offset; 300 + build_addiu_rt_rs(5, 5, offset); /* $a1, $a1, offset */ 298 301 299 302 load_offset -= offset; 300 - 301 - emit_instruction(mi); 302 303 } 303 304 304 305 static inline void build_addiu_a0(unsigned long offset) 305 306 { 306 - union mips_instruction mi; 307 - 308 - BUG_ON(offset > 0x7fff); 309 - 310 - mi.i_format.opcode = cpu_has_64bit_gp_regs ? daddiu_op : addiu_op; 311 - mi.i_format.rs = 4; /* $a0 */ 312 - mi.i_format.rt = 4; /* $a0 */ 313 - mi.i_format.simmediate = offset; 307 + build_addiu_rt_rs(4, 4, offset); /* $a0, $a0, offset */ 314 308 315 309 store_offset -= offset; 316 - 317 - emit_instruction(mi); 318 310 } 319 311 320 312 static inline void build_bne(unsigned int *dest)
+30 -12
arch/mips/mm/tlbex.c
··· 6 6 * Synthesize TLB refill handlers at runtime. 7 7 * 8 8 * Copyright (C) 2004,2005,2006 by Thiemo Seufer 9 - * Copyright (C) 2005 Maciej W. Rozycki 9 + * Copyright (C) 2005, 2007 Maciej W. Rozycki 10 10 * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org) 11 11 * 12 12 * ... and the days got worse and worse and now you see ··· 27 27 #include <linux/string.h> 28 28 #include <linux/init.h> 29 29 30 + #include <asm/bugs.h> 30 31 #include <asm/pgtable.h> 31 32 #include <asm/cacheflush.h> 32 33 #include <asm/mmu_context.h> ··· 294 293 break; 295 294 } 296 295 297 - if (!ip) 296 + if (!ip || (opc == insn_daddiu && r4k_daddiu_bug())) 298 297 panic("Unsupported TLB synthesizer instruction %d", opc); 299 298 300 299 op = ip->match; ··· 526 525 #define i_ssnop(buf) i_sll(buf, 0, 0, 1) 527 526 #define i_ehb(buf) i_sll(buf, 0, 0, 3) 528 527 529 - #ifdef CONFIG_64BIT 530 528 static __init int __maybe_unused in_compat_space_p(long addr) 531 529 { 532 530 /* Is this address in 32bit compat space? */ 531 + #ifdef CONFIG_64BIT 533 532 return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L); 533 + #else 534 + return 1; 535 + #endif 534 536 } 535 537 536 538 static __init int __maybe_unused rel_highest(long val) 537 539 { 540 + #ifdef CONFIG_64BIT 538 541 return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000; 542 + #else 543 + return 0; 544 + #endif 539 545 } 540 546 541 547 static __init int __maybe_unused rel_higher(long val) 542 548 { 549 + #ifdef CONFIG_64BIT 543 550 return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000; 544 - } 551 + #else 552 + return 0; 545 553 #endif 554 + } 546 555 547 556 static __init int rel_hi(long val) 548 557 { ··· 566 555 567 556 static __init void i_LA_mostly(u32 **buf, unsigned int rs, long addr) 568 557 { 569 - #ifdef CONFIG_64BIT 570 558 if (!in_compat_space_p(addr)) { 571 559 i_lui(buf, rs, rel_highest(addr)); 572 560 if (rel_higher(addr)) ··· 577 567 } else 578 568 i_dsll32(buf, rs, rs, 0); 579 569 } else 580 - #endif 581 570 i_lui(buf, rs, rel_hi(addr)); 582 571 } 583 572 584 - static __init void __maybe_unused i_LA(u32 **buf, unsigned int rs, 585 - long addr) 573 + static __init void __maybe_unused i_LA(u32 **buf, unsigned int rs, long addr) 586 574 { 587 575 i_LA_mostly(buf, rs, addr); 588 - if (rel_lo(addr)) 589 - i_ADDIU(buf, rs, rs, rel_lo(addr)); 576 + if (rel_lo(addr)) { 577 + if (!in_compat_space_p(addr)) 578 + i_daddiu(buf, rs, rs, rel_lo(addr)); 579 + else 580 + i_addiu(buf, rs, rs, rel_lo(addr)); 581 + } 590 582 } 591 583 592 584 /* ··· 1097 1085 } else { 1098 1086 i_LA_mostly(p, ptr, modd); 1099 1087 il_b(p, r, label_vmalloc_done); 1100 - i_daddiu(p, ptr, ptr, rel_lo(modd)); 1088 + if (in_compat_space_p(modd)) 1089 + i_addiu(p, ptr, ptr, rel_lo(modd)); 1090 + else 1091 + i_daddiu(p, ptr, ptr, rel_lo(modd)); 1101 1092 } 1102 1093 1103 1094 l_vmalloc(l, *p); ··· 1121 1106 } else { 1122 1107 i_LA_mostly(p, ptr, swpd); 1123 1108 il_b(p, r, label_vmalloc_done); 1124 - i_daddiu(p, ptr, ptr, rel_lo(swpd)); 1109 + if (in_compat_space_p(swpd)) 1110 + i_addiu(p, ptr, ptr, rel_lo(swpd)); 1111 + else 1112 + i_daddiu(p, ptr, ptr, rel_lo(swpd)); 1125 1113 } 1126 1114 } 1127 1115
+10 -1
include/asm-mips/delay.h
··· 28 28 " .set reorder \n" 29 29 : "=r" (loops) 30 30 : "0" (loops)); 31 - else if (sizeof(long) == 8) 31 + else if (sizeof(long) == 8 && !DADDI_WAR) 32 32 __asm__ __volatile__ ( 33 33 " .set noreorder \n" 34 34 " .align 3 \n" ··· 37 37 " .set reorder \n" 38 38 : "=r" (loops) 39 39 : "0" (loops)); 40 + else if (sizeof(long) == 8 && DADDI_WAR) 41 + __asm__ __volatile__ ( 42 + " .set noreorder \n" 43 + " .align 3 \n" 44 + "1: bnez %0, 1b \n" 45 + " dsubu %0, %2 \n" 46 + " .set reorder \n" 47 + : "=r" (loops) 48 + : "0" (loops), "r" (1)); 40 49 } 41 50 42 51
+9
include/asm-mips/stackframe.h
··· 6 6 * Copyright (C) 1994, 95, 96, 99, 2001 Ralf Baechle 7 7 * Copyright (C) 1994, 1995, 1996 Paul M. Antoine. 8 8 * Copyright (C) 1999 Silicon Graphics, Inc. 9 + * Copyright (C) 2007 Maciej W. Rozycki 9 10 */ 10 11 #ifndef _ASM_STACKFRAME_H 11 12 #define _ASM_STACKFRAME_H ··· 146 145 .set reorder 147 146 /* Called from user mode, new stack. */ 148 147 get_saved_sp 148 + #ifndef CONFIG_CPU_DADDI_WORKAROUNDS 149 149 8: move k0, sp 150 150 PTR_SUBU sp, k1, PT_SIZE 151 + #else 152 + .set at=k0 153 + 8: PTR_SUBU k1, PT_SIZE 154 + .set noat 155 + move k0, sp 156 + move sp, k1 157 + #endif 151 158 LONG_S k0, PT_R29(sp) 152 159 LONG_S $3, PT_R3(sp) 153 160 /*
+10 -3
include/asm-mips/uaccess.h
··· 5 5 * 6 6 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 03, 04 by Ralf Baechle 7 7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 8 + * Copyright (C) 2007 Maciej W. Rozycki 8 9 */ 9 10 #ifndef _ASM_UACCESS_H 10 11 #define _ASM_UACCESS_H ··· 388 387 "jal\t" #destination "\n\t" 389 388 #endif 390 389 390 + #ifndef CONFIG_CPU_DADDI_WORKAROUNDS 391 + #define DADDI_SCRATCH "$0" 392 + #else 393 + #define DADDI_SCRATCH "$3" 394 + #endif 395 + 391 396 extern size_t __copy_user(void *__to, const void *__from, size_t __n); 392 397 393 398 #define __invoke_copy_to_user(to, from, n) \ ··· 410 403 : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r) \ 411 404 : \ 412 405 : "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31", \ 413 - "memory"); \ 406 + DADDI_SCRATCH, "memory"); \ 414 407 __cu_len_r; \ 415 408 }) 416 409 ··· 519 512 : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r) \ 520 513 : \ 521 514 : "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31", \ 522 - "memory"); \ 515 + DADDI_SCRATCH, "memory"); \ 523 516 __cu_len_r; \ 524 517 }) 525 518 ··· 542 535 : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r) \ 543 536 : \ 544 537 : "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31", \ 545 - "memory"); \ 538 + DADDI_SCRATCH, "memory"); \ 546 539 __cu_len_r; \ 547 540 }) 548 541