Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ps3-lpm.c
Go to the documentation of this file.
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/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 /* BOOKMARK tag macros */
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 /* CBE PM CONTROL register macros */
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 /* CBE PM START STOP register macros */
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 /* CBE PM COUNTER register macres */
57 #define PS3_PM_COUNTER_MASK_HI 0xFFFFFFFF00000000ULL
58 #define PS3_PM_COUNTER_MASK_LO 0x00000000FFFFFFFFULL
59 
60 /* BASE SIGNAL GROUP NUMBER macros */
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 
98 };
99 
100 #define PS3_LPM_SHADOW_REG_INIT 0xFFFFFFFF00000000ULL
101 
129 struct ps3_lpm_priv {
137  void *tb_cache;
142 };
143 
144 enum {
146 };
147 
156 static struct ps3_lpm_priv *lpm_priv;
157 
158 static struct device *sbd_core(void)
159 {
160  BUG_ON(!lpm_priv || !lpm_priv->sbd);
161  return &lpm_priv->sbd->core;
162 }
163 
175 
176 void ps3_set_bookmark(u64 bookmark)
177 {
178  /*
179  * As per the PPE book IV, to avoid bookmark loss there must
180  * not be a traced branch within 10 cycles of setting the
181  * SPRN_BKMK register. The actual text is unclear if 'within'
182  * includes cycles before the call.
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 }
190 
191 void ps3_set_pm_bookmark(u64 tag, u64 incident, u64 th_id)
192 {
193  u64 bookmark;
194 
195  bookmark = (get_tb() & 0x00000000FFFFFFFFULL) |
197  bookmark = ((tag << 56) & PS3_PM_BOOKMARK_TAG_MASK_LO) |
198  (incident << 48) | (th_id << 32) | bookmark;
199  ps3_set_bookmark(bookmark);
200 }
202 
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 }
246 
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 }
307 
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 }
328 
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 }
355 
363 {
364  return 0;
365 }
367 
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 }
394 
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 }
446 
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,
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,
470  &dummy);
471  lpm_priv->shadow.debug_bus_control = val;
472  break;
473  case pm_control:
477  if (val != lpm_priv->shadow.pm_control)
478  result = lv1_set_lpm_general_control(lpm_priv->lpm_id,
479  val,
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,
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 }
514 
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 }
535 
540 void 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 }
567 
568 static 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)
578  else
580 }
581 
582 static 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 
600 static u64 pm_translate_signal_group_number_on_island4(u64 subgroup)
601 {
602  return PM_ISLAND4_BASE_SIGNAL_GROUP_NUMBER + subgroup;
603 }
604 
605 static 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 
621 static 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 
662 static u64 pm_translate_signal_group_number_on_island7(u64 subgroup)
663 {
664  return PM_ISLAND7_BASE_SIGNAL_GROUP_NUMBER + subgroup;
665 }
666 
667 static u64 pm_translate_signal_group_number_on_island8(u64 subgroup)
668 {
669  return PM_ISLAND8_BASE_SIGNAL_GROUP_NUMBER + subgroup;
670 }
671 
672 static 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 
744 static 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 
760 static 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 
776 int 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) {
794  signal_select = 1;
795  signal_select = signal_select << (63 - signal_bit);
796  break;
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  * 0: physical object.
808  * 1: logical object.
809  * This parameter is only used for the PPE and SPE signals.
810  */
811  attr1 = 1;
812 
813  /*
814  * This parameter is used to specify the target physical/logical
815  * PPE/SPE object.
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  * This parameter is only used for setting the SPE signal.
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 }
837 
839 {
840  return get_hard_smp_processor_id(cpu);
841 }
843 
851 {
852  int result;
853  u64 tmp;
854  int insert_bookmark = 0;
855 
856  lpm_priv->tb_count = 0;
857 
859  if (!(lpm_priv->shadow.pm_start_stop &
862  result = lv1_set_lpm_trigger_control(lpm_priv->lpm_id,
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)
887 }
889 
895 {
896  int result;
897  u64 tmp;
898 
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 }
916 
929 int 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 }
971 
984 int 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 }
1034 
1043 {
1044  return ps3_read_pm(cpu, pm_status);
1045 }
1047 
1056 {
1057  if (mask)
1058  ps3_write_pm(cpu, pm_status, mask);
1059 }
1061 
1069 {
1071  ps3_write_pm(cpu, pm_status, 0);
1072 }
1074 
1086 int 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  /* Note tb_cache needs 128 byte alignment. */
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 {
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 
1158 fail_construct:
1159  kfree(lpm_priv->tb_cache_internal);
1160  lpm_priv->tb_cache_internal = NULL;
1161 fail_malloc:
1162 fail_align:
1163  atomic_dec(&lpm_priv->open);
1164  return result;
1165 }
1167 
1173 int 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 }
1187 
1188 static 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 
1213 static 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 
1226 static 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 
1235 static 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 
1241 static 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 
1247 module_init(ps3_lpm_init);
1248 module_exit(ps3_lpm_exit);
1249 
1250 MODULE_LICENSE("GPL v2");
1251 MODULE_DESCRIPTION("PS3 Logical Performance Monitor Driver");
1252 MODULE_AUTHOR("Sony Corporation");