xref: /linux/arch/mips/kernel/watch.c (revision 44f57d78)
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) 2008 David Daney
7  */
8 
9 #include <linux/sched.h>
10 
11 #include <asm/processor.h>
12 #include <asm/watch.h>
13 
14 /*
15  * Install the watch registers for the current thread.	A maximum of
16  * four registers are installed although the machine may have more.
17  */
18 void mips_install_watch_registers(struct task_struct *t)
19 {
20 	struct mips3264_watch_reg_state *watches = &t->thread.watch.mips3264;
21 	unsigned int watchhi = MIPS_WATCHHI_G |		/* Trap all ASIDs */
22 			       MIPS_WATCHHI_IRW;	/* Clear result bits */
23 
24 	switch (current_cpu_data.watch_reg_use_cnt) {
25 	default:
26 		BUG();
27 	case 4:
28 		write_c0_watchlo3(watches->watchlo[3]);
29 		write_c0_watchhi3(watchhi | watches->watchhi[3]);
30 		/* fall through */
31 	case 3:
32 		write_c0_watchlo2(watches->watchlo[2]);
33 		write_c0_watchhi2(watchhi | watches->watchhi[2]);
34 		/* fall through */
35 	case 2:
36 		write_c0_watchlo1(watches->watchlo[1]);
37 		write_c0_watchhi1(watchhi | watches->watchhi[1]);
38 		/* fall through */
39 	case 1:
40 		write_c0_watchlo0(watches->watchlo[0]);
41 		write_c0_watchhi0(watchhi | watches->watchhi[0]);
42 	}
43 }
44 
45 /*
46  * Read back the watchhi registers so the user space debugger has
47  * access to the I, R, and W bits.  A maximum of four registers are
48  * read although the machine may have more.
49  */
50 void mips_read_watch_registers(void)
51 {
52 	struct mips3264_watch_reg_state *watches =
53 		&current->thread.watch.mips3264;
54 	unsigned int watchhi_mask = MIPS_WATCHHI_MASK | MIPS_WATCHHI_IRW;
55 
56 	switch (current_cpu_data.watch_reg_use_cnt) {
57 	default:
58 		BUG();
59 	case 4:
60 		watches->watchhi[3] = (read_c0_watchhi3() & watchhi_mask);
61 		/* fall through */
62 	case 3:
63 		watches->watchhi[2] = (read_c0_watchhi2() & watchhi_mask);
64 		/* fall through */
65 	case 2:
66 		watches->watchhi[1] = (read_c0_watchhi1() & watchhi_mask);
67 		/* fall through */
68 	case 1:
69 		watches->watchhi[0] = (read_c0_watchhi0() & watchhi_mask);
70 	}
71 	if (current_cpu_data.watch_reg_use_cnt == 1 &&
72 	    (watches->watchhi[0] & MIPS_WATCHHI_IRW) == 0) {
73 		/* Pathological case of release 1 architecture that
74 		 * doesn't set the condition bits.  We assume that
75 		 * since we got here, the watch condition was met and
76 		 * signal that the conditions requested in watchlo
77 		 * were met.  */
78 		watches->watchhi[0] |= (watches->watchlo[0] & MIPS_WATCHHI_IRW);
79 	}
80  }
81 
82 /*
83  * Disable all watch registers.	 Although only four registers are
84  * installed, all are cleared to eliminate the possibility of endless
85  * looping in the watch handler.
86  */
87 void mips_clear_watch_registers(void)
88 {
89 	switch (current_cpu_data.watch_reg_count) {
90 	default:
91 		BUG();
92 	case 8:
93 		write_c0_watchlo7(0);
94 		/* fall through */
95 	case 7:
96 		write_c0_watchlo6(0);
97 		/* fall through */
98 	case 6:
99 		write_c0_watchlo5(0);
100 		/* fall through */
101 	case 5:
102 		write_c0_watchlo4(0);
103 		/* fall through */
104 	case 4:
105 		write_c0_watchlo3(0);
106 		/* fall through */
107 	case 3:
108 		write_c0_watchlo2(0);
109 		/* fall through */
110 	case 2:
111 		write_c0_watchlo1(0);
112 		/* fall through */
113 	case 1:
114 		write_c0_watchlo0(0);
115 	}
116 }
117 
118 void mips_probe_watch_registers(struct cpuinfo_mips *c)
119 {
120 	unsigned int t;
121 
122 	if ((c->options & MIPS_CPU_WATCH) == 0)
123 		return;
124 	/*
125 	 * Check which of the I,R and W bits are supported, then
126 	 * disable the register.
127 	 */
128 	write_c0_watchlo0(MIPS_WATCHLO_IRW);
129 	back_to_back_c0_hazard();
130 	t = read_c0_watchlo0();
131 	write_c0_watchlo0(0);
132 	c->watch_reg_masks[0] = t & MIPS_WATCHLO_IRW;
133 
134 	/* Write the mask bits and read them back to determine which
135 	 * can be used. */
136 	c->watch_reg_count = 1;
137 	c->watch_reg_use_cnt = 1;
138 	t = read_c0_watchhi0();
139 	write_c0_watchhi0(t | MIPS_WATCHHI_MASK);
140 	back_to_back_c0_hazard();
141 	t = read_c0_watchhi0();
142 	c->watch_reg_masks[0] |= (t & MIPS_WATCHHI_MASK);
143 	if ((t & MIPS_WATCHHI_M) == 0)
144 		return;
145 
146 	write_c0_watchlo1(MIPS_WATCHLO_IRW);
147 	back_to_back_c0_hazard();
148 	t = read_c0_watchlo1();
149 	write_c0_watchlo1(0);
150 	c->watch_reg_masks[1] = t & MIPS_WATCHLO_IRW;
151 
152 	c->watch_reg_count = 2;
153 	c->watch_reg_use_cnt = 2;
154 	t = read_c0_watchhi1();
155 	write_c0_watchhi1(t | MIPS_WATCHHI_MASK);
156 	back_to_back_c0_hazard();
157 	t = read_c0_watchhi1();
158 	c->watch_reg_masks[1] |= (t & MIPS_WATCHHI_MASK);
159 	if ((t & MIPS_WATCHHI_M) == 0)
160 		return;
161 
162 	write_c0_watchlo2(MIPS_WATCHLO_IRW);
163 	back_to_back_c0_hazard();
164 	t = read_c0_watchlo2();
165 	write_c0_watchlo2(0);
166 	c->watch_reg_masks[2] = t & MIPS_WATCHLO_IRW;
167 
168 	c->watch_reg_count = 3;
169 	c->watch_reg_use_cnt = 3;
170 	t = read_c0_watchhi2();
171 	write_c0_watchhi2(t | MIPS_WATCHHI_MASK);
172 	back_to_back_c0_hazard();
173 	t = read_c0_watchhi2();
174 	c->watch_reg_masks[2] |= (t & MIPS_WATCHHI_MASK);
175 	if ((t & MIPS_WATCHHI_M) == 0)
176 		return;
177 
178 	write_c0_watchlo3(MIPS_WATCHLO_IRW);
179 	back_to_back_c0_hazard();
180 	t = read_c0_watchlo3();
181 	write_c0_watchlo3(0);
182 	c->watch_reg_masks[3] = t & MIPS_WATCHLO_IRW;
183 
184 	c->watch_reg_count = 4;
185 	c->watch_reg_use_cnt = 4;
186 	t = read_c0_watchhi3();
187 	write_c0_watchhi3(t | MIPS_WATCHHI_MASK);
188 	back_to_back_c0_hazard();
189 	t = read_c0_watchhi3();
190 	c->watch_reg_masks[3] |= (t & MIPS_WATCHHI_MASK);
191 	if ((t & MIPS_WATCHHI_M) == 0)
192 		return;
193 
194 	/* We use at most 4, but probe and report up to 8. */
195 	c->watch_reg_count = 5;
196 	t = read_c0_watchhi4();
197 	if ((t & MIPS_WATCHHI_M) == 0)
198 		return;
199 
200 	c->watch_reg_count = 6;
201 	t = read_c0_watchhi5();
202 	if ((t & MIPS_WATCHHI_M) == 0)
203 		return;
204 
205 	c->watch_reg_count = 7;
206 	t = read_c0_watchhi6();
207 	if ((t & MIPS_WATCHHI_M) == 0)
208 		return;
209 
210 	c->watch_reg_count = 8;
211 }
212