Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions arch/riscv/include/asm/kvm_vcpu_pmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ void kvm_riscv_vcpu_pmu_init(struct kvm_vcpu *vcpu);
int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long saddr_low,
unsigned long saddr_high, unsigned long flags,
struct kvm_vcpu_sbi_return *retdata);
int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low,
unsigned long saddr_high, unsigned long num_events,
unsigned long flags, struct kvm_vcpu_sbi_return *retdata);
void kvm_riscv_vcpu_pmu_deinit(struct kvm_vcpu *vcpu);
void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu);

Expand Down
2 changes: 1 addition & 1 deletion arch/riscv/include/asm/kvm_vcpu_sbi.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

#define KVM_SBI_IMPID 3

#define KVM_SBI_VERSION_MAJOR 2
#define KVM_SBI_VERSION_MAJOR 3
#define KVM_SBI_VERSION_MINOR 0

enum kvm_riscv_sbi_ext_status {
Expand Down
15 changes: 15 additions & 0 deletions arch/riscv/include/asm/sbi.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ enum sbi_ext_pmu_fid {
SBI_EXT_PMU_COUNTER_FW_READ,
SBI_EXT_PMU_COUNTER_FW_READ_HI,
SBI_EXT_PMU_SNAPSHOT_SET_SHMEM,
SBI_EXT_PMU_EVENT_GET_INFO,
};

union sbi_pmu_ctr_info {
Expand All @@ -161,8 +162,21 @@ struct riscv_pmu_snapshot_data {
u64 reserved[447];
};

struct riscv_pmu_event_info {
u32 event_idx;
u32 output;
u64 event_data;
};

#define RISCV_PMU_EVENT_INFO_OUTPUT_MASK 0x01

#define RISCV_PMU_RAW_EVENT_MASK GENMASK_ULL(47, 0)
#define RISCV_PMU_PLAT_FW_EVENT_MASK GENMASK_ULL(61, 0)
/* SBI v3.0 allows extended hpmeventX width value */
#define RISCV_PMU_RAW_EVENT_V2_MASK GENMASK_ULL(55, 0)
#define RISCV_PMU_RAW_EVENT_IDX 0x20000
#define RISCV_PMU_RAW_EVENT_V2_IDX 0x30000
#define RISCV_PLAT_FW_EVENT 0xFFFF

/** General pmu event codes specified in SBI PMU extension */
enum sbi_pmu_hw_generic_events_t {
Expand Down Expand Up @@ -219,6 +233,7 @@ enum sbi_pmu_event_type {
SBI_PMU_EVENT_TYPE_HW = 0x0,
SBI_PMU_EVENT_TYPE_CACHE = 0x1,
SBI_PMU_EVENT_TYPE_RAW = 0x2,
SBI_PMU_EVENT_TYPE_RAW_V2 = 0x3,
SBI_PMU_EVENT_TYPE_FW = 0xf,
};

Expand Down
73 changes: 63 additions & 10 deletions arch/riscv/kvm/vcpu_pmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ static u32 kvm_pmu_get_perf_event_type(unsigned long eidx)
type = PERF_TYPE_HW_CACHE;
break;
case SBI_PMU_EVENT_TYPE_RAW:
case SBI_PMU_EVENT_TYPE_RAW_V2:
case SBI_PMU_EVENT_TYPE_FW:
type = PERF_TYPE_RAW;
break;
Expand Down Expand Up @@ -128,6 +129,9 @@ static u64 kvm_pmu_get_perf_event_config(unsigned long eidx, uint64_t evt_data)
case SBI_PMU_EVENT_TYPE_RAW:
config = evt_data & RISCV_PMU_RAW_EVENT_MASK;
break;
case SBI_PMU_EVENT_TYPE_RAW_V2:
config = evt_data & RISCV_PMU_RAW_EVENT_V2_MASK;
break;
case SBI_PMU_EVENT_TYPE_FW:
if (ecode < SBI_PMU_FW_MAX)
config = (1ULL << 63) | ecode;
Expand Down Expand Up @@ -327,7 +331,7 @@ static long kvm_pmu_create_perf_event(struct kvm_pmc *pmc, struct perf_event_att

event = perf_event_create_kernel_counter(attr, -1, current, kvm_riscv_pmu_overflow, pmc);
if (IS_ERR(event)) {
pr_err("kvm pmu event creation failed for eidx %lx: %ld\n", eidx, PTR_ERR(event));
pr_debug("kvm pmu event creation failed for eidx %lx: %ld\n", eidx, PTR_ERR(event));
return PTR_ERR(event);
}

Expand Down Expand Up @@ -415,8 +419,6 @@ int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long s
int snapshot_area_size = sizeof(struct riscv_pmu_snapshot_data);
int sbiret = 0;
gpa_t saddr;
unsigned long hva;
bool writable;

if (!kvpmu || flags) {
sbiret = SBI_ERR_INVALID_PARAM;
Expand All @@ -438,19 +440,14 @@ int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long s
goto out;
}

hva = kvm_vcpu_gfn_to_hva_prot(vcpu, saddr >> PAGE_SHIFT, &writable);
if (kvm_is_error_hva(hva) || !writable) {
sbiret = SBI_ERR_INVALID_ADDRESS;
goto out;
}

kvpmu->sdata = kzalloc(snapshot_area_size, GFP_ATOMIC);
if (!kvpmu->sdata)
return -ENOMEM;

/* No need to check writable slot explicitly as kvm_vcpu_write_guest does it internally */
if (kvm_vcpu_write_guest(vcpu, saddr, kvpmu->sdata, snapshot_area_size)) {
kfree(kvpmu->sdata);
sbiret = SBI_ERR_FAILURE;
sbiret = SBI_ERR_INVALID_ADDRESS;
goto out;
}

Expand All @@ -462,6 +459,62 @@ int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long s
return 0;
}

int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low,
unsigned long saddr_high, unsigned long num_events,
unsigned long flags, struct kvm_vcpu_sbi_return *retdata)
{
struct riscv_pmu_event_info *einfo = NULL;
int shmem_size = num_events * sizeof(*einfo);
gpa_t shmem;
u32 eidx, etype;
u64 econfig;
int ret;

if (flags != 0 || (saddr_low & (SZ_16 - 1) || num_events == 0)) {
ret = SBI_ERR_INVALID_PARAM;
goto out;
}

shmem = saddr_low;
if (saddr_high != 0) {
if (IS_ENABLED(CONFIG_32BIT)) {
shmem |= ((gpa_t)saddr_high << 32);
} else {
ret = SBI_ERR_INVALID_ADDRESS;
goto out;
}
}

einfo = kzalloc(shmem_size, GFP_KERNEL);
if (!einfo)
return -ENOMEM;

ret = kvm_vcpu_read_guest(vcpu, shmem, einfo, shmem_size);
if (ret) {
ret = SBI_ERR_FAILURE;
goto free_mem;
}

for (int i = 0; i < num_events; i++) {
eidx = einfo[i].event_idx;
etype = kvm_pmu_get_perf_event_type(eidx);
econfig = kvm_pmu_get_perf_event_config(eidx, einfo[i].event_data);
ret = riscv_pmu_get_event_info(etype, econfig, NULL);
einfo[i].output = (ret > 0) ? 1 : 0;
}

ret = kvm_vcpu_write_guest(vcpu, shmem, einfo, shmem_size);
if (ret)
ret = SBI_ERR_INVALID_ADDRESS;

free_mem:
kfree(einfo);
out:
retdata->err_val = ret;

return 0;
}

int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu,
struct kvm_vcpu_sbi_return *retdata)
{
Expand Down
3 changes: 3 additions & 0 deletions arch/riscv/kvm/vcpu_sbi_pmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ static int kvm_sbi_ext_pmu_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
case SBI_EXT_PMU_SNAPSHOT_SET_SHMEM:
ret = kvm_riscv_vcpu_pmu_snapshot_set_shmem(vcpu, cp->a0, cp->a1, cp->a2, retdata);
break;
case SBI_EXT_PMU_EVENT_GET_INFO:
ret = kvm_riscv_vcpu_pmu_event_info(vcpu, cp->a0, cp->a1, cp->a2, cp->a3, retdata);
break;
default:
retdata->err_val = SBI_ERR_NOT_SUPPORTED;
}
Expand Down
9 changes: 2 additions & 7 deletions arch/riscv/kvm/vcpu_sbi_sta.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ static int kvm_sbi_sta_steal_time_set_shmem(struct kvm_vcpu *vcpu)
unsigned long shmem_phys_hi = cp->a1;
u32 flags = cp->a2;
struct sbi_sta_struct zero_sta = {0};
unsigned long hva;
bool writable;
gpa_t shmem;
int ret;

Expand All @@ -107,13 +105,10 @@ static int kvm_sbi_sta_steal_time_set_shmem(struct kvm_vcpu *vcpu)
return SBI_ERR_INVALID_ADDRESS;
}

hva = kvm_vcpu_gfn_to_hva_prot(vcpu, shmem >> PAGE_SHIFT, &writable);
if (kvm_is_error_hva(hva) || !writable)
return SBI_ERR_INVALID_ADDRESS;

/* No need to check writable slot explicitly as kvm_vcpu_write_guest does it internally */
ret = kvm_vcpu_write_guest(vcpu, shmem, &zero_sta, sizeof(zero_sta));
if (ret)
return SBI_ERR_FAILURE;
return SBI_ERR_INVALID_ADDRESS;

vcpu->arch.sta.shmem = shmem;
vcpu->arch.sta.last_steal = current->sched_info.run_delay;
Expand Down
4 changes: 2 additions & 2 deletions drivers/perf/riscv_pmu_legacy.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ static int pmu_legacy_ctr_get_idx(struct perf_event *event)
struct perf_event_attr *attr = &event->attr;

if (event->attr.type != PERF_TYPE_HARDWARE)
return -EOPNOTSUPP;
return -ENOENT;
if (attr->config == PERF_COUNT_HW_CPU_CYCLES)
return RISCV_PMU_LEGACY_CYCLE;
else if (attr->config == PERF_COUNT_HW_INSTRUCTIONS)
return RISCV_PMU_LEGACY_INSTRET;
else
return -EOPNOTSUPP;
return -ENOENT;
}

/* For legacy config & counter index are same */
Expand Down
Loading
Loading