[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [kvm-unit-tests RFC 4/4] spe: Test Profiling Buffer Events
From: |
Auger Eric |
Subject: |
Re: [kvm-unit-tests RFC 4/4] spe: Test Profiling Buffer Events |
Date: |
Tue, 1 Sep 2020 09:34:02 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.5.0 |
Hi,
On 8/31/20 9:34 PM, Eric Auger wrote:
> Setup the infrastructure to check the occurence of events.
> The test checks the Buffer Full event occurs when no space
> is available. The PPI is handled and we check the syndrome register
> against the expected event.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> ---
> arm/spe.c | 141 +++++++++++++++++++++++++++++++++++++++++++++-
> arm/unittests.cfg | 8 +++
> 2 files changed, 148 insertions(+), 1 deletion(-)
>
> diff --git a/arm/spe.c b/arm/spe.c
> index 7996f79..2f5ee35 100644
> --- a/arm/spe.c
> +++ b/arm/spe.c
> @@ -19,6 +19,7 @@
> #include "alloc_page.h"
> #include <bitops.h>
> #include "alloc.h"
> +#include <asm/gic.h>
>
> struct spe {
> int min_interval;
> @@ -36,13 +37,37 @@ struct spe {
> bool unique_record_size;
> };
>
> +enum spe_event_exception_class {
> + EC_STAGE1_DATA_ABORT = 0x24,
> + EC_STAGE2_DATA_ABORT = 0x25,
> + EC_OTHER = 0,
> +};
> +
> +struct spe_event {
> + enum spe_event_exception_class ec;
> + bool dl; /* data lost */
> + bool ea; /* external abort */
> + bool s; /* service */
> + bool coll; /* collision */
> + union {
> + bool buffer_filled; /* ec = other */
> + } mss;
> +};
> +
> static struct spe spe;
>
> +struct spe_stats {
> + struct spe_event observed;
> + bool unexpected;
> +};
> +static struct spe_stats spe_stats;
> +
> #ifdef __arm__
>
> static bool spe_probe(void) { return false; }
> static void test_spe_introspection(void) { }
> static void test_spe_buffer(void) { }
> +static void test_spe_events(void) { }
>
> #else
>
> @@ -95,6 +120,16 @@ static void test_spe_buffer(void) { }
> #define PMSCR_EL1_TS 0x20
> #define PMSCR_EL1_PCT 0x40
>
> +#define PMBSR_EL1_COLL 0x10000
> +#define PMBSR_EL1_S 0x20000
> +#define PMBSR_EL1_EA 0x40000
> +#define PMBSR_EL1_DL 0x80000
> +#define PMBSR_EL1_EC_SHIFT 26
> +#define PMBSR_EL1_EC_MASK 0x3F
> +#define PMBSR_EL1_MISS_MASK 0xFFFF
> +
> +#define SPE_PPI 21
> +
> static int min_interval(uint8_t idr_bits)
> {
> switch (idr_bits) {
> @@ -119,6 +154,44 @@ static int min_interval(uint8_t idr_bits)
> }
> }
>
> +static int decode_syndrome_register(uint64_t sr, struct spe_event *event,
> bool verbose)
> +{
> + if (!sr)
> + return 0;
> +
> + if (sr & PMBSR_EL1_S)
> + event->s = true;
> + if (sr & PMBSR_EL1_COLL)
> + event->coll = true;
> + if (sr & PMBSR_EL1_EA)
> + event->ea = true;
> + if (sr & PMBSR_EL1_DL)
> + event->dl = true;
> + if (verbose)
> + report_info("PMBSR_EL1: Service=%d Collision=%d External
> Fault=%d DataLost=%d",
> + event->s, event->coll, event->ea, event->dl);
> +
> + switch ((sr >> PMBSR_EL1_EC_SHIFT) & PMBSR_EL1_EC_MASK) {
> + case EC_OTHER:
> + event->ec = EC_OTHER;
> + event->mss.buffer_filled = sr & 0x1;
> + if (verbose)
> + report_info("PMBSR_EL1: EC = OTHER buffer filled=%d",
> event->mss.buffer_filled);
> + break;
> + case EC_STAGE1_DATA_ABORT:
> + event->ec = EC_STAGE1_DATA_ABORT;
> + report_info("PMBSR_EL1: EC = stage 1 data abort");
> + break;
> + case EC_STAGE2_DATA_ABORT:
> + event->ec = EC_STAGE2_DATA_ABORT;
> + report_info("PMBSR_EL1: EC = stage 2 data abort");
> + break;
> + default:
> + return -1;
> + }
> + return 0;
> +}
> +
> static bool spe_probe(void)
> {
> uint64_t pmbidr_el1, pmsidr_el1;
> @@ -224,6 +297,13 @@ static void reset(void)
>
> /* Make sure the syndrome register is void */
> write_sysreg_s(0, PMBSR_EL1);
> +
> + memset(&spe_stats, 0, sizeof(spe_stats));
> +}
> +
> +inline bool event_match(struct spe_event *observed, struct spe_event
> *expected)
> +{
> + return !memcmp(observed, expected, sizeof(struct spe_event));
> }
>
> static inline void drain(void)
> @@ -235,6 +315,7 @@ static inline void drain(void)
>
> static void test_spe_buffer(void)
> {
> + struct spe_event observed = {}, expected = {};
> uint64_t pmbsr_el1, val1, val2;
> void *addr = malloc(10 * PAGE_SIZE);
>
> @@ -290,7 +371,61 @@ static void test_spe_buffer(void)
> report_info("This corresponds to %ld record(s) of %d bytes",
> val2 / spe.maxsize, spe.maxsize);
> pmbsr_el1 = read_sysreg_s(PMBSR_EL1);
> - report(!pmbsr_el1, "PMBSR_EL1: no event");
> + report(!(decode_syndrome_register(pmbsr_el1, &observed, true)) &&
> + event_match(&observed, &expected), "PMBSR_EL1: no event");
> +
> + free(addr);
> +}
> +
> +static void irq_handler(struct pt_regs *regs)
> +{
> + uint32_t irqstat, irqnr;
> +
> + irqstat = gic_read_iar();
> + irqnr = gic_iar_irqnr(irqstat);
> +
> + if (irqnr == SPE_PPI) {
> + uint64_t pmbsr_el1 = read_sysreg_s(PMBSR_EL1);
> +
> + if (decode_syndrome_register(pmbsr_el1, &spe_stats.observed,
> true))
> + spe_stats.unexpected = true;
> + report_info("SPE IRQ! SR=0x%lx", pmbsr_el1);
> + write_sysreg_s(0, PMBSR_EL1);
> + } else {
> + spe_stats.unexpected = true;
> + }
> + gic_write_eoir(irqstat);
> +}
> +
> +static inline bool has_event_occurred(struct spe_event *expected)
> +{
> + return (!spe_stats.unexpected && event_match(&spe_stats.observed,
> expected));
> +}
> +
> +static void test_spe_events(void)
> +{
> + struct spe_event expected = {.ec = EC_OTHER, .mss.buffer_filled = true,
> .s = true};
> + void *addr = malloc(10 * PAGE_SIZE);
> +
> + gic_enable_defaults();
> + install_irq_handler(EL1H_IRQ, irq_handler);
> + local_irq_enable();
> + gic_enable_irq(SPE_PPI);
> +
> + reset();
> +
> + /* Willingly set pmblimitr tp pmdptr */
> + spe.pmblimitr_el1 = spe.pmbptr_el1;
> +
> + mem_access_loop(addr, 100000, spe.pmblimitr_el1 | PMBLIMITR_EL1_E);
> + drain();
> + report(has_event_occurred(&expected), "PMBSR_EL1: buffer full event");
> +
> + /* redo it once */
I noticed I must reset the stats here. I will fix that in next version.
Thanks
Eric
> +
> + mem_access_loop(addr, 100000, spe.pmblimitr_el1 | PMBLIMITR_EL1_E);
> + drain();
> + report(has_event_occurred(&expected), "PMBSR_EL1: buffer full event");
>
> free(addr);
> }
> @@ -317,6 +452,10 @@ int main(int argc, char *argv[])
> report_prefix_push(argv[1]);
> test_spe_buffer();
> report_prefix_pop();
> + } else if (strcmp(argv[1], "spe-events") == 0) {
> + report_prefix_push(argv[1]);
> + test_spe_events();
> + report_prefix_pop();
> } else {
> report_abort("Unknown sub-test '%s'", argv[1]);
> }
> diff --git a/arm/unittests.cfg b/arm/unittests.cfg
> index bb0e84c..b2b07be 100644
> --- a/arm/unittests.cfg
> +++ b/arm/unittests.cfg
> @@ -150,6 +150,14 @@ extra_params = -append 'spe-buffer'
> accel = kvm
> arch = arm64
>
> +[spe-events]
> +file = spe.flat
> +groups = spe
> +arch = arm64
> +extra_params = -append 'spe-events'
> +accel = kvm
> +arch = arm64
> +
> # Test GIC emulation
> [gicv2-ipi]
> file = gic.flat
>
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: [kvm-unit-tests RFC 4/4] spe: Test Profiling Buffer Events,
Auger Eric <=