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 fallthrough; 31 case 3: 32 write_c0_watchlo2(watches->watchlo[2]); 33 write_c0_watchhi2(watchhi | watches->watchhi[2]); 34 fallthrough; 35 case 2: 36 write_c0_watchlo1(watches->watchlo[1]); 37 write_c0_watchhi1(watchhi | watches->watchhi[1]); 38 fallthrough; 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 ¤t->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 fallthrough; 62 case 3: 63 watches->watchhi[2] = (read_c0_watchhi2() & watchhi_mask); 64 fallthrough; 65 case 2: 66 watches->watchhi[1] = (read_c0_watchhi1() & watchhi_mask); 67 fallthrough; 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 fallthrough; 95 case 7: 96 write_c0_watchlo6(0); 97 fallthrough; 98 case 6: 99 write_c0_watchlo5(0); 100 fallthrough; 101 case 5: 102 write_c0_watchlo4(0); 103 fallthrough; 104 case 4: 105 write_c0_watchlo3(0); 106 fallthrough; 107 case 3: 108 write_c0_watchlo2(0); 109 fallthrough; 110 case 2: 111 write_c0_watchlo1(0); 112 fallthrough; 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.