common.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /**
  2. * @file arch/alpha/oprofile/common.c
  3. *
  4. * @remark Copyright 2002 OProfile authors
  5. * @remark Read the file COPYING
  6. *
  7. * @author Richard Henderson <rth@twiddle.net>
  8. */
  9. #include <linux/oprofile.h>
  10. #include <linux/init.h>
  11. #include <linux/smp.h>
  12. #include <linux/errno.h>
  13. #include <asm/ptrace.h>
  14. #include "op_impl.h"
  15. extern struct op_axp_model op_model_ev4 __attribute__((weak));
  16. extern struct op_axp_model op_model_ev5 __attribute__((weak));
  17. extern struct op_axp_model op_model_pca56 __attribute__((weak));
  18. extern struct op_axp_model op_model_ev6 __attribute__((weak));
  19. extern struct op_axp_model op_model_ev67 __attribute__((weak));
  20. static struct op_axp_model *model;
  21. extern void (*perf_irq)(unsigned long, struct pt_regs *);
  22. static void (*save_perf_irq)(unsigned long, struct pt_regs *);
  23. static struct op_counter_config ctr[20];
  24. static struct op_system_config sys;
  25. static struct op_register_config reg;
  26. /* Called from do_entInt to handle the performance monitor interrupt. */
  27. static void
  28. op_handle_interrupt(unsigned long which, struct pt_regs *regs)
  29. {
  30. model->handle_interrupt(which, regs, ctr);
  31. /* If the user has selected an interrupt frequency that is
  32. not exactly the width of the counter, write a new value
  33. into the counter such that it'll overflow after N more
  34. events. */
  35. if ((reg.need_reset >> which) & 1)
  36. model->reset_ctr(&reg, which);
  37. }
  38. static int
  39. op_axp_setup(void)
  40. {
  41. unsigned long i, e;
  42. /* Install our interrupt handler into the existing hook. */
  43. save_perf_irq = perf_irq;
  44. perf_irq = op_handle_interrupt;
  45. /* Compute the mask of enabled counters. */
  46. for (i = e = 0; i < model->num_counters; ++i)
  47. if (ctr[i].enabled)
  48. e |= 1 << i;
  49. reg.enable = e;
  50. /* Pre-compute the values to stuff in the hardware registers. */
  51. model->reg_setup(&reg, ctr, &sys);
  52. /* Configure the registers on all cpus. */
  53. (void)smp_call_function(model->cpu_setup, &reg, 1);
  54. model->cpu_setup(&reg);
  55. return 0;
  56. }
  57. static void
  58. op_axp_shutdown(void)
  59. {
  60. /* Remove our interrupt handler. We may be removing this module. */
  61. perf_irq = save_perf_irq;
  62. }
  63. static void
  64. op_axp_cpu_start(void *dummy)
  65. {
  66. wrperfmon(1, reg.enable);
  67. }
  68. static int
  69. op_axp_start(void)
  70. {
  71. (void)smp_call_function(op_axp_cpu_start, NULL, 1);
  72. op_axp_cpu_start(NULL);
  73. return 0;
  74. }
  75. static inline void
  76. op_axp_cpu_stop(void *dummy)
  77. {
  78. /* Disable performance monitoring for all counters. */
  79. wrperfmon(0, -1);
  80. }
  81. static void
  82. op_axp_stop(void)
  83. {
  84. (void)smp_call_function(op_axp_cpu_stop, NULL, 1);
  85. op_axp_cpu_stop(NULL);
  86. }
  87. static int
  88. op_axp_create_files(struct super_block *sb, struct dentry *root)
  89. {
  90. int i;
  91. for (i = 0; i < model->num_counters; ++i) {
  92. struct dentry *dir;
  93. char buf[4];
  94. snprintf(buf, sizeof buf, "%d", i);
  95. dir = oprofilefs_mkdir(sb, root, buf);
  96. oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
  97. oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
  98. oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
  99. /* Dummies. */
  100. oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
  101. oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
  102. oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
  103. }
  104. if (model->can_set_proc_mode) {
  105. oprofilefs_create_ulong(sb, root, "enable_pal",
  106. &sys.enable_pal);
  107. oprofilefs_create_ulong(sb, root, "enable_kernel",
  108. &sys.enable_kernel);
  109. oprofilefs_create_ulong(sb, root, "enable_user",
  110. &sys.enable_user);
  111. }
  112. return 0;
  113. }
  114. int __init
  115. oprofile_arch_init(struct oprofile_operations *ops)
  116. {
  117. struct op_axp_model *lmodel = NULL;
  118. switch (implver()) {
  119. case IMPLVER_EV4:
  120. lmodel = &op_model_ev4;
  121. break;
  122. case IMPLVER_EV5:
  123. /* 21164PC has a slightly different set of events.
  124. Recognize the chip by the presence of the MAX insns. */
  125. if (!amask(AMASK_MAX))
  126. lmodel = &op_model_pca56;
  127. else
  128. lmodel = &op_model_ev5;
  129. break;
  130. case IMPLVER_EV6:
  131. /* 21264A supports ProfileMe.
  132. Recognize the chip by the presence of the CIX insns. */
  133. if (!amask(AMASK_CIX))
  134. lmodel = &op_model_ev67;
  135. else
  136. lmodel = &op_model_ev6;
  137. break;
  138. }
  139. if (!lmodel)
  140. return -ENODEV;
  141. model = lmodel;
  142. ops->create_files = op_axp_create_files;
  143. ops->setup = op_axp_setup;
  144. ops->shutdown = op_axp_shutdown;
  145. ops->start = op_axp_start;
  146. ops->stop = op_axp_stop;
  147. ops->cpu_type = lmodel->cpu_type;
  148. printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
  149. lmodel->cpu_type);
  150. return 0;
  151. }
  152. void
  153. oprofile_arch_exit(void)
  154. {
  155. }