{"id":2220966,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2220966/?format=json","web_url":"http://patchwork.ozlabs.org/project/ltp/patch/20260408132211.653130-2-piotr.kubaj@intel.com/","project":{"id":59,"url":"http://patchwork.ozlabs.org/api/1.1/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":""},"msgid":"<20260408132211.653130-2-piotr.kubaj@intel.com>","date":"2026-04-08T13:22:12","name":"[v15] thermal: add new test group","commit_ref":null,"pull_url":null,"state":"changes-requested","archived":false,"hash":"a83fb672fd04fb6e039c5432e3acd9dcfd1a3b53","submitter":{"id":92049,"url":"http://patchwork.ozlabs.org/api/1.1/people/92049/?format=json","name":"Piotr Kubaj","email":"piotr.kubaj@intel.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/ltp/patch/20260408132211.653130-2-piotr.kubaj@intel.com/mbox/","series":[{"id":499141,"url":"http://patchwork.ozlabs.org/api/1.1/series/499141/?format=json","web_url":"http://patchwork.ozlabs.org/project/ltp/list/?series=499141","date":"2026-04-08T13:22:12","name":"[v15] thermal: add new test group","version":15,"mbox":"http://patchwork.ozlabs.org/series/499141/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2220966/comments/","check":"warning","checks":"http://patchwork.ozlabs.org/api/patches/2220966/checks/","tags":{},"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=SI6NYHi1;\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 4frP0p2B6sz1yD3\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 08 Apr 2026 23:24:07 +1000 (AEST)","from picard.linux.it (localhost [IPv6:::1])\n\tby picard.linux.it (Postfix) with ESMTP id 219663E2E68\n\tfor <incoming@patchwork.ozlabs.org>; Wed,  8 Apr 2026 15:24:04 +0200 (CEST)","from in-4.smtp.seeweb.it (in-4.smtp.seeweb.it [217.194.8.4])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n (No client certificate requested)\n by picard.linux.it (Postfix) with ESMTPS id AB1B33E1228\n for <ltp@lists.linux.it>; Wed,  8 Apr 2026 15:24:00 +0200 (CEST)","from mgamail.intel.com (mgamail.intel.com [198.175.65.18])\n (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n (No client certificate requested)\n by in-4.smtp.seeweb.it (Postfix) with ESMTPS id 3C6081000999\n for <ltp@lists.linux.it>; Wed,  8 Apr 2026 15:23:58 +0200 (CEST)","from fmviesa007.fm.intel.com ([10.60.135.147])\n by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 08 Apr 2026 06:23:56 -0700","from pkubaj-desk.igk.intel.com (HELO intel.com) ([10.217.160.221])\n by fmviesa007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 08 Apr 2026 06:23:53 -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=1775654640; x=1807190640;\n h=from:to:cc:subject:date:message-id:mime-version:\n content-transfer-encoding;\n bh=50KMLnrslnOfeGwD2tjDSZoCNqZuREkDfJJK37iCrzU=;\n b=SI6NYHi1KqE2l0jm+q/8ai5Hi7L/c8Hy5sjvwC8HUKGJSw2R4HOwJLQd\n Y8hy2wla53sdSsZSoPOA9MUsxrmfg/m0hKxCO5IheO/0poGnBJ1DloV7g\n b1qmr0IJUgJsU7CYWmm/VSWrPmYiWbMR8c/Da/HoatYzaOeiIT9AjU9qc\n kAvF8iu18fucgDhbNCQRlG/C+pJqPfflhro4yHYRPAKkTRSXvbYH+wIGk\n uyBrLKiCrMkHv3oRE99SrgUteb1+JTjCa32Y96BMHqcH4+mO4ERvlCFVV\n 9Djm4CPyRNomV9pr4gpn2MBM8wKO4ML3Y2/WkGfusprcnnY75Fw7AkYmM Q==;","X-CSE-ConnectionGUID":["IYO2B226Sfe+tAewXzvAHw==","WwntemekRku9RkfzBA08eQ=="],"X-CSE-MsgGUID":["bj/H5UVdQHOM/pcY5v7gHg==","j4WYYlCeS/+KK2KOeXecgA=="],"X-IronPort-AV":["E=McAfee;i=\"6800,10657,11753\"; a=\"76648198\"","E=Sophos;i=\"6.23,167,1770624000\"; d=\"scan'208\";a=\"76648198\"","E=Sophos;i=\"6.23,167,1770624000\"; d=\"scan'208\";a=\"225294915\""],"X-ExtLoop1":"1","From":"Piotr Kubaj <piotr.kubaj@intel.com>","To":"ltp@lists.linux.it","Date":"Wed,  8 Apr 2026 15:22:12 +0200","Message-ID":"<20260408132211.653130-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-4.smtp.seeweb.it","X-Virus-Scanned":"clamav-milter 1.0.9 at in-4.smtp.seeweb.it","X-Virus-Status":"Clean","Subject":"[LTP] [PATCH v15] 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---\nAddress Andrea's feedback.\nAlso, nproc is now a global variable, so read_interrupts() may be\nreduced to taking only one parameter.\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 | 232 ++++++++++++++++++\n 5 files changed, 246 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..b9a6018aa\n--- /dev/null\n+++ b/testcases/kernel/thermal/thermal_interrupt_events.c\n@@ -0,0 +1,232 @@\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\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\tinterrupts_found = true;\n+\t\t\tchar *ptr = strchr(line, ':');\n+\n+\t\t\tfor (int i = 0; i < nproc; i++) {\n+\t\t\t\tchar *endptr;\n+\n+\t\t\t\twhile (*ptr && !isdigit(*ptr))\n+\t\t\t\t\tptr++;\n+\n+\t\t\t\terrno = 0;\n+\n+\t\t\t\tinterrupts[i] = strtoull(ptr, &endptr, 10);\n+\n+\t\t\t\tif (ptr == endptr)\n+\t\t\t\t\ttst_brk(TBROK, \"interrupt not found\");\n+\n+\t\t\t\tif (errno == ERANGE)\n+\t\t\t\t\ttst_brk(TCONF, \"interrupt out of range\");\n+\n+\t\t\t\tptr = endptr;\n+\t\t\t\ttst_res(TDEBUG, \"interrupts[%d]: %\" PRIu64, i, interrupts[i]);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\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_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_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+\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+\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\ttst_res(TFAIL, \"CPU %d interrupt counter: %\" PRIu64 \" (previous: %\" PRIu64 \")\",\n+\t\t\t\t\t\tj, interrupt_later[j], interrupt_init[j]);\n+\t\t\t}\n+\t\t\tif (temp <= temp_high)\n+\t\t\t\ttst_res(TFAIL, \"Zone temperature is not rising 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+\n+static struct tst_test test = {\n+\t.cleanup = cleanup,\n+\t.forks_child = 1,\n+\t.needs_drivers = (const char *const []) {\n+\t\t\"x86_pkg_temp_thermal\",\n+\t\tNULL\n+\t},\n+\t.min_runtime = 180,\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":["v15"]}