162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Dhrystone benchmark test module
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2022 Glider bv
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "dhry.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/moduleparam.h>
1362306a36Sopenharmony_ci#include <linux/mutex.h>
1462306a36Sopenharmony_ci#include <linux/smp.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define DHRY_VAX	1757
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic int dhry_run_set(const char *val, const struct kernel_param *kp);
1962306a36Sopenharmony_cistatic const struct kernel_param_ops run_ops = {
2062306a36Sopenharmony_ci	.flags = KERNEL_PARAM_OPS_FL_NOARG,
2162306a36Sopenharmony_ci	.set = dhry_run_set,
2262306a36Sopenharmony_ci};
2362306a36Sopenharmony_cistatic bool dhry_run;
2462306a36Sopenharmony_cimodule_param_cb(run, &run_ops, &dhry_run, 0200);
2562306a36Sopenharmony_ciMODULE_PARM_DESC(run, "Run the test (default: false)");
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic int iterations = -1;
2862306a36Sopenharmony_cimodule_param(iterations, int, 0644);
2962306a36Sopenharmony_ciMODULE_PARM_DESC(iterations,
3062306a36Sopenharmony_ci		"Number of iterations through the benchmark (default: auto)");
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic void dhry_benchmark(void)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	unsigned int cpu = get_cpu();
3562306a36Sopenharmony_ci	int i, n;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (iterations > 0) {
3862306a36Sopenharmony_ci		n = dhry(iterations);
3962306a36Sopenharmony_ci		goto report;
4062306a36Sopenharmony_ci	}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	for (i = DHRY_VAX; i > 0; i <<= 1) {
4362306a36Sopenharmony_ci		n = dhry(i);
4462306a36Sopenharmony_ci		if (n != -EAGAIN)
4562306a36Sopenharmony_ci			break;
4662306a36Sopenharmony_ci	}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cireport:
4962306a36Sopenharmony_ci	put_cpu();
5062306a36Sopenharmony_ci	if (n >= 0)
5162306a36Sopenharmony_ci		pr_info("CPU%u: Dhrystones per Second: %d (%d DMIPS)\n", cpu,
5262306a36Sopenharmony_ci			n, n / DHRY_VAX);
5362306a36Sopenharmony_ci	else if (n == -EAGAIN)
5462306a36Sopenharmony_ci		pr_err("Please increase the number of iterations\n");
5562306a36Sopenharmony_ci	else
5662306a36Sopenharmony_ci		pr_err("Dhrystone benchmark failed error %pe\n", ERR_PTR(n));
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic int dhry_run_set(const char *val, const struct kernel_param *kp)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	int ret;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (val) {
6462306a36Sopenharmony_ci		ret = param_set_bool(val, kp);
6562306a36Sopenharmony_ci		if (ret)
6662306a36Sopenharmony_ci			return ret;
6762306a36Sopenharmony_ci	} else {
6862306a36Sopenharmony_ci		dhry_run = true;
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (dhry_run && system_state == SYSTEM_RUNNING)
7262306a36Sopenharmony_ci		dhry_benchmark();
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	return 0;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic int __init dhry_init(void)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	if (dhry_run)
8062306a36Sopenharmony_ci		dhry_benchmark();
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return 0;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_cimodule_init(dhry_init);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ciMODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
8762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
88