xref: /openbmc/linux/arch/mips/kernel/watch.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
16aa3524cSDavid Daney /*
26aa3524cSDavid Daney  * This file is subject to the terms and conditions of the GNU General Public
36aa3524cSDavid Daney  * License.  See the file "COPYING" in the main directory of this archive
46aa3524cSDavid Daney  * for more details.
56aa3524cSDavid Daney  *
66aa3524cSDavid Daney  * Copyright (C) 2008 David Daney
76aa3524cSDavid Daney  */
86aa3524cSDavid Daney 
96aa3524cSDavid Daney #include <linux/sched.h>
106aa3524cSDavid Daney 
116aa3524cSDavid Daney #include <asm/processor.h>
126aa3524cSDavid Daney #include <asm/watch.h>
136aa3524cSDavid Daney 
146aa3524cSDavid Daney /*
156aa3524cSDavid Daney  * Install the watch registers for the current thread.	A maximum of
166aa3524cSDavid Daney  * four registers are installed although the machine may have more.
176aa3524cSDavid Daney  */
mips_install_watch_registers(struct task_struct * t)18a7e89326SJames Hogan void mips_install_watch_registers(struct task_struct *t)
196aa3524cSDavid Daney {
20a7e89326SJames Hogan 	struct mips3264_watch_reg_state *watches = &t->thread.watch.mips3264;
21f609cc3aSMatt Redfearn 	unsigned int watchhi = MIPS_WATCHHI_G |		/* Trap all ASIDs */
22f609cc3aSMatt Redfearn 			       MIPS_WATCHHI_IRW;	/* Clear result bits */
23f609cc3aSMatt Redfearn 
246aa3524cSDavid Daney 	switch (current_cpu_data.watch_reg_use_cnt) {
256aa3524cSDavid Daney 	default:
266aa3524cSDavid Daney 		BUG();
276aa3524cSDavid Daney 	case 4:
286aa3524cSDavid Daney 		write_c0_watchlo3(watches->watchlo[3]);
29f609cc3aSMatt Redfearn 		write_c0_watchhi3(watchhi | watches->watchhi[3]);
30*c9b02990SLiangliang Huang 		fallthrough;
316aa3524cSDavid Daney 	case 3:
326aa3524cSDavid Daney 		write_c0_watchlo2(watches->watchlo[2]);
33f609cc3aSMatt Redfearn 		write_c0_watchhi2(watchhi | watches->watchhi[2]);
34*c9b02990SLiangliang Huang 		fallthrough;
356aa3524cSDavid Daney 	case 2:
366aa3524cSDavid Daney 		write_c0_watchlo1(watches->watchlo[1]);
37f609cc3aSMatt Redfearn 		write_c0_watchhi1(watchhi | watches->watchhi[1]);
38*c9b02990SLiangliang Huang 		fallthrough;
396aa3524cSDavid Daney 	case 1:
406aa3524cSDavid Daney 		write_c0_watchlo0(watches->watchlo[0]);
41f609cc3aSMatt Redfearn 		write_c0_watchhi0(watchhi | watches->watchhi[0]);
426aa3524cSDavid Daney 	}
436aa3524cSDavid Daney }
446aa3524cSDavid Daney 
456aa3524cSDavid Daney /*
466aa3524cSDavid Daney  * Read back the watchhi registers so the user space debugger has
476aa3524cSDavid Daney  * access to the I, R, and W bits.  A maximum of four registers are
486aa3524cSDavid Daney  * read although the machine may have more.
496aa3524cSDavid Daney  */
mips_read_watch_registers(void)506aa3524cSDavid Daney void mips_read_watch_registers(void)
516aa3524cSDavid Daney {
526aa3524cSDavid Daney 	struct mips3264_watch_reg_state *watches =
536aa3524cSDavid Daney 		&current->thread.watch.mips3264;
54705e71adSMatt Redfearn 	unsigned int watchhi_mask = MIPS_WATCHHI_MASK | MIPS_WATCHHI_IRW;
55705e71adSMatt Redfearn 
566aa3524cSDavid Daney 	switch (current_cpu_data.watch_reg_use_cnt) {
576aa3524cSDavid Daney 	default:
586aa3524cSDavid Daney 		BUG();
596aa3524cSDavid Daney 	case 4:
60705e71adSMatt Redfearn 		watches->watchhi[3] = (read_c0_watchhi3() & watchhi_mask);
61*c9b02990SLiangliang Huang 		fallthrough;
626aa3524cSDavid Daney 	case 3:
63705e71adSMatt Redfearn 		watches->watchhi[2] = (read_c0_watchhi2() & watchhi_mask);
64*c9b02990SLiangliang Huang 		fallthrough;
656aa3524cSDavid Daney 	case 2:
66705e71adSMatt Redfearn 		watches->watchhi[1] = (read_c0_watchhi1() & watchhi_mask);
67*c9b02990SLiangliang Huang 		fallthrough;
686aa3524cSDavid Daney 	case 1:
69705e71adSMatt Redfearn 		watches->watchhi[0] = (read_c0_watchhi0() & watchhi_mask);
706aa3524cSDavid Daney 	}
716aa3524cSDavid Daney 	if (current_cpu_data.watch_reg_use_cnt == 1 &&
7250af501cSJames Hogan 	    (watches->watchhi[0] & MIPS_WATCHHI_IRW) == 0) {
736aa3524cSDavid Daney 		/* Pathological case of release 1 architecture that
746aa3524cSDavid Daney 		 * doesn't set the condition bits.  We assume that
756aa3524cSDavid Daney 		 * since we got here, the watch condition was met and
766aa3524cSDavid Daney 		 * signal that the conditions requested in watchlo
776aa3524cSDavid Daney 		 * were met.  */
7850af501cSJames Hogan 		watches->watchhi[0] |= (watches->watchlo[0] & MIPS_WATCHHI_IRW);
796aa3524cSDavid Daney 	}
806aa3524cSDavid Daney  }
816aa3524cSDavid Daney 
826aa3524cSDavid Daney /*
836aa3524cSDavid Daney  * Disable all watch registers.	 Although only four registers are
846aa3524cSDavid Daney  * installed, all are cleared to eliminate the possibility of endless
856aa3524cSDavid Daney  * looping in the watch handler.
866aa3524cSDavid Daney  */
mips_clear_watch_registers(void)876aa3524cSDavid Daney void mips_clear_watch_registers(void)
886aa3524cSDavid Daney {
896aa3524cSDavid Daney 	switch (current_cpu_data.watch_reg_count) {
906aa3524cSDavid Daney 	default:
916aa3524cSDavid Daney 		BUG();
926aa3524cSDavid Daney 	case 8:
936aa3524cSDavid Daney 		write_c0_watchlo7(0);
94*c9b02990SLiangliang Huang 		fallthrough;
956aa3524cSDavid Daney 	case 7:
966aa3524cSDavid Daney 		write_c0_watchlo6(0);
97*c9b02990SLiangliang Huang 		fallthrough;
986aa3524cSDavid Daney 	case 6:
996aa3524cSDavid Daney 		write_c0_watchlo5(0);
100*c9b02990SLiangliang Huang 		fallthrough;
1016aa3524cSDavid Daney 	case 5:
1026aa3524cSDavid Daney 		write_c0_watchlo4(0);
103*c9b02990SLiangliang Huang 		fallthrough;
1046aa3524cSDavid Daney 	case 4:
1056aa3524cSDavid Daney 		write_c0_watchlo3(0);
106*c9b02990SLiangliang Huang 		fallthrough;
1076aa3524cSDavid Daney 	case 3:
1086aa3524cSDavid Daney 		write_c0_watchlo2(0);
109*c9b02990SLiangliang Huang 		fallthrough;
1106aa3524cSDavid Daney 	case 2:
1116aa3524cSDavid Daney 		write_c0_watchlo1(0);
112*c9b02990SLiangliang Huang 		fallthrough;
1136aa3524cSDavid Daney 	case 1:
1146aa3524cSDavid Daney 		write_c0_watchlo0(0);
1156aa3524cSDavid Daney 	}
1166aa3524cSDavid Daney }
1176aa3524cSDavid Daney 
mips_probe_watch_registers(struct cpuinfo_mips * c)118078a55fcSPaul Gortmaker void mips_probe_watch_registers(struct cpuinfo_mips *c)
1196aa3524cSDavid Daney {
1206aa3524cSDavid Daney 	unsigned int t;
1216aa3524cSDavid Daney 
1226aa3524cSDavid Daney 	if ((c->options & MIPS_CPU_WATCH) == 0)
1236aa3524cSDavid Daney 		return;
1246aa3524cSDavid Daney 	/*
1256aa3524cSDavid Daney 	 * Check which of the I,R and W bits are supported, then
1266aa3524cSDavid Daney 	 * disable the register.
1276aa3524cSDavid Daney 	 */
12850af501cSJames Hogan 	write_c0_watchlo0(MIPS_WATCHLO_IRW);
129c5e1503fSPaul Burton 	back_to_back_c0_hazard();
1306aa3524cSDavid Daney 	t = read_c0_watchlo0();
1316aa3524cSDavid Daney 	write_c0_watchlo0(0);
13250af501cSJames Hogan 	c->watch_reg_masks[0] = t & MIPS_WATCHLO_IRW;
1336aa3524cSDavid Daney 
1346aa3524cSDavid Daney 	/* Write the mask bits and read them back to determine which
1356aa3524cSDavid Daney 	 * can be used. */
1366aa3524cSDavid Daney 	c->watch_reg_count = 1;
1376aa3524cSDavid Daney 	c->watch_reg_use_cnt = 1;
1386aa3524cSDavid Daney 	t = read_c0_watchhi0();
13950af501cSJames Hogan 	write_c0_watchhi0(t | MIPS_WATCHHI_MASK);
140c5e1503fSPaul Burton 	back_to_back_c0_hazard();
1416aa3524cSDavid Daney 	t = read_c0_watchhi0();
14250af501cSJames Hogan 	c->watch_reg_masks[0] |= (t & MIPS_WATCHHI_MASK);
14350af501cSJames Hogan 	if ((t & MIPS_WATCHHI_M) == 0)
1446aa3524cSDavid Daney 		return;
1456aa3524cSDavid Daney 
14650af501cSJames Hogan 	write_c0_watchlo1(MIPS_WATCHLO_IRW);
147c5e1503fSPaul Burton 	back_to_back_c0_hazard();
1486aa3524cSDavid Daney 	t = read_c0_watchlo1();
1496aa3524cSDavid Daney 	write_c0_watchlo1(0);
15050af501cSJames Hogan 	c->watch_reg_masks[1] = t & MIPS_WATCHLO_IRW;
1516aa3524cSDavid Daney 
1526aa3524cSDavid Daney 	c->watch_reg_count = 2;
1536aa3524cSDavid Daney 	c->watch_reg_use_cnt = 2;
1546aa3524cSDavid Daney 	t = read_c0_watchhi1();
15550af501cSJames Hogan 	write_c0_watchhi1(t | MIPS_WATCHHI_MASK);
156c5e1503fSPaul Burton 	back_to_back_c0_hazard();
1576aa3524cSDavid Daney 	t = read_c0_watchhi1();
15850af501cSJames Hogan 	c->watch_reg_masks[1] |= (t & MIPS_WATCHHI_MASK);
15950af501cSJames Hogan 	if ((t & MIPS_WATCHHI_M) == 0)
1606aa3524cSDavid Daney 		return;
1616aa3524cSDavid Daney 
16250af501cSJames Hogan 	write_c0_watchlo2(MIPS_WATCHLO_IRW);
163c5e1503fSPaul Burton 	back_to_back_c0_hazard();
1646aa3524cSDavid Daney 	t = read_c0_watchlo2();
1656aa3524cSDavid Daney 	write_c0_watchlo2(0);
16650af501cSJames Hogan 	c->watch_reg_masks[2] = t & MIPS_WATCHLO_IRW;
1676aa3524cSDavid Daney 
1686aa3524cSDavid Daney 	c->watch_reg_count = 3;
1696aa3524cSDavid Daney 	c->watch_reg_use_cnt = 3;
1706aa3524cSDavid Daney 	t = read_c0_watchhi2();
17150af501cSJames Hogan 	write_c0_watchhi2(t | MIPS_WATCHHI_MASK);
172c5e1503fSPaul Burton 	back_to_back_c0_hazard();
1736aa3524cSDavid Daney 	t = read_c0_watchhi2();
17450af501cSJames Hogan 	c->watch_reg_masks[2] |= (t & MIPS_WATCHHI_MASK);
17550af501cSJames Hogan 	if ((t & MIPS_WATCHHI_M) == 0)
1766aa3524cSDavid Daney 		return;
1776aa3524cSDavid Daney 
17850af501cSJames Hogan 	write_c0_watchlo3(MIPS_WATCHLO_IRW);
179c5e1503fSPaul Burton 	back_to_back_c0_hazard();
1806aa3524cSDavid Daney 	t = read_c0_watchlo3();
1816aa3524cSDavid Daney 	write_c0_watchlo3(0);
18250af501cSJames Hogan 	c->watch_reg_masks[3] = t & MIPS_WATCHLO_IRW;
1836aa3524cSDavid Daney 
1846aa3524cSDavid Daney 	c->watch_reg_count = 4;
1856aa3524cSDavid Daney 	c->watch_reg_use_cnt = 4;
1866aa3524cSDavid Daney 	t = read_c0_watchhi3();
18750af501cSJames Hogan 	write_c0_watchhi3(t | MIPS_WATCHHI_MASK);
188c5e1503fSPaul Burton 	back_to_back_c0_hazard();
1896aa3524cSDavid Daney 	t = read_c0_watchhi3();
19050af501cSJames Hogan 	c->watch_reg_masks[3] |= (t & MIPS_WATCHHI_MASK);
19150af501cSJames Hogan 	if ((t & MIPS_WATCHHI_M) == 0)
1926aa3524cSDavid Daney 		return;
1936aa3524cSDavid Daney 
1946aa3524cSDavid Daney 	/* We use at most 4, but probe and report up to 8. */
1956aa3524cSDavid Daney 	c->watch_reg_count = 5;
1966aa3524cSDavid Daney 	t = read_c0_watchhi4();
19750af501cSJames Hogan 	if ((t & MIPS_WATCHHI_M) == 0)
1986aa3524cSDavid Daney 		return;
1996aa3524cSDavid Daney 
2006aa3524cSDavid Daney 	c->watch_reg_count = 6;
2016aa3524cSDavid Daney 	t = read_c0_watchhi5();
20250af501cSJames Hogan 	if ((t & MIPS_WATCHHI_M) == 0)
2036aa3524cSDavid Daney 		return;
2046aa3524cSDavid Daney 
2056aa3524cSDavid Daney 	c->watch_reg_count = 7;
2066aa3524cSDavid Daney 	t = read_c0_watchhi6();
20750af501cSJames Hogan 	if ((t & MIPS_WATCHHI_M) == 0)
2086aa3524cSDavid Daney 		return;
2096aa3524cSDavid Daney 
2106aa3524cSDavid Daney 	c->watch_reg_count = 8;
2116aa3524cSDavid Daney }
212