Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus

Pull MIPS fixes from Ralf Baechle:
 "More 3.18 fixes for MIPS:

   - backtraces were not quite working on on 64-bit kernels
   - loongson needs a different cache coherency setting
   - Loongson 3 is a MIPS64 R2 version but due to erratum we treat is an
     older architecture revision.
   - fix build errors due to undefined references to __node_distances
     for certain configurations.
   - fix instruction decodig in the jump label code.
   - for certain configurations copy_{from,to}_user destroy the content
     of $3 so that register needs to be marked as clobbed by the calling
     code.
   - Hardware Table Walker fixes.
   - fill the delay slot of the last instruction of memcpy otherwise
     whatever ends up there randomly might have undesirable effects.
   - ensure get_user/__get_user always zero the variable to be read even
     in case of an error"

* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus:
  MIPS: jump_label.c: Handle the microMIPS J instruction encoding
  MIPS: jump_label.c: Correct the span of the J instruction
  MIPS: Zero variable read by get_user / __get_user in case of an error.
  MIPS: lib: memcpy: Restore NOP on delay slot before returning to caller
  MIPS: tlb-r4k: Add missing HTW stop/start sequences
  MIPS: asm: uaccess: Add v1 register to clobber list on EVA
  MIPS: oprofile: Fix backtrace on 64-bit kernel
  MIPS: Loongson: Set Loongson-3's ISA level to MIPS64R1
  MIPS: Loongson: Fix the write-combine CCA value setting
  MIPS: IP27: Fix __node_distances undefined error
  MIPS: Loongson3: Fix __node_distances undefined error
This commit is contained in:
Linus Torvalds 2014-11-21 16:14:58 -08:00
commit e6a588d086
10 changed files with 60 additions and 20 deletions

View File

@ -20,9 +20,15 @@
#define WORD_INSN ".word" #define WORD_INSN ".word"
#endif #endif
#ifdef CONFIG_CPU_MICROMIPS
#define NOP_INSN "nop32"
#else
#define NOP_INSN "nop"
#endif
static __always_inline bool arch_static_branch(struct static_key *key) static __always_inline bool arch_static_branch(struct static_key *key)
{ {
asm_volatile_goto("1:\tnop\n\t" asm_volatile_goto("1:\t" NOP_INSN "\n\t"
"nop\n\t" "nop\n\t"
".pushsection __jump_table, \"aw\"\n\t" ".pushsection __jump_table, \"aw\"\n\t"
WORD_INSN " 1b, %l[l_yes], %0\n\t" WORD_INSN " 1b, %l[l_yes], %0\n\t"

View File

@ -41,10 +41,8 @@
#define cpu_has_mcheck 0 #define cpu_has_mcheck 0
#define cpu_has_mdmx 0 #define cpu_has_mdmx 0
#define cpu_has_mips16 0 #define cpu_has_mips16 0
#define cpu_has_mips32r1 0
#define cpu_has_mips32r2 0 #define cpu_has_mips32r2 0
#define cpu_has_mips3d 0 #define cpu_has_mips3d 0
#define cpu_has_mips64r1 0
#define cpu_has_mips64r2 0 #define cpu_has_mips64r2 0
#define cpu_has_mipsmt 0 #define cpu_has_mipsmt 0
#define cpu_has_prefetch 0 #define cpu_has_prefetch 0

View File

@ -301,7 +301,8 @@ do { \
__get_kernel_common((x), size, __gu_ptr); \ __get_kernel_common((x), size, __gu_ptr); \
else \ else \
__get_user_common((x), size, __gu_ptr); \ __get_user_common((x), size, __gu_ptr); \
} \ } else \
(x) = 0; \
\ \
__gu_err; \ __gu_err; \
}) })
@ -316,6 +317,7 @@ do { \
" .insn \n" \ " .insn \n" \
" .section .fixup,\"ax\" \n" \ " .section .fixup,\"ax\" \n" \
"3: li %0, %4 \n" \ "3: li %0, %4 \n" \
" move %1, $0 \n" \
" j 2b \n" \ " j 2b \n" \
" .previous \n" \ " .previous \n" \
" .section __ex_table,\"a\" \n" \ " .section __ex_table,\"a\" \n" \
@ -630,6 +632,7 @@ do { \
" .insn \n" \ " .insn \n" \
" .section .fixup,\"ax\" \n" \ " .section .fixup,\"ax\" \n" \
"3: li %0, %4 \n" \ "3: li %0, %4 \n" \
" move %1, $0 \n" \
" j 2b \n" \ " j 2b \n" \
" .previous \n" \ " .previous \n" \
" .section __ex_table,\"a\" \n" \ " .section __ex_table,\"a\" \n" \
@ -773,10 +776,11 @@ extern void __put_user_unaligned_unknown(void);
"jal\t" #destination "\n\t" "jal\t" #destination "\n\t"
#endif #endif
#ifndef CONFIG_CPU_DADDI_WORKAROUNDS #if defined(CONFIG_CPU_DADDI_WORKAROUNDS) || (defined(CONFIG_EVA) && \
#define DADDI_SCRATCH "$0" defined(CONFIG_CPU_HAS_PREFETCH))
#else
#define DADDI_SCRATCH "$3" #define DADDI_SCRATCH "$3"
#else
#define DADDI_SCRATCH "$0"
#endif #endif
extern size_t __copy_user(void *__to, const void *__from, size_t __n); extern size_t __copy_user(void *__to, const void *__from, size_t __n);

View File

@ -757,31 +757,34 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
c->cputype = CPU_LOONGSON2; c->cputype = CPU_LOONGSON2;
__cpu_name[cpu] = "ICT Loongson-2"; __cpu_name[cpu] = "ICT Loongson-2";
set_elf_platform(cpu, "loongson2e"); set_elf_platform(cpu, "loongson2e");
set_isa(c, MIPS_CPU_ISA_III);
break; break;
case PRID_REV_LOONGSON2F: case PRID_REV_LOONGSON2F:
c->cputype = CPU_LOONGSON2; c->cputype = CPU_LOONGSON2;
__cpu_name[cpu] = "ICT Loongson-2"; __cpu_name[cpu] = "ICT Loongson-2";
set_elf_platform(cpu, "loongson2f"); set_elf_platform(cpu, "loongson2f");
set_isa(c, MIPS_CPU_ISA_III);
break; break;
case PRID_REV_LOONGSON3A: case PRID_REV_LOONGSON3A:
c->cputype = CPU_LOONGSON3; c->cputype = CPU_LOONGSON3;
c->writecombine = _CACHE_UNCACHED_ACCELERATED;
__cpu_name[cpu] = "ICT Loongson-3"; __cpu_name[cpu] = "ICT Loongson-3";
set_elf_platform(cpu, "loongson3a"); set_elf_platform(cpu, "loongson3a");
set_isa(c, MIPS_CPU_ISA_M64R1);
break; break;
case PRID_REV_LOONGSON3B_R1: case PRID_REV_LOONGSON3B_R1:
case PRID_REV_LOONGSON3B_R2: case PRID_REV_LOONGSON3B_R2:
c->cputype = CPU_LOONGSON3; c->cputype = CPU_LOONGSON3;
__cpu_name[cpu] = "ICT Loongson-3"; __cpu_name[cpu] = "ICT Loongson-3";
set_elf_platform(cpu, "loongson3b"); set_elf_platform(cpu, "loongson3b");
set_isa(c, MIPS_CPU_ISA_M64R1);
break; break;
} }
set_isa(c, MIPS_CPU_ISA_III);
c->options = R4K_OPTS | c->options = R4K_OPTS |
MIPS_CPU_FPU | MIPS_CPU_LLSC | MIPS_CPU_FPU | MIPS_CPU_LLSC |
MIPS_CPU_32FPR; MIPS_CPU_32FPR;
c->tlbsize = 64; c->tlbsize = 64;
c->writecombine = _CACHE_UNCACHED_ACCELERATED;
break; break;
case PRID_IMP_LOONGSON_32: /* Loongson-1 */ case PRID_IMP_LOONGSON_32: /* Loongson-1 */
decode_configs(c); decode_configs(c);

View File

@ -18,31 +18,53 @@
#ifdef HAVE_JUMP_LABEL #ifdef HAVE_JUMP_LABEL
#define J_RANGE_MASK ((1ul << 28) - 1) /*
* Define parameters for the standard MIPS and the microMIPS jump
* instruction encoding respectively:
*
* - the ISA bit of the target, either 0 or 1 respectively,
*
* - the amount the jump target address is shifted right to fit in the
* immediate field of the machine instruction, either 2 or 1,
*
* - the mask determining the size of the jump region relative to the
* delay-slot instruction, either 256MB or 128MB,
*
* - the jump target alignment, either 4 or 2 bytes.
*/
#define J_ISA_BIT IS_ENABLED(CONFIG_CPU_MICROMIPS)
#define J_RANGE_SHIFT (2 - J_ISA_BIT)
#define J_RANGE_MASK ((1ul << (26 + J_RANGE_SHIFT)) - 1)
#define J_ALIGN_MASK ((1ul << J_RANGE_SHIFT) - 1)
void arch_jump_label_transform(struct jump_entry *e, void arch_jump_label_transform(struct jump_entry *e,
enum jump_label_type type) enum jump_label_type type)
{ {
union mips_instruction *insn_p;
union mips_instruction insn; union mips_instruction insn;
union mips_instruction *insn_p =
(union mips_instruction *)(unsigned long)e->code;
/* Jump only works within a 256MB aligned region. */ insn_p = (union mips_instruction *)msk_isa16_mode(e->code);
BUG_ON((e->target & ~J_RANGE_MASK) != (e->code & ~J_RANGE_MASK));
/* Target must have 4 byte alignment. */ /* Jump only works within an aligned region its delay slot is in. */
BUG_ON((e->target & 3) != 0); BUG_ON((e->target & ~J_RANGE_MASK) != ((e->code + 4) & ~J_RANGE_MASK));
/* Target must have the right alignment and ISA must be preserved. */
BUG_ON((e->target & J_ALIGN_MASK) != J_ISA_BIT);
if (type == JUMP_LABEL_ENABLE) { if (type == JUMP_LABEL_ENABLE) {
insn.j_format.opcode = j_op; insn.j_format.opcode = J_ISA_BIT ? mm_j32_op : j_op;
insn.j_format.target = (e->target & J_RANGE_MASK) >> 2; insn.j_format.target = e->target >> J_RANGE_SHIFT;
} else { } else {
insn.word = 0; /* nop */ insn.word = 0; /* nop */
} }
get_online_cpus(); get_online_cpus();
mutex_lock(&text_mutex); mutex_lock(&text_mutex);
*insn_p = insn; if (IS_ENABLED(CONFIG_CPU_MICROMIPS)) {
insn_p->halfword[0] = insn.word >> 16;
insn_p->halfword[1] = insn.word;
} else
*insn_p = insn;
flush_icache_range((unsigned long)insn_p, flush_icache_range((unsigned long)insn_p,
(unsigned long)insn_p + sizeof(*insn_p)); (unsigned long)insn_p + sizeof(*insn_p));

View File

@ -503,6 +503,7 @@
STOREB(t0, NBYTES-2(dst), .Ls_exc_p1\@) STOREB(t0, NBYTES-2(dst), .Ls_exc_p1\@)
.Ldone\@: .Ldone\@:
jr ra jr ra
nop
.if __memcpy == 1 .if __memcpy == 1
END(memcpy) END(memcpy)
.set __memcpy, 0 .set __memcpy, 0

View File

@ -33,6 +33,7 @@
static struct node_data prealloc__node_data[MAX_NUMNODES]; static struct node_data prealloc__node_data[MAX_NUMNODES];
unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES]; unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES];
EXPORT_SYMBOL(__node_distances);
struct node_data *__node_data[MAX_NUMNODES]; struct node_data *__node_data[MAX_NUMNODES];
EXPORT_SYMBOL(__node_data); EXPORT_SYMBOL(__node_data);

View File

@ -299,6 +299,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
local_irq_save(flags); local_irq_save(flags);
htw_stop();
pid = read_c0_entryhi() & ASID_MASK; pid = read_c0_entryhi() & ASID_MASK;
address &= (PAGE_MASK << 1); address &= (PAGE_MASK << 1);
write_c0_entryhi(address | pid); write_c0_entryhi(address | pid);
@ -346,6 +347,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
tlb_write_indexed(); tlb_write_indexed();
} }
tlbw_use_hazard(); tlbw_use_hazard();
htw_start();
flush_itlb_vm(vma); flush_itlb_vm(vma);
local_irq_restore(flags); local_irq_restore(flags);
} }
@ -422,6 +424,7 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
local_irq_save(flags); local_irq_save(flags);
/* Save old context and create impossible VPN2 value */ /* Save old context and create impossible VPN2 value */
htw_stop();
old_ctx = read_c0_entryhi(); old_ctx = read_c0_entryhi();
old_pagemask = read_c0_pagemask(); old_pagemask = read_c0_pagemask();
wired = read_c0_wired(); wired = read_c0_wired();
@ -443,6 +446,7 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
write_c0_entryhi(old_ctx); write_c0_entryhi(old_ctx);
write_c0_pagemask(old_pagemask); write_c0_pagemask(old_pagemask);
htw_start();
out: out:
local_irq_restore(flags); local_irq_restore(flags);
return ret; return ret;

View File

@ -92,7 +92,7 @@ static inline int unwind_user_frame(struct stackframe *old_frame,
/* This marks the end of the previous function, /* This marks the end of the previous function,
which means we overran. */ which means we overran. */
break; break;
stack_size = (unsigned) stack_adjustment; stack_size = (unsigned long) stack_adjustment;
} else if (is_ra_save_ins(&ip)) { } else if (is_ra_save_ins(&ip)) {
int ra_slot = ip.i_format.simmediate; int ra_slot = ip.i_format.simmediate;
if (ra_slot < 0) if (ra_slot < 0)

View File

@ -107,6 +107,7 @@ static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth)
} }
unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES]; unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
EXPORT_SYMBOL(__node_distances);
static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b) static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b)
{ {