From: Karel Zak <kzak@redhat.com>
Date: Thu, 21 Aug 2025 11:35:17 +0200
Subject: lscpu: use maximum CPU speed from DMI,
 avoid duplicate version string

* Read maximum CPU speed from DMI
* Don't use max speed if nonsensical
* Avoid appending "CPU @ speed" to the version string if it's already included.
  (This is a code robustness improvement as DMI is currently read for ARMs only,
   and the issue was detected on Intel.)

Fixes: https://github.com/util-linux/util-linux/commit/a772d7c493afcec32f0123fc947013f74db6e45d
Signed-off-by: Karel Zak <kzak@redhat.com>
---
 sys-utils/lscpu-dmi.c | 21 +++++++++++++++++----
 sys-utils/lscpu.h     |  1 +
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/sys-utils/lscpu-dmi.c b/sys-utils/lscpu-dmi.c
index 2171f76..a04cbb5 100644
--- a/sys-utils/lscpu-dmi.c
+++ b/sys-utils/lscpu-dmi.c
@@ -76,6 +76,7 @@ int parse_dmi_table(uint16_t len, uint16_t num,
 				di->processor_manufacturer = dmi_string(&h, data[0x7]);
 				di->processor_version = dmi_string(&h, data[0x10]);
 				di->current_speed = *((uint16_t *)(&data[0x16]));
+				di->max_speed = *((uint16_t *)(&data[0x14]));
 				di->part_num = dmi_string(&h, data[0x22]);
 
 				if (data[0x6] == 0xfe)
@@ -122,10 +123,22 @@ int dmi_decode_cputype(struct lscpu_cputype *ct)
 	if (di.processor_manufacturer)
 		ct->bios_vendor = xstrdup(di.processor_manufacturer);
 
-	snprintf(buf, sizeof(buf), "%s %s CPU @ %d.%dGHz",
-			(di.processor_version ?: ""), (di.part_num ?: ""),
-			di.current_speed/1000, (di.current_speed % 1000) / 100);
-	ct->bios_modelname = xstrdup(buf);
+	/* The CPU version string may include the maximum speed (e.g., on Intel); in
+	 * this case, use the version string as the complete model name. */
+	if (di.processor_version && strstr(di.processor_version, " CPU @ "))
+		ct->bios_modelname = xstrdup(di.processor_version);
+	else {
+		/* DMI may provide incorrect data (max_speed < current_speed) */
+		uint16_t speed = max(di.current_speed, di.max_speed);
+
+		snprintf(buf, sizeof(buf), "%s %s CPU @ %d.%dGHz",
+			(di.processor_version ?: ""),
+			(di.part_num ?: ""),
+			speed/1000,
+			(speed % 1000) / 100);
+
+		ct->bios_modelname = xstrdup(buf);
+	}
 
 	/* Get CPU family */
 	memset(buf, 0, sizeof(buf));
diff --git a/sys-utils/lscpu.h b/sys-utils/lscpu.h
index 459fea8..64570f6 100644
--- a/sys-utils/lscpu.h
+++ b/sys-utils/lscpu.h
@@ -344,6 +344,7 @@ struct dmi_info {
 	char *processor_manufacturer;
 	char *processor_version;
 	uint16_t current_speed;
+	uint16_t max_speed;
 	char *part_num;
 };
 
