diff options
Diffstat (limited to 'arch/mips/sibyte/sb1250/bcm1250_tbprof.c')
-rw-r--r-- | arch/mips/sibyte/sb1250/bcm1250_tbprof.c | 154 |
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 | ||
232 | int sbprof_zbprof_stop(void) | 240 | int 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 | ||
336 | static int sbprof_tb_ioctl(struct inode *inode, | 347 | static 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 | ||