@@ -44,11 +44,6 @@ static uint64_t get_pmcr_n(uint64_t pmcr)
4444 return FIELD_GET (ARMV8_PMU_PMCR_N , pmcr );
4545}
4646
47- static void set_pmcr_n (uint64_t * pmcr , uint64_t pmcr_n )
48- {
49- u64p_replace_bits ((__u64 * ) pmcr , pmcr_n , ARMV8_PMU_PMCR_N );
50- }
51-
5247static uint64_t get_counters_mask (uint64_t n )
5348{
5449 uint64_t mask = BIT (ARMV8_PMU_CYCLE_IDX );
@@ -414,10 +409,6 @@ static void create_vpmu_vm(void *guest_code)
414409 .attr = KVM_ARM_VCPU_PMU_V3_IRQ ,
415410 .addr = (uint64_t )& irq ,
416411 };
417- struct kvm_device_attr init_attr = {
418- .group = KVM_ARM_VCPU_PMU_V3_CTRL ,
419- .attr = KVM_ARM_VCPU_PMU_V3_INIT ,
420- };
421412
422413 /* The test creates the vpmu_vm multiple times. Ensure a clean state */
423414 memset (& vpmu_vm , 0 , sizeof (vpmu_vm ));
@@ -444,9 +435,7 @@ static void create_vpmu_vm(void *guest_code)
444435 pmuver >= ID_AA64DFR0_EL1_PMUVer_IMP ,
445436 "Unexpected PMUVER (0x%x) on the vCPU with PMUv3" , pmuver );
446437
447- /* Initialize vPMU */
448438 vcpu_ioctl (vpmu_vm .vcpu , KVM_SET_DEVICE_ATTR , & irq_attr );
449- vcpu_ioctl (vpmu_vm .vcpu , KVM_SET_DEVICE_ATTR , & init_attr );
450439}
451440
452441static void destroy_vpmu_vm (void )
@@ -472,33 +461,28 @@ static void run_vcpu(struct kvm_vcpu *vcpu, uint64_t pmcr_n)
472461 }
473462}
474463
475- static void test_create_vpmu_vm_with_pmcr_n ( uint64_t pmcr_n , bool expect_fail )
464+ static void test_create_vpmu_vm_with_nr_counters ( unsigned int nr_counters , bool expect_fail )
476465{
477466 struct kvm_vcpu * vcpu ;
478- uint64_t pmcr , pmcr_orig ;
467+ unsigned int prev ;
468+ int ret ;
479469
480470 create_vpmu_vm (guest_code );
481471 vcpu = vpmu_vm .vcpu ;
482472
483- pmcr_orig = vcpu_get_reg (vcpu , KVM_ARM64_SYS_REG (SYS_PMCR_EL0 ));
484- pmcr = pmcr_orig ;
473+ prev = get_pmcr_n (vcpu_get_reg (vcpu , KVM_ARM64_SYS_REG (SYS_PMCR_EL0 )));
485474
486- /*
487- * Setting a larger value of PMCR.N should not modify the field, and
488- * return a success.
489- */
490- set_pmcr_n (& pmcr , pmcr_n );
491- vcpu_set_reg (vcpu , KVM_ARM64_SYS_REG (SYS_PMCR_EL0 ), pmcr );
492- pmcr = vcpu_get_reg (vcpu , KVM_ARM64_SYS_REG (SYS_PMCR_EL0 ));
475+ ret = __vcpu_device_attr_set (vcpu , KVM_ARM_VCPU_PMU_V3_CTRL ,
476+ KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS , & nr_counters );
493477
494478 if (expect_fail )
495- TEST_ASSERT (pmcr_orig == pmcr ,
496- "PMCR.N modified by KVM to a larger value (PMCR: 0x%lx) for pmcr_n: 0x%lx " ,
497- pmcr , pmcr_n );
479+ TEST_ASSERT (ret && errno == EINVAL ,
480+ "Setting more PMU counters (%u) than available (%u) unexpectedly succeeded " ,
481+ nr_counters , prev );
498482 else
499- TEST_ASSERT (pmcr_n == get_pmcr_n ( pmcr ),
500- "Failed to update PMCR.N to %lu (received: %lu)" ,
501- pmcr_n , get_pmcr_n ( pmcr ) );
483+ TEST_ASSERT (! ret , KVM_IOCTL_ERROR ( KVM_SET_DEVICE_ATTR , ret ));
484+
485+ vcpu_device_attr_set ( vcpu , KVM_ARM_VCPU_PMU_V3_CTRL , KVM_ARM_VCPU_PMU_V3_INIT , NULL );
502486}
503487
504488/*
@@ -513,7 +497,7 @@ static void run_access_test(uint64_t pmcr_n)
513497
514498 pr_debug ("Test with pmcr_n %lu\n" , pmcr_n );
515499
516- test_create_vpmu_vm_with_pmcr_n (pmcr_n , false);
500+ test_create_vpmu_vm_with_nr_counters (pmcr_n , false);
517501 vcpu = vpmu_vm .vcpu ;
518502
519503 /* Save the initial sp to restore them later to run the guest again */
@@ -554,7 +538,7 @@ static void run_pmregs_validity_test(uint64_t pmcr_n)
554538 uint64_t set_reg_id , clr_reg_id , reg_val ;
555539 uint64_t valid_counters_mask , max_counters_mask ;
556540
557- test_create_vpmu_vm_with_pmcr_n (pmcr_n , false);
541+ test_create_vpmu_vm_with_nr_counters (pmcr_n , false);
558542 vcpu = vpmu_vm .vcpu ;
559543
560544 valid_counters_mask = get_counters_mask (pmcr_n );
@@ -608,7 +592,7 @@ static void run_error_test(uint64_t pmcr_n)
608592{
609593 pr_debug ("Error test with pmcr_n %lu (larger than the host)\n" , pmcr_n );
610594
611- test_create_vpmu_vm_with_pmcr_n (pmcr_n , true);
595+ test_create_vpmu_vm_with_nr_counters (pmcr_n , true);
612596 destroy_vpmu_vm ();
613597}
614598
@@ -626,12 +610,25 @@ static uint64_t get_pmcr_n_limit(void)
626610 return get_pmcr_n (pmcr );
627611}
628612
613+ static bool kvm_supports_nr_counters_attr (void )
614+ {
615+ bool supported ;
616+
617+ create_vpmu_vm (NULL );
618+ supported = !__vcpu_has_device_attr (vpmu_vm .vcpu , KVM_ARM_VCPU_PMU_V3_CTRL ,
619+ KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS );
620+ destroy_vpmu_vm ();
621+
622+ return supported ;
623+ }
624+
629625int main (void )
630626{
631627 uint64_t i , pmcr_n ;
632628
633629 TEST_REQUIRE (kvm_has_cap (KVM_CAP_ARM_PMU_V3 ));
634630 TEST_REQUIRE (kvm_supports_vgic_v3 ());
631+ TEST_REQUIRE (kvm_supports_nr_counters_attr ());
635632
636633 pmcr_n = get_pmcr_n_limit ();
637634 for (i = 0 ; i <= pmcr_n ; i ++ ) {
0 commit comments