pmu.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. /*
  2. * linux/arch/arm/kernel/pmu.c
  3. *
  4. * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. */
  11. #include <linux/cpumask.h>
  12. #include <linux/err.h>
  13. #include <linux/interrupt.h>
  14. #include <linux/kernel.h>
  15. #include <linux/module.h>
  16. #include <asm/pmu.h>
  17. /*
  18. * Define the IRQs for the system. We could use something like a platform
  19. * device but that seems fairly heavyweight for this. Also, the performance
  20. * counters can't be removed or hotplugged.
  21. *
  22. * Ordering is important: init_pmu() will use the ordering to set the affinity
  23. * to the corresponding core. e.g. the first interrupt will go to cpu 0, the
  24. * second goes to cpu 1 etc.
  25. */
  26. static const int irqs[] = {
  27. #if defined(CONFIG_ARCH_OMAP2)
  28. 3,
  29. #elif defined(CONFIG_ARCH_BCMRING)
  30. IRQ_PMUIRQ,
  31. #elif defined(CONFIG_MACH_REALVIEW_EB)
  32. IRQ_EB11MP_PMU_CPU0,
  33. IRQ_EB11MP_PMU_CPU1,
  34. IRQ_EB11MP_PMU_CPU2,
  35. IRQ_EB11MP_PMU_CPU3,
  36. #elif defined(CONFIG_ARCH_OMAP3)
  37. INT_34XX_BENCH_MPU_EMUL,
  38. #elif defined(CONFIG_ARCH_IOP32X)
  39. IRQ_IOP32X_CORE_PMU,
  40. #elif defined(CONFIG_ARCH_IOP33X)
  41. IRQ_IOP33X_CORE_PMU,
  42. #elif defined(CONFIG_ARCH_PXA)
  43. IRQ_PMU,
  44. #endif
  45. };
  46. static const struct pmu_irqs pmu_irqs = {
  47. .irqs = irqs,
  48. .num_irqs = ARRAY_SIZE(irqs),
  49. };
  50. static volatile long pmu_lock;
  51. const struct pmu_irqs *
  52. reserve_pmu(void)
  53. {
  54. return test_and_set_bit_lock(0, &pmu_lock) ? ERR_PTR(-EBUSY) :
  55. &pmu_irqs;
  56. }
  57. EXPORT_SYMBOL_GPL(reserve_pmu);
  58. int
  59. release_pmu(const struct pmu_irqs *irqs)
  60. {
  61. if (WARN_ON(irqs != &pmu_irqs))
  62. return -EINVAL;
  63. clear_bit_unlock(0, &pmu_lock);
  64. return 0;
  65. }
  66. EXPORT_SYMBOL_GPL(release_pmu);
  67. static int
  68. set_irq_affinity(int irq,
  69. unsigned int cpu)
  70. {
  71. #ifdef CONFIG_SMP
  72. int err = irq_set_affinity(irq, cpumask_of(cpu));
  73. if (err)
  74. pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
  75. irq, cpu);
  76. return err;
  77. #else
  78. return 0;
  79. #endif
  80. }
  81. int
  82. init_pmu(void)
  83. {
  84. int i, err = 0;
  85. for (i = 0; i < pmu_irqs.num_irqs; ++i) {
  86. err = set_irq_affinity(pmu_irqs.irqs[i], i);
  87. if (err)
  88. break;
  89. }
  90. return err;
  91. }
  92. EXPORT_SYMBOL_GPL(init_pmu);