1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include <linux/slab.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/interrupt.h>
25#include <linux/uaccess.h>
26#include <asm/smp.h>
27#include <asm/time.h>
28#include <asm/ps3.h>
29#include <asm/lv1call.h>
30#include <asm/cell-pmu.h>
31
32
33
34#define PS3_PM_BOOKMARK_START 0x8000000000000000ULL
35#define PS3_PM_BOOKMARK_STOP 0x4000000000000000ULL
36#define PS3_PM_BOOKMARK_TAG_KERNEL 0x1000000000000000ULL
37#define PS3_PM_BOOKMARK_TAG_USER 0x3000000000000000ULL
38#define PS3_PM_BOOKMARK_TAG_MASK_HI 0xF000000000000000ULL
39#define PS3_PM_BOOKMARK_TAG_MASK_LO 0x0F00000000000000ULL
40
41
42#define PS3_PM_CONTROL_PPU_TH0_BOOKMARK 0x00001000
43#define PS3_PM_CONTROL_PPU_TH1_BOOKMARK 0x00000800
44#define PS3_PM_CONTROL_PPU_COUNT_MODE_MASK 0x000C0000
45#define PS3_PM_CONTROL_PPU_COUNT_MODE_PROBLEM 0x00080000
46#define PS3_WRITE_PM_MASK 0xFFFFFFFFFFFFFFFFULL
47
48
49#define PS3_PM_START_STOP_PPU_TH0_BOOKMARK_START 0x02000000
50#define PS3_PM_START_STOP_PPU_TH1_BOOKMARK_START 0x01000000
51#define PS3_PM_START_STOP_PPU_TH0_BOOKMARK_STOP 0x00020000
52#define PS3_PM_START_STOP_PPU_TH1_BOOKMARK_STOP 0x00010000
53#define PS3_PM_START_STOP_START_MASK 0xFF000000
54#define PS3_PM_START_STOP_STOP_MASK 0x00FF0000
55
56
57#define PS3_PM_COUNTER_MASK_HI 0xFFFFFFFF00000000ULL
58#define PS3_PM_COUNTER_MASK_LO 0x00000000FFFFFFFFULL
59
60
61#define PM_ISLAND2_BASE_SIGNAL_GROUP_NUMBER 0
62#define PM_ISLAND2_SIGNAL_GROUP_NUMBER1 6
63#define PM_ISLAND2_SIGNAL_GROUP_NUMBER2 7
64#define PM_ISLAND3_BASE_SIGNAL_GROUP_NUMBER 7
65#define PM_ISLAND4_BASE_SIGNAL_GROUP_NUMBER 15
66#define PM_SPU_TRIGGER_SIGNAL_GROUP_NUMBER 17
67#define PM_SPU_EVENT_SIGNAL_GROUP_NUMBER 18
68#define PM_ISLAND5_BASE_SIGNAL_GROUP_NUMBER 18
69#define PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER 24
70#define PM_ISLAND7_BASE_SIGNAL_GROUP_NUMBER 49
71#define PM_ISLAND8_BASE_SIGNAL_GROUP_NUMBER 52
72#define PM_SIG_GROUP_SPU 41
73#define PM_SIG_GROUP_SPU_TRIGGER 42
74#define PM_SIG_GROUP_SPU_EVENT 43
75#define PM_SIG_GROUP_MFC_MAX 60
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93struct ps3_lpm_shadow_regs {
94 u64 pm_control;
95 u64 pm_start_stop;
96 u64 group_control;
97 u64 debug_bus_control;
98};
99
100#define PS3_LPM_SHADOW_REG_INIT 0xFFFFFFFF00000000ULL
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129struct ps3_lpm_priv {
130 atomic_t open;
131 u64 rights;
132 u64 node_id;
133 u64 pu_id;
134 u64 lpm_id;
135 u64 outlet_id;
136 u64 tb_count;
137 void *tb_cache;
138 u64 tb_cache_size;
139 void *tb_cache_internal;
140 struct ps3_lpm_shadow_regs shadow;
141 struct ps3_system_bus_device *sbd;
142};
143
144enum {
145 PS3_LPM_DEFAULT_TB_CACHE_SIZE = 0x4000,
146};
147
148
149
150
151
152
153
154
155
156static struct ps3_lpm_priv *lpm_priv;
157
158static struct device *sbd_core(void)
159{
160 BUG_ON(!lpm_priv || !lpm_priv->sbd);
161 return &lpm_priv->sbd->core;
162}
163
164
165
166
167
168
169
170
171
172
173
174enum {use_start_stop_bookmark = 1,};
175
176void ps3_set_bookmark(u64 bookmark)
177{
178
179
180
181
182
183
184
185 asm volatile("nop;nop;nop;nop;nop;nop;nop;nop;nop;");
186 mtspr(SPRN_BKMK, bookmark);
187 asm volatile("nop;nop;nop;nop;nop;nop;nop;nop;nop;");
188}
189EXPORT_SYMBOL_GPL(ps3_set_bookmark);
190
191void ps3_set_pm_bookmark(u64 tag, u64 incident, u64 th_id)
192{
193 u64 bookmark;
194
195 bookmark = (get_tb() & 0x00000000FFFFFFFFULL) |
196 PS3_PM_BOOKMARK_TAG_KERNEL;
197 bookmark = ((tag << 56) & PS3_PM_BOOKMARK_TAG_MASK_LO) |
198 (incident << 48) | (th_id << 32) | bookmark;
199 ps3_set_bookmark(bookmark);
200}
201EXPORT_SYMBOL_GPL(ps3_set_pm_bookmark);
202
203
204
205
206
207
208
209
210u32 ps3_read_phys_ctr(u32 cpu, u32 phys_ctr)
211{
212 int result;
213 u64 counter0415;
214 u64 counter2637;
215
216 if (phys_ctr >= NR_PHYS_CTRS) {
217 dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
218 __LINE__, phys_ctr);
219 return 0;
220 }
221
222 result = lv1_set_lpm_counter(lpm_priv->lpm_id, 0, 0, 0, 0, &counter0415,
223 &counter2637);
224 if (result) {
225 dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter failed: "
226 "phys_ctr %u, %s\n", __func__, __LINE__, phys_ctr,
227 ps3_result(result));
228 return 0;
229 }
230
231 switch (phys_ctr) {
232 case 0:
233 return counter0415 >> 32;
234 case 1:
235 return counter0415 & PS3_PM_COUNTER_MASK_LO;
236 case 2:
237 return counter2637 >> 32;
238 case 3:
239 return counter2637 & PS3_PM_COUNTER_MASK_LO;
240 default:
241 BUG();
242 }
243 return 0;
244}
245EXPORT_SYMBOL_GPL(ps3_read_phys_ctr);
246
247
248
249
250
251
252
253
254void ps3_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val)
255{
256 u64 counter0415;
257 u64 counter0415_mask;
258 u64 counter2637;
259 u64 counter2637_mask;
260 int result;
261
262 if (phys_ctr >= NR_PHYS_CTRS) {
263 dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
264 __LINE__, phys_ctr);
265 return;
266 }
267
268 switch (phys_ctr) {
269 case 0:
270 counter0415 = (u64)val << 32;
271 counter0415_mask = PS3_PM_COUNTER_MASK_HI;
272 counter2637 = 0x0;
273 counter2637_mask = 0x0;
274 break;
275 case 1:
276 counter0415 = (u64)val;
277 counter0415_mask = PS3_PM_COUNTER_MASK_LO;
278 counter2637 = 0x0;
279 counter2637_mask = 0x0;
280 break;
281 case 2:
282 counter0415 = 0x0;
283 counter0415_mask = 0x0;
284 counter2637 = (u64)val << 32;
285 counter2637_mask = PS3_PM_COUNTER_MASK_HI;
286 break;
287 case 3:
288 counter0415 = 0x0;
289 counter0415_mask = 0x0;
290 counter2637 = (u64)val;
291 counter2637_mask = PS3_PM_COUNTER_MASK_LO;
292 break;
293 default:
294 BUG();
295 }
296
297 result = lv1_set_lpm_counter(lpm_priv->lpm_id,
298 counter0415, counter0415_mask,
299 counter2637, counter2637_mask,
300 &counter0415, &counter2637);
301 if (result)
302 dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter failed: "
303 "phys_ctr %u, val %u, %s\n", __func__, __LINE__,
304 phys_ctr, val, ps3_result(result));
305}
306EXPORT_SYMBOL_GPL(ps3_write_phys_ctr);
307
308
309
310
311
312
313
314
315u32 ps3_read_ctr(u32 cpu, u32 ctr)
316{
317 u32 val;
318 u32 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
319
320 val = ps3_read_phys_ctr(cpu, phys_ctr);
321
322 if (ps3_get_ctr_size(cpu, phys_ctr) == 16)
323 val = (ctr < NR_PHYS_CTRS) ? (val >> 16) : (val & 0xffff);
324
325 return val;
326}
327EXPORT_SYMBOL_GPL(ps3_read_ctr);
328
329
330
331
332
333
334
335
336void ps3_write_ctr(u32 cpu, u32 ctr, u32 val)
337{
338 u32 phys_ctr;
339 u32 phys_val;
340
341 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
342
343 if (ps3_get_ctr_size(cpu, phys_ctr) == 16) {
344 phys_val = ps3_read_phys_ctr(cpu, phys_ctr);
345
346 if (ctr < NR_PHYS_CTRS)
347 val = (val << 16) | (phys_val & 0xffff);
348 else
349 val = (val & 0xffff) | (phys_val & 0xffff0000);
350 }
351
352 ps3_write_phys_ctr(cpu, phys_ctr, val);
353}
354EXPORT_SYMBOL_GPL(ps3_write_ctr);
355
356
357
358
359
360
361
362u32 ps3_read_pm07_control(u32 cpu, u32 ctr)
363{
364 return 0;
365}
366EXPORT_SYMBOL_GPL(ps3_read_pm07_control);
367
368
369
370
371
372
373
374void ps3_write_pm07_control(u32 cpu, u32 ctr, u32 val)
375{
376 int result;
377 static const u64 mask = 0xFFFFFFFFFFFFFFFFULL;
378 u64 old_value;
379
380 if (ctr >= NR_CTRS) {
381 dev_dbg(sbd_core(), "%s:%u: ctr too big: %u\n", __func__,
382 __LINE__, ctr);
383 return;
384 }
385
386 result = lv1_set_lpm_counter_control(lpm_priv->lpm_id, ctr, val, mask,
387 &old_value);
388 if (result)
389 dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter_control "
390 "failed: ctr %u, %s\n", __func__, __LINE__, ctr,
391 ps3_result(result));
392}
393EXPORT_SYMBOL_GPL(ps3_write_pm07_control);
394
395
396
397
398
399u32 ps3_read_pm(u32 cpu, enum pm_reg_name reg)
400{
401 int result = 0;
402 u64 val = 0;
403
404 switch (reg) {
405 case pm_control:
406 return lpm_priv->shadow.pm_control;
407 case trace_address:
408 return CBE_PM_TRACE_BUF_EMPTY;
409 case pm_start_stop:
410 return lpm_priv->shadow.pm_start_stop;
411 case pm_interval:
412 result = lv1_set_lpm_interval(lpm_priv->lpm_id, 0, 0, &val);
413 if (result) {
414 val = 0;
415 dev_dbg(sbd_core(), "%s:%u: lv1 set_inteval failed: "
416 "reg %u, %s\n", __func__, __LINE__, reg,
417 ps3_result(result));
418 }
419 return (u32)val;
420 case group_control:
421 return lpm_priv->shadow.group_control;
422 case debug_bus_control:
423 return lpm_priv->shadow.debug_bus_control;
424 case pm_status:
425 result = lv1_get_lpm_interrupt_status(lpm_priv->lpm_id,
426 &val);
427 if (result) {
428 val = 0;
429 dev_dbg(sbd_core(), "%s:%u: lv1 get_lpm_status failed: "
430 "reg %u, %s\n", __func__, __LINE__, reg,
431 ps3_result(result));
432 }
433 return (u32)val;
434 case ext_tr_timer:
435 return 0;
436 default:
437 dev_dbg(sbd_core(), "%s:%u: unknown reg: %d\n", __func__,
438 __LINE__, reg);
439 BUG();
440 break;
441 }
442
443 return 0;
444}
445EXPORT_SYMBOL_GPL(ps3_read_pm);
446
447
448
449
450
451void ps3_write_pm(u32 cpu, enum pm_reg_name reg, u32 val)
452{
453 int result = 0;
454 u64 dummy;
455
456 switch (reg) {
457 case group_control:
458 if (val != lpm_priv->shadow.group_control)
459 result = lv1_set_lpm_group_control(lpm_priv->lpm_id,
460 val,
461 PS3_WRITE_PM_MASK,
462 &dummy);
463 lpm_priv->shadow.group_control = val;
464 break;
465 case debug_bus_control:
466 if (val != lpm_priv->shadow.debug_bus_control)
467 result = lv1_set_lpm_debug_bus_control(lpm_priv->lpm_id,
468 val,
469 PS3_WRITE_PM_MASK,
470 &dummy);
471 lpm_priv->shadow.debug_bus_control = val;
472 break;
473 case pm_control:
474 if (use_start_stop_bookmark)
475 val |= (PS3_PM_CONTROL_PPU_TH0_BOOKMARK |
476 PS3_PM_CONTROL_PPU_TH1_BOOKMARK);
477 if (val != lpm_priv->shadow.pm_control)
478 result = lv1_set_lpm_general_control(lpm_priv->lpm_id,
479 val,
480 PS3_WRITE_PM_MASK,
481 0, 0, &dummy,
482 &dummy);
483 lpm_priv->shadow.pm_control = val;
484 break;
485 case pm_interval:
486 result = lv1_set_lpm_interval(lpm_priv->lpm_id, val,
487 PS3_WRITE_PM_MASK, &dummy);
488 break;
489 case pm_start_stop:
490 if (val != lpm_priv->shadow.pm_start_stop)
491 result = lv1_set_lpm_trigger_control(lpm_priv->lpm_id,
492 val,
493 PS3_WRITE_PM_MASK,
494 &dummy);
495 lpm_priv->shadow.pm_start_stop = val;
496 break;
497 case trace_address:
498 case ext_tr_timer:
499 case pm_status:
500 break;
501 default:
502 dev_dbg(sbd_core(), "%s:%u: unknown reg: %d\n", __func__,
503 __LINE__, reg);
504 BUG();
505 break;
506 }
507
508 if (result)
509 dev_err(sbd_core(), "%s:%u: lv1 set_control failed: "
510 "reg %u, %s\n", __func__, __LINE__, reg,
511 ps3_result(result));
512}
513EXPORT_SYMBOL_GPL(ps3_write_pm);
514
515
516
517
518
519
520
521u32 ps3_get_ctr_size(u32 cpu, u32 phys_ctr)
522{
523 u32 pm_ctrl;
524
525 if (phys_ctr >= NR_PHYS_CTRS) {
526 dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
527 __LINE__, phys_ctr);
528 return 0;
529 }
530
531 pm_ctrl = ps3_read_pm(cpu, pm_control);
532 return (pm_ctrl & CBE_PM_16BIT_CTR(phys_ctr)) ? 16 : 32;
533}
534EXPORT_SYMBOL_GPL(ps3_get_ctr_size);
535
536
537
538
539
540void ps3_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size)
541{
542 u32 pm_ctrl;
543
544 if (phys_ctr >= NR_PHYS_CTRS) {
545 dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
546 __LINE__, phys_ctr);
547 return;
548 }
549
550 pm_ctrl = ps3_read_pm(cpu, pm_control);
551
552 switch (ctr_size) {
553 case 16:
554 pm_ctrl |= CBE_PM_16BIT_CTR(phys_ctr);
555 ps3_write_pm(cpu, pm_control, pm_ctrl);
556 break;
557
558 case 32:
559 pm_ctrl &= ~CBE_PM_16BIT_CTR(phys_ctr);
560 ps3_write_pm(cpu, pm_control, pm_ctrl);
561 break;
562 default:
563 BUG();
564 }
565}
566EXPORT_SYMBOL_GPL(ps3_set_ctr_size);
567
568static u64 pm_translate_signal_group_number_on_island2(u64 subgroup)
569{
570
571 if (subgroup == 2)
572 subgroup = 3;
573
574 if (subgroup <= 6)
575 return PM_ISLAND2_BASE_SIGNAL_GROUP_NUMBER + subgroup;
576 else if (subgroup == 7)
577 return PM_ISLAND2_SIGNAL_GROUP_NUMBER1;
578 else
579 return PM_ISLAND2_SIGNAL_GROUP_NUMBER2;
580}
581
582static u64 pm_translate_signal_group_number_on_island3(u64 subgroup)
583{
584
585 switch (subgroup) {
586 case 2:
587 case 3:
588 case 4:
589 subgroup += 2;
590 break;
591 case 5:
592 subgroup = 8;
593 break;
594 default:
595 break;
596 }
597 return PM_ISLAND3_BASE_SIGNAL_GROUP_NUMBER + subgroup;
598}
599
600static u64 pm_translate_signal_group_number_on_island4(u64 subgroup)
601{
602 return PM_ISLAND4_BASE_SIGNAL_GROUP_NUMBER + subgroup;
603}
604
605static u64 pm_translate_signal_group_number_on_island5(u64 subgroup)
606{
607
608 switch (subgroup) {
609 case 3:
610 subgroup = 4;
611 break;
612 case 4:
613 subgroup = 6;
614 break;
615 default:
616 break;
617 }
618 return PM_ISLAND5_BASE_SIGNAL_GROUP_NUMBER + subgroup;
619}
620
621static u64 pm_translate_signal_group_number_on_island6(u64 subgroup,
622 u64 subsubgroup)
623{
624 switch (subgroup) {
625 case 3:
626 case 4:
627 case 5:
628 subgroup += 1;
629 break;
630 default:
631 break;
632 }
633
634 switch (subsubgroup) {
635 case 4:
636 case 5:
637 case 6:
638 subsubgroup += 2;
639 break;
640 case 7:
641 case 8:
642 case 9:
643 case 10:
644 subsubgroup += 4;
645 break;
646 case 11:
647 case 12:
648 case 13:
649 subsubgroup += 5;
650 break;
651 default:
652 break;
653 }
654
655 if (subgroup <= 5)
656 return (PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER + subgroup);
657 else
658 return (PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER + subgroup
659 + subsubgroup - 1);
660}
661
662static u64 pm_translate_signal_group_number_on_island7(u64 subgroup)
663{
664 return PM_ISLAND7_BASE_SIGNAL_GROUP_NUMBER + subgroup;
665}
666
667static u64 pm_translate_signal_group_number_on_island8(u64 subgroup)
668{
669 return PM_ISLAND8_BASE_SIGNAL_GROUP_NUMBER + subgroup;
670}
671
672static u64 pm_signal_group_to_ps3_lv1_signal_group(u64 group)
673{
674 u64 island;
675 u64 subgroup;
676 u64 subsubgroup;
677
678 subgroup = 0;
679 subsubgroup = 0;
680 island = 0;
681 if (group < 1000) {
682 if (group < 100) {
683 if (20 <= group && group < 30) {
684 island = 2;
685 subgroup = group - 20;
686 } else if (30 <= group && group < 40) {
687 island = 3;
688 subgroup = group - 30;
689 } else if (40 <= group && group < 50) {
690 island = 4;
691 subgroup = group - 40;
692 } else if (50 <= group && group < 60) {
693 island = 5;
694 subgroup = group - 50;
695 } else if (60 <= group && group < 70) {
696 island = 6;
697 subgroup = group - 60;
698 } else if (70 <= group && group < 80) {
699 island = 7;
700 subgroup = group - 70;
701 } else if (80 <= group && group < 90) {
702 island = 8;
703 subgroup = group - 80;
704 }
705 } else if (200 <= group && group < 300) {
706 island = 2;
707 subgroup = group - 200;
708 } else if (600 <= group && group < 700) {
709 island = 6;
710 subgroup = 5;
711 subsubgroup = group - 650;
712 }
713 } else if (6000 <= group && group < 7000) {
714 island = 6;
715 subgroup = 5;
716 subsubgroup = group - 6500;
717 }
718
719 switch (island) {
720 case 2:
721 return pm_translate_signal_group_number_on_island2(subgroup);
722 case 3:
723 return pm_translate_signal_group_number_on_island3(subgroup);
724 case 4:
725 return pm_translate_signal_group_number_on_island4(subgroup);
726 case 5:
727 return pm_translate_signal_group_number_on_island5(subgroup);
728 case 6:
729 return pm_translate_signal_group_number_on_island6(subgroup,
730 subsubgroup);
731 case 7:
732 return pm_translate_signal_group_number_on_island7(subgroup);
733 case 8:
734 return pm_translate_signal_group_number_on_island8(subgroup);
735 default:
736 dev_dbg(sbd_core(), "%s:%u: island not found: %llu\n", __func__,
737 __LINE__, group);
738 BUG();
739 break;
740 }
741 return 0;
742}
743
744static u64 pm_bus_word_to_ps3_lv1_bus_word(u8 word)
745{
746
747 switch (word) {
748 case 1:
749 return 0xF000;
750 case 2:
751 return 0x0F00;
752 case 4:
753 return 0x00F0;
754 case 8:
755 default:
756 return 0x000F;
757 }
758}
759
760static int __ps3_set_signal(u64 lv1_signal_group, u64 bus_select,
761 u64 signal_select, u64 attr1, u64 attr2, u64 attr3)
762{
763 int ret;
764
765 ret = lv1_set_lpm_signal(lpm_priv->lpm_id, lv1_signal_group, bus_select,
766 signal_select, attr1, attr2, attr3);
767 if (ret)
768 dev_err(sbd_core(),
769 "%s:%u: error:%d 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx\n",
770 __func__, __LINE__, ret, lv1_signal_group, bus_select,
771 signal_select, attr1, attr2, attr3);
772
773 return ret;
774}
775
776int ps3_set_signal(u64 signal_group, u8 signal_bit, u16 sub_unit,
777 u8 bus_word)
778{
779 int ret;
780 u64 lv1_signal_group;
781 u64 bus_select;
782 u64 signal_select;
783 u64 attr1, attr2, attr3;
784
785 if (signal_group == 0)
786 return __ps3_set_signal(0, 0, 0, 0, 0, 0);
787
788 lv1_signal_group =
789 pm_signal_group_to_ps3_lv1_signal_group(signal_group);
790 bus_select = pm_bus_word_to_ps3_lv1_bus_word(bus_word);
791
792 switch (signal_group) {
793 case PM_SIG_GROUP_SPU_TRIGGER:
794 signal_select = 1;
795 signal_select = signal_select << (63 - signal_bit);
796 break;
797 case PM_SIG_GROUP_SPU_EVENT:
798 signal_select = 1;
799 signal_select = (signal_select << (63 - signal_bit)) | 0x3;
800 break;
801 default:
802 signal_select = 0;
803 break;
804 }
805
806
807
808
809
810
811 attr1 = 1;
812
813
814
815
816
817 if (PM_SIG_GROUP_SPU <= signal_group &&
818 signal_group < PM_SIG_GROUP_MFC_MAX)
819 attr2 = sub_unit;
820 else
821 attr2 = lpm_priv->pu_id;
822
823
824
825
826 attr3 = 0;
827
828 ret = __ps3_set_signal(lv1_signal_group, bus_select, signal_select,
829 attr1, attr2, attr3);
830 if (ret)
831 dev_err(sbd_core(), "%s:%u: __ps3_set_signal failed: %d\n",
832 __func__, __LINE__, ret);
833
834 return ret;
835}
836EXPORT_SYMBOL_GPL(ps3_set_signal);
837
838u32 ps3_get_hw_thread_id(int cpu)
839{
840 return get_hard_smp_processor_id(cpu);
841}
842EXPORT_SYMBOL_GPL(ps3_get_hw_thread_id);
843
844
845
846
847
848
849
850void ps3_enable_pm(u32 cpu)
851{
852 int result;
853 u64 tmp;
854 int insert_bookmark = 0;
855
856 lpm_priv->tb_count = 0;
857
858 if (use_start_stop_bookmark) {
859 if (!(lpm_priv->shadow.pm_start_stop &
860 (PS3_PM_START_STOP_START_MASK
861 | PS3_PM_START_STOP_STOP_MASK))) {
862 result = lv1_set_lpm_trigger_control(lpm_priv->lpm_id,
863 (PS3_PM_START_STOP_PPU_TH0_BOOKMARK_START |
864 PS3_PM_START_STOP_PPU_TH1_BOOKMARK_START |
865 PS3_PM_START_STOP_PPU_TH0_BOOKMARK_STOP |
866 PS3_PM_START_STOP_PPU_TH1_BOOKMARK_STOP),
867 0xFFFFFFFFFFFFFFFFULL, &tmp);
868
869 if (result)
870 dev_err(sbd_core(), "%s:%u: "
871 "lv1_set_lpm_trigger_control failed: "
872 "%s\n", __func__, __LINE__,
873 ps3_result(result));
874
875 insert_bookmark = !result;
876 }
877 }
878
879 result = lv1_start_lpm(lpm_priv->lpm_id);
880
881 if (result)
882 dev_err(sbd_core(), "%s:%u: lv1_start_lpm failed: %s\n",
883 __func__, __LINE__, ps3_result(result));
884
885 if (use_start_stop_bookmark && !result && insert_bookmark)
886 ps3_set_bookmark(get_tb() | PS3_PM_BOOKMARK_START);
887}
888EXPORT_SYMBOL_GPL(ps3_enable_pm);
889
890
891
892
893
894void ps3_disable_pm(u32 cpu)
895{
896 int result;
897 u64 tmp;
898
899 ps3_set_bookmark(get_tb() | PS3_PM_BOOKMARK_STOP);
900
901 result = lv1_stop_lpm(lpm_priv->lpm_id, &tmp);
902
903 if (result) {
904 if(result != LV1_WRONG_STATE)
905 dev_err(sbd_core(), "%s:%u: lv1_stop_lpm failed: %s\n",
906 __func__, __LINE__, ps3_result(result));
907 return;
908 }
909
910 lpm_priv->tb_count = tmp;
911
912 dev_dbg(sbd_core(), "%s:%u: tb_count %llu (%llxh)\n", __func__, __LINE__,
913 lpm_priv->tb_count, lpm_priv->tb_count);
914}
915EXPORT_SYMBOL_GPL(ps3_disable_pm);
916
917
918
919
920
921
922
923
924
925
926
927
928
929int ps3_lpm_copy_tb(unsigned long offset, void *buf, unsigned long count,
930 unsigned long *bytes_copied)
931{
932 int result;
933
934 *bytes_copied = 0;
935
936 if (!lpm_priv->tb_cache)
937 return -EPERM;
938
939 if (offset >= lpm_priv->tb_count)
940 return 0;
941
942 count = min_t(u64, count, lpm_priv->tb_count - offset);
943
944 while (*bytes_copied < count) {
945 const unsigned long request = count - *bytes_copied;
946 u64 tmp;
947
948 result = lv1_copy_lpm_trace_buffer(lpm_priv->lpm_id, offset,
949 request, &tmp);
950 if (result) {
951 dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%lx\n",
952 __func__, __LINE__, request, offset);
953
954 dev_err(sbd_core(), "%s:%u: lv1_copy_lpm_trace_buffer "
955 "failed: %s\n", __func__, __LINE__,
956 ps3_result(result));
957 return result == LV1_WRONG_STATE ? -EBUSY : -EINVAL;
958 }
959
960 memcpy(buf, lpm_priv->tb_cache, tmp);
961 buf += tmp;
962 *bytes_copied += tmp;
963 offset += tmp;
964 }
965 dev_dbg(sbd_core(), "%s:%u: copied %lxh bytes\n", __func__, __LINE__,
966 *bytes_copied);
967
968 return 0;
969}
970EXPORT_SYMBOL_GPL(ps3_lpm_copy_tb);
971
972
973
974
975
976
977
978
979
980
981
982
983
984int ps3_lpm_copy_tb_to_user(unsigned long offset, void __user *buf,
985 unsigned long count, unsigned long *bytes_copied)
986{
987 int result;
988
989 *bytes_copied = 0;
990
991 if (!lpm_priv->tb_cache)
992 return -EPERM;
993
994 if (offset >= lpm_priv->tb_count)
995 return 0;
996
997 count = min_t(u64, count, lpm_priv->tb_count - offset);
998
999 while (*bytes_copied < count) {
1000 const unsigned long request = count - *bytes_copied;
1001 u64 tmp;
1002
1003 result = lv1_copy_lpm_trace_buffer(lpm_priv->lpm_id, offset,
1004 request, &tmp);
1005 if (result) {
1006 dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%lx\n",
1007 __func__, __LINE__, request, offset);
1008 dev_err(sbd_core(), "%s:%u: lv1_copy_lpm_trace_buffer "
1009 "failed: %s\n", __func__, __LINE__,
1010 ps3_result(result));
1011 return result == LV1_WRONG_STATE ? -EBUSY : -EINVAL;
1012 }
1013
1014 result = copy_to_user(buf, lpm_priv->tb_cache, tmp);
1015
1016 if (result) {
1017 dev_dbg(sbd_core(), "%s:%u: 0x%llx bytes at 0x%p\n",
1018 __func__, __LINE__, tmp, buf);
1019 dev_err(sbd_core(), "%s:%u: copy_to_user failed: %d\n",
1020 __func__, __LINE__, result);
1021 return -EFAULT;
1022 }
1023
1024 buf += tmp;
1025 *bytes_copied += tmp;
1026 offset += tmp;
1027 }
1028 dev_dbg(sbd_core(), "%s:%u: copied %lxh bytes\n", __func__, __LINE__,
1029 *bytes_copied);
1030
1031 return 0;
1032}
1033EXPORT_SYMBOL_GPL(ps3_lpm_copy_tb_to_user);
1034
1035
1036
1037
1038
1039
1040
1041
1042u32 ps3_get_and_clear_pm_interrupts(u32 cpu)
1043{
1044 return ps3_read_pm(cpu, pm_status);
1045}
1046EXPORT_SYMBOL_GPL(ps3_get_and_clear_pm_interrupts);
1047
1048
1049
1050
1051
1052
1053
1054
1055void ps3_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask)
1056{
1057 if (mask)
1058 ps3_write_pm(cpu, pm_status, mask);
1059}
1060EXPORT_SYMBOL_GPL(ps3_enable_pm_interrupts);
1061
1062
1063
1064
1065
1066
1067
1068void ps3_disable_pm_interrupts(u32 cpu)
1069{
1070 ps3_get_and_clear_pm_interrupts(cpu);
1071 ps3_write_pm(cpu, pm_status, 0);
1072}
1073EXPORT_SYMBOL_GPL(ps3_disable_pm_interrupts);
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086int ps3_lpm_open(enum ps3_lpm_tb_type tb_type, void *tb_cache,
1087 u64 tb_cache_size)
1088{
1089 int result;
1090 u64 tb_size;
1091
1092 BUG_ON(!lpm_priv);
1093 BUG_ON(tb_type != PS3_LPM_TB_TYPE_NONE
1094 && tb_type != PS3_LPM_TB_TYPE_INTERNAL);
1095
1096 if (tb_type == PS3_LPM_TB_TYPE_NONE && tb_cache)
1097 dev_dbg(sbd_core(), "%s:%u: bad in vals\n", __func__, __LINE__);
1098
1099 if (!atomic_add_unless(&lpm_priv->open, 1, 1)) {
1100 dev_dbg(sbd_core(), "%s:%u: busy\n", __func__, __LINE__);
1101 return -EBUSY;
1102 }
1103
1104
1105
1106 if (tb_type == PS3_LPM_TB_TYPE_NONE) {
1107 lpm_priv->tb_cache_size = 0;
1108 lpm_priv->tb_cache_internal = NULL;
1109 lpm_priv->tb_cache = NULL;
1110 } else if (tb_cache) {
1111 if (tb_cache != (void *)_ALIGN_UP((unsigned long)tb_cache, 128)
1112 || tb_cache_size != _ALIGN_UP(tb_cache_size, 128)) {
1113 dev_err(sbd_core(), "%s:%u: unaligned tb_cache\n",
1114 __func__, __LINE__);
1115 result = -EINVAL;
1116 goto fail_align;
1117 }
1118 lpm_priv->tb_cache_size = tb_cache_size;
1119 lpm_priv->tb_cache_internal = NULL;
1120 lpm_priv->tb_cache = tb_cache;
1121 } else {
1122 lpm_priv->tb_cache_size = PS3_LPM_DEFAULT_TB_CACHE_SIZE;
1123 lpm_priv->tb_cache_internal = kzalloc(
1124 lpm_priv->tb_cache_size + 127, GFP_KERNEL);
1125 if (!lpm_priv->tb_cache_internal) {
1126 dev_err(sbd_core(), "%s:%u: alloc internal tb_cache "
1127 "failed\n", __func__, __LINE__);
1128 result = -ENOMEM;
1129 goto fail_malloc;
1130 }
1131 lpm_priv->tb_cache = (void *)_ALIGN_UP(
1132 (unsigned long)lpm_priv->tb_cache_internal, 128);
1133 }
1134
1135 result = lv1_construct_lpm(lpm_priv->node_id, tb_type, 0, 0,
1136 ps3_mm_phys_to_lpar(__pa(lpm_priv->tb_cache)),
1137 lpm_priv->tb_cache_size, &lpm_priv->lpm_id,
1138 &lpm_priv->outlet_id, &tb_size);
1139
1140 if (result) {
1141 dev_err(sbd_core(), "%s:%u: lv1_construct_lpm failed: %s\n",
1142 __func__, __LINE__, ps3_result(result));
1143 result = -EINVAL;
1144 goto fail_construct;
1145 }
1146
1147 lpm_priv->shadow.pm_control = PS3_LPM_SHADOW_REG_INIT;
1148 lpm_priv->shadow.pm_start_stop = PS3_LPM_SHADOW_REG_INIT;
1149 lpm_priv->shadow.group_control = PS3_LPM_SHADOW_REG_INIT;
1150 lpm_priv->shadow.debug_bus_control = PS3_LPM_SHADOW_REG_INIT;
1151
1152 dev_dbg(sbd_core(), "%s:%u: lpm_id 0x%llx, outlet_id 0x%llx, "
1153 "tb_size 0x%llx\n", __func__, __LINE__, lpm_priv->lpm_id,
1154 lpm_priv->outlet_id, tb_size);
1155
1156 return 0;
1157
1158fail_construct:
1159 kfree(lpm_priv->tb_cache_internal);
1160 lpm_priv->tb_cache_internal = NULL;
1161fail_malloc:
1162fail_align:
1163 atomic_dec(&lpm_priv->open);
1164 return result;
1165}
1166EXPORT_SYMBOL_GPL(ps3_lpm_open);
1167
1168
1169
1170
1171
1172
1173int ps3_lpm_close(void)
1174{
1175 dev_dbg(sbd_core(), "%s:%u\n", __func__, __LINE__);
1176
1177 lv1_destruct_lpm(lpm_priv->lpm_id);
1178 lpm_priv->lpm_id = 0;
1179
1180 kfree(lpm_priv->tb_cache_internal);
1181 lpm_priv->tb_cache_internal = NULL;
1182
1183 atomic_dec(&lpm_priv->open);
1184 return 0;
1185}
1186EXPORT_SYMBOL_GPL(ps3_lpm_close);
1187
1188static int __devinit ps3_lpm_probe(struct ps3_system_bus_device *dev)
1189{
1190 dev_dbg(&dev->core, " -> %s:%u\n", __func__, __LINE__);
1191
1192 if (lpm_priv) {
1193 dev_info(&dev->core, "%s:%u: called twice\n",
1194 __func__, __LINE__);
1195 return -EBUSY;
1196 }
1197
1198 lpm_priv = kzalloc(sizeof(*lpm_priv), GFP_KERNEL);
1199
1200 if (!lpm_priv)
1201 return -ENOMEM;
1202
1203 lpm_priv->sbd = dev;
1204 lpm_priv->node_id = dev->lpm.node_id;
1205 lpm_priv->pu_id = dev->lpm.pu_id;
1206 lpm_priv->rights = dev->lpm.rights;
1207
1208 dev_info(&dev->core, " <- %s:%u:\n", __func__, __LINE__);
1209
1210 return 0;
1211}
1212
1213static int ps3_lpm_remove(struct ps3_system_bus_device *dev)
1214{
1215 dev_dbg(&dev->core, " -> %s:%u:\n", __func__, __LINE__);
1216
1217 ps3_lpm_close();
1218
1219 kfree(lpm_priv);
1220 lpm_priv = NULL;
1221
1222 dev_info(&dev->core, " <- %s:%u:\n", __func__, __LINE__);
1223 return 0;
1224}
1225
1226static struct ps3_system_bus_driver ps3_lpm_driver = {
1227 .match_id = PS3_MATCH_ID_LPM,
1228 .core.name = "ps3-lpm",
1229 .core.owner = THIS_MODULE,
1230 .probe = ps3_lpm_probe,
1231 .remove = ps3_lpm_remove,
1232 .shutdown = ps3_lpm_remove,
1233};
1234
1235static int __init ps3_lpm_init(void)
1236{
1237 pr_debug("%s:%d:\n", __func__, __LINE__);
1238 return ps3_system_bus_driver_register(&ps3_lpm_driver);
1239}
1240
1241static void __exit ps3_lpm_exit(void)
1242{
1243 pr_debug("%s:%d:\n", __func__, __LINE__);
1244 ps3_system_bus_driver_unregister(&ps3_lpm_driver);
1245}
1246
1247module_init(ps3_lpm_init);
1248module_exit(ps3_lpm_exit);
1249
1250MODULE_LICENSE("GPL v2");
1251MODULE_DESCRIPTION("PS3 Logical Performance Monitor Driver");
1252MODULE_AUTHOR("Sony Corporation");
1253MODULE_ALIAS(PS3_MODULE_ALIAS_LPM);
1254