{"id":2230926,"url":"http://patchwork.ozlabs.org/api/1.2/patches/2230926/?format=json","web_url":"http://patchwork.ozlabs.org/project/ltp/patch/20260430084239.320182-2-piotr.kubaj@intel.com/","project":{"id":59,"url":"http://patchwork.ozlabs.org/api/1.2/projects/59/?format=json","name":"Linux Test Project development","link_name":"ltp","list_id":"ltp.lists.linux.it","list_email":"ltp@lists.linux.it","web_url":"","scm_url":"","webscm_url":"","list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20260430084239.320182-2-piotr.kubaj@intel.com>","list_archive_url":null,"date":"2026-04-30T08:42:40","name":"[v18] thermal: add new test group","commit_ref":null,"pull_url":null,"state":"needs-review-ack","archived":false,"hash":"6b7c819d87feede13263e6769ad3212bd8efacb6","submitter":{"id":92049,"url":"http://patchwork.ozlabs.org/api/1.2/people/92049/?format=json","name":"Kubaj, Piotr","email":"piotr.kubaj@intel.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/ltp/patch/20260430084239.320182-2-piotr.kubaj@intel.com/mbox/","series":[{"id":502236,"url":"http://patchwork.ozlabs.org/api/1.2/series/502236/?format=json","web_url":"http://patchwork.ozlabs.org/project/ltp/list/?series=502236","date":"2026-04-30T08:42:40","name":"[v18] thermal: add new test group","version":18,"mbox":"http://patchwork.ozlabs.org/series/502236/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2230926/comments/","check":"warning","checks":"http://patchwork.ozlabs.org/api/patches/2230926/checks/","tags":{},"related":[],"headers":{"Return-Path":"<ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it>","X-Original-To":["incoming@patchwork.ozlabs.org","ltp@lists.linux.it"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","ltp@picard.linux.it"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256\n header.s=Intel header.b=UPjH8i3B;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.linux.it\n (client-ip=2001:1418:10:5::2; helo=picard.linux.it;\n envelope-from=ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it;\n receiver=patchwork.ozlabs.org)"],"Received":["from picard.linux.it (picard.linux.it [IPv6:2001:1418:10:5::2])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g5nkc70JLz1xqf\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 30 Apr 2026 18:43:20 +1000 (AEST)","from picard.linux.it (localhost [IPv6:::1])\n\tby picard.linux.it (Postfix) with ESMTP id A2DE03E659F\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 30 Apr 2026 10:43:17 +0200 (CEST)","from in-6.smtp.seeweb.it (in-6.smtp.seeweb.it [217.194.8.6])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature ECDSA (secp384r1))\n (No client certificate requested)\n by picard.linux.it (Postfix) with ESMTPS id 39F5B3E2CDC\n for <ltp@lists.linux.it>; Thu, 30 Apr 2026 10:43:14 +0200 (CEST)","from mgamail.intel.com (mgamail.intel.com [198.175.65.9])\n (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n (No client certificate requested)\n by in-6.smtp.seeweb.it (Postfix) with ESMTPS id 957DF1400961\n for <ltp@lists.linux.it>; Thu, 30 Apr 2026 10:43:10 +0200 (CEST)","from fmviesa010.fm.intel.com ([10.60.135.150])\n by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 30 Apr 2026 01:43:08 -0700","from pkubaj-desk.igk.intel.com (HELO intel.com) ([10.217.160.221])\n by fmviesa010-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 30 Apr 2026 01:43:06 -0700"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple;\n d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n t=1777538593; x=1809074593;\n h=from:to:cc:subject:date:message-id:mime-version:\n content-transfer-encoding;\n bh=vmAc3gCpRgMwG3wSYXfHnATrzHsGSqeO/MYvj/Sob44=;\n b=UPjH8i3BPmlrXU14p543x64I63tcC+NTljMrdnqBp7JvRQ9ijYtVZdta\n rHws5PZo8kXZ2FjByTzpwX6zaRLtPRhLZZ1Q5654S5q/fkiIUj/cIJtAY\n Wjs/vheIzwrUTKa9vq+TM0mjqUHcl9o/bPRSWoeCC/P2lB1Ms56TPE/RR\n N6DW9RjPbilWOsjXGG6ykLckWhccgNlQS1ZoRbsFwEj1UkMgaHOwPMIzV\n We5STRLhYmA+a6xMEepYdla6b/uzsXLmzE2b5EI0j0t0nqViGwizixXoQ\n QV2mIUx6CUgPw1PCqzxmROZCM7CZn3F4mJ6xxy+lKvMdi95znplejfj8p w==;","X-CSE-ConnectionGUID":["kvOaMh2hQBGycG40F3rRvQ==","TM592QtjRCukcaGobZNqMA=="],"X-CSE-MsgGUID":["azobSVfkRmWvolWdwwo27Q==","rzZqvm62TqmEaioUzQJrVA=="],"X-IronPort-AV":["E=McAfee;i=\"6800,10657,11771\"; a=\"101144741\"","E=Sophos;i=\"6.23,207,1770624000\"; d=\"scan'208\";a=\"101144741\"","E=Sophos;i=\"6.23,207,1770624000\"; d=\"scan'208\";a=\"230174870\""],"X-ExtLoop1":"1","From":"Piotr Kubaj <piotr.kubaj@intel.com>","To":"ltp@lists.linux.it","Date":"Thu, 30 Apr 2026 10:42:40 +0200","Message-ID":"<20260430084239.320182-2-piotr.kubaj@intel.com>","X-Mailer":"git-send-email 2.47.3","MIME-Version":"1.0","X-Spam-Status":"No, score=0.1 required=7.0 tests=DKIM_SIGNED,DKIM_VALID,\n DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS shortcircuit=no\n autolearn=disabled version=4.0.1","X-Spam-Checker-Version":"SpamAssassin 4.0.1 (2024-03-25) on in-6.smtp.seeweb.it","X-Virus-Scanned":"clamav-milter 1.0.9 at in-6.smtp.seeweb.it","X-Virus-Status":"Clean","Subject":"[LTP] [PATCH v18] thermal: add new test group","X-BeenThere":"ltp@lists.linux.it","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"Linux Test Project <ltp.lists.linux.it>","List-Unsubscribe":"<https://lists.linux.it/options/ltp>,\n <mailto:ltp-request@lists.linux.it?subject=unsubscribe>","List-Archive":"<http://lists.linux.it/pipermail/ltp/>","List-Post":"<mailto:ltp@lists.linux.it>","List-Help":"<mailto:ltp-request@lists.linux.it?subject=help>","List-Subscribe":"<https://lists.linux.it/listinfo/ltp>,\n <mailto:ltp-request@lists.linux.it?subject=subscribe>","Cc":"helena.anna.dubel@intel.com, tomasz.ossowski@intel.com,\n rafael.j.wysocki@intel.com, daniel.niestepski@intel.com","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it","Sender":"\"ltp\" <ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it>"},"content":"Currently consists of only one test for the CPU package thermal sensor\ninterface for Intel platforms.\nIt works by checking the initial count of thermal interrupts. Then it\ndecreases the threshold for sending a thermal interrupt to just above\nthe current temperature and runs a workload on the CPU. Finally, it\nrestores the original thermal threshold and checks whether the number\nof thermal interrupts increased.\n\nSigned-off-by: Piotr Kubaj <piotr.kubaj@intel.com>\n---\nFix compilation, needs_drivers was removed so switch to needs_kconfigs.\n runtest/thermal                               |   3 +\n testcases/kernel/Makefile                     |   1 +\n testcases/kernel/thermal/.gitignore           |   1 +\n testcases/kernel/thermal/Makefile             |   9 +\n .../kernel/thermal/thermal_interrupt_events.c | 242 ++++++++++++++++++\n 5 files changed, 256 insertions(+)\n create mode 100644 runtest/thermal\n create mode 100644 testcases/kernel/thermal/.gitignore\n create mode 100644 testcases/kernel/thermal/Makefile\n create mode 100644 testcases/kernel/thermal/thermal_interrupt_events.c","diff":"diff --git a/runtest/thermal b/runtest/thermal\nnew file mode 100644\nindex 000000000..57e3d29f8\n--- /dev/null\n+++ b/runtest/thermal\n@@ -0,0 +1,3 @@\n+# Thermal driver API\n+# https://docs.kernel.org/driver-api/thermal/\n+thermal_interrupt_events thermal_interrupt_events\ndiff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile\nindex 98fd45a9d..ac816e4e8 100644\n--- a/testcases/kernel/Makefile\n+++ b/testcases/kernel/Makefile\n@@ -36,6 +36,7 @@ SUBDIRS\t\t\t+= connectors \\\n \t\t\t   sched \\\n \t\t\t   security \\\n \t\t\t   sound \\\n+\t\t\t   thermal \\\n \t\t\t   tracing \\\n \t\t\t   uevents \\\n \t\t\t   watchqueue \\\ndiff --git a/testcases/kernel/thermal/.gitignore b/testcases/kernel/thermal/.gitignore\nnew file mode 100644\nindex 000000000..1090bdad8\n--- /dev/null\n+++ b/testcases/kernel/thermal/.gitignore\n@@ -0,0 +1 @@\n+thermal_interrupt_events\ndiff --git a/testcases/kernel/thermal/Makefile b/testcases/kernel/thermal/Makefile\nnew file mode 100644\nindex 000000000..4657c3fb3\n--- /dev/null\n+++ b/testcases/kernel/thermal/Makefile\n@@ -0,0 +1,9 @@\n+# SPDX-License-Identifier: GPL-2.0-or-later\n+# Copyright (c) 2025, Intel Corporation. All rights reserved.\n+# Author:Piotr Kubaj <piotr.kubaj@intel.com>\n+\n+top_srcdir             ?= ../../..\n+\n+include $(top_srcdir)/include/mk/testcases.mk\n+\n+include $(top_srcdir)/include/mk/generic_leaf_target.mk\ndiff --git a/testcases/kernel/thermal/thermal_interrupt_events.c b/testcases/kernel/thermal/thermal_interrupt_events.c\nnew file mode 100644\nindex 000000000..1f24c3ae4\n--- /dev/null\n+++ b/testcases/kernel/thermal/thermal_interrupt_events.c\n@@ -0,0 +1,242 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+/*\n+ * Copyright (C) 2026 Intel - http://www.intel.com/\n+ */\n+\n+/*\\\n+ * Tests the CPU package thermal sensor interface for Intel platforms.\n+\n+ * Works by checking the initial count of thermal interrupts. Then it\n+ * decreases the threshold for sending a thermal interrupt to just above\n+ * the current temperature and runs a workload on the CPU. Finally, it restores\n+ * the original thermal threshold and checks whether the number of thermal\n+ * interrupts increased.\n+ */\n+\n+#include <ctype.h>\n+#include <inttypes.h>\n+#include \"tst_safe_stdio.h\"\n+#include \"tst_test.h\"\n+#include \"tst_timer_test.h\"\n+\n+#define\tTEST_RUNTIME\t3\n+#define\tRUNTIME\t\t30\n+#define\tSLEEP\t\t10\n+#define\tTEMP_INCREMENT\t10\n+\n+static bool x86_pkg_temp_tz_found, *x86_pkg_temp_tz;\n+static char temp_path[PATH_MAX], trip_path[PATH_MAX];\n+static int nproc, temp_high, temp, *trip_orig, tz_counter;\n+static uint64_t *interrupt_init, *interrupt_later;\n+\n+static void read_interrupts(uint64_t *interrupts)\n+{\n+\tbool interrupts_found = false;\n+\tchar line[8192];\n+\n+\tmemset(interrupts, 0, nproc * sizeof(*interrupts));\n+\tFILE *fp = SAFE_FOPEN(\"/proc/interrupts\", \"r\");\n+\n+\twhile (fgets(line, sizeof(line), fp)) {\n+\t\tif (!strstr(line, \"Thermal event interrupts\"))\n+\t\t\tcontinue;\n+\n+\t\tinterrupts_found = true;\n+\t\tchar *ptr = strchr(line, ':');\n+\n+\t\tfor (int i = 0; i < nproc; i++) {\n+\t\t\tchar *endptr;\n+\n+\t\t\twhile (*ptr && !isdigit(*ptr))\n+\t\t\t\tptr++;\n+\n+\t\t\terrno = 0;\n+\n+\t\t\tinterrupts[i] = strtoull(ptr, &endptr, 10);\n+\n+\t\t\tif (ptr == endptr)\n+\t\t\t\ttst_brk(TBROK, \"CPU %d: interrupt not found\", i);\n+\n+\t\t\tif (errno == ERANGE)\n+\t\t\t\ttst_brk(TBROK, \"CPU %d: interrupt out of range\", i);\n+\n+\t\t\tptr = endptr;\n+\t\t\ttst_res(TDEBUG, \"interrupts[%d]: %\" PRIu64, i, interrupts[i]);\n+\t\t}\n+\t\tbreak;\n+\t}\n+\tSAFE_FCLOSE(fp);\n+\tif (!interrupts_found)\n+\t\ttst_brk(TCONF, \"No Thermal event interrupts line in /proc/interrupts\");\n+}\n+\n+static void setup(void)\n+{\n+\tchar line[8192];\n+\n+\tnproc = tst_ncpus();\n+\ttst_set_runtime(nproc * TEST_RUNTIME);\n+\n+\ttst_res(TDEBUG, \"Number of logical cores: %d\", nproc);\n+\tinterrupt_init = SAFE_CALLOC(nproc, sizeof(uint64_t));\n+\tinterrupt_later = SAFE_CALLOC(nproc, sizeof(uint64_t));\n+\n+\tDIR *dir = SAFE_OPENDIR(\"/sys/class/thermal/\");\n+\tstruct dirent *entry;\n+\n+\twhile ((entry = SAFE_READDIR(dir))) {\n+\t\tif ((!strncmp(entry->d_name, \"thermal_zone\", sizeof(\"thermal_zone\") - 1)))\n+\t\t\ttz_counter++;\n+\t}\n+\tSAFE_CLOSEDIR(dir);\n+\ttst_res(TDEBUG, \"Found %d thermal zone(s)\", tz_counter);\n+\n+\tx86_pkg_temp_tz = SAFE_CALLOC(tz_counter, sizeof(bool));\n+\ttrip_orig = SAFE_CALLOC(tz_counter, sizeof(int));\n+\n+\tfor (int i = 0; i < tz_counter; i++) {\n+\t\tchar path[PATH_MAX];\n+\n+\t\tsnprintf(path, PATH_MAX, \"/sys/class/thermal/thermal_zone%d/type\", i);\n+\t\ttst_res(TDEBUG, \"Checking whether %s is x86_pkg_temp\", path);\n+\n+\t\tSAFE_FILE_SCANF(path, \"%8191s\", line);\n+\t\tif (strstr(line, \"x86_pkg_temp\")) {\n+\t\t\ttst_res(TDEBUG, \"Thermal zone %d uses x86_pkg_temp\", i);\n+\t\t\tx86_pkg_temp_tz[i] = true;\n+\t\t\tx86_pkg_temp_tz_found = true;\n+\t\t\tsnprintf(trip_path, PATH_MAX, \"/sys/class/thermal/thermal_zone%d/trip_point_1_temp\", i);\n+\t\t\tSAFE_ACCESS(trip_path, R_OK | W_OK);\n+\t\t\tSAFE_FILE_SCANF(trip_path, \"%d\", &trip_orig[i]);\n+\t\t}\n+\t}\n+\n+\tif (!x86_pkg_temp_tz_found)\n+\t\ttst_brk(TCONF, \"No thermal zone uses x86_pkg_temp\");\n+}\n+\n+static void cpu_workload(double run_time)\n+{\n+\ttst_timer_start(CLOCK_MONOTONIC);\n+\tint num = 2;\n+\n+\twhile (!tst_timer_expired_ms(run_time * 1000)) {\n+\t\tfor (int i = 2; i * i <= num; i++) {\n+\t\t\tif (num % i == 0)\n+\t\t\t\tbreak;\n+\t\t}\n+\t\tnum++;\n+\t\tSAFE_FILE_SCANF(temp_path, \"%d\", &temp);\n+\n+\t\tif (temp > temp_high)\n+\t\t\tbreak;\n+\t}\n+}\n+\n+static void test_zone(int i)\n+{\n+\tint sleep_time = SLEEP;\n+\tdouble run_time = RUNTIME;\n+\n+\tsnprintf(temp_path, PATH_MAX, \"/sys/class/thermal/thermal_zone%d/temp\", i);\n+\ttst_res(TINFO, \"Testing %s\", temp_path);\n+\tSAFE_FILE_SCANF(temp_path, \"%d\", &temp);\n+\tif (temp < 0)\n+\t\ttst_brk(TBROK, \"Unexpected zone temperature value %d\", temp);\n+\n+\ttst_res(TDEBUG, \"Current temperature for %s: %d\", temp_path, temp);\n+\n+\ttemp_high = temp + TEMP_INCREMENT;\n+\n+\tsnprintf(trip_path, PATH_MAX, \"/sys/class/thermal/thermal_zone%d/trip_point_1_temp\", i);\n+\n+\ttst_res(TDEBUG, \"Setting new trip_point_1_temp value: %d\", temp_high);\n+\tSAFE_FILE_PRINTF(trip_path, \"%d\", temp_high);\n+\n+\twhile (sleep_time > 0) {\n+\t\ttst_res(TDEBUG, \"Running for %f seconds, then sleeping for %d seconds\", run_time, sleep_time);\n+\n+\t\tfor (int j = 0; j < nproc; j++) {\n+\t\t\tif (!SAFE_FORK()) {\n+\t\t\t\tcpu_workload(run_time);\n+\t\t\t\texit(0);\n+\t\t\t}\n+\t\t}\n+\n+\t\ttst_reap_children();\n+\n+\t\tSAFE_FILE_SCANF(temp_path, \"%d\", &temp);\n+\t\ttst_res(TDEBUG, \"Temperature for %s after a test: %d\", temp_path, temp);\n+\n+\t\tif (temp > temp_high)\n+\t\t\tbreak;\n+\t\tsleep(sleep_time--);\n+\t\trun_time -= 3;\n+\t}\n+}\n+\n+static void cleanup(void)\n+{\n+\tif (x86_pkg_temp_tz_found) {\n+\t\tfor (int i = 0; i < tz_counter; i++) {\n+\t\t\tif (x86_pkg_temp_tz[i]) {\n+\t\t\t\tsnprintf(trip_path, PATH_MAX, \"/sys/class/thermal/thermal_zone%d/trip_point_1_temp\", i);\n+\t\t\t\tSAFE_FILE_PRINTF(trip_path, \"%d\", trip_orig[i]);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tfree(x86_pkg_temp_tz);\n+\tfree(interrupt_init);\n+\tfree(interrupt_later);\n+\tfree(trip_orig);\n+}\n+\n+static void run(void)\n+{\n+\tfor (int i = 0; i < tz_counter; i++) {\n+\t\tif (x86_pkg_temp_tz[i]) {\n+\t\t\tread_interrupts(interrupt_init);\n+\t\t\ttest_zone(i);\n+\t\t\tread_interrupts(interrupt_later);\n+\n+\t\t\tbool interrupt_increased = false;\n+\t\t\tfor (int j = 0; j < nproc; j++) {\n+\t\t\t\tif (interrupt_later[j] > interrupt_init[j]) {\n+\t\t\t\t\tinterrupt_increased = true;\n+\t\t\t\t\ttst_res(TINFO, \"CPU %d interrupt counter: %\" PRIu64 \" (previous: %\" PRIu64 \")\",\n+\t\t\t\t\t\tj, interrupt_later[j], interrupt_init[j]);\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\t\tif (!interrupt_increased)\n+\t\t\t\ttst_res(TFAIL, \"No thermal interrupt increase detected\");\n+\t\t\telse if (temp <= temp_high)\n+\t\t\t\ttst_res(TFAIL, \"Thermal interrupts increased but temperature did not rise as expected\");\n+\t\t\telse\n+\t\t\t\ttst_res(TPASS, \"x86 package thermal interrupt triggered\");\n+\t\t}\n+\t}\n+}\n+\n+static struct tst_test test = {\n+\t.cleanup = cleanup,\n+\t.forks_child = 1,\n+\t.needs_kconfigs = (const char *const []) {\n+\t\t\"CONFIG_X86_PKG_TEMP_THERMAL\",\n+\t\tNULL\n+\t},\n+\t.min_runtime = 5,\n+\t.needs_root = 1,\n+\t.setup = setup,\n+\t.supported_archs = (const char *const []) {\n+\t\t\"x86\",\n+\t\t\"x86_64\",\n+\t\tNULL\n+\t},\n+\t.tags = (const struct tst_tag[]) {\n+\t\t{\"linux-git\", \"9635c586a559ba0e45b2bfbff79c937ddbaf1a62\"},\n+\t\t{}\n+\t},\n+\t.test_all = run\n+};\n","prefixes":["v18"]}