aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/sibyte/sb1250/bcm1250_tbprof.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/sibyte/sb1250/bcm1250_tbprof.c')
-rw-r--r--arch/mips/sibyte/sb1250/bcm1250_tbprof.c154
1 files changed, 85 insertions, 69 deletions
diff --git a/arch/mips/sibyte/sb1250/bcm1250_tbprof.c b/arch/mips/sibyte/sb1250/bcm1250_tbprof.c
index 7f813ae9eaff..992e0d8dbb67 100644
--- a/arch/mips/sibyte/sb1250/bcm1250_tbprof.c
+++ b/arch/mips/sibyte/sb1250/bcm1250_tbprof.c
@@ -28,6 +28,8 @@
28#include <linux/fs.h> 28#include <linux/fs.h>
29#include <linux/errno.h> 29#include <linux/errno.h>
30#include <linux/reboot.h> 30#include <linux/reboot.h>
31#include <linux/smp_lock.h>
32#include <linux/wait.h>
31#include <asm/uaccess.h> 33#include <asm/uaccess.h>
32#include <asm/io.h> 34#include <asm/io.h>
33#include <asm/sibyte/sb1250.h> 35#include <asm/sibyte/sb1250.h>
@@ -64,24 +66,25 @@ static void arm_tb(void)
64 u_int64_t tb_options = M_SCD_TRACE_CFG_FREEZE_FULL; 66 u_int64_t tb_options = M_SCD_TRACE_CFG_FREEZE_FULL;
65 /* Generate an SCD_PERFCNT interrupt in TB_PERIOD Zclks to 67 /* Generate an SCD_PERFCNT interrupt in TB_PERIOD Zclks to
66 trigger start of trace. XXX vary sampling period */ 68 trigger start of trace. XXX vary sampling period */
67 bus_writeq(0, IOADDR(A_SCD_PERF_CNT_1)); 69 __raw_writeq(0, IOADDR(A_SCD_PERF_CNT_1));
68 scdperfcnt = bus_readq(IOADDR(A_SCD_PERF_CNT_CFG)); 70 scdperfcnt = __raw_readq(IOADDR(A_SCD_PERF_CNT_CFG));
69 /* Unfortunately, in Pass 2 we must clear all counters to knock down 71 /* Unfortunately, in Pass 2 we must clear all counters to knock down
70 a previous interrupt request. This means that bus profiling 72 a previous interrupt request. This means that bus profiling
71 requires ALL of the SCD perf counters. */ 73 requires ALL of the SCD perf counters. */
72 bus_writeq((scdperfcnt & ~M_SPC_CFG_SRC1) | // keep counters 0,2,3 as is 74 __raw_writeq((scdperfcnt & ~M_SPC_CFG_SRC1) |
73 M_SPC_CFG_ENABLE | // enable counting 75 // keep counters 0,2,3 as is
74 M_SPC_CFG_CLEAR | // clear all counters 76 M_SPC_CFG_ENABLE | // enable counting
75 V_SPC_CFG_SRC1(1), // counter 1 counts cycles 77 M_SPC_CFG_CLEAR | // clear all counters
76 IOADDR(A_SCD_PERF_CNT_CFG)); 78 V_SPC_CFG_SRC1(1), // counter 1 counts cycles
77 bus_writeq(next, IOADDR(A_SCD_PERF_CNT_1)); 79 IOADDR(A_SCD_PERF_CNT_CFG));
80 __raw_writeq(next, IOADDR(A_SCD_PERF_CNT_1));
78 /* Reset the trace buffer */ 81 /* Reset the trace buffer */
79 bus_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG)); 82 __raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
80#if 0 && defined(M_SCD_TRACE_CFG_FORCECNT) 83#if 0 && defined(M_SCD_TRACE_CFG_FORCECNT)
81 /* XXXKW may want to expose control to the data-collector */ 84 /* XXXKW may want to expose control to the data-collector */
82 tb_options |= M_SCD_TRACE_CFG_FORCECNT; 85 tb_options |= M_SCD_TRACE_CFG_FORCECNT;
83#endif 86#endif
84 bus_writeq(tb_options, IOADDR(A_SCD_TRACE_CFG)); 87 __raw_writeq(tb_options, IOADDR(A_SCD_TRACE_CFG));
85 sbp.tb_armed = 1; 88 sbp.tb_armed = 1;
86} 89}
87 90
@@ -93,23 +96,30 @@ static irqreturn_t sbprof_tb_intr(int irq, void *dev_id, struct pt_regs *regs)
93 /* XXX should use XKPHYS to make writes bypass L2 */ 96 /* XXX should use XKPHYS to make writes bypass L2 */
94 u_int64_t *p = sbp.sbprof_tbbuf[sbp.next_tb_sample++]; 97 u_int64_t *p = sbp.sbprof_tbbuf[sbp.next_tb_sample++];
95 /* Read out trace */ 98 /* Read out trace */
96 bus_writeq(M_SCD_TRACE_CFG_START_READ, IOADDR(A_SCD_TRACE_CFG)); 99 __raw_writeq(M_SCD_TRACE_CFG_START_READ,
100 IOADDR(A_SCD_TRACE_CFG));
97 __asm__ __volatile__ ("sync" : : : "memory"); 101 __asm__ __volatile__ ("sync" : : : "memory");
98 /* Loop runs backwards because bundles are read out in reverse order */ 102 /* Loop runs backwards because bundles are read out in reverse order */
99 for (i = 256 * 6; i > 0; i -= 6) { 103 for (i = 256 * 6; i > 0; i -= 6) {
100 // Subscripts decrease to put bundle in the order 104 // Subscripts decrease to put bundle in the order
101 // t0 lo, t0 hi, t1 lo, t1 hi, t2 lo, t2 hi 105 // t0 lo, t0 hi, t1 lo, t1 hi, t2 lo, t2 hi
102 p[i-1] = bus_readq(IOADDR(A_SCD_TRACE_READ)); // read t2 hi 106 p[i - 1] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
103 p[i-2] = bus_readq(IOADDR(A_SCD_TRACE_READ)); // read t2 lo 107 // read t2 hi
104 p[i-3] = bus_readq(IOADDR(A_SCD_TRACE_READ)); // read t1 hi 108 p[i - 2] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
105 p[i-4] = bus_readq(IOADDR(A_SCD_TRACE_READ)); // read t1 lo 109 // read t2 lo
106 p[i-5] = bus_readq(IOADDR(A_SCD_TRACE_READ)); // read t0 hi 110 p[i - 3] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
107 p[i-6] = bus_readq(IOADDR(A_SCD_TRACE_READ)); // read t0 lo 111 // read t1 hi
112 p[i - 4] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
113 // read t1 lo
114 p[i - 5] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
115 // read t0 hi
116 p[i - 6] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
117 // read t0 lo
108 } 118 }
109 if (!sbp.tb_enable) { 119 if (!sbp.tb_enable) {
110 DBG(printk(DEVNAME ": tb_intr shutdown\n")); 120 DBG(printk(DEVNAME ": tb_intr shutdown\n"));
111 bus_writeq(M_SCD_TRACE_CFG_RESET, 121 __raw_writeq(M_SCD_TRACE_CFG_RESET,
112 IOADDR(A_SCD_TRACE_CFG)); 122 IOADDR(A_SCD_TRACE_CFG));
113 sbp.tb_armed = 0; 123 sbp.tb_armed = 0;
114 wake_up(&sbp.tb_sync); 124 wake_up(&sbp.tb_sync);
115 } else { 125 } else {
@@ -118,7 +128,7 @@ static irqreturn_t sbprof_tb_intr(int irq, void *dev_id, struct pt_regs *regs)
118 } else { 128 } else {
119 /* No more trace buffer samples */ 129 /* No more trace buffer samples */
120 DBG(printk(DEVNAME ": tb_intr full\n")); 130 DBG(printk(DEVNAME ": tb_intr full\n"));
121 bus_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG)); 131 __raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
122 sbp.tb_armed = 0; 132 sbp.tb_armed = 0;
123 if (!sbp.tb_enable) { 133 if (!sbp.tb_enable) {
124 wake_up(&sbp.tb_sync); 134 wake_up(&sbp.tb_sync);
@@ -152,13 +162,11 @@ int sbprof_zbprof_start(struct file *filp)
152 return -EBUSY; 162 return -EBUSY;
153 } 163 }
154 /* Make sure there isn't a perf-cnt interrupt waiting */ 164 /* Make sure there isn't a perf-cnt interrupt waiting */
155 scdperfcnt = bus_readq(IOADDR(A_SCD_PERF_CNT_CFG)); 165 scdperfcnt = __raw_readq(IOADDR(A_SCD_PERF_CNT_CFG));
156 /* Disable and clear counters, override SRC_1 */ 166 /* Disable and clear counters, override SRC_1 */
157 bus_writeq((scdperfcnt & ~(M_SPC_CFG_SRC1 | M_SPC_CFG_ENABLE)) | 167 __raw_writeq((scdperfcnt & ~(M_SPC_CFG_SRC1 | M_SPC_CFG_ENABLE)) |
158 M_SPC_CFG_ENABLE | 168 M_SPC_CFG_ENABLE | M_SPC_CFG_CLEAR | V_SPC_CFG_SRC1(1),
159 M_SPC_CFG_CLEAR | 169 IOADDR(A_SCD_PERF_CNT_CFG));
160 V_SPC_CFG_SRC1(1),
161 IOADDR(A_SCD_PERF_CNT_CFG));
162 170
163 /* We grab this interrupt to prevent others from trying to use 171 /* We grab this interrupt to prevent others from trying to use
164 it, even though we don't want to service the interrupts 172 it, even though we don't want to service the interrupts
@@ -172,55 +180,55 @@ int sbprof_zbprof_start(struct file *filp)
172 /* I need the core to mask these, but the interrupt mapper to 180 /* I need the core to mask these, but the interrupt mapper to
173 pass them through. I am exploiting my knowledge that 181 pass them through. I am exploiting my knowledge that
174 cp0_status masks out IP[5]. krw */ 182 cp0_status masks out IP[5]. krw */
175 bus_writeq(K_INT_MAP_I3, 183 __raw_writeq(K_INT_MAP_I3,
176 IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) + 184 IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) +
177 (K_INT_PERF_CNT << 3))); 185 (K_INT_PERF_CNT << 3)));
178 186
179 /* Initialize address traps */ 187 /* Initialize address traps */
180 bus_writeq(0, IOADDR(A_ADDR_TRAP_UP_0)); 188 __raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_0));
181 bus_writeq(0, IOADDR(A_ADDR_TRAP_UP_1)); 189 __raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_1));
182 bus_writeq(0, IOADDR(A_ADDR_TRAP_UP_2)); 190 __raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_2));
183 bus_writeq(0, IOADDR(A_ADDR_TRAP_UP_3)); 191 __raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_3));
184 192
185 bus_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_0)); 193 __raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_0));
186 bus_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_1)); 194 __raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_1));
187 bus_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_2)); 195 __raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_2));
188 bus_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_3)); 196 __raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_3));
189 197
190 bus_writeq(0, IOADDR(A_ADDR_TRAP_CFG_0)); 198 __raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_0));
191 bus_writeq(0, IOADDR(A_ADDR_TRAP_CFG_1)); 199 __raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_1));
192 bus_writeq(0, IOADDR(A_ADDR_TRAP_CFG_2)); 200 __raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_2));
193 bus_writeq(0, IOADDR(A_ADDR_TRAP_CFG_3)); 201 __raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_3));
194 202
195 /* Initialize Trace Event 0-7 */ 203 /* Initialize Trace Event 0-7 */
196 // when interrupt 204 // when interrupt
197 bus_writeq(M_SCD_TREVT_INTERRUPT, IOADDR(A_SCD_TRACE_EVENT_0)); 205 __raw_writeq(M_SCD_TREVT_INTERRUPT, IOADDR(A_SCD_TRACE_EVENT_0));
198 bus_writeq(0, IOADDR(A_SCD_TRACE_EVENT_1)); 206 __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_1));
199 bus_writeq(0, IOADDR(A_SCD_TRACE_EVENT_2)); 207 __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_2));
200 bus_writeq(0, IOADDR(A_SCD_TRACE_EVENT_3)); 208 __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_3));
201 bus_writeq(0, IOADDR(A_SCD_TRACE_EVENT_4)); 209 __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_4));
202 bus_writeq(0, IOADDR(A_SCD_TRACE_EVENT_5)); 210 __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_5));
203 bus_writeq(0, IOADDR(A_SCD_TRACE_EVENT_6)); 211 __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_6));
204 bus_writeq(0, IOADDR(A_SCD_TRACE_EVENT_7)); 212 __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_7));
205 213
206 /* Initialize Trace Sequence 0-7 */ 214 /* Initialize Trace Sequence 0-7 */
207 // Start on event 0 (interrupt) 215 // Start on event 0 (interrupt)
208 bus_writeq(V_SCD_TRSEQ_FUNC_START | 0x0fff, 216 __raw_writeq(V_SCD_TRSEQ_FUNC_START | 0x0fff,
209 IOADDR(A_SCD_TRACE_SEQUENCE_0)); 217 IOADDR(A_SCD_TRACE_SEQUENCE_0));
210 // dsamp when d used | asamp when a used 218 // dsamp when d used | asamp when a used
211 bus_writeq(M_SCD_TRSEQ_ASAMPLE | M_SCD_TRSEQ_DSAMPLE | 219 __raw_writeq(M_SCD_TRSEQ_ASAMPLE | M_SCD_TRSEQ_DSAMPLE |
212 K_SCD_TRSEQ_TRIGGER_ALL, 220 K_SCD_TRSEQ_TRIGGER_ALL,
213 IOADDR(A_SCD_TRACE_SEQUENCE_1)); 221 IOADDR(A_SCD_TRACE_SEQUENCE_1));
214 bus_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_2)); 222 __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_2));
215 bus_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_3)); 223 __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_3));
216 bus_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_4)); 224 __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_4));
217 bus_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_5)); 225 __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_5));
218 bus_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_6)); 226 __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_6));
219 bus_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_7)); 227 __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_7));
220 228
221 /* Now indicate the PERF_CNT interrupt as a trace-relevant interrupt */ 229 /* Now indicate the PERF_CNT interrupt as a trace-relevant interrupt */
222 bus_writeq((1ULL << K_INT_PERF_CNT), 230 __raw_writeq(1ULL << K_INT_PERF_CNT,
223 IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_TRACE))); 231 IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_TRACE)));
224 232
225 arm_tb(); 233 arm_tb();
226 234
@@ -231,6 +239,7 @@ int sbprof_zbprof_start(struct file *filp)
231 239
232int sbprof_zbprof_stop(void) 240int sbprof_zbprof_stop(void)
233{ 241{
242 DEFINE_WAIT(wait);
234 DBG(printk(DEVNAME ": stopping\n")); 243 DBG(printk(DEVNAME ": stopping\n"));
235 244
236 if (sbp.tb_enable) { 245 if (sbp.tb_enable) {
@@ -240,7 +249,9 @@ int sbprof_zbprof_stop(void)
240 this sleep happens. */ 249 this sleep happens. */
241 if (sbp.tb_armed) { 250 if (sbp.tb_armed) {
242 DBG(printk(DEVNAME ": wait for disarm\n")); 251 DBG(printk(DEVNAME ": wait for disarm\n"));
243 interruptible_sleep_on(&sbp.tb_sync); 252 prepare_to_wait(&sbp.tb_sync, &wait, TASK_INTERRUPTIBLE);
253 schedule();
254 finish_wait(&sbp.tb_sync, &wait);
244 DBG(printk(DEVNAME ": disarm complete\n")); 255 DBG(printk(DEVNAME ": disarm complete\n"));
245 } 256 }
246 free_irq(K_INT_TRACE_FREEZE, &sbp); 257 free_irq(K_INT_TRACE_FREEZE, &sbp);
@@ -333,13 +344,13 @@ static ssize_t sbprof_tb_read(struct file *filp, char *buf,
333 return count; 344 return count;
334} 345}
335 346
336static int sbprof_tb_ioctl(struct inode *inode, 347static long sbprof_tb_ioctl(struct file *filp,
337 struct file *filp, 348 unsigned int command,
338 unsigned int command, 349 unsigned long arg)
339 unsigned long arg)
340{ 350{
341 int error = 0; 351 int error = 0;
342 352
353 lock_kernel();
343 switch (command) { 354 switch (command) {
344 case SBPROF_ZBSTART: 355 case SBPROF_ZBSTART:
345 error = sbprof_zbprof_start(filp); 356 error = sbprof_zbprof_start(filp);
@@ -348,13 +359,17 @@ static int sbprof_tb_ioctl(struct inode *inode,
348 error = sbprof_zbprof_stop(); 359 error = sbprof_zbprof_stop();
349 break; 360 break;
350 case SBPROF_ZBWAITFULL: 361 case SBPROF_ZBWAITFULL:
351 interruptible_sleep_on(&sbp.tb_read); 362 DEFINE_WAIT(wait);
363 prepare_to_wait(&sbp.tb_read, &wait, TASK_INTERRUPTIBLE);
364 schedule();
365 finish_wait(&sbp.tb_read, &wait);
352 /* XXXKW check if interrupted? */ 366 /* XXXKW check if interrupted? */
353 return put_user(TB_FULL, (int *) arg); 367 return put_user(TB_FULL, (int *) arg);
354 default: 368 default:
355 error = -EINVAL; 369 error = -EINVAL;
356 break; 370 break;
357 } 371 }
372 unlock_kernel();
358 373
359 return error; 374 return error;
360} 375}
@@ -364,7 +379,8 @@ static struct file_operations sbprof_tb_fops = {
364 .open = sbprof_tb_open, 379 .open = sbprof_tb_open,
365 .release = sbprof_tb_release, 380 .release = sbprof_tb_release,
366 .read = sbprof_tb_read, 381 .read = sbprof_tb_read,
367 .ioctl = sbprof_tb_ioctl, 382 .unlocked_ioctl = sbprof_tb_ioctl,
383 .compat_ioctl = sbprof_tb_ioctl,
368 .mmap = NULL, 384 .mmap = NULL,
369}; 385};
370 386