aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Yamamoto <TakashiA.Yamamoto@jp.sony.com>2008-01-18 15:32:46 -0500
committerPaul Mackerras <paulus@samba.org>2008-01-25 06:52:53 -0500
commit781749a46b34dc5c9e4000df7b9d37d675c17463 (patch)
tree98b51b049f48804978c9139db6427945a1186963
parented7570022a42a60ecb67c53f429bc96c7bc5597d (diff)
[POWERPC] PS3: Add logical performance monitor driver support
Add PS3 logical performance monitor (lpm) device driver. The PS3's LV1 hypervisor provides a Logical Performance Monitor that abstracts the Cell processor's performance monitor features for use by guest operating systems. Signed-off-by: Takashi Yamamoto <TakashiA.Yamamoto@jp.sony.com> Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/platforms/ps3/Kconfig13
-rw-r--r--drivers/ps3/Makefile1
-rw-r--r--drivers/ps3/ps3-lpm.c1248
-rw-r--r--include/asm-powerpc/ps3.h62
4 files changed, 1324 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index 298f1c9679fb..a3d708fe5709 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -138,4 +138,17 @@ config PS3_FLASH
138 be disabled on the kernel command line using "ps3flash=off", to 138 be disabled on the kernel command line using "ps3flash=off", to
139 not allocate this fixed buffer. 139 not allocate this fixed buffer.
140 140
141config PS3_LPM
142 tristate "PS3 Logical Performance Monitor support"
143 depends on PPC_PS3
144 help
145 Include support for the PS3 Logical Performance Monitor.
146
147 This support is required to use the logical performance monitor
148 of the PS3's LV1 hypervisor.
149
150 If you intend to use the advanced performance monitoring and
151 profiling support of the Cell processor with programs like
152 oprofile and perfmon2, then say Y or M, otherwise say N.
153
141endmenu 154endmenu
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile
index 1f5a2d33bf5b..ccea15c11c19 100644
--- a/drivers/ps3/Makefile
+++ b/drivers/ps3/Makefile
@@ -4,3 +4,4 @@ ps3av_mod-objs += ps3av.o ps3av_cmd.o
4obj-$(CONFIG_PPC_PS3) += sys-manager-core.o 4obj-$(CONFIG_PPC_PS3) += sys-manager-core.o
5obj-$(CONFIG_PS3_SYS_MANAGER) += ps3-sys-manager.o 5obj-$(CONFIG_PS3_SYS_MANAGER) += ps3-sys-manager.o
6obj-$(CONFIG_PS3_STORAGE) += ps3stor_lib.o 6obj-$(CONFIG_PS3_STORAGE) += ps3stor_lib.o
7obj-$(CONFIG_PS3_LPM) += ps3-lpm.o
diff --git a/drivers/ps3/ps3-lpm.c b/drivers/ps3/ps3-lpm.c
new file mode 100644
index 000000000000..4c066545d176
--- /dev/null
+++ b/drivers/ps3/ps3-lpm.c
@@ -0,0 +1,1248 @@
1/*
2 * PS3 Logical Performance Monitor.
3 *
4 * Copyright (C) 2007 Sony Computer Entertainment Inc.
5 * Copyright 2007 Sony Corp.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/interrupt.h>
24#include <linux/uaccess.h>
25#include <asm/ps3.h>
26#include <asm/lv1call.h>
27#include <asm/cell-pmu.h>
28
29
30/* BOOKMARK tag macros */
31#define PS3_PM_BOOKMARK_START 0x8000000000000000ULL
32#define PS3_PM_BOOKMARK_STOP 0x4000000000000000ULL
33#define PS3_PM_BOOKMARK_TAG_KERNEL 0x1000000000000000ULL
34#define PS3_PM_BOOKMARK_TAG_USER 0x3000000000000000ULL
35#define PS3_PM_BOOKMARK_TAG_MASK_HI 0xF000000000000000ULL
36#define PS3_PM_BOOKMARK_TAG_MASK_LO 0x0F00000000000000ULL
37
38/* CBE PM CONTROL register macros */
39#define PS3_PM_CONTROL_PPU_TH0_BOOKMARK 0x00001000
40#define PS3_PM_CONTROL_PPU_TH1_BOOKMARK 0x00000800
41#define PS3_PM_CONTROL_PPU_COUNT_MODE_MASK 0x000C0000
42#define PS3_PM_CONTROL_PPU_COUNT_MODE_PROBLEM 0x00080000
43#define PS3_WRITE_PM_MASK 0xFFFFFFFFFFFFFFFFULL
44
45/* CBE PM START STOP register macros */
46#define PS3_PM_START_STOP_PPU_TH0_BOOKMARK_START 0x02000000
47#define PS3_PM_START_STOP_PPU_TH1_BOOKMARK_START 0x01000000
48#define PS3_PM_START_STOP_PPU_TH0_BOOKMARK_STOP 0x00020000
49#define PS3_PM_START_STOP_PPU_TH1_BOOKMARK_STOP 0x00010000
50#define PS3_PM_START_STOP_START_MASK 0xFF000000
51#define PS3_PM_START_STOP_STOP_MASK 0x00FF0000
52
53/* CBE PM COUNTER register macres */
54#define PS3_PM_COUNTER_MASK_HI 0xFFFFFFFF00000000ULL
55#define PS3_PM_COUNTER_MASK_LO 0x00000000FFFFFFFFULL
56
57/* BASE SIGNAL GROUP NUMBER macros */
58#define PM_ISLAND2_BASE_SIGNAL_GROUP_NUMBER 0
59#define PM_ISLAND2_SIGNAL_GROUP_NUMBER1 6
60#define PM_ISLAND2_SIGNAL_GROUP_NUMBER2 7
61#define PM_ISLAND3_BASE_SIGNAL_GROUP_NUMBER 7
62#define PM_ISLAND4_BASE_SIGNAL_GROUP_NUMBER 15
63#define PM_SPU_TRIGGER_SIGNAL_GROUP_NUMBER 17
64#define PM_SPU_EVENT_SIGNAL_GROUP_NUMBER 18
65#define PM_ISLAND5_BASE_SIGNAL_GROUP_NUMBER 18
66#define PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER 24
67#define PM_ISLAND7_BASE_SIGNAL_GROUP_NUMBER 49
68#define PM_ISLAND8_BASE_SIGNAL_GROUP_NUMBER 52
69#define PM_SIG_GROUP_SPU 41
70#define PM_SIG_GROUP_SPU_TRIGGER 42
71#define PM_SIG_GROUP_SPU_EVENT 43
72#define PM_SIG_GROUP_MFC_MAX 60
73
74/**
75 * struct ps3_lpm_shadow_regs - Performance monitor shadow registers.
76 *
77 * @pm_control: Shadow of the processor's pm_control register.
78 * @pm_start_stop: Shadow of the processor's pm_start_stop register.
79 * @pm_interval: Shadow of the processor's pm_interval register.
80 * @group_control: Shadow of the processor's group_control register.
81 * @debug_bus_control: Shadow of the processor's debug_bus_control register.
82 *
83 * The logical performance monitor provides a write-only interface to
84 * these processor registers. These shadow variables cache the processor
85 * register values for reading.
86 *
87 * The initial value of the shadow registers at lpm creation is
88 * PS3_LPM_SHADOW_REG_INIT.
89 */
90
91struct ps3_lpm_shadow_regs {
92 u64 pm_control;
93 u64 pm_start_stop;
94 u64 pm_interval;
95 u64 group_control;
96 u64 debug_bus_control;
97};
98
99#define PS3_LPM_SHADOW_REG_INIT 0xFFFFFFFF00000000ULL
100
101/**
102 * struct ps3_lpm_priv - Private lpm device data.
103 *
104 * @open: An atomic variable indicating the lpm driver has been opened.
105 * @rights: The lpm rigths granted by the system policy module. A logical
106 * OR of enum ps3_lpm_rights.
107 * @node_id: The node id of a BE prosessor whose performance monitor this
108 * lpar has the right to use.
109 * @pu_id: The lv1 id of the logical PU.
110 * @lpm_id: The lv1 id of this lpm instance.
111 * @outlet_id: The outlet created by lv1 for this lpm instance.
112 * @tb_count: The number of bytes of data held in the lv1 trace buffer.
113 * @tb_cache: Kernel buffer to receive the data from the lv1 trace buffer.
114 * Must be 128 byte aligned.
115 * @tb_cache_size: Size of the kernel @tb_cache buffer. Must be 128 byte
116 * aligned.
117 * @tb_cache_internal: An unaligned buffer allocated by this driver to be
118 * used for the trace buffer cache when ps3_lpm_open() is called with a
119 * NULL tb_cache argument. Otherwise unused.
120 * @shadow: Processor register shadow of type struct ps3_lpm_shadow_regs.
121 * @sbd: The struct ps3_system_bus_device attached to this driver.
122 *
123 * The trace buffer is a buffer allocated and used internally to the lv1
124 * hypervisor to collect trace data. The trace buffer cache is a guest
125 * buffer that accepts the trace data from the trace buffer.
126 */
127
128struct ps3_lpm_priv {
129 atomic_t open;
130 u64 rights;
131 u64 node_id;
132 u64 pu_id;
133 u64 lpm_id;
134 u64 outlet_id;
135 u64 tb_count;
136 void *tb_cache;
137 u64 tb_cache_size;
138 void *tb_cache_internal;
139 struct ps3_lpm_shadow_regs shadow;
140 struct ps3_system_bus_device *sbd;
141};
142
143enum {
144 PS3_LPM_DEFAULT_TB_CACHE_SIZE = 0x4000,
145};
146
147/**
148 * lpm_priv - Static instance of the lpm data.
149 *
150 * Since the exported routines don't support the notion of a device
151 * instance we need to hold the instance in this static variable
152 * and then only allow at most one instance at a time to be created.
153 */
154
155static struct ps3_lpm_priv *lpm_priv;
156
157static struct device *sbd_core(void)
158{
159 BUG_ON(!lpm_priv || !lpm_priv->sbd);
160 return &lpm_priv->sbd->core;
161}
162
163/**
164 * use_start_stop_bookmark - Enable the PPU bookmark trace.
165 *
166 * And it enables PPU bookmark triggers ONLY if the other triggers are not set.
167 * The start/stop bookmarks are inserted at ps3_enable_pm() and ps3_disable_pm()
168 * to start/stop LPM.
169 *
170 * Used to get good quality of the performance counter.
171 */
172
173enum {use_start_stop_bookmark = 1,};
174
175void ps3_set_bookmark(u64 bookmark)
176{
177 /*
178 * As per the PPE book IV, to avoid bookmark loss there must
179 * not be a traced branch within 10 cycles of setting the
180 * SPRN_BKMK register. The actual text is unclear if 'within'
181 * includes cycles before the call.
182 */
183
184 asm volatile("or 29, 29, 29;"); /* db10cyc */
185 mtspr(SPRN_BKMK, bookmark);
186 asm volatile("or 29, 29, 29;"); /* db10cyc */
187}
188EXPORT_SYMBOL_GPL(ps3_set_bookmark);
189
190void ps3_set_pm_bookmark(u64 tag, u64 incident, u64 th_id)
191{
192 u64 bookmark;
193
194 bookmark = (get_tb() & 0x00000000FFFFFFFFULL) |
195 PS3_PM_BOOKMARK_TAG_KERNEL;
196 bookmark = ((tag << 56) & PS3_PM_BOOKMARK_TAG_MASK_LO) |
197 (incident << 48) | (th_id << 32) | bookmark;
198 ps3_set_bookmark(bookmark);
199}
200EXPORT_SYMBOL_GPL(ps3_set_pm_bookmark);
201
202/**
203 * ps3_read_phys_ctr - Read physical counter registers.
204 *
205 * Each physical counter can act as one 32 bit counter or as two 16 bit
206 * counters.
207 */
208
209u32 ps3_read_phys_ctr(u32 cpu, u32 phys_ctr)
210{
211 int result;
212 u64 counter0415;
213 u64 counter2637;
214
215 if (phys_ctr >= NR_PHYS_CTRS) {
216 dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
217 __LINE__, phys_ctr);
218 return 0;
219 }
220
221 result = lv1_set_lpm_counter(lpm_priv->lpm_id, 0, 0, 0, 0, &counter0415,
222 &counter2637);
223 if (result) {
224 dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter failed: "
225 "phys_ctr %u, %s\n", __func__, __LINE__, phys_ctr,
226 ps3_result(result));
227 return 0;
228 }
229
230 switch (phys_ctr) {
231 case 0:
232 return counter0415 >> 32;
233 case 1:
234 return counter0415 & PS3_PM_COUNTER_MASK_LO;
235 case 2:
236 return counter2637 >> 32;
237 case 3:
238 return counter2637 & PS3_PM_COUNTER_MASK_LO;
239 default:
240 BUG();
241 }
242 return 0;
243}
244EXPORT_SYMBOL_GPL(ps3_read_phys_ctr);
245
246/**
247 * ps3_write_phys_ctr - Write physical counter registers.
248 *
249 * Each physical counter can act as one 32 bit counter or as two 16 bit
250 * counters.
251 */
252
253void ps3_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val)
254{
255 u64 counter0415;
256 u64 counter0415_mask;
257 u64 counter2637;
258 u64 counter2637_mask;
259 int result;
260
261 if (phys_ctr >= NR_PHYS_CTRS) {
262 dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
263 __LINE__, phys_ctr);
264 return;
265 }
266
267 switch (phys_ctr) {
268 case 0:
269 counter0415 = (u64)val << 32;
270 counter0415_mask = PS3_PM_COUNTER_MASK_HI;
271 counter2637 = 0x0;
272 counter2637_mask = 0x0;
273 break;
274 case 1:
275 counter0415 = (u64)val;
276 counter0415_mask = PS3_PM_COUNTER_MASK_LO;
277 counter2637 = 0x0;
278 counter2637_mask = 0x0;
279 break;
280 case 2:
281 counter0415 = 0x0;
282 counter0415_mask = 0x0;
283 counter2637 = (u64)val << 32;
284 counter2637_mask = PS3_PM_COUNTER_MASK_HI;
285 break;
286 case 3:
287 counter0415 = 0x0;
288 counter0415_mask = 0x0;
289 counter2637 = (u64)val;
290 counter2637_mask = PS3_PM_COUNTER_MASK_LO;
291 break;
292 default:
293 BUG();
294 }
295
296 result = lv1_set_lpm_counter(lpm_priv->lpm_id,
297 counter0415, counter0415_mask,
298 counter2637, counter2637_mask,
299 &counter0415, &counter2637);
300 if (result)
301 dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter failed: "
302 "phys_ctr %u, val %u, %s\n", __func__, __LINE__,
303 phys_ctr, val, ps3_result(result));
304}
305EXPORT_SYMBOL_GPL(ps3_write_phys_ctr);
306
307/**
308 * ps3_read_ctr - Read counter.
309 *
310 * Read 16 or 32 bits depending on the current size of the counter.
311 * Counters 4, 5, 6 & 7 are always 16 bit.
312 */
313
314u32 ps3_read_ctr(u32 cpu, u32 ctr)
315{
316 u32 val;
317 u32 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
318
319 val = ps3_read_phys_ctr(cpu, phys_ctr);
320
321 if (ps3_get_ctr_size(cpu, phys_ctr) == 16)
322 val = (ctr < NR_PHYS_CTRS) ? (val >> 16) : (val & 0xffff);
323
324 return val;
325}
326EXPORT_SYMBOL_GPL(ps3_read_ctr);
327
328/**
329 * ps3_write_ctr - Write counter.
330 *
331 * Write 16 or 32 bits depending on the current size of the counter.
332 * Counters 4, 5, 6 & 7 are always 16 bit.
333 */
334
335void ps3_write_ctr(u32 cpu, u32 ctr, u32 val)
336{
337 u32 phys_ctr;
338 u32 phys_val;
339
340 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
341
342 if (ps3_get_ctr_size(cpu, phys_ctr) == 16) {
343 phys_val = ps3_read_phys_ctr(cpu, phys_ctr);
344
345 if (ctr < NR_PHYS_CTRS)
346 val = (val << 16) | (phys_val & 0xffff);
347 else
348 val = (val & 0xffff) | (phys_val & 0xffff0000);
349 }
350
351 ps3_write_phys_ctr(cpu, phys_ctr, val);
352}
353EXPORT_SYMBOL_GPL(ps3_write_ctr);
354
355/**
356 * ps3_read_pm07_control - Read counter control registers.
357 *
358 * Each logical counter has a corresponding control register.
359 */
360
361u32 ps3_read_pm07_control(u32 cpu, u32 ctr)
362{
363 return 0;
364}
365EXPORT_SYMBOL_GPL(ps3_read_pm07_control);
366
367/**
368 * ps3_write_pm07_control - Write counter control registers.
369 *
370 * Each logical counter has a corresponding control register.
371 */
372
373void ps3_write_pm07_control(u32 cpu, u32 ctr, u32 val)
374{
375 int result;
376 static const u64 mask = 0xFFFFFFFFFFFFFFFFULL;
377 u64 old_value;
378
379 if (ctr >= NR_CTRS) {
380 dev_dbg(sbd_core(), "%s:%u: ctr too big: %u\n", __func__,
381 __LINE__, ctr);
382 return;
383 }
384
385 result = lv1_set_lpm_counter_control(lpm_priv->lpm_id, ctr, val, mask,
386 &old_value);
387 if (result)
388 dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter_control "
389 "failed: ctr %u, %s\n", __func__, __LINE__, ctr,
390 ps3_result(result));
391}
392EXPORT_SYMBOL_GPL(ps3_write_pm07_control);
393
394/**
395 * ps3_read_pm - Read Other LPM control registers.
396 */
397
398u32 ps3_read_pm(u32 cpu, enum pm_reg_name reg)
399{
400 int result = 0;
401 u64 val = 0;
402
403 switch (reg) {
404 case pm_control:
405 return lpm_priv->shadow.pm_control;
406 case trace_address:
407 return CBE_PM_TRACE_BUF_EMPTY;
408 case pm_start_stop:
409 return lpm_priv->shadow.pm_start_stop;
410 case pm_interval:
411 return lpm_priv->shadow.pm_interval;
412 case group_control:
413 return lpm_priv->shadow.group_control;
414 case debug_bus_control:
415 return lpm_priv->shadow.debug_bus_control;
416 case pm_status:
417 result = lv1_get_lpm_interrupt_status(lpm_priv->lpm_id,
418 &val);
419 if (result) {
420 val = 0;
421 dev_dbg(sbd_core(), "%s:%u: lv1 get_lpm_status failed: "
422 "reg %u, %s\n", __func__, __LINE__, reg,
423 ps3_result(result));
424 }
425 return (u32)val;
426 case ext_tr_timer:
427 return 0;
428 default:
429 dev_dbg(sbd_core(), "%s:%u: unknown reg: %d\n", __func__,
430 __LINE__, reg);
431 BUG();
432 break;
433 }
434
435 return 0;
436}
437EXPORT_SYMBOL_GPL(ps3_read_pm);
438
439/**
440 * ps3_write_pm - Write Other LPM control registers.
441 */
442
443void ps3_write_pm(u32 cpu, enum pm_reg_name reg, u32 val)
444{
445 int result = 0;
446 u64 dummy;
447
448 switch (reg) {
449 case group_control:
450 if (val != lpm_priv->shadow.group_control)
451 result = lv1_set_lpm_group_control(lpm_priv->lpm_id,
452 val,
453 PS3_WRITE_PM_MASK,
454 &dummy);
455 lpm_priv->shadow.group_control = val;
456 break;
457 case debug_bus_control:
458 if (val != lpm_priv->shadow.debug_bus_control)
459 result = lv1_set_lpm_debug_bus_control(lpm_priv->lpm_id,
460 val,
461 PS3_WRITE_PM_MASK,
462 &dummy);
463 lpm_priv->shadow.debug_bus_control = val;
464 break;
465 case pm_control:
466 if (use_start_stop_bookmark)
467 val |= (PS3_PM_CONTROL_PPU_TH0_BOOKMARK |
468 PS3_PM_CONTROL_PPU_TH1_BOOKMARK);
469 if (val != lpm_priv->shadow.pm_control)
470 result = lv1_set_lpm_general_control(lpm_priv->lpm_id,
471 val,
472 PS3_WRITE_PM_MASK,
473 0, 0, &dummy,
474 &dummy);
475 lpm_priv->shadow.pm_control = val;
476 break;
477 case pm_interval:
478 if (val != lpm_priv->shadow.pm_interval)
479 result = lv1_set_lpm_interval(lpm_priv->lpm_id, val,
480 PS3_WRITE_PM_MASK, &dummy);
481 lpm_priv->shadow.pm_interval = val;
482 break;
483 case pm_start_stop:
484 if (val != lpm_priv->shadow.pm_start_stop)
485 result = lv1_set_lpm_trigger_control(lpm_priv->lpm_id,
486 val,
487 PS3_WRITE_PM_MASK,
488 &dummy);
489 lpm_priv->shadow.pm_start_stop = val;
490 break;
491 case trace_address:
492 case ext_tr_timer:
493 case pm_status:
494 break;
495 default:
496 dev_dbg(sbd_core(), "%s:%u: unknown reg: %d\n", __func__,
497 __LINE__, reg);
498 BUG();
499 break;
500 }
501
502 if (result)
503 dev_err(sbd_core(), "%s:%u: lv1 set_control failed: "
504 "reg %u, %s\n", __func__, __LINE__, reg,
505 ps3_result(result));
506}
507EXPORT_SYMBOL_GPL(ps3_write_pm);
508
509/**
510 * ps3_get_ctr_size - Get the size of a physical counter.
511 *
512 * Returns either 16 or 32.
513 */
514
515u32 ps3_get_ctr_size(u32 cpu, u32 phys_ctr)
516{
517 u32 pm_ctrl;
518
519 if (phys_ctr >= NR_PHYS_CTRS) {
520 dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
521 __LINE__, phys_ctr);
522 return 0;
523 }
524
525 pm_ctrl = ps3_read_pm(cpu, pm_control);
526 return (pm_ctrl & CBE_PM_16BIT_CTR(phys_ctr)) ? 16 : 32;
527}
528EXPORT_SYMBOL_GPL(ps3_get_ctr_size);
529
530/**
531 * ps3_set_ctr_size - Set the size of a physical counter to 16 or 32 bits.
532 */
533
534void ps3_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size)
535{
536 u32 pm_ctrl;
537
538 if (phys_ctr >= NR_PHYS_CTRS) {
539 dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
540 __LINE__, phys_ctr);
541 return;
542 }
543
544 pm_ctrl = ps3_read_pm(cpu, pm_control);
545
546 switch (ctr_size) {
547 case 16:
548 pm_ctrl |= CBE_PM_16BIT_CTR(phys_ctr);
549 ps3_write_pm(cpu, pm_control, pm_ctrl);
550 break;
551
552 case 32:
553 pm_ctrl &= ~CBE_PM_16BIT_CTR(phys_ctr);
554 ps3_write_pm(cpu, pm_control, pm_ctrl);
555 break;
556 default:
557 BUG();
558 }
559}
560EXPORT_SYMBOL_GPL(ps3_set_ctr_size);
561
562static u64 pm_translate_signal_group_number_on_island2(u64 subgroup)
563{
564
565 if (subgroup == 2)
566 subgroup = 3;
567
568 if (subgroup <= 6)
569 return PM_ISLAND2_BASE_SIGNAL_GROUP_NUMBER + subgroup;
570 else if (subgroup == 7)
571 return PM_ISLAND2_SIGNAL_GROUP_NUMBER1;
572 else
573 return PM_ISLAND2_SIGNAL_GROUP_NUMBER2;
574}
575
576static u64 pm_translate_signal_group_number_on_island3(u64 subgroup)
577{
578
579 switch (subgroup) {
580 case 2:
581 case 3:
582 case 4:
583 subgroup += 2;
584 break;
585 case 5:
586 subgroup = 8;
587 break;
588 default:
589 break;
590 }
591 return PM_ISLAND3_BASE_SIGNAL_GROUP_NUMBER + subgroup;
592}
593
594static u64 pm_translate_signal_group_number_on_island4(u64 subgroup)
595{
596 return PM_ISLAND4_BASE_SIGNAL_GROUP_NUMBER + subgroup;
597}
598
599static u64 pm_translate_signal_group_number_on_island5(u64 subgroup)
600{
601
602 switch (subgroup) {
603 case 3:
604 subgroup = 4;
605 break;
606 case 4:
607 subgroup = 6;
608 break;
609 default:
610 break;
611 }
612 return PM_ISLAND5_BASE_SIGNAL_GROUP_NUMBER + subgroup;
613}
614
615static u64 pm_translate_signal_group_number_on_island6(u64 subgroup,
616 u64 subsubgroup)
617{
618 switch (subgroup) {
619 case 3:
620 case 4:
621 case 5:
622 subgroup += 1;
623 break;
624 default:
625 break;
626 }
627
628 switch (subsubgroup) {
629 case 4:
630 case 5:
631 case 6:
632 subsubgroup += 2;
633 break;
634 case 7:
635 case 8:
636 case 9:
637 case 10:
638 subsubgroup += 4;
639 break;
640 case 11:
641 case 12:
642 case 13:
643 subsubgroup += 5;
644 break;
645 default:
646 break;
647 }
648
649 if (subgroup <= 5)
650 return (PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER + subgroup);
651 else
652 return (PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER + subgroup
653 + subsubgroup - 1);
654}
655
656static u64 pm_translate_signal_group_number_on_island7(u64 subgroup)
657{
658 return PM_ISLAND7_BASE_SIGNAL_GROUP_NUMBER + subgroup;
659}
660
661static u64 pm_translate_signal_group_number_on_island8(u64 subgroup)
662{
663 return PM_ISLAND8_BASE_SIGNAL_GROUP_NUMBER + subgroup;
664}
665
666static u64 pm_signal_group_to_ps3_lv1_signal_group(u64 group)
667{
668 u64 island;
669 u64 subgroup;
670 u64 subsubgroup;
671
672 subgroup = 0;
673 subsubgroup = 0;
674 island = 0;
675 if (group < 1000) {
676 if (group < 100) {
677 if (20 <= group && group < 30) {
678 island = 2;
679 subgroup = group - 20;
680 } else if (30 <= group && group < 40) {
681 island = 3;
682 subgroup = group - 30;
683 } else if (40 <= group && group < 50) {
684 island = 4;
685 subgroup = group - 40;
686 } else if (50 <= group && group < 60) {
687 island = 5;
688 subgroup = group - 50;
689 } else if (60 <= group && group < 70) {
690 island = 6;
691 subgroup = group - 60;
692 } else if (70 <= group && group < 80) {
693 island = 7;
694 subgroup = group - 70;
695 } else if (80 <= group && group < 90) {
696 island = 8;
697 subgroup = group - 80;
698 }
699 } else if (200 <= group && group < 300) {
700 island = 2;
701 subgroup = group - 200;
702 } else if (600 <= group && group < 700) {
703 island = 6;
704 subgroup = 5;
705 subsubgroup = group - 650;
706 }
707 } else if (6000 <= group && group < 7000) {
708 island = 6;
709 subgroup = 5;
710 subsubgroup = group - 6500;
711 }
712
713 switch (island) {
714 case 2:
715 return pm_translate_signal_group_number_on_island2(subgroup);
716 case 3:
717 return pm_translate_signal_group_number_on_island3(subgroup);
718 case 4:
719 return pm_translate_signal_group_number_on_island4(subgroup);
720 case 5:
721 return pm_translate_signal_group_number_on_island5(subgroup);
722 case 6:
723 return pm_translate_signal_group_number_on_island6(subgroup,
724 subsubgroup);
725 case 7:
726 return pm_translate_signal_group_number_on_island7(subgroup);
727 case 8:
728 return pm_translate_signal_group_number_on_island8(subgroup);
729 default:
730 dev_dbg(sbd_core(), "%s:%u: island not found: %lu\n", __func__,
731 __LINE__, group);
732 BUG();
733 break;
734 }
735 return 0;
736}
737
738static u64 pm_bus_word_to_ps3_lv1_bus_word(u8 word)
739{
740
741 switch (word) {
742 case 1:
743 return 0xF000;
744 case 2:
745 return 0x0F00;
746 case 4:
747 return 0x00F0;
748 case 8:
749 default:
750 return 0x000F;
751 }
752}
753
754static int __ps3_set_signal(u64 lv1_signal_group, u64 bus_select,
755 u64 signal_select, u64 attr1, u64 attr2, u64 attr3)
756{
757 int ret;
758
759 ret = lv1_set_lpm_signal(lpm_priv->lpm_id, lv1_signal_group, bus_select,
760 signal_select, attr1, attr2, attr3);
761 if (ret)
762 dev_err(sbd_core(),
763 "%s:%u: error:%d 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
764 __func__, __LINE__, ret, lv1_signal_group, bus_select,
765 signal_select, attr1, attr2, attr3);
766
767 return ret;
768}
769
770int ps3_set_signal(u64 signal_group, u8 signal_bit, u16 sub_unit,
771 u8 bus_word)
772{
773 int ret;
774 u64 lv1_signal_group;
775 u64 bus_select;
776 u64 signal_select;
777 u64 attr1, attr2, attr3;
778
779 if (signal_group == 0)
780 return __ps3_set_signal(0, 0, 0, 0, 0, 0);
781
782 lv1_signal_group =
783 pm_signal_group_to_ps3_lv1_signal_group(signal_group);
784 bus_select = pm_bus_word_to_ps3_lv1_bus_word(bus_word);
785
786 switch (signal_group) {
787 case PM_SIG_GROUP_SPU_TRIGGER:
788 signal_select = 1;
789 signal_select = signal_select << (63 - signal_bit);
790 break;
791 case PM_SIG_GROUP_SPU_EVENT:
792 signal_select = 1;
793 signal_select = (signal_select << (63 - signal_bit)) | 0x3;
794 break;
795 default:
796 signal_select = 0;
797 break;
798 }
799
800 /*
801 * 0: physical object.
802 * 1: logical object.
803 * This parameter is only used for the PPE and SPE signals.
804 */
805 attr1 = 1;
806
807 /*
808 * This parameter is used to specify the target physical/logical
809 * PPE/SPE object.
810 */
811 if (PM_SIG_GROUP_SPU <= signal_group &&
812 signal_group < PM_SIG_GROUP_MFC_MAX)
813 attr2 = sub_unit;
814 else
815 attr2 = lpm_priv->pu_id;
816
817 /*
818 * This parameter is only used for setting the SPE signal.
819 */
820 attr3 = 0;
821
822 ret = __ps3_set_signal(lv1_signal_group, bus_select, signal_select,
823 attr1, attr2, attr3);
824 if (ret)
825 dev_err(sbd_core(), "%s:%u: __ps3_set_signal failed: %d\n",
826 __func__, __LINE__, ret);
827
828 return ret;
829}
830EXPORT_SYMBOL_GPL(ps3_set_signal);
831
832u32 ps3_get_hw_thread_id(int cpu)
833{
834 return get_hard_smp_processor_id(cpu);
835}
836EXPORT_SYMBOL_GPL(ps3_get_hw_thread_id);
837
838/**
839 * ps3_enable_pm - Enable the entire performance monitoring unit.
840 *
841 * When we enable the LPM, all pending writes to counters get committed.
842 */
843
844void ps3_enable_pm(u32 cpu)
845{
846 int result;
847 u64 tmp;
848 int insert_bookmark = 0;
849
850 lpm_priv->tb_count = 0;
851
852 if (use_start_stop_bookmark) {
853 if (!(lpm_priv->shadow.pm_start_stop &
854 (PS3_PM_START_STOP_START_MASK
855 | PS3_PM_START_STOP_STOP_MASK))) {
856 result = lv1_set_lpm_trigger_control(lpm_priv->lpm_id,
857 (PS3_PM_START_STOP_PPU_TH0_BOOKMARK_START |
858 PS3_PM_START_STOP_PPU_TH1_BOOKMARK_START |
859 PS3_PM_START_STOP_PPU_TH0_BOOKMARK_STOP |
860 PS3_PM_START_STOP_PPU_TH1_BOOKMARK_STOP),
861 0xFFFFFFFFFFFFFFFFULL, &tmp);
862
863 if (result)
864 dev_err(sbd_core(), "%s:%u: "
865 "lv1_set_lpm_trigger_control failed: "
866 "%s\n", __func__, __LINE__,
867 ps3_result(result));
868
869 insert_bookmark = !result;
870 }
871 }
872
873 result = lv1_start_lpm(lpm_priv->lpm_id);
874
875 if (result)
876 dev_err(sbd_core(), "%s:%u: lv1_start_lpm failed: %s\n",
877 __func__, __LINE__, ps3_result(result));
878
879 if (use_start_stop_bookmark && !result && insert_bookmark)
880 ps3_set_bookmark(get_tb() | PS3_PM_BOOKMARK_START);
881}
882EXPORT_SYMBOL_GPL(ps3_enable_pm);
883
884/**
885 * ps3_disable_pm - Disable the entire performance monitoring unit.
886 */
887
888void ps3_disable_pm(u32 cpu)
889{
890 int result;
891 u64 tmp;
892
893 ps3_set_bookmark(get_tb() | PS3_PM_BOOKMARK_STOP);
894
895 result = lv1_stop_lpm(lpm_priv->lpm_id, &tmp);
896
897 if (result) {
898 if(result != LV1_WRONG_STATE)
899 dev_err(sbd_core(), "%s:%u: lv1_stop_lpm failed: %s\n",
900 __func__, __LINE__, ps3_result(result));
901 return;
902 }
903
904 lpm_priv->tb_count = tmp;
905
906 dev_dbg(sbd_core(), "%s:%u: tb_count %lu (%lxh)\n", __func__, __LINE__,
907 lpm_priv->tb_count, lpm_priv->tb_count);
908}
909EXPORT_SYMBOL_GPL(ps3_disable_pm);
910
911/**
912 * ps3_lpm_copy_tb - Copy data from the trace buffer to a kernel buffer.
913 * @offset: Offset in bytes from the start of the trace buffer.
914 * @buf: Copy destination.
915 * @count: Maximum count of bytes to copy.
916 * @bytes_copied: Pointer to a variable that will recieve the number of
917 * bytes copied to @buf.
918 *
919 * On error @buf will contain any successfully copied trace buffer data
920 * and bytes_copied will be set to the number of bytes successfully copied.
921 */
922
923int ps3_lpm_copy_tb(unsigned long offset, void *buf, unsigned long count,
924 unsigned long *bytes_copied)
925{
926 int result;
927
928 *bytes_copied = 0;
929
930 if (!lpm_priv->tb_cache)
931 return -EPERM;
932
933 if (offset >= lpm_priv->tb_count)
934 return 0;
935
936 count = min(count, lpm_priv->tb_count - offset);
937
938 while (*bytes_copied < count) {
939 const unsigned long request = count - *bytes_copied;
940 u64 tmp;
941
942 result = lv1_copy_lpm_trace_buffer(lpm_priv->lpm_id, offset,
943 request, &tmp);
944 if (result) {
945 dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%lx\n",
946 __func__, __LINE__, request, offset);
947
948 dev_err(sbd_core(), "%s:%u: lv1_copy_lpm_trace_buffer "
949 "failed: %s\n", __func__, __LINE__,
950 ps3_result(result));
951 return result == LV1_WRONG_STATE ? -EBUSY : -EINVAL;
952 }
953
954 memcpy(buf, lpm_priv->tb_cache, tmp);
955 buf += tmp;
956 *bytes_copied += tmp;
957 offset += tmp;
958 }
959 dev_dbg(sbd_core(), "%s:%u: copied %lxh bytes\n", __func__, __LINE__,
960 *bytes_copied);
961
962 return 0;
963}
964EXPORT_SYMBOL_GPL(ps3_lpm_copy_tb);
965
966/**
967 * ps3_lpm_copy_tb_to_user - Copy data from the trace buffer to a user buffer.
968 * @offset: Offset in bytes from the start of the trace buffer.
969 * @buf: A __user copy destination.
970 * @count: Maximum count of bytes to copy.
971 * @bytes_copied: Pointer to a variable that will recieve the number of
972 * bytes copied to @buf.
973 *
974 * On error @buf will contain any successfully copied trace buffer data
975 * and bytes_copied will be set to the number of bytes successfully copied.
976 */
977
978int ps3_lpm_copy_tb_to_user(unsigned long offset, void __user *buf,
979 unsigned long count, unsigned long *bytes_copied)
980{
981 int result;
982
983 *bytes_copied = 0;
984
985 if (!lpm_priv->tb_cache)
986 return -EPERM;
987
988 if (offset >= lpm_priv->tb_count)
989 return 0;
990
991 count = min(count, lpm_priv->tb_count - offset);
992
993 while (*bytes_copied < count) {
994 const unsigned long request = count - *bytes_copied;
995 u64 tmp;
996
997 result = lv1_copy_lpm_trace_buffer(lpm_priv->lpm_id, offset,
998 request, &tmp);
999 if (result) {
1000 dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%lx\n",
1001 __func__, __LINE__, request, offset);
1002 dev_err(sbd_core(), "%s:%u: lv1_copy_lpm_trace_buffer "
1003 "failed: %s\n", __func__, __LINE__,
1004 ps3_result(result));
1005 return result == LV1_WRONG_STATE ? -EBUSY : -EINVAL;
1006 }
1007
1008 result = copy_to_user(buf, lpm_priv->tb_cache, tmp);
1009
1010 if (result) {
1011 dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%p\n",
1012 __func__, __LINE__, tmp, buf);
1013 dev_err(sbd_core(), "%s:%u: copy_to_user failed: %d\n",
1014 __func__, __LINE__, result);
1015 return -EFAULT;
1016 }
1017
1018 buf += tmp;
1019 *bytes_copied += tmp;
1020 offset += tmp;
1021 }
1022 dev_dbg(sbd_core(), "%s:%u: copied %lxh bytes\n", __func__, __LINE__,
1023 *bytes_copied);
1024
1025 return 0;
1026}
1027EXPORT_SYMBOL_GPL(ps3_lpm_copy_tb_to_user);
1028
1029/**
1030 * ps3_get_and_clear_pm_interrupts -
1031 *
1032 * Clearing interrupts for the entire performance monitoring unit.
1033 * Reading pm_status clears the interrupt bits.
1034 */
1035
1036u32 ps3_get_and_clear_pm_interrupts(u32 cpu)
1037{
1038 return ps3_read_pm(cpu, pm_status);
1039}
1040EXPORT_SYMBOL_GPL(ps3_get_and_clear_pm_interrupts);
1041
1042/**
1043 * ps3_enable_pm_interrupts -
1044 *
1045 * Enabling interrupts for the entire performance monitoring unit.
1046 * Enables the interrupt bits in the pm_status register.
1047 */
1048
1049void ps3_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask)
1050{
1051 if (mask)
1052 ps3_write_pm(cpu, pm_status, mask);
1053}
1054EXPORT_SYMBOL_GPL(ps3_enable_pm_interrupts);
1055
1056/**
1057 * ps3_enable_pm_interrupts -
1058 *
1059 * Disabling interrupts for the entire performance monitoring unit.
1060 */
1061
1062void ps3_disable_pm_interrupts(u32 cpu)
1063{
1064 ps3_get_and_clear_pm_interrupts(cpu);
1065 ps3_write_pm(cpu, pm_status, 0);
1066}
1067EXPORT_SYMBOL_GPL(ps3_disable_pm_interrupts);
1068
1069/**
1070 * ps3_lpm_open - Open the logical performance monitor device.
1071 * @tb_type: Specifies the type of trace buffer lv1 sould use for this lpm
1072 * instance, specified by one of enum ps3_lpm_tb_type.
1073 * @tb_cache: Optional user supplied buffer to use as the trace buffer cache.
1074 * If NULL, the driver will allocate and manage an internal buffer.
1075 * Unused when when @tb_type is PS3_LPM_TB_TYPE_NONE.
1076 * @tb_cache_size: The size in bytes of the user supplied @tb_cache buffer.
1077 * Unused when @tb_cache is NULL or @tb_type is PS3_LPM_TB_TYPE_NONE.
1078 */
1079
1080int ps3_lpm_open(enum ps3_lpm_tb_type tb_type, void *tb_cache,
1081 u64 tb_cache_size)
1082{
1083 int result;
1084 u64 tb_size;
1085
1086 BUG_ON(!lpm_priv);
1087 BUG_ON(tb_type != PS3_LPM_TB_TYPE_NONE
1088 && tb_type != PS3_LPM_TB_TYPE_INTERNAL);
1089
1090 if (tb_type == PS3_LPM_TB_TYPE_NONE && tb_cache)
1091 dev_dbg(sbd_core(), "%s:%u: bad in vals\n", __func__, __LINE__);
1092
1093 if (!atomic_add_unless(&lpm_priv->open, 1, 1)) {
1094 dev_dbg(sbd_core(), "%s:%u: busy\n", __func__, __LINE__);
1095 return -EBUSY;
1096 }
1097
1098 /* Note tb_cache needs 128 byte alignment. */
1099
1100 if (tb_type == PS3_LPM_TB_TYPE_NONE) {
1101 lpm_priv->tb_cache_size = 0;
1102 lpm_priv->tb_cache_internal = NULL;
1103 lpm_priv->tb_cache = NULL;
1104 } else if (tb_cache) {
1105 if (tb_cache != (void *)_ALIGN_UP((unsigned long)tb_cache, 128)
1106 || tb_cache_size != _ALIGN_UP(tb_cache_size, 128)) {
1107 dev_err(sbd_core(), "%s:%u: unaligned tb_cache\n",
1108 __func__, __LINE__);
1109 result = -EINVAL;
1110 goto fail_align;
1111 }
1112 lpm_priv->tb_cache_size = tb_cache_size;
1113 lpm_priv->tb_cache_internal = NULL;
1114 lpm_priv->tb_cache = tb_cache;
1115 } else {
1116 lpm_priv->tb_cache_size = PS3_LPM_DEFAULT_TB_CACHE_SIZE;
1117 lpm_priv->tb_cache_internal = kzalloc(
1118 lpm_priv->tb_cache_size + 127, GFP_KERNEL);
1119 if (!lpm_priv->tb_cache_internal) {
1120 dev_err(sbd_core(), "%s:%u: alloc internal tb_cache "
1121 "failed\n", __func__, __LINE__);
1122 result = -ENOMEM;
1123 goto fail_malloc;
1124 }
1125 lpm_priv->tb_cache = (void *)_ALIGN_UP(
1126 (unsigned long)lpm_priv->tb_cache_internal, 128);
1127 }
1128
1129 result = lv1_construct_lpm(lpm_priv->node_id, tb_type, 0, 0,
1130 ps3_mm_phys_to_lpar(__pa(lpm_priv->tb_cache)),
1131 lpm_priv->tb_cache_size, &lpm_priv->lpm_id,
1132 &lpm_priv->outlet_id, &tb_size);
1133
1134 if (result) {
1135 dev_err(sbd_core(), "%s:%u: lv1_construct_lpm failed: %s\n",
1136 __func__, __LINE__, ps3_result(result));
1137 result = -EINVAL;
1138 goto fail_construct;
1139 }
1140
1141 lpm_priv->shadow.pm_control = PS3_LPM_SHADOW_REG_INIT;
1142 lpm_priv->shadow.pm_start_stop = PS3_LPM_SHADOW_REG_INIT;
1143 lpm_priv->shadow.pm_interval = PS3_LPM_SHADOW_REG_INIT;
1144 lpm_priv->shadow.group_control = PS3_LPM_SHADOW_REG_INIT;
1145 lpm_priv->shadow.debug_bus_control = PS3_LPM_SHADOW_REG_INIT;
1146
1147 dev_dbg(sbd_core(), "%s:%u: lpm_id 0x%lx, outlet_id 0x%lx, "
1148 "tb_size 0x%lx\n", __func__, __LINE__, lpm_priv->lpm_id,
1149 lpm_priv->outlet_id, tb_size);
1150
1151 return 0;
1152
1153fail_construct:
1154 kfree(lpm_priv->tb_cache_internal);
1155 lpm_priv->tb_cache_internal = NULL;
1156fail_malloc:
1157fail_align:
1158 atomic_dec(&lpm_priv->open);
1159 return result;
1160}
1161EXPORT_SYMBOL_GPL(ps3_lpm_open);
1162
1163/**
1164 * ps3_lpm_close - Close the lpm device.
1165 *
1166 */
1167
1168int ps3_lpm_close(void)
1169{
1170 dev_dbg(sbd_core(), "%s:%u\n", __func__, __LINE__);
1171
1172 lv1_destruct_lpm(lpm_priv->lpm_id);
1173 lpm_priv->lpm_id = 0;
1174
1175 kfree(lpm_priv->tb_cache_internal);
1176 lpm_priv->tb_cache_internal = NULL;
1177
1178 atomic_dec(&lpm_priv->open);
1179 return 0;
1180}
1181EXPORT_SYMBOL_GPL(ps3_lpm_close);
1182
1183static int __devinit ps3_lpm_probe(struct ps3_system_bus_device *dev)
1184{
1185 dev_dbg(&dev->core, " -> %s:%u\n", __func__, __LINE__);
1186
1187 if (lpm_priv) {
1188 dev_info(&dev->core, "%s:%u: called twice\n",
1189 __func__, __LINE__);
1190 return -EBUSY;
1191 }
1192
1193 lpm_priv = kzalloc(sizeof(*lpm_priv), GFP_KERNEL);
1194
1195 if (!lpm_priv)
1196 return -ENOMEM;
1197
1198 lpm_priv->sbd = dev;
1199 lpm_priv->node_id = dev->lpm.node_id;
1200 lpm_priv->pu_id = dev->lpm.pu_id;
1201 lpm_priv->rights = dev->lpm.rights;
1202
1203 dev_info(&dev->core, " <- %s:%u:\n", __func__, __LINE__);
1204
1205 return 0;
1206}
1207
1208static int ps3_lpm_remove(struct ps3_system_bus_device *dev)
1209{
1210 dev_dbg(&dev->core, " -> %s:%u:\n", __func__, __LINE__);
1211
1212 ps3_lpm_close();
1213
1214 kfree(lpm_priv);
1215 lpm_priv = NULL;
1216
1217 dev_info(&dev->core, " <- %s:%u:\n", __func__, __LINE__);
1218 return 0;
1219}
1220
1221static struct ps3_system_bus_driver ps3_lpm_driver = {
1222 .match_id = PS3_MATCH_ID_LPM,
1223 .core.name = "ps3-lpm",
1224 .core.owner = THIS_MODULE,
1225 .probe = ps3_lpm_probe,
1226 .remove = ps3_lpm_remove,
1227 .shutdown = ps3_lpm_remove,
1228};
1229
1230static int __init ps3_lpm_init(void)
1231{
1232 pr_debug("%s:%d:\n", __func__, __LINE__);
1233 return ps3_system_bus_driver_register(&ps3_lpm_driver);
1234}
1235
1236static void __exit ps3_lpm_exit(void)
1237{
1238 pr_debug("%s:%d:\n", __func__, __LINE__);
1239 ps3_system_bus_driver_unregister(&ps3_lpm_driver);
1240}
1241
1242module_init(ps3_lpm_init);
1243module_exit(ps3_lpm_exit);
1244
1245MODULE_LICENSE("GPL v2");
1246MODULE_DESCRIPTION("PS3 Logical Performance Monitor Driver");
1247MODULE_AUTHOR("Sony Corporation");
1248MODULE_ALIAS(PS3_MODULE_ALIAS_LPM);
diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h
index 001121b3eb1b..2b693673eff4 100644
--- a/include/asm-powerpc/ps3.h
+++ b/include/asm-powerpc/ps3.h
@@ -24,6 +24,7 @@
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/types.h> 25#include <linux/types.h>
26#include <linux/device.h> 26#include <linux/device.h>
27#include "cell-pmu.h"
27 28
28union ps3_firmware_version { 29union ps3_firmware_version {
29 u64 raw; 30 u64 raw;
@@ -446,5 +447,66 @@ struct ps3_prealloc {
446extern struct ps3_prealloc ps3fb_videomemory; 447extern struct ps3_prealloc ps3fb_videomemory;
447extern struct ps3_prealloc ps3flash_bounce_buffer; 448extern struct ps3_prealloc ps3flash_bounce_buffer;
448 449
450/* logical performance monitor */
451
452/**
453 * enum ps3_lpm_rights - Rigths granted by the system policy module.
454 *
455 * @PS3_LPM_RIGHTS_USE_LPM: The right to use the lpm.
456 * @PS3_LPM_RIGHTS_USE_TB: The right to use the internal trace buffer.
457 */
458
459enum ps3_lpm_rights {
460 PS3_LPM_RIGHTS_USE_LPM = 0x001,
461 PS3_LPM_RIGHTS_USE_TB = 0x100,
462};
463
464/**
465 * enum ps3_lpm_tb_type - Type of trace buffer lv1 should use.
466 *
467 * @PS3_LPM_TB_TYPE_NONE: Do not use a trace buffer.
468 * @PS3_LPM_RIGHTS_USE_TB: Use the lv1 internal trace buffer. Must have
469 * rights @PS3_LPM_RIGHTS_USE_TB.
470 */
471
472enum ps3_lpm_tb_type {
473 PS3_LPM_TB_TYPE_NONE = 0,
474 PS3_LPM_TB_TYPE_INTERNAL = 1,
475};
476
477int ps3_lpm_open(enum ps3_lpm_tb_type tb_type, void *tb_cache,
478 u64 tb_cache_size);
479int ps3_lpm_close(void);
480int ps3_lpm_copy_tb(unsigned long offset, void *buf, unsigned long count,
481 unsigned long *bytes_copied);
482int ps3_lpm_copy_tb_to_user(unsigned long offset, void __user *buf,
483 unsigned long count, unsigned long *bytes_copied);
484void ps3_set_bookmark(u64 bookmark);
485void ps3_set_pm_bookmark(u64 tag, u64 incident, u64 th_id);
486int ps3_set_signal(u64 rtas_signal_group, u8 signal_bit, u16 sub_unit,
487 u8 bus_word);
488
489u32 ps3_read_phys_ctr(u32 cpu, u32 phys_ctr);
490void ps3_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val);
491u32 ps3_read_ctr(u32 cpu, u32 ctr);
492void ps3_write_ctr(u32 cpu, u32 ctr, u32 val);
493
494u32 ps3_read_pm07_control(u32 cpu, u32 ctr);
495void ps3_write_pm07_control(u32 cpu, u32 ctr, u32 val);
496u32 ps3_read_pm(u32 cpu, enum pm_reg_name reg);
497void ps3_write_pm(u32 cpu, enum pm_reg_name reg, u32 val);
498
499u32 ps3_get_ctr_size(u32 cpu, u32 phys_ctr);
500void ps3_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size);
501
502void ps3_enable_pm(u32 cpu);
503void ps3_disable_pm(u32 cpu);
504void ps3_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask);
505void ps3_disable_pm_interrupts(u32 cpu);
506
507u32 ps3_get_and_clear_pm_interrupts(u32 cpu);
508void ps3_sync_irq(int node);
509u32 ps3_get_hw_thread_id(int cpu);
510u64 ps3_get_spe_id(void *arg);
449 511
450#endif 512#endif