14
14
#include "test_util.h"
15
15
#include "processor.h"
16
16
#include "sbi.h"
17
+ #include "arch_timer.h"
17
18
18
19
/* Maximum counters(firmware + hardware) */
19
20
#define RISCV_MAX_PMU_COUNTERS 64
@@ -24,6 +25,9 @@ union sbi_pmu_ctr_info ctrinfo_arr[RISCV_MAX_PMU_COUNTERS];
24
25
static void * snapshot_gva ;
25
26
static vm_paddr_t snapshot_gpa ;
26
27
28
+ static int vcpu_shared_irq_count ;
29
+ static int counter_in_use ;
30
+
27
31
/* Cache the available counters in a bitmask */
28
32
static unsigned long counter_mask_available ;
29
33
@@ -120,6 +124,31 @@ static void guest_illegal_exception_handler(struct ex_regs *regs)
120
124
regs -> epc += 4 ;
121
125
}
122
126
127
+ static void guest_irq_handler (struct ex_regs * regs )
128
+ {
129
+ unsigned int irq_num = regs -> cause & ~CAUSE_IRQ_FLAG ;
130
+ struct riscv_pmu_snapshot_data * snapshot_data = snapshot_gva ;
131
+ unsigned long overflown_mask ;
132
+ unsigned long counter_val = 0 ;
133
+
134
+ /* Validate that we are in the correct irq handler */
135
+ GUEST_ASSERT_EQ (irq_num , IRQ_PMU_OVF );
136
+
137
+ /* Stop all counters first to avoid further interrupts */
138
+ stop_counter (counter_in_use , SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT );
139
+
140
+ csr_clear (CSR_SIP , BIT (IRQ_PMU_OVF ));
141
+
142
+ overflown_mask = READ_ONCE (snapshot_data -> ctr_overflow_mask );
143
+ GUEST_ASSERT (overflown_mask & 0x01 );
144
+
145
+ WRITE_ONCE (vcpu_shared_irq_count , vcpu_shared_irq_count + 1 );
146
+
147
+ counter_val = READ_ONCE (snapshot_data -> ctr_values [0 ]);
148
+ /* Now start the counter to mimick the real driver behavior */
149
+ start_counter (counter_in_use , SBI_PMU_START_FLAG_SET_INIT_VALUE , counter_val );
150
+ }
151
+
123
152
static unsigned long get_counter_index (unsigned long cbase , unsigned long cmask ,
124
153
unsigned long cflags ,
125
154
unsigned long event )
@@ -318,6 +347,33 @@ static void test_pmu_event_snapshot(unsigned long event)
318
347
stop_reset_counter (counter , 0 );
319
348
}
320
349
350
+ static void test_pmu_event_overflow (unsigned long event )
351
+ {
352
+ unsigned long counter ;
353
+ unsigned long counter_value_post ;
354
+ unsigned long counter_init_value = ULONG_MAX - 10000 ;
355
+ struct riscv_pmu_snapshot_data * snapshot_data = snapshot_gva ;
356
+
357
+ counter = get_counter_index (0 , counter_mask_available , 0 , event );
358
+ counter_in_use = counter ;
359
+
360
+ /* The counter value is updated w.r.t relative index of cbase passed to start/stop */
361
+ WRITE_ONCE (snapshot_data -> ctr_values [0 ], counter_init_value );
362
+ start_counter (counter , SBI_PMU_START_FLAG_INIT_SNAPSHOT , 0 );
363
+ dummy_func_loop (10000 );
364
+ udelay (msecs_to_usecs (2000 ));
365
+ /* irq handler should have stopped the counter */
366
+ stop_counter (counter , SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT );
367
+
368
+ counter_value_post = READ_ONCE (snapshot_data -> ctr_values [0 ]);
369
+ /* The counter value after stopping should be less the init value due to overflow */
370
+ __GUEST_ASSERT (counter_value_post < counter_init_value ,
371
+ "counter_value_post %lx counter_init_value %lx for counter\n" ,
372
+ counter_value_post , counter_init_value );
373
+
374
+ stop_reset_counter (counter , 0 );
375
+ }
376
+
321
377
static void test_invalid_event (void )
322
378
{
323
379
struct sbiret ret ;
@@ -413,6 +469,34 @@ static void test_pmu_events_snaphost(void)
413
469
GUEST_DONE ();
414
470
}
415
471
472
+ static void test_pmu_events_overflow (void )
473
+ {
474
+ int num_counters = 0 ;
475
+
476
+ /* Verify presence of SBI PMU and minimum requrired SBI version */
477
+ verify_sbi_requirement_assert ();
478
+
479
+ snapshot_set_shmem (snapshot_gpa , 0 );
480
+ csr_set (CSR_IE , BIT (IRQ_PMU_OVF ));
481
+ local_irq_enable ();
482
+
483
+ /* Get the counter details */
484
+ num_counters = get_num_counters ();
485
+ update_counter_info (num_counters );
486
+
487
+ /*
488
+ * Qemu supports overflow for cycle/instruction.
489
+ * This test may fail on any platform that do not support overflow for these two events.
490
+ */
491
+ test_pmu_event_overflow (SBI_PMU_HW_CPU_CYCLES );
492
+ GUEST_ASSERT_EQ (vcpu_shared_irq_count , 1 );
493
+
494
+ test_pmu_event_overflow (SBI_PMU_HW_INSTRUCTIONS );
495
+ GUEST_ASSERT_EQ (vcpu_shared_irq_count , 2 );
496
+
497
+ GUEST_DONE ();
498
+ }
499
+
416
500
static void run_vcpu (struct kvm_vcpu * vcpu )
417
501
{
418
502
struct ucall uc ;
@@ -498,6 +582,32 @@ static void test_vm_events_snapshot_test(void *guest_code)
498
582
test_vm_destroy (vm );
499
583
}
500
584
585
+ static void test_vm_events_overflow (void * guest_code )
586
+ {
587
+ struct kvm_vm * vm = NULL ;
588
+ struct kvm_vcpu * vcpu ;
589
+
590
+ vm = vm_create_with_one_vcpu (& vcpu , guest_code );
591
+ __TEST_REQUIRE (__vcpu_has_sbi_ext (vcpu , KVM_RISCV_SBI_EXT_PMU ),
592
+ "SBI PMU not available, skipping test" );
593
+
594
+ __TEST_REQUIRE (__vcpu_has_isa_ext (vcpu , KVM_RISCV_ISA_EXT_SSCOFPMF ),
595
+ "Sscofpmf is not available, skipping overflow test" );
596
+
597
+ test_vm_setup_snapshot_mem (vm , vcpu );
598
+ vm_init_vector_tables (vm );
599
+ vm_install_interrupt_handler (vm , guest_irq_handler );
600
+
601
+ vcpu_init_vector_tables (vcpu );
602
+ /* Initialize guest timer frequency. */
603
+ vcpu_get_reg (vcpu , RISCV_TIMER_REG (frequency ), & timer_freq );
604
+ sync_global_to_guest (vm , timer_freq );
605
+
606
+ run_vcpu (vcpu );
607
+
608
+ test_vm_destroy (vm );
609
+ }
610
+
501
611
int main (void )
502
612
{
503
613
test_vm_basic_test (test_pmu_basic_sanity );
@@ -509,5 +619,8 @@ int main(void)
509
619
test_vm_events_snapshot_test (test_pmu_events_snaphost );
510
620
pr_info ("SBI PMU event verification with snapshot test : PASS\n" );
511
621
622
+ test_vm_events_overflow (test_pmu_events_overflow );
623
+ pr_info ("SBI PMU event verification with overflow test : PASS\n" );
624
+
512
625
return 0 ;
513
626
}
0 commit comments