Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 16c19a2e authored by Jack Miller's avatar Jack Miller Committed by Michael Ellerman
Browse files

selftests/powerpc: Load Monitor Register Tests



Adds two tests. One is a simple test to ensure that the new registers
LMRR and LMSER are properly maintained. The other actually uses the
existing EBB test infrastructure to test that LMRR and LMSER behave as
documented.

Signed-off-by: default avatarJack Miller <jack@codezen.org>
Signed-off-by: default avatarMichael Neuling <mikey@neuling.org>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent bd3ea317
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -20,3 +20,5 @@ back_to_back_ebbs_test
lost_exception_test
no_handler_test
cycles_with_mmcr2_test
ebb_lmr
ebb_lmr_regs
 No newline at end of file
+1 −1
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@ TEST_PROGS := reg_access_test event_attributes_test cycles_test \
	 fork_cleanup_test ebb_on_child_test			\
	 ebb_on_willing_child_test back_to_back_ebbs_test	\
	 lost_exception_test no_handler_test			\
	 cycles_with_mmcr2_test
	 cycles_with_mmcr2_test ebb_lmr ebb_lmr_regs

all: $(TEST_PROGS)

+143 −0
Original line number Diff line number Diff line
/*
 * Copyright 2016, Jack Miller, IBM Corp.
 * Licensed under GPLv2.
 */

#include <stdlib.h>
#include <stdio.h>

#include "ebb.h"
#include "ebb_lmr.h"

#define SIZE		(32 * 1024 * 1024)	/* 32M */
#define LM_SIZE		0	/* Smallest encoding, 32M */

#define SECTIONS	64	/* 1 per bit in LMSER */
#define SECTION_SIZE	(SIZE / SECTIONS)
#define SECTION_LONGS   (SECTION_SIZE / sizeof(long))

static unsigned long *test_mem;

static int lmr_count = 0;

void ebb_lmr_handler(void)
{
	lmr_count++;
}

void ldmx_full_section(unsigned long *mem, int section)
{
	unsigned long *ptr;
	int i;

	for (i = 0; i < SECTION_LONGS; i++) {
		ptr = &mem[(SECTION_LONGS * section) + i];
		ldmx((unsigned long) &ptr);
		ebb_lmr_reset();
	}
}

unsigned long section_masks[] = {
	0x8000000000000000,
	0xFF00000000000000,
	0x0000000F70000000,
	0x8000000000000001,
	0xF0F0F0F0F0F0F0F0,
	0x0F0F0F0F0F0F0F0F,
	0x0
};

int ebb_lmr_section_test(unsigned long *mem)
{
	unsigned long *mask = section_masks;
	int i;

	for (; *mask; mask++) {
		mtspr(SPRN_LMSER, *mask);
		printf("Testing mask 0x%016lx\n", mfspr(SPRN_LMSER));

		for (i = 0; i < 64; i++) {
			lmr_count = 0;
			ldmx_full_section(mem, i);
			if (*mask & (1UL << (63 - i)))
				FAIL_IF(lmr_count != SECTION_LONGS);
			else
				FAIL_IF(lmr_count);
		}
	}

	return 0;
}

int ebb_lmr(void)
{
	int i;

	SKIP_IF(!lmr_is_supported());

	setup_ebb_handler(ebb_lmr_handler);

	ebb_global_enable();

	FAIL_IF(posix_memalign((void **)&test_mem, SIZE, SIZE) != 0);

	mtspr(SPRN_LMSER, 0);

	FAIL_IF(mfspr(SPRN_LMSER) != 0);

	mtspr(SPRN_LMRR, ((unsigned long)test_mem | LM_SIZE));

	FAIL_IF(mfspr(SPRN_LMRR) != ((unsigned long)test_mem | LM_SIZE));

	/* Read every single byte to ensure we get no false positives */
	for (i = 0; i < SECTIONS; i++)
		ldmx_full_section(test_mem, i);

	FAIL_IF(lmr_count != 0);

	/* Turn on the first section */

	mtspr(SPRN_LMSER, (1UL << 63));
	FAIL_IF(mfspr(SPRN_LMSER) != (1UL << 63));

	/* Enable LM (BESCR) */

	mtspr(SPRN_BESCR, mfspr(SPRN_BESCR) | BESCR_LME);
	FAIL_IF(!(mfspr(SPRN_BESCR) & BESCR_LME));

	ldmx((unsigned long)&test_mem);

	FAIL_IF(lmr_count != 1);	// exactly one exception
	FAIL_IF(mfspr(SPRN_BESCR) & BESCR_LME);	// LM now disabled
	FAIL_IF(!(mfspr(SPRN_BESCR) & BESCR_LMEO));	// occurred bit set

	printf("Simple LMR EBB OK\n");

	/* This shouldn't cause an EBB since it's been disabled */
	ldmx((unsigned long)&test_mem);
	FAIL_IF(lmr_count != 1);

	printf("LMR disable on EBB OK\n");

	ebb_lmr_reset();

	/* This should cause an EBB or reset is broken */
	ldmx((unsigned long)&test_mem);
	FAIL_IF(lmr_count != 2);

	printf("LMR reset EBB OK\n");

	ebb_lmr_reset();

	return ebb_lmr_section_test(test_mem);
}

int main(void)
{
	int ret = test_harness(ebb_lmr, "ebb_lmr");

	if (test_mem)
		free(test_mem);

	return ret;
}
+39 −0
Original line number Diff line number Diff line
#ifndef _SELFTESTS_POWERPC_PMU_EBB_LMR_H
#define _SELFTESTS_POWERPC_PMU_EBB_LMR_H

#include "reg.h"

#ifndef PPC_FEATURE2_ARCH_3_00
#define PPC_FEATURE2_ARCH_3_00 0x00800000
#endif

#define lmr_is_supported() have_hwcap2(PPC_FEATURE2_ARCH_3_00)

static inline void ebb_lmr_reset(void)
{
	unsigned long bescr = mfspr(SPRN_BESCR);
	bescr &= ~(BESCR_LMEO);
	bescr |= BESCR_LME;
	mtspr(SPRN_BESCR, bescr);
}

#define LDMX(t, a, b)\
	(0x7c00026a |				\
	 (((t) & 0x1f) << 21) |			\
	 (((a) & 0x1f) << 16) |			\
	 (((b) & 0x1f) << 11))

static inline unsigned long ldmx(unsigned long address)
{
	unsigned long ret;

	asm volatile ("mr 9, %1\r\n"
		      ".long " __stringify(LDMX(9, 0, 9)) "\r\n"
		      "mr %0, 9\r\n":"=r"(ret)
		      :"r"(address)
		      :"r9");

	return ret;
}

#endif
+37 −0
Original line number Diff line number Diff line
/*
 * Copyright 2016, Jack Miller, IBM Corp.
 * Licensed under GPLv2.
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include "ebb.h"
#include "ebb_lmr.h"

#define CHECKS 10000

int ebb_lmr_regs(void)
{
	int i;

	SKIP_IF(!lmr_is_supported());

	ebb_global_enable();

	for (i = 0; i < CHECKS; i++) {
		mtspr(SPRN_LMRR, i << 25);	// skip size and rsvd bits
		mtspr(SPRN_LMSER, i);

		FAIL_IF(mfspr(SPRN_LMRR) != (i << 25));
		FAIL_IF(mfspr(SPRN_LMSER) != i);
	}

	return 0;
}

int main(void)
{
	return test_harness(ebb_lmr_regs, "ebb_lmr_regs");
}
Loading