pmu.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * linux/arch/arm/kernel/pmu.c
  3. *
  4. * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
  5. * Copyright (C) 2010 ARM Ltd, Will Deacon
  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 version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. */
  12. #define pr_fmt(fmt) "PMU: " fmt
  13. #include <linux/cpumask.h>
  14. #include <linux/err.h>
  15. #include <linux/interrupt.h>
  16. #include <linux/kernel.h>
  17. #include <linux/module.h>
  18. #include <linux/of_device.h>
  19. #include <linux/platform_device.h>
  20. #include <asm/pmu.h>
  21. static volatile long pmu_lock;
  22. static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES];
  23. static int __devinit pmu_register(struct platform_device *pdev,
  24. enum arm_pmu_type type)
  25. {
  26. if (type < 0 || type >= ARM_NUM_PMU_DEVICES) {
  27. pr_warning("received registration request for unknown "
  28. "device %d\n", type);
  29. return -EINVAL;
  30. }
  31. if (pmu_devices[type]) {
  32. pr_warning("rejecting duplicate registration of PMU device "
  33. "type %d.", type);
  34. return -ENOSPC;
  35. }
  36. pr_info("registered new PMU device of type %d\n", type);
  37. pmu_devices[type] = pdev;
  38. return 0;
  39. }
  40. #define OF_MATCH_PMU(_name, _type) { \
  41. .compatible = _name, \
  42. .data = (void *)_type, \
  43. }
  44. #define OF_MATCH_CPU(name) OF_MATCH_PMU(name, ARM_PMU_DEVICE_CPU)
  45. static struct of_device_id armpmu_of_device_ids[] = {
  46. OF_MATCH_CPU("arm,cortex-a9-pmu"),
  47. OF_MATCH_CPU("arm,cortex-a8-pmu"),
  48. OF_MATCH_CPU("arm,arm1136-pmu"),
  49. OF_MATCH_CPU("arm,arm1176-pmu"),
  50. {},
  51. };
  52. #define PLAT_MATCH_PMU(_name, _type) { \
  53. .name = _name, \
  54. .driver_data = _type, \
  55. }
  56. #define PLAT_MATCH_CPU(_name) PLAT_MATCH_PMU(_name, ARM_PMU_DEVICE_CPU)
  57. static struct platform_device_id armpmu_plat_device_ids[] = {
  58. PLAT_MATCH_CPU("arm-pmu"),
  59. {},
  60. };
  61. enum arm_pmu_type armpmu_device_type(struct platform_device *pdev)
  62. {
  63. const struct of_device_id *of_id;
  64. const struct platform_device_id *pdev_id;
  65. /* provided by of_device_id table */
  66. if (pdev->dev.of_node) {
  67. of_id = of_match_device(armpmu_of_device_ids, &pdev->dev);
  68. BUG_ON(!of_id);
  69. return (enum arm_pmu_type)of_id->data;
  70. }
  71. /* Provided by platform_device_id table */
  72. pdev_id = platform_get_device_id(pdev);
  73. BUG_ON(!pdev_id);
  74. return pdev_id->driver_data;
  75. }
  76. static int __devinit armpmu_device_probe(struct platform_device *pdev)
  77. {
  78. return pmu_register(pdev, armpmu_device_type(pdev));
  79. }
  80. static struct platform_driver armpmu_driver = {
  81. .driver = {
  82. .name = "arm-pmu",
  83. .of_match_table = armpmu_of_device_ids,
  84. },
  85. .probe = armpmu_device_probe,
  86. .id_table = armpmu_plat_device_ids,
  87. };
  88. static int __init register_pmu_driver(void)
  89. {
  90. return platform_driver_register(&armpmu_driver);
  91. }
  92. device_initcall(register_pmu_driver);
  93. struct platform_device *
  94. reserve_pmu(enum arm_pmu_type device)
  95. {
  96. struct platform_device *pdev;
  97. if (test_and_set_bit_lock(device, &pmu_lock)) {
  98. pdev = ERR_PTR(-EBUSY);
  99. } else if (pmu_devices[device] == NULL) {
  100. clear_bit_unlock(device, &pmu_lock);
  101. pdev = ERR_PTR(-ENODEV);
  102. } else {
  103. pdev = pmu_devices[device];
  104. }
  105. return pdev;
  106. }
  107. EXPORT_SYMBOL_GPL(reserve_pmu);
  108. int
  109. release_pmu(enum arm_pmu_type device)
  110. {
  111. if (WARN_ON(!pmu_devices[device]))
  112. return -EINVAL;
  113. clear_bit_unlock(device, &pmu_lock);
  114. return 0;
  115. }
  116. EXPORT_SYMBOL_GPL(release_pmu);
  117. static int
  118. set_irq_affinity(int irq,
  119. unsigned int cpu)
  120. {
  121. #ifdef CONFIG_SMP
  122. int err = irq_set_affinity(irq, cpumask_of(cpu));
  123. if (err)
  124. pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
  125. irq, cpu);
  126. return err;
  127. #else
  128. return -EINVAL;
  129. #endif
  130. }
  131. static int
  132. init_cpu_pmu(void)
  133. {
  134. int i, irqs, err = 0;
  135. struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU];
  136. if (!pdev)
  137. return -ENODEV;
  138. irqs = pdev->num_resources;
  139. /*
  140. * If we have a single PMU interrupt that we can't shift, assume that
  141. * we're running on a uniprocessor machine and continue.
  142. */
  143. if (irqs == 1 && !irq_can_set_affinity(platform_get_irq(pdev, 0)))
  144. return 0;
  145. for (i = 0; i < irqs; ++i) {
  146. err = set_irq_affinity(platform_get_irq(pdev, i), i);
  147. if (err)
  148. break;
  149. }
  150. return err;
  151. }
  152. int
  153. init_pmu(enum arm_pmu_type device)
  154. {
  155. int err = 0;
  156. switch (device) {
  157. case ARM_PMU_DEVICE_CPU:
  158. err = init_cpu_pmu();
  159. break;
  160. default:
  161. pr_warning("attempt to initialise unknown device %d\n",
  162. device);
  163. err = -EINVAL;
  164. }
  165. return err;
  166. }
  167. EXPORT_SYMBOL_GPL(init_pmu);