18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Test context switching to see if the DSCR SPR is correctly preserved
38c2ecf20Sopenharmony_ci * when within a transaction.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Note: We assume that the DSCR has been left at the default value (0)
68c2ecf20Sopenharmony_ci * for all CPUs.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Method:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Set a value into the DSCR.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * Start a transaction, and suspend it (*).
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Hard loop checking to see if the transaction has become doomed.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * Now that we *may* have been preempted, record the DSCR and TEXASR SPRS.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * If the abort was because of a context switch, check the DSCR value.
198c2ecf20Sopenharmony_ci * Otherwise, try again.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * (*) If the transaction is not suspended we can't see the problem because
228c2ecf20Sopenharmony_ci * the transaction abort handler will restore the DSCR to it's checkpointed
238c2ecf20Sopenharmony_ci * value before we regain control.
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <inttypes.h>
278c2ecf20Sopenharmony_ci#include <stdio.h>
288c2ecf20Sopenharmony_ci#include <stdlib.h>
298c2ecf20Sopenharmony_ci#include <assert.h>
308c2ecf20Sopenharmony_ci#include <asm/tm.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include "utils.h"
338c2ecf20Sopenharmony_ci#include "tm.h"
348c2ecf20Sopenharmony_ci#include "../pmu/lib.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define SPRN_DSCR       0x03
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ciint test_body(void)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	uint64_t rv, dscr1 = 1, dscr2, texasr;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	SKIP_IF(!have_htm());
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	printf("Check DSCR TM context switch: ");
458c2ecf20Sopenharmony_ci	fflush(stdout);
468c2ecf20Sopenharmony_ci	for (;;) {
478c2ecf20Sopenharmony_ci		asm __volatile__ (
488c2ecf20Sopenharmony_ci			/* set a known value into the DSCR */
498c2ecf20Sopenharmony_ci			"ld      3, %[dscr1];"
508c2ecf20Sopenharmony_ci			"mtspr   %[sprn_dscr], 3;"
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci			"li      %[rv], 1;"
538c2ecf20Sopenharmony_ci			/* start and suspend a transaction */
548c2ecf20Sopenharmony_ci			"tbegin.;"
558c2ecf20Sopenharmony_ci			"beq     1f;"
568c2ecf20Sopenharmony_ci			"tsuspend.;"
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci			/* hard loop until the transaction becomes doomed */
598c2ecf20Sopenharmony_ci			"2: ;"
608c2ecf20Sopenharmony_ci			"tcheck 0;"
618c2ecf20Sopenharmony_ci			"bc      4, 0, 2b;"
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci			/* record DSCR and TEXASR */
648c2ecf20Sopenharmony_ci			"mfspr   3, %[sprn_dscr];"
658c2ecf20Sopenharmony_ci			"std     3, %[dscr2];"
668c2ecf20Sopenharmony_ci			"mfspr   3, %[sprn_texasr];"
678c2ecf20Sopenharmony_ci			"std     3, %[texasr];"
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci			"tresume.;"
708c2ecf20Sopenharmony_ci			"tend.;"
718c2ecf20Sopenharmony_ci			"li      %[rv], 0;"
728c2ecf20Sopenharmony_ci			"1: ;"
738c2ecf20Sopenharmony_ci			: [rv]"=r"(rv), [dscr2]"=m"(dscr2), [texasr]"=m"(texasr)
748c2ecf20Sopenharmony_ci			: [dscr1]"m"(dscr1)
758c2ecf20Sopenharmony_ci			, [sprn_dscr]"i"(SPRN_DSCR), [sprn_texasr]"i"(SPRN_TEXASR)
768c2ecf20Sopenharmony_ci			: "memory", "r3"
778c2ecf20Sopenharmony_ci		);
788c2ecf20Sopenharmony_ci		assert(rv); /* make sure the transaction aborted */
798c2ecf20Sopenharmony_ci		if ((texasr >> 56) != TM_CAUSE_RESCHED) {
808c2ecf20Sopenharmony_ci			continue;
818c2ecf20Sopenharmony_ci		}
828c2ecf20Sopenharmony_ci		if (dscr2 != dscr1) {
838c2ecf20Sopenharmony_ci			printf(" FAIL\n");
848c2ecf20Sopenharmony_ci			return 1;
858c2ecf20Sopenharmony_ci		} else {
868c2ecf20Sopenharmony_ci			printf(" OK\n");
878c2ecf20Sopenharmony_ci			return 0;
888c2ecf20Sopenharmony_ci		}
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int tm_resched_dscr(void)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	return eat_cpu(test_body);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ciint main(int argc, const char *argv[])
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	return test_harness(tm_resched_dscr, "tm_resched_dscr");
1008c2ecf20Sopenharmony_ci}
101