vcpu_sbi_pmu.c 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2023 Rivos Inc
  4. *
  5. * Authors:
  6. * Atish Patra <atishp@rivosinc.com>
  7. */
  8. #include <linux/errno.h>
  9. #include <linux/err.h>
  10. #include <linux/kvm_host.h>
  11. #include <asm/csr.h>
  12. #include <asm/sbi.h>
  13. #include <asm/kvm_vcpu_sbi.h>
  14. static int kvm_sbi_ext_pmu_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
  15. struct kvm_vcpu_sbi_return *retdata)
  16. {
  17. int ret = 0;
  18. struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
  19. struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu);
  20. unsigned long funcid = cp->a6;
  21. u64 temp;
  22. if (!kvpmu->init_done) {
  23. retdata->err_val = SBI_ERR_NOT_SUPPORTED;
  24. return 0;
  25. }
  26. switch (funcid) {
  27. case SBI_EXT_PMU_NUM_COUNTERS:
  28. ret = kvm_riscv_vcpu_pmu_num_ctrs(vcpu, retdata);
  29. break;
  30. case SBI_EXT_PMU_COUNTER_GET_INFO:
  31. ret = kvm_riscv_vcpu_pmu_ctr_info(vcpu, cp->a0, retdata);
  32. break;
  33. case SBI_EXT_PMU_COUNTER_CFG_MATCH:
  34. #if defined(CONFIG_32BIT)
  35. temp = ((uint64_t)cp->a5 << 32) | cp->a4;
  36. #else
  37. temp = cp->a4;
  38. #endif
  39. /*
  40. * This can fail if perf core framework fails to create an event.
  41. * No need to forward the error to userspace and exit the guest.
  42. * The operation can continue without profiling. Forward the
  43. * appropriate SBI error to the guest.
  44. */
  45. ret = kvm_riscv_vcpu_pmu_ctr_cfg_match(vcpu, cp->a0, cp->a1,
  46. cp->a2, cp->a3, temp, retdata);
  47. break;
  48. case SBI_EXT_PMU_COUNTER_START:
  49. #if defined(CONFIG_32BIT)
  50. temp = ((uint64_t)cp->a4 << 32) | cp->a3;
  51. #else
  52. temp = cp->a3;
  53. #endif
  54. ret = kvm_riscv_vcpu_pmu_ctr_start(vcpu, cp->a0, cp->a1, cp->a2,
  55. temp, retdata);
  56. break;
  57. case SBI_EXT_PMU_COUNTER_STOP:
  58. ret = kvm_riscv_vcpu_pmu_ctr_stop(vcpu, cp->a0, cp->a1, cp->a2, retdata);
  59. break;
  60. case SBI_EXT_PMU_COUNTER_FW_READ:
  61. ret = kvm_riscv_vcpu_pmu_fw_ctr_read(vcpu, cp->a0, retdata);
  62. break;
  63. case SBI_EXT_PMU_COUNTER_FW_READ_HI:
  64. if (IS_ENABLED(CONFIG_32BIT))
  65. ret = kvm_riscv_vcpu_pmu_fw_ctr_read_hi(vcpu, cp->a0, retdata);
  66. else
  67. retdata->out_val = 0;
  68. break;
  69. case SBI_EXT_PMU_SNAPSHOT_SET_SHMEM:
  70. ret = kvm_riscv_vcpu_pmu_snapshot_set_shmem(vcpu, cp->a0, cp->a1, cp->a2, retdata);
  71. break;
  72. default:
  73. retdata->err_val = SBI_ERR_NOT_SUPPORTED;
  74. }
  75. return ret;
  76. }
  77. static unsigned long kvm_sbi_ext_pmu_probe(struct kvm_vcpu *vcpu)
  78. {
  79. struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu);
  80. return kvpmu->init_done;
  81. }
  82. const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu = {
  83. .extid_start = SBI_EXT_PMU,
  84. .extid_end = SBI_EXT_PMU,
  85. .handler = kvm_sbi_ext_pmu_handler,
  86. .probe = kvm_sbi_ext_pmu_probe,
  87. };