hwprobe.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright 2023 Rivos, Inc
  4. */
  5. #include <linux/string.h>
  6. #include <linux/types.h>
  7. #include <vdso/datapage.h>
  8. #include <vdso/helpers.h>
  9. extern int riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
  10. size_t cpusetsize, unsigned long *cpus,
  11. unsigned int flags);
  12. static int riscv_vdso_get_values(struct riscv_hwprobe *pairs, size_t pair_count,
  13. size_t cpusetsize, unsigned long *cpus,
  14. unsigned int flags)
  15. {
  16. const struct vdso_data *vd = __arch_get_vdso_data();
  17. const struct arch_vdso_data *avd = &vd->arch_data;
  18. bool all_cpus = !cpusetsize && !cpus;
  19. struct riscv_hwprobe *p = pairs;
  20. struct riscv_hwprobe *end = pairs + pair_count;
  21. /*
  22. * Defer to the syscall for exotic requests. The vdso has answers
  23. * stashed away only for the "all cpus" case. If all CPUs are
  24. * homogeneous, then this function can handle requests for arbitrary
  25. * masks.
  26. */
  27. if ((flags != 0) || (!all_cpus && !avd->homogeneous_cpus))
  28. return riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags);
  29. /* This is something we can handle, fill out the pairs. */
  30. while (p < end) {
  31. if (riscv_hwprobe_key_is_valid(p->key)) {
  32. p->value = avd->all_cpu_hwprobe_values[p->key];
  33. } else {
  34. p->key = -1;
  35. p->value = 0;
  36. }
  37. p++;
  38. }
  39. return 0;
  40. }
  41. static int riscv_vdso_get_cpus(struct riscv_hwprobe *pairs, size_t pair_count,
  42. size_t cpusetsize, unsigned long *cpus,
  43. unsigned int flags)
  44. {
  45. const struct vdso_data *vd = __arch_get_vdso_data();
  46. const struct arch_vdso_data *avd = &vd->arch_data;
  47. struct riscv_hwprobe *p = pairs;
  48. struct riscv_hwprobe *end = pairs + pair_count;
  49. unsigned char *c = (unsigned char *)cpus;
  50. bool empty_cpus = true;
  51. bool clear_all = false;
  52. int i;
  53. if (!cpusetsize || !cpus)
  54. return -EINVAL;
  55. for (i = 0; i < cpusetsize; i++) {
  56. if (c[i]) {
  57. empty_cpus = false;
  58. break;
  59. }
  60. }
  61. if (empty_cpus || flags != RISCV_HWPROBE_WHICH_CPUS || !avd->homogeneous_cpus)
  62. return riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags);
  63. while (p < end) {
  64. if (riscv_hwprobe_key_is_valid(p->key)) {
  65. struct riscv_hwprobe t = {
  66. .key = p->key,
  67. .value = avd->all_cpu_hwprobe_values[p->key],
  68. };
  69. if (!riscv_hwprobe_pair_cmp(&t, p))
  70. clear_all = true;
  71. } else {
  72. clear_all = true;
  73. p->key = -1;
  74. p->value = 0;
  75. }
  76. p++;
  77. }
  78. if (clear_all) {
  79. for (i = 0; i < cpusetsize; i++)
  80. c[i] = 0;
  81. }
  82. return 0;
  83. }
  84. /* Add a prototype to avoid -Wmissing-prototypes warning. */
  85. int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
  86. size_t cpusetsize, unsigned long *cpus,
  87. unsigned int flags);
  88. int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
  89. size_t cpusetsize, unsigned long *cpus,
  90. unsigned int flags)
  91. {
  92. if (flags & RISCV_HWPROBE_WHICH_CPUS)
  93. return riscv_vdso_get_cpus(pairs, pair_count, cpusetsize,
  94. cpus, flags);
  95. return riscv_vdso_get_values(pairs, pair_count, cpusetsize,
  96. cpus, flags);
  97. }