pmu.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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/platform_device.h>
  19. #include <asm/pmu.h>
  20. static volatile long pmu_lock;
  21. static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES];
  22. static int __devinit pmu_device_probe(struct platform_device *pdev)
  23. {
  24. if (pdev->id < 0 || pdev->id >= ARM_NUM_PMU_DEVICES) {
  25. pr_warning("received registration request for unknown "
  26. "device %d\n", pdev->id);
  27. return -EINVAL;
  28. }
  29. if (pmu_devices[pdev->id])
  30. pr_warning("registering new PMU device type %d overwrites "
  31. "previous registration!\n", pdev->id);
  32. else
  33. pr_info("registered new PMU device of type %d\n",
  34. pdev->id);
  35. pmu_devices[pdev->id] = pdev;
  36. return 0;
  37. }
  38. static struct platform_driver pmu_driver = {
  39. .driver = {
  40. .name = "arm-pmu",
  41. },
  42. .probe = pmu_device_probe,
  43. };
  44. static int __init register_pmu_driver(void)
  45. {
  46. return platform_driver_register(&pmu_driver);
  47. }
  48. device_initcall(register_pmu_driver);
  49. struct platform_device *
  50. reserve_pmu(enum arm_pmu_type device)
  51. {
  52. struct platform_device *pdev;
  53. if (test_and_set_bit_lock(device, &pmu_lock)) {
  54. pdev = ERR_PTR(-EBUSY);
  55. } else if (pmu_devices[device] == NULL) {
  56. clear_bit_unlock(device, &pmu_lock);
  57. pdev = ERR_PTR(-ENODEV);
  58. } else {
  59. pdev = pmu_devices[device];
  60. }
  61. return pdev;
  62. }
  63. EXPORT_SYMBOL_GPL(reserve_pmu);
  64. int
  65. release_pmu(struct platform_device *pdev)
  66. {
  67. if (WARN_ON(pdev != pmu_devices[pdev->id]))
  68. return -EINVAL;
  69. clear_bit_unlock(pdev->id, &pmu_lock);
  70. return 0;
  71. }
  72. EXPORT_SYMBOL_GPL(release_pmu);
  73. static int
  74. set_irq_affinity(int irq,
  75. unsigned int cpu)
  76. {
  77. #ifdef CONFIG_SMP
  78. int err = irq_set_affinity(irq, cpumask_of(cpu));
  79. if (err)
  80. pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
  81. irq, cpu);
  82. return err;
  83. #else
  84. return -EINVAL;
  85. #endif
  86. }
  87. static int
  88. init_cpu_pmu(void)
  89. {
  90. int i, irqs, err = 0;
  91. struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU];
  92. if (!pdev)
  93. return -ENODEV;
  94. irqs = pdev->num_resources;
  95. /*
  96. * If we have a single PMU interrupt that we can't shift, assume that
  97. * we're running on a uniprocessor machine and continue.
  98. */
  99. if (irqs == 1 && !irq_can_set_affinity(platform_get_irq(pdev, 0)))
  100. return 0;
  101. for (i = 0; i < irqs; ++i) {
  102. err = set_irq_affinity(platform_get_irq(pdev, i), i);
  103. if (err)
  104. break;
  105. }
  106. return err;
  107. }
  108. int
  109. init_pmu(enum arm_pmu_type device)
  110. {
  111. int err = 0;
  112. switch (device) {
  113. case ARM_PMU_DEVICE_CPU:
  114. err = init_cpu_pmu();
  115. break;
  116. default:
  117. pr_warning("attempt to initialise unknown device %d\n",
  118. device);
  119. err = -EINVAL;
  120. }
  121. return err;
  122. }
  123. EXPORT_SYMBOL_GPL(init_pmu);