vcpu_sbi_hsm.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2021 Western Digital Corporation or its affiliates.
  4. *
  5. * Authors:
  6. * Atish Patra <atish.patra@wdc.com>
  7. */
  8. #include <linux/errno.h>
  9. #include <linux/err.h>
  10. #include <linux/kvm_host.h>
  11. #include <linux/wordpart.h>
  12. #include <asm/sbi.h>
  13. #include <asm/kvm_vcpu_sbi.h>
  14. static int kvm_sbi_hsm_vcpu_start(struct kvm_vcpu *vcpu)
  15. {
  16. struct kvm_cpu_context *reset_cntx;
  17. struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
  18. struct kvm_vcpu *target_vcpu;
  19. unsigned long target_vcpuid = cp->a0;
  20. int ret = 0;
  21. target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, target_vcpuid);
  22. if (!target_vcpu)
  23. return SBI_ERR_INVALID_PARAM;
  24. spin_lock(&target_vcpu->arch.mp_state_lock);
  25. if (!kvm_riscv_vcpu_stopped(target_vcpu)) {
  26. ret = SBI_ERR_ALREADY_AVAILABLE;
  27. goto out;
  28. }
  29. spin_lock(&target_vcpu->arch.reset_cntx_lock);
  30. reset_cntx = &target_vcpu->arch.guest_reset_context;
  31. /* start address */
  32. reset_cntx->sepc = cp->a1;
  33. /* target vcpu id to start */
  34. reset_cntx->a0 = target_vcpuid;
  35. /* private data passed from kernel */
  36. reset_cntx->a1 = cp->a2;
  37. spin_unlock(&target_vcpu->arch.reset_cntx_lock);
  38. kvm_make_request(KVM_REQ_VCPU_RESET, target_vcpu);
  39. __kvm_riscv_vcpu_power_on(target_vcpu);
  40. out:
  41. spin_unlock(&target_vcpu->arch.mp_state_lock);
  42. return ret;
  43. }
  44. static int kvm_sbi_hsm_vcpu_stop(struct kvm_vcpu *vcpu)
  45. {
  46. int ret = 0;
  47. spin_lock(&vcpu->arch.mp_state_lock);
  48. if (kvm_riscv_vcpu_stopped(vcpu)) {
  49. ret = SBI_ERR_FAILURE;
  50. goto out;
  51. }
  52. __kvm_riscv_vcpu_power_off(vcpu);
  53. out:
  54. spin_unlock(&vcpu->arch.mp_state_lock);
  55. return ret;
  56. }
  57. static int kvm_sbi_hsm_vcpu_get_status(struct kvm_vcpu *vcpu)
  58. {
  59. struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
  60. unsigned long target_vcpuid = cp->a0;
  61. struct kvm_vcpu *target_vcpu;
  62. target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, target_vcpuid);
  63. if (!target_vcpu)
  64. return SBI_ERR_INVALID_PARAM;
  65. if (kvm_riscv_vcpu_stopped(target_vcpu))
  66. return SBI_HSM_STATE_STOPPED;
  67. else if (target_vcpu->stat.generic.blocking)
  68. return SBI_HSM_STATE_SUSPENDED;
  69. else
  70. return SBI_HSM_STATE_STARTED;
  71. }
  72. static int kvm_sbi_ext_hsm_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
  73. struct kvm_vcpu_sbi_return *retdata)
  74. {
  75. int ret = 0;
  76. struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
  77. unsigned long funcid = cp->a6;
  78. switch (funcid) {
  79. case SBI_EXT_HSM_HART_START:
  80. ret = kvm_sbi_hsm_vcpu_start(vcpu);
  81. break;
  82. case SBI_EXT_HSM_HART_STOP:
  83. ret = kvm_sbi_hsm_vcpu_stop(vcpu);
  84. break;
  85. case SBI_EXT_HSM_HART_STATUS:
  86. ret = kvm_sbi_hsm_vcpu_get_status(vcpu);
  87. if (ret >= 0) {
  88. retdata->out_val = ret;
  89. retdata->err_val = 0;
  90. }
  91. return 0;
  92. case SBI_EXT_HSM_HART_SUSPEND:
  93. switch (lower_32_bits(cp->a0)) {
  94. case SBI_HSM_SUSPEND_RET_DEFAULT:
  95. kvm_riscv_vcpu_wfi(vcpu);
  96. break;
  97. case SBI_HSM_SUSPEND_NON_RET_DEFAULT:
  98. ret = SBI_ERR_NOT_SUPPORTED;
  99. break;
  100. default:
  101. ret = SBI_ERR_INVALID_PARAM;
  102. }
  103. break;
  104. default:
  105. ret = SBI_ERR_NOT_SUPPORTED;
  106. }
  107. retdata->err_val = ret;
  108. return 0;
  109. }
  110. const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm = {
  111. .extid_start = SBI_EXT_HSM,
  112. .extid_end = SBI_EXT_HSM,
  113. .handler = kvm_sbi_ext_hsm_handler,
  114. };