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 */
38notrace 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}
58EXPORT_SYMBOL(arch_local_irq_disable);
59
60notrace 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}
85EXPORT_SYMBOL(arch_local_irq_save);
86
87notrace 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}
111EXPORT_SYMBOL(arch_local_irq_restore);
112
113#endif /* !CONFIG_CPU_HAS_DIEI */
114