1  /*
2   * This file is subject to the terms and conditions of the GNU General Public
3   * License.  See the file "COPYING" in the main directory of this archive
4   * for more details.
5   *
6   * Copyright (C) 1994, 95, 96, 97, 98, 99, 2003 by Ralf Baechle
7   * Copyright (C) 1996 by Paul M. Antoine
8   * Copyright (C) 1999 Silicon Graphics
9   * Copyright (C) 2000 MIPS Technologies, Inc.
10   */
11  #include <asm/irqflags.h>
12  #include <asm/hazards.h>
13  #include <linux/compiler.h>
14  #include <linux/preempt.h>
15  #include <linux/export.h>
16  #include <linux/stringify.h>
17  
18  #if !defined(CONFIG_CPU_HAS_DIEI)
19  
20  /*
21   * For cli() we have to insert nops to make sure that the new value
22   * has actually arrived in the status register before the end of this
23   * macro.
24   * R4000/R4400 need three nops, the R4600 two nops and the R10000 needs
25   * no nops at all.
26   */
27  /*
28   * For TX49, operating only IE bit is not enough.
29   *
30   * If mfc0 $12 follows store and the mfc0 is last instruction of a
31   * page and fetching the next instruction causes TLB miss, the result
32   * of the mfc0 might wrongly contain EXL bit.
33   *
34   * ERT-TX49H2-027, ERT-TX49H3-012, ERT-TX49HL3-006, ERT-TX49H4-008
35   *
36   * Workaround: mask EXL bit of the result or place a nop before mfc0.
37   */
arch_local_irq_disable(void)38  notrace void arch_local_irq_disable(void)
39  {
40  	preempt_disable_notrace();
41  
42  	__asm__ __volatile__(
43  	"	.set	push						\n"
44  	"	.set	noat						\n"
45  	"	mfc0	$1,$12						\n"
46  	"	ori	$1,0x1f						\n"
47  	"	xori	$1,0x1f						\n"
48  	"	.set	noreorder					\n"
49  	"	mtc0	$1,$12						\n"
50  	"	" __stringify(__irq_disable_hazard) "			\n"
51  	"	.set	pop						\n"
52  	: /* no outputs */
53  	: /* no inputs */
54  	: "memory");
55  
56  	preempt_enable_notrace();
57  }
58  EXPORT_SYMBOL(arch_local_irq_disable);
59  
arch_local_irq_save(void)60  notrace unsigned long arch_local_irq_save(void)
61  {
62  	unsigned long flags;
63  
64  	preempt_disable_notrace();
65  
66  	__asm__ __volatile__(
67  	"	.set	push						\n"
68  	"	.set	reorder						\n"
69  	"	.set	noat						\n"
70  	"	mfc0	%[flags], $12					\n"
71  	"	ori	$1, %[flags], 0x1f				\n"
72  	"	xori	$1, 0x1f					\n"
73  	"	.set	noreorder					\n"
74  	"	mtc0	$1, $12						\n"
75  	"	" __stringify(__irq_disable_hazard) "			\n"
76  	"	.set	pop						\n"
77  	: [flags] "=r" (flags)
78  	: /* no inputs */
79  	: "memory");
80  
81  	preempt_enable_notrace();
82  
83  	return flags;
84  }
85  EXPORT_SYMBOL(arch_local_irq_save);
86  
arch_local_irq_restore(unsigned long flags)87  notrace void arch_local_irq_restore(unsigned long flags)
88  {
89  	unsigned long __tmp1;
90  
91  	preempt_disable_notrace();
92  
93  	__asm__ __volatile__(
94  	"	.set	push						\n"
95  	"	.set	noreorder					\n"
96  	"	.set	noat						\n"
97  	"	mfc0	$1, $12						\n"
98  	"	andi	%[flags], 1					\n"
99  	"	ori	$1, 0x1f					\n"
100  	"	xori	$1, 0x1f					\n"
101  	"	or	%[flags], $1					\n"
102  	"	mtc0	%[flags], $12					\n"
103  	"	" __stringify(__irq_disable_hazard) "			\n"
104  	"	.set	pop						\n"
105  	: [flags] "=r" (__tmp1)
106  	: "0" (flags)
107  	: "memory");
108  
109  	preempt_enable_notrace();
110  }
111  EXPORT_SYMBOL(arch_local_irq_restore);
112  
113  #endif /* !CONFIG_CPU_HAS_DIEI */
114