From 652dc1328110d8635447e21f7f6a10fd0593ef35 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 5 Mar 2026 13:35:40 -0600 Subject: [PATCH 01/52] rtc: abx80x: Remove use of i2c_match_id() The function i2c_match_id() is used to fetch the matching ID from the i2c_device_id table. This is often used to then retrieve the matching driver_data. This can be done in one step with the helper i2c_get_match_data(). This helper has a couple other benefits: * It doesn't need the i2c_device_id passed in so we do not need to have that forward declared, allowing us to remove those or move the i2c_device_id table down to its more natural spot with the other module info. * It also checks for device match data, which allows for OF and ACPI based probing. That means we do not have to manually check those first and can remove those checks. Signed-off-by: Andrew Davis Link: https://patch.msgid.link/20260305193545.796294-2-afd@ti.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-abx80x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index 3fee27914ba8..eca09872ea97 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -772,8 +772,7 @@ static int abx80x_probe(struct i2c_client *client) struct abx80x_priv *priv; int i, data, err, trickle_cfg = -EINVAL; char buf[7]; - const struct i2c_device_id *id = i2c_match_id(abx80x_id, client); - unsigned int part = id->driver_data; + unsigned int part = (uintptr_t)i2c_get_match_data(client); unsigned int partnumber; unsigned int majrev, minrev; unsigned int lot; From aade5f4bf9e236fe3fee127e0acbbabc93609ad6 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 5 Mar 2026 13:35:41 -0600 Subject: [PATCH 02/52] rtc: m41t80: Remove use of i2c_match_id() The function i2c_match_id() is used to fetch the matching ID from the i2c_device_id table. This is often used to then retrieve the matching driver_data. This can be done in one step with the helper i2c_get_match_data(). This helper has a couple other benefits: * It doesn't need the i2c_device_id passed in so we do not need to have that forward declared, allowing us to remove those or move the i2c_device_id table down to its more natural spot with the other module info. * It also checks for device match data, which allows for OF and ACPI based probing. That means we do not have to manually check those first and can remove those checks. Signed-off-by: Andrew Davis Link: https://patch.msgid.link/20260305193545.796294-3-afd@ti.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m41t80.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 740cab013f59..b26afef37d9c 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -924,13 +924,7 @@ static int m41t80_probe(struct i2c_client *client) return -ENOMEM; m41t80_data->client = client; - if (client->dev.of_node) { - m41t80_data->features = (unsigned long) - of_device_get_match_data(&client->dev); - } else { - const struct i2c_device_id *id = i2c_match_id(m41t80_id, client); - m41t80_data->features = id->driver_data; - } + m41t80_data->features = (unsigned long)i2c_get_match_data(client); i2c_set_clientdata(client, m41t80_data); m41t80_data->rtc = devm_rtc_allocate_device(&client->dev); From c85ac0b4d7c52b30aca9c4a7914279dd072d105f Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 5 Mar 2026 13:35:42 -0600 Subject: [PATCH 03/52] rtc: pcf2127: Remove use of i2c_match_id() The function i2c_match_id() is used to fetch the matching ID from the i2c_device_id table. This is often used to then retrieve the matching driver_data. This can be done in one step with the helper i2c_get_match_data(). This helper has a couple other benefits: * It doesn't need the i2c_device_id passed in so we do not need to have that forward declared, allowing us to remove those or move the i2c_device_id table down to its more natural spot with the other module info. * It also checks for device match data, which allows for OF and ACPI based probing. That means we do not have to manually check those first and can remove those checks. Signed-off-by: Andrew Davis Link: https://patch.msgid.link/20260305193545.796294-4-afd@ti.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index bb4fe81d3d62..e4785c5a55d0 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1449,10 +1449,10 @@ static const struct regmap_bus pcf2127_i2c_regmap = { static struct i2c_driver pcf2127_i2c_driver; static const struct i2c_device_id pcf2127_i2c_id[] = { - { "pcf2127", PCF2127 }, - { "pcf2129", PCF2129 }, - { "pca2129", PCF2129 }, - { "pcf2131", PCF2131 }, + { "pcf2127", (kernel_ulong_t)&pcf21xx_cfg[PCF2127] }, + { "pcf2129", (kernel_ulong_t)&pcf21xx_cfg[PCF2129] }, + { "pca2129", (kernel_ulong_t)&pcf21xx_cfg[PCF2129] }, + { "pcf2131", (kernel_ulong_t)&pcf21xx_cfg[PCF2131] }, { } }; MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id); @@ -1469,18 +1469,9 @@ static int pcf2127_i2c_probe(struct i2c_client *client) if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; - if (client->dev.of_node) { - variant = of_device_get_match_data(&client->dev); - if (!variant) - return -ENODEV; - } else { - enum pcf21xx_type type = - i2c_match_id(pcf2127_i2c_id, client)->driver_data; - - if (type >= PCF21XX_LAST_ID) - return -ENODEV; - variant = &pcf21xx_cfg[type]; - } + variant = i2c_get_match_data(client); + if (!variant) + return -ENODEV; config.max_register = variant->max_register, From 022bfe69575d2d3ba39172b05c1162fd41c7f2b5 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 5 Mar 2026 13:35:43 -0600 Subject: [PATCH 04/52] rtc: rs5c372: Remove use of i2c_match_id() The function i2c_match_id() is used to fetch the matching ID from the i2c_device_id table. This is often used to then retrieve the matching driver_data. This can be done in one step with the helper i2c_get_match_data(). This helper has a couple other benefits: * It doesn't need the i2c_device_id passed in so we do not need to have that forward declared, allowing us to remove those or move the i2c_device_id table down to its more natural spot with the other module info. * It also checks for device match data, which allows for OF and ACPI based probing. That means we do not have to manually check those first and can remove those checks. Signed-off-by: Andrew Davis Link: https://patch.msgid.link/20260305193545.796294-5-afd@ti.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rs5c372.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index f8fab0205f8c..936f4f05c8c7 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -825,12 +825,7 @@ static int rs5c372_probe(struct i2c_client *client) rs5c372->client = client; i2c_set_clientdata(client, rs5c372); - if (client->dev.of_node) { - rs5c372->type = (uintptr_t)of_device_get_match_data(&client->dev); - } else { - const struct i2c_device_id *id = i2c_match_id(rs5c372_id, client); - rs5c372->type = id->driver_data; - } + rs5c372->type = (uintptr_t)i2c_get_match_data(client); /* we read registers 0x0f then 0x00-0x0f; skip the first one */ rs5c372->regs = &rs5c372->buf[1]; From c79e6131b17eb574ce2d065995a81c933616f880 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 5 Mar 2026 13:35:44 -0600 Subject: [PATCH 05/52] rtc: rv8803: Remove use of i2c_match_id() The function i2c_match_id() is used to fetch the matching ID from the i2c_device_id table. This is often used to then retrieve the matching driver_data. This can be done in one step with the helper i2c_get_match_data(). This helper has a couple other benefits: * It doesn't need the i2c_device_id passed in so we do not need to have that forward declared, allowing us to remove those or move the i2c_device_id table down to its more natural spot with the other module info. * It also checks for device match data, which allows for OF and ACPI based probing. That means we do not have to manually check those first and can remove those checks. Signed-off-by: Andrew Davis Link: https://patch.msgid.link/20260305193545.796294-6-afd@ti.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rv8803.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 4e9e04cbec89..2bf988a89fd7 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -667,13 +667,7 @@ static int rv8803_probe(struct i2c_client *client) mutex_init(&rv8803->flags_lock); rv8803->client = client; - if (client->dev.of_node) { - rv8803->type = (uintptr_t)of_device_get_match_data(&client->dev); - } else { - const struct i2c_device_id *id = i2c_match_id(rv8803_id, client); - - rv8803->type = id->driver_data; - } + rv8803->type = (uintptr_t)i2c_get_match_data(client); i2c_set_clientdata(client, rv8803); flags = rv8803_read_reg(client, RV8803_FLAG); From fbae853a00b472d905175a6844b74d0eb3526d4b Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 5 Mar 2026 13:35:45 -0600 Subject: [PATCH 06/52] rtc: rx8025: Remove use of i2c_match_id() The function i2c_match_id() is used to fetch the matching ID from the i2c_device_id table. This is often used to then retrieve the matching driver_data. This can be done in one step with the helper i2c_get_match_data(). This helper has a couple other benefits: * It doesn't need the i2c_device_id passed in so we do not need to have that forward declared, allowing us to remove those or move the i2c_device_id table down to its more natural spot with the other module info. * It also checks for device match data, which allows for OF and ACPI based probing. That means we do not have to manually check those first and can remove those checks. Signed-off-by: Andrew Davis Link: https://patch.msgid.link/20260305193545.796294-7-afd@ti.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index ced6e7adfe8d..c57081f9e02b 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -522,7 +522,6 @@ static const struct attribute_group rx8025_attr_group = { static int rx8025_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_match_id(rx8025_id, client); struct i2c_adapter *adapter = client->adapter; struct rx8025_data *rx8025; int err = 0; @@ -540,8 +539,7 @@ static int rx8025_probe(struct i2c_client *client) i2c_set_clientdata(client, rx8025); - if (id) - rx8025->model = id->driver_data; + rx8025->model = (uintptr_t)i2c_get_match_data(client); err = rx8025_init_client(client); if (err) From cbf39bfd4bf938494dcc5f699e6bfa04e1916873 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Tue, 3 Mar 2026 16:36:33 +0000 Subject: [PATCH 07/52] dt-bindings: rtc: mpfs-rtc: permit resets The RTC on mpfs and pic64gx has a reset pin, but until now this has been undocumented because platform firmware takes the RTC out of reset on first-party boards (or those using modified versions of the vendor firmware), but not all boards may take this approach. Permit providing a reset in devicetree for Linux, or other devicetree-consuming software, to use. Signed-off-by: Conor Dooley Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260303-flounder-slate-dd69766990ce@spud Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/microchip,mpfs-rtc.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/microchip,mpfs-rtc.yaml b/Documentation/devicetree/bindings/rtc/microchip,mpfs-rtc.yaml index a3e60d9f8399..e26e92b1af03 100644 --- a/Documentation/devicetree/bindings/rtc/microchip,mpfs-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/microchip,mpfs-rtc.yaml @@ -47,6 +47,9 @@ properties: - const: rtc - const: rtcref + resets: + maxItems: 1 + required: - compatible - reg From 0d65a9d93d870ef3d13642f88d0e6d562790c96d Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Thu, 12 Mar 2026 10:52:58 +0200 Subject: [PATCH 08/52] rtc: max77686: convert to i2c_new_ancillary_device Convert RTC I2C device creation from devm_i2c_new_dummy_device() to i2c_new_ancillary_device() to enable the use of a device tree-specified RTC address instead of a hardcoded value. If the device tree does not provide an address, use hardcoded values as a fallback. This addresses an issue with the MAX77663 PMIC, which can have the RTC at different I2C positions (either 0x48, like the MAX77714, or 0x68, like the MAX77620). The MAX77620 value is used as the default. The I2C position of the MAX77663 is factory-set and cannot be detected from the chip itself. Signed-off-by: Svyatoslav Ryhel Link: https://patch.msgid.link/20260312085258.11431-6-clamor95@gmail.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-max77686.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 69ea3ce75b5a..3cdfd78a07cc 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -686,6 +686,11 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info) return ret; } +static void max77686_rtc_release_dev(void *client) +{ + i2c_unregister_device(client); +} + static int max77686_init_rtc_regmap(struct max77686_rtc_info *info) { struct device *parent = info->dev->parent; @@ -713,12 +718,17 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info) goto add_rtc_irq; } - client = devm_i2c_new_dummy_device(info->dev, parent_i2c->adapter, - info->drv_data->rtc_i2c_addr); + client = i2c_new_ancillary_device(parent_i2c, "rtc", + info->drv_data->rtc_i2c_addr); if (IS_ERR(client)) return dev_err_probe(info->dev, PTR_ERR(client), "Failed to allocate I2C device for RTC\n"); + ret = devm_add_action_or_reset(info->dev, max77686_rtc_release_dev, + client); + if (ret) + return ret; + info->rtc_regmap = devm_regmap_init_i2c(client, info->drv_data->regmap_config); if (IS_ERR(info->rtc_regmap)) From 10663044bee592ba049a2aa37f4431fbdf93b739 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Mon, 9 Mar 2026 09:57:42 +0100 Subject: [PATCH 09/52] dt-bindings: rtc: microcrystal,rv3028: Allow to specify vdd-supply In case the VDD supply voltage regulator of the RTC needs to be specified explicitly, allow to set vdd-supply. Signed-off-by: Frieder Schrempf Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260309085749.25747-2-frieder@fris.de Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml b/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml index cda8ad7c1203..2ea3b4041953 100644 --- a/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml +++ b/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml @@ -32,6 +32,8 @@ properties: - 9000 - 15000 + vdd-supply: true + required: - compatible - reg From 5ff89ef425d17a43b1a48173482f8bfe2ce4fcd1 Mon Sep 17 00:00:00 2001 From: Piyush Patle Date: Sat, 28 Feb 2026 00:21:15 +0530 Subject: [PATCH 10/52] dt-bindings: rtc: isl12026: convert to YAML schema Convert the ISL12026 RTC binding from text format to YAML schema. Remove the legacy text binding. The new schema enables dtbs_check validation. Signed-off-by: Piyush Patle Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260227185115.174997-1-piyushpatle228@gmail.com Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/isil,isl12026.txt | 28 --------- .../bindings/rtc/isil,isl12026.yaml | 59 +++++++++++++++++++ 2 files changed, 59 insertions(+), 28 deletions(-) delete mode 100644 Documentation/devicetree/bindings/rtc/isil,isl12026.txt create mode 100644 Documentation/devicetree/bindings/rtc/isil,isl12026.yaml diff --git a/Documentation/devicetree/bindings/rtc/isil,isl12026.txt b/Documentation/devicetree/bindings/rtc/isil,isl12026.txt deleted file mode 100644 index 2e0be45193bb..000000000000 --- a/Documentation/devicetree/bindings/rtc/isil,isl12026.txt +++ /dev/null @@ -1,28 +0,0 @@ -ISL12026 I2C RTC/EEPROM - -ISL12026 is an I2C RTC/EEPROM combination device. The RTC and control -registers respond at bus address 0x6f, and the EEPROM array responds -at bus address 0x57. The canonical "reg" value will be for the RTC portion. - -Required properties supported by the device: - - - "compatible": must be "isil,isl12026" - - "reg": I2C bus address of the device (always 0x6f) - -Optional properties: - - - "isil,pwr-bsw": If present PWR.BSW bit must be set to the specified - value for proper operation. - - - "isil,pwr-sbib": If present PWR.SBIB bit must be set to the specified - value for proper operation. - - -Example: - - rtc@6f { - compatible = "isil,isl12026"; - reg = <0x6f>; - isil,pwr-bsw = <0>; - isil,pwr-sbib = <1>; - } diff --git a/Documentation/devicetree/bindings/rtc/isil,isl12026.yaml b/Documentation/devicetree/bindings/rtc/isil,isl12026.yaml new file mode 100644 index 000000000000..152edce2ab41 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/isil,isl12026.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/isil,isl12026.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Intersil ISL12026 I2C RTC/EEPROM + +maintainers: + - Piyush Patle + +description: + The ISL12026 is a combination RTC and EEPROM device connected via I2C. + The RTC and control registers respond at address 0x6f, while the EEPROM + array responds at address 0x57. The "reg" property refers to the RTC + portion of the device. + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + const: isil,isl12026 + + reg: + maxItems: 1 + description: I2C address of the RTC portion (must be 0x6f) + + isil,pwr-bsw: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1 ] + description: + Value written to the PWR.BSW bit for proper device operation. + + isil,pwr-sbib: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1 ] + description: + Value written to the PWR.SBIB bit for proper device operation. + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + rtc@6f { + compatible = "isil,isl12026"; + reg = <0x6f>; + isil,pwr-bsw = <0>; + isil,pwr-sbib = <1>; + }; + }; From 5827fe59745dc717e878177f104f0c1a96cfcb7f Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Wed, 4 Mar 2026 14:53:29 -0800 Subject: [PATCH 11/52] rtc: armada38x: zalloc + calloc to single allocation Use a flexible array member to simplify allocation. Signed-off-by: Rosen Penev Reviewed-by: Gregory CLEMENT Link: https://patch.msgid.link/20260304225329.24510-1-rosenp@gmail.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-armada38x.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index 713fa0d077cd..245290ae1a8d 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -72,8 +72,8 @@ struct armada38x_rtc { spinlock_t lock; int irq; bool initialized; - struct value_to_freq *val_to_freq; const struct armada38x_rtc_data *data; + struct value_to_freq val_to_freq[]; }; #define ALARM1 0 @@ -490,18 +490,13 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev) { struct armada38x_rtc *rtc; - rtc = devm_kzalloc(&pdev->dev, sizeof(struct armada38x_rtc), + rtc = devm_kzalloc(&pdev->dev, struct_size(rtc, val_to_freq, SAMPLE_NR), GFP_KERNEL); if (!rtc) return -ENOMEM; rtc->data = of_device_get_match_data(&pdev->dev); - rtc->val_to_freq = devm_kcalloc(&pdev->dev, SAMPLE_NR, - sizeof(struct value_to_freq), GFP_KERNEL); - if (!rtc->val_to_freq) - return -ENOMEM; - spin_lock_init(&rtc->lock); rtc->regs = devm_platform_ioremap_resource_byname(pdev, "rtc"); From b47bcab6ee92d5ca6ba55c06b9a503e2663e942f Mon Sep 17 00:00:00 2001 From: Mauricio Faria de Oliveira Date: Tue, 17 Mar 2026 20:22:16 -0300 Subject: [PATCH 12/52] rtc: add data_race() in rtc_dev_poll() The unlocked read of rtc->irq_data in rtc_dev_poll() can race with the write in rtc_handle_legacy_irq() and also, theoretically, with the write in rtc_dev_read(). These races should be safe (see inline comment), thus annotate the read with data_race() for KCSAN. Reported-by: syzbot+2d4127acca35ed7b31ad@syzkaller.appspotmail.com Closes: https://syzbot.org/bug?extid=2d4127acca35ed7b31ad Signed-off-by: Mauricio Faria de Oliveira Link: https://patch.msgid.link/20260317-irq_data-v1-1-a2741002be60@igalia.com Signed-off-by: Alexandre Belloni --- drivers/rtc/dev.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c index baf1a8ca8b2b..8ba7c25d2565 100644 --- a/drivers/rtc/dev.c +++ b/drivers/rtc/dev.c @@ -195,7 +195,16 @@ static __poll_t rtc_dev_poll(struct file *file, poll_table *wait) poll_wait(file, &rtc->irq_queue, wait); - data = rtc->irq_data; + /* + * This read can race with the write in rtc_handle_legacy_irq(). + * + * - If this check misses a zero to non-zero transition the next check + * will pick it up (rtc_handle_legacy_irq() wakes up rtc->irq_queue). + * - Non-zero to non-zero transition misses do not change return value. + * - And a non-zero to zero transition is unlikely to be missed, since + * it occurs on rtc_dev_read(), during which polling is not expected. + */ + data = data_race(rtc->irq_data); return (data != 0) ? (EPOLLIN | EPOLLRDNORM) : 0; } From 3177779ae17db4c66c851f799505fb95c7530c03 Mon Sep 17 00:00:00 2001 From: Jori Koolstra Date: Fri, 6 Mar 2026 19:33:17 +0100 Subject: [PATCH 13/52] virt: coco: change tsm_class to a const struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The class_create() call has been deprecated in favor of class_register() as the driver core now allows for a struct class to be in read-only memory. Change tsm_class to be a const struct class and drop the class_create() call. Compile tested only. Link: https://lore.kernel.org/all/2023040244-duffel-pushpin-f738@gregkh/ Changes with v1: - Removed redundant int err variable. Suggested-by: Greg Kroah-Hartman Signed-off-by: Jori Koolstra Reviewed-by: Thomas Weißschuh Link: https://patch.msgid.link/20260306183325.245254-1-jkoolstra@xs4all.nl Signed-off-by: Dan Williams --- drivers/virt/coco/tsm-core.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/virt/coco/tsm-core.c b/drivers/virt/coco/tsm-core.c index 98dcf7d836df..e784993353d8 100644 --- a/drivers/virt/coco/tsm-core.c +++ b/drivers/virt/coco/tsm-core.c @@ -9,7 +9,11 @@ #include #include -static struct class *tsm_class; +static void tsm_release(struct device *); +static const struct class tsm_class = { + .name = "tsm", + .dev_release = tsm_release +}; static DEFINE_IDA(tsm_ida); static int match_id(struct device *dev, const void *data) @@ -22,7 +26,7 @@ static int match_id(struct device *dev, const void *data) struct tsm_dev *find_tsm_dev(int id) { - struct device *dev = class_find_device(tsm_class, NULL, &id, match_id); + struct device *dev = class_find_device(&tsm_class, NULL, &id, match_id); if (!dev) return NULL; @@ -46,7 +50,7 @@ static struct tsm_dev *alloc_tsm_dev(struct device *parent) tsm_dev->id = id; dev = &tsm_dev->dev; dev->parent = parent; - dev->class = tsm_class; + dev->class = &tsm_class; device_initialize(dev); return no_free_ptr(tsm_dev); @@ -114,18 +118,13 @@ static void tsm_release(struct device *dev) static int __init tsm_init(void) { - tsm_class = class_create("tsm"); - if (IS_ERR(tsm_class)) - return PTR_ERR(tsm_class); - - tsm_class->dev_release = tsm_release; - return 0; + return class_register(&tsm_class); } module_init(tsm_init) static void __exit tsm_exit(void) { - class_destroy(tsm_class); + class_unregister(&tsm_class); } module_exit(tsm_exit) From b2b0dcaa28d2d7389e5845285a50d0151dd6c017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Pfl=C3=BCger?= Date: Sun, 29 Mar 2026 09:27:45 +0200 Subject: [PATCH 14/52] dt-bindings: rtc: sc2731: Add compatible for SC2730 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RTC block found in the SC2730 PMIC is compatible with the one found in the SC2731 PMIC. Acked-by: Rob Herring (Arm) Signed-off-by: Otto Pflüger Link: https://patch.msgid.link/20260329-sc27xx-mfd-cells-v3-1-9158dee41f74@abscue.de Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/sprd,sc2731-rtc.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/rtc/sprd,sc2731-rtc.yaml b/Documentation/devicetree/bindings/rtc/sprd,sc2731-rtc.yaml index 5756f617df36..1deae2f4f09d 100644 --- a/Documentation/devicetree/bindings/rtc/sprd,sc2731-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/sprd,sc2731-rtc.yaml @@ -13,7 +13,12 @@ maintainers: properties: compatible: - const: sprd,sc2731-rtc + oneOf: + - items: + - enum: + - sprd,sc2730-rtc + - const: sprd,sc2731-rtc + - const: sprd,sc2731-rtc reg: maxItems: 1 From d1b091aaba8c6a61950ac8bd15be61418f8dbf88 Mon Sep 17 00:00:00 2001 From: Anushka Badhe Date: Wed, 25 Mar 2026 15:00:03 +0530 Subject: [PATCH 15/52] dt-bindings: rtc: add olpc,xo1-rtc to trivial-rtc Add the OLPC XO-1 RTC compatible string to the trivial-rtc schema instead of creating a standalone binding file, as it only requires a compatible property with no additional configuration. Signed-off-by: Anushka Badhe Acked-by: Conor Dooley Link: https://patch.msgid.link/20260325093003.44051-1-anushkabadhe@gmail.com Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/olpc-xo1-rtc.txt | 5 ----- Documentation/devicetree/bindings/rtc/trivial-rtc.yaml | 2 ++ 2 files changed, 2 insertions(+), 5 deletions(-) delete mode 100644 Documentation/devicetree/bindings/rtc/olpc-xo1-rtc.txt diff --git a/Documentation/devicetree/bindings/rtc/olpc-xo1-rtc.txt b/Documentation/devicetree/bindings/rtc/olpc-xo1-rtc.txt deleted file mode 100644 index a2891ceb6344..000000000000 --- a/Documentation/devicetree/bindings/rtc/olpc-xo1-rtc.txt +++ /dev/null @@ -1,5 +0,0 @@ -OLPC XO-1 RTC -~~~~~~~~~~~~~ - -Required properties: - - compatible : "olpc,xo1-rtc" diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml index b47822370d6f..722176c831aa 100644 --- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml @@ -65,6 +65,8 @@ properties: - microcrystal,rv3029 # Real Time Clock - microcrystal,rv8523 + # OLPC XO-1 RTC + - olpc,xo1-rtc # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC - ricoh,r2025sd # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC From e9f850ba66cdf6b77fb4f005e46c4b605c4de434 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 4 Mar 2026 13:55:43 +0100 Subject: [PATCH 16/52] rtc: cmos: Use platform_get_irq_optional() in cmos_platform_probe() The rtc-cmos driver can live without an IRQ and returning an error code from platform_get_irq() is not a problem for it in general, so make it call platform_get_irq_optional() in cmos_platform_probe() instead of platform_get_irq() to avoid a confusing error message printed by the latter if an IRQ cannot be found for index 0, which is possible on x86 platforms. Additionally, on x86, if the IRQ is not defined and the system has a legacy PIC, hardcode it to RTC_IRQ, which should be safe then (and which is what the dropped PNP code did). Fixes: d15f1c2e413e ("ACPI: PNP: Drop CMOS RTC PNP device support") Reported-by: Nathan Chancellor Closes: https://lore.kernel.org/linux-acpi/20260303060752.GA2749263@ax162/ Tested-by: Nathan Chancellor Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/12857714.O9o76ZdvQC@rafael.j.wysocki Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 0743c6acd6e2..9cc1c3b53c4b 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -1493,9 +1493,18 @@ static int __init cmos_platform_probe(struct platform_device *pdev) resource = platform_get_resource(pdev, IORESOURCE_IO, 0); else resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (irq < 0) + irq = platform_get_irq_optional(pdev, 0); + if (irq < 0) { irq = -1; +#ifdef CONFIG_X86 + /* + * On some x86 systems, the IRQ is not defined, but it should + * always be safe to hardcode it on systems with a legacy PIC. + */ + if (nr_legacy_irqs()) + irq = RTC_IRQ; +#endif + } return cmos_do_probe(&pdev->dev, resource, irq); } From 0e9b12ee74c57617bb362deb3c82e35fe49694b5 Mon Sep 17 00:00:00 2001 From: Akashdeep Kaur Date: Fri, 13 Mar 2026 16:47:40 +0530 Subject: [PATCH 17/52] rtc: ti-k3: Add support to resume from IO DDR low power mode Restore the RTC HW context which may be lost when system enters certain low power mode (IO+DDR mode). Check if the RTC registers are locked which would indicate loss of context (reset) and restore the context as needed. Signed-off-by: Akashdeep Kaur Reviewed-by: Vignesh Raghavendra Link: https://patch.msgid.link/20260313111740.1492519-1-a-kaur@ti.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ti-k3.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-ti-k3.c b/drivers/rtc/rtc-ti-k3.c index ec759d8f7023..e801f5b9d757 100644 --- a/drivers/rtc/rtc-ti-k3.c +++ b/drivers/rtc/rtc-ti-k3.c @@ -640,10 +640,18 @@ static int __maybe_unused ti_k3_rtc_suspend(struct device *dev) static int __maybe_unused ti_k3_rtc_resume(struct device *dev) { struct ti_k3_rtc *priv = dev_get_drvdata(dev); + int ret = 0; + + if (k3rtc_check_unlocked(priv)) { + /* RTC locked implies low power mode exit where RTC loses context */ + ret = k3rtc_configure(dev); + if (ret) + return ret; + } if (device_may_wakeup(dev)) disable_irq_wake(priv->irq); - return 0; + return ret; } static SIMPLE_DEV_PM_OPS(ti_k3_rtc_pm_ops, ti_k3_rtc_suspend, ti_k3_rtc_resume); From 095a3e886dd250acc9ff692f8fcc296f0023a5c6 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Sun, 22 Feb 2026 18:30:51 -0500 Subject: [PATCH 18/52] rtc: pic32: allow driver to be compiled with COMPILE_TEST This driver currently only supports builds against a PIC32 target. Now that commit ed65ae9f6c6b ("rtc: pic32: update include to use pic32.h from platform_data") is merged, it's possible to compile this driver on other architectures. To avoid future breakage of this driver in the future, let's update the Kconfig so that it can be built with COMPILE_TEST enabled on all architectures. Signed-off-by: Brian Masney Link: https://patch.msgid.link/20260222-rtc-pic32-v1-1-3f8eb654a34d@redhat.com Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index b46ac73a2124..364afc73f8ab 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1986,7 +1986,7 @@ config RTC_DRV_XGENE config RTC_DRV_PIC32 tristate "Microchip PIC32 RTC" - depends on MACH_PIC32 + depends on MACH_PIC32 || COMPILE_TEST default y help If you say yes here you get support for the PIC32 RTC module. From 30c4d2f26bb3538c328035cea2e6265c8320539e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 7 Apr 2026 14:27:17 +0200 Subject: [PATCH 19/52] rtc: ntxec: fix OF node reference imbalance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver reuses the OF node of the parent multi-function device but fails to take another reference to balance the one dropped by the platform bus code when unbinding the MFD and deregistering the child devices. Fix this by using the intended helper for reusing OF nodes. Fixes: 435af89786c6 ("rtc: New driver for RTC in Netronix embedded controller") Cc: stable@vger.kernel.org # 5.13 Cc: Jonathan Neuschäfer Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260407122717.2676774-1-johan@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ntxec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-ntxec.c b/drivers/rtc/rtc-ntxec.c index 850ca49186fd..d28ddb34e19e 100644 --- a/drivers/rtc/rtc-ntxec.c +++ b/drivers/rtc/rtc-ntxec.c @@ -110,7 +110,7 @@ static int ntxec_rtc_probe(struct platform_device *pdev) struct rtc_device *dev; struct ntxec_rtc *rtc; - pdev->dev.of_node = pdev->dev.parent->of_node; + device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); if (!rtc) From 0fedce7244e4b85c049ce579c87e298a1b0b811d Mon Sep 17 00:00:00 2001 From: "Anthony Pighin (Nokia)" Date: Tue, 25 Nov 2025 18:00:10 +0000 Subject: [PATCH 20/52] rtc: abx80x: Disable alarm feature if no interrupt attached Commit 795cda8338ea ("rtc: interface: Fix long-standing race when setting alarm") exposed an issue where the rtc-abx80x driver does not clear the alarm feature bit, but instead relies on the set_alarm operation to return invalid. For example, when a RTC_UIE_ON ioctl is handled, it should abort at the feature validation. Instead, it proceeds to the rtc_timer_enqueue(), which used to return an error from the set_alarm call. However, following the race condition handling, which likely should not be discarding predecing errors, a success condition is returned to the ioctl() caller. This results in (for example): hwclock: select() to /dev/rtc0 to wait for clock tick timed out Notwithstanding the validity of the race condition handling, if an interrupt wasn't specified, or could not be attached, the driver should clear the alarm feature bit. Fixes: 718a820a303c ("rtc: abx80x: add alarm support") Signed-off-by: Anthony Pighin Link: https://patch.msgid.link/BN0PR08MB69510928028C933749F4139383D1A@BN0PR08MB6951.namprd08.prod.outlook.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-abx80x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index eca09872ea97..00d7de64ed3e 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -932,6 +932,8 @@ static int abx80x_probe(struct i2c_client *client) client->irq = 0; } } + if (client->irq <= 0) + clear_bit(RTC_FEATURE_ALARM, priv->rtc->features); err = rtc_add_group(priv->rtc, &rtc_calib_attr_group); if (err) { From 2452dcf4d740effff5aa71b7f6529ee8c04fd8f6 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Thu, 2 Apr 2026 16:51:16 +0200 Subject: [PATCH 21/52] kbuild: builddeb - avoid recompiles for non-cross-compiles Commit e2c318225ac1 ("kbuild: deb-pkg: add pkg.linux-upstream.nokernelheaders build profile") changed how install-extmod-build gets called, making it always rebuild the host programs below scripts/ if HOSTCC wasn't specified with its full triplet on the make command line. That is, apparently, needed to fix up commit f1d87664b82a ("kbuild: cross-compile linux-headers package when possible") for cross-compiles. However, in the much more common case of non-cross-compile builds this will lead to unnecessary rebuilding of host tools including gcc plugins. This, in turn, will lead to a full kernel rebuild on the next 'make bindeb-pkg' which is unfortunate. Avoid that by only triggering the rebuild of host tools for actual cross-compile builds. Signed-off-by: Mathias Krause Fixes: e2c318225ac1 ("kbuild: deb-pkg: add pkg.linux-upstream.nokernelheaders build profile") Cc: Masahiro Yamada Reviewed-by: Nathan Chancellor Reviewed-by: Nicolas Schier Link: https://patch.msgid.link/20260402145116.1010901-1-minipli@grsecurity.net Signed-off-by: Nicolas Schier --- scripts/package/builddeb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 3627ca227e5a..ba1defc61652 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -139,7 +139,13 @@ install_kernel_headers () { pdir=debian/$1 version=${1#linux-headers-} - CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" + # Override $CC only for cross-compiles, to not unnecessarily rebuild + # scripts/ including plugins, which may lead to a full kernel rebuild. + if [ -n "${CROSS_COMPILE}" ]; then + CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" + else + "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" + fi mkdir -p $pdir/lib/modules/$version/ ln -s /usr/src/linux-headers-$version $pdir/lib/modules/$version/build From feffac1874820d501e51cd8dcee697063b792c82 Mon Sep 17 00:00:00 2001 From: Kaushlendra Kumar Date: Tue, 17 Mar 2026 16:36:15 +0530 Subject: [PATCH 22/52] tools/power/x86: Add SOC slider and platform profile support Add support for reading and writing SOC slider parameters and platform profile via sysfs in x86_energy_perf_policy. New command-line options: --soc-slider-balance --soc-slider-offset --platform-profile These options allow control of the processor thermal SOC slider balance and offset through the processor_thermal_soc_slider module, as well as the platform profile class interface. When no update flags are set, the tool now also prints the current SOC slider and platform profile values alongside existing MSR output. Signed-off-by: Kaushlendra Kumar Signed-off-by: Len Brown --- .../x86_energy_perf_policy.c | 132 +++++++++++++++++- 1 file changed, 130 insertions(+), 2 deletions(-) diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c index ac37132207a4..1f330c82d7c1 100644 --- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c +++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c @@ -92,8 +92,18 @@ unsigned int has_hwp_request_pkg; /* IA32_HWP_REQUEST_PKG */ unsigned int bdx_highest_ratio; +unsigned char update_soc_slider_balance; +unsigned char update_soc_slider_offset; +unsigned char update_platform_profile; +int soc_slider_balance; +int soc_slider_offset; +char platform_profile[64]; + #define PATH_TO_CPU "/sys/devices/system/cpu/" #define SYSFS_PATH_MAX 255 +#define PATH_SOC_SLIDER_BALANCE "/sys/module/processor_thermal_soc_slider/parameters/slider_balance" +#define PATH_SOC_SLIDER_OFFSET "/sys/module/processor_thermal_soc_slider/parameters/slider_offset" +#define PATH_PLATFORM_PROFILE "/sys/class/platform-profile/platform-profile-0/profile" static int use_android_msr_path; @@ -106,6 +116,7 @@ void usage(void) fprintf(stderr, "scope: --cpu cpu-list [--hwp-use-pkg #] | --pkg pkg-list\n"); fprintf(stderr, "field: --all | --epb | --hwp-epp | --hwp-min | --hwp-max | --hwp-desired\n"); fprintf(stderr, "other: --hwp-enable | --turbo-enable (0 | 1) | --help | --force\n"); + fprintf(stderr, "soc-slider: --soc-slider-balance # | --soc-slider-offset # | --platform-profile \n"); fprintf(stderr, "value: ( # | \"normal\" | \"performance\" | \"balance-performance\" | \"balance-power\"| \"power\")\n"); fprintf(stderr, "--hwp-window usec\n"); @@ -518,6 +529,23 @@ void for_packages(unsigned long long pkg_set, int (func)(int)) } } +static int parse_cmdline_int(const char *s, int *out) +{ + char *endp; + long val; + + val = strtol(s, &endp, 0); + if (endp == s || errno == ERANGE) + return -1; + if (*endp != '\0') + return -1; + if (val < INT_MIN || val > INT_MAX) + return -1; + + *out = (int)val; + return 0; +} + void print_version(void) { printf("x86_energy_perf_policy 2025.11.22 Len Brown \n"); @@ -546,12 +574,15 @@ void cmdline(int argc, char **argv) {"hwp-use-pkg", required_argument, 0, 'u'}, {"version", no_argument, 0, 'v'}, {"hwp-window", required_argument, 0, 'w'}, + {"soc-slider-balance", required_argument, 0, 'S'}, + {"soc-slider-offset", required_argument, 0, 'O'}, + {"platform-profile", required_argument, 0, 'F'}, {0, 0, 0, 0 } }; progname = argv[0]; - while ((opt = getopt_long_only(argc, argv, "+a:c:dD:E:e:f:m:M:rt:u:vw:", + while ((opt = getopt_long_only(argc, argv, "+a:c:dD:E:e:f:m:M:rt:u:vw::S:O:F:", long_options, &option_index)) != -1) { switch (opt) { case 'a': @@ -579,12 +610,23 @@ void cmdline(int argc, char **argv) case 'D': req_update.hwp_desired = parse_cmdline_hwp_desired(parse_optarg_string(optarg)); break; + case 'F': + if (strlen(optarg) >= sizeof(platform_profile)) + errx(1, "--platform-profile: value too long"); + strcpy(platform_profile, optarg); + update_platform_profile = 1; + break; case 'm': req_update.hwp_min = parse_cmdline_hwp_min(parse_optarg_string(optarg)); break; case 'M': req_update.hwp_max = parse_cmdline_hwp_max(parse_optarg_string(optarg)); break; + case 'O': + if (parse_cmdline_int(optarg, &soc_slider_offset)) + errx(1, "--soc-slider-offset: invalid value"); + update_soc_slider_offset = 1; + break; case 'p': parse_cmdline_pkg(optarg); break; @@ -594,6 +636,11 @@ void cmdline(int argc, char **argv) case 'r': /* v1 used -r to specify read-only mode, now the default */ break; + case 'S': + if (parse_cmdline_int(optarg, &soc_slider_balance)) + errx(1, "--soc-slider-balance: invalid value"); + update_soc_slider_balance = 1; + break; case 't': turbo_update_value = parse_cmdline_turbo(parse_optarg_string(optarg)); break; @@ -777,6 +824,31 @@ static unsigned int write_sysfs(const char *path, char *buf, size_t buflen) return (unsigned int) numwritten; } +static int sysfs_read_string(const char *path, char *buf, size_t buflen) +{ + unsigned int len; + size_t n; + + len = read_sysfs(path, buf, buflen); + if (!len) + return -1; + + n = strcspn(buf, "\n"); + buf[n] = '\0'; + return 0; +} + +static int sysfs_write_string(const char *path, const char *buf) +{ + char tmp[128]; + int len; + + len = snprintf(tmp, sizeof(tmp), "%s\n", buf); + if (len < 0 || len >= (int)sizeof(tmp)) + return -1; + return write_sysfs(path, tmp, (size_t)len + 1) ? 0 : -1; +} + void print_hwp_cap(int cpu, struct msr_hwp_cap *cap, char *str) { if (cpu != -1) @@ -900,6 +972,55 @@ static int set_epb_sysfs(int cpu, int val) return (int)val; } +static int soc_slider_available(void) +{ + if (access(PATH_SOC_SLIDER_BALANCE, R_OK) && + access(PATH_SOC_SLIDER_OFFSET, R_OK) && + access(PATH_PLATFORM_PROFILE, R_OK)) + return 0; + + return 1; +} + +static void print_soc_slider(void) +{ + char buf[64]; + + if (!soc_slider_available()) + return; + + if (sysfs_read_string(PATH_SOC_SLIDER_BALANCE, buf, sizeof(buf)) == 0) + printf("soc-slider-balance: %s\n", buf); + if (sysfs_read_string(PATH_SOC_SLIDER_OFFSET, buf, sizeof(buf)) == 0) + printf("soc-slider-offset: %s\n", buf); + if (sysfs_read_string(PATH_PLATFORM_PROFILE, buf, sizeof(buf)) == 0) + printf("platform-profile: %s\n", buf); +} + +static int update_soc_slider(void) +{ + char tmp[32]; + + if (update_soc_slider_balance) { + snprintf(tmp, sizeof(tmp), "%d", soc_slider_balance); + if (sysfs_write_string(PATH_SOC_SLIDER_BALANCE, tmp)) + err(1, "soc-slider-balance write failed"); + } + + if (update_soc_slider_offset) { + snprintf(tmp, sizeof(tmp), "%d", soc_slider_offset); + if (sysfs_write_string(PATH_SOC_SLIDER_OFFSET, tmp)) + err(1, "soc-slider-offset write failed"); + } + + if (update_platform_profile) { + if (sysfs_write_string(PATH_PLATFORM_PROFILE, platform_profile)) + err(1, "platform-profile write failed"); + } + + return 0; +} + int print_cpu_msrs(int cpu) { struct msr_hwp_request req; @@ -1604,10 +1725,14 @@ int main(int argc, char **argv) return -EINVAL; /* display information only, no updates to settings */ - if (!update_epb && !update_turbo && !hwp_update_enabled()) { + if (!update_epb && !update_turbo && !hwp_update_enabled() && + !update_soc_slider_balance && !update_soc_slider_offset && + !update_platform_profile) { if (cpu_selected_set) for_all_cpus_in_set(cpu_setsize, cpu_selected_set, print_cpu_msrs); + print_soc_slider(); + if (has_hwp_request_pkg) { if (pkg_selected_set == 0) pkg_selected_set = pkg_present_set; @@ -1628,5 +1753,8 @@ int main(int argc, char **argv) } else if (pkg_selected_set) for_packages(pkg_selected_set, update_hwp_request_pkg_msr); + if (update_soc_slider_balance || update_soc_slider_offset || update_platform_profile) + update_soc_slider(); + return 0; } From e6ffe09488e2010a04eb11e884cfee630e8c56a6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 16 Feb 2026 12:04:59 +0100 Subject: [PATCH 23/52] tpm: Make tcpci_pm_ops variable static const File-scope 'tcpci_pm_ops' is not used outside of this unit and is not modified anywhere, so make it static const to silence sparse warning: tcpci.c:1002:1: warning: symbol 'tcpci_pm_ops' was not declared. Should it be static? Signed-off-by: Krzysztof Kozlowski Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm2-cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 3a77be7ebf4a..e00f668f8c84 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -21,7 +21,7 @@ static bool disable_pcr_integrity; module_param(disable_pcr_integrity, bool, 0444); MODULE_PARM_DESC(disable_pcr_integrity, "Disable integrity protection of TPM2_PCR_Extend"); -struct tpm2_hash tpm2_hash_map[] = { +static const struct tpm2_hash tpm2_hash_map[] = { {HASH_ALGO_SHA1, TPM_ALG_SHA1}, {HASH_ALGO_SHA256, TPM_ALG_SHA256}, {HASH_ALGO_SHA384, TPM_ALG_SHA384}, From 48fe2cddc85c7849463bd01ae8b8c6b575ff508b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 23 Feb 2026 16:55:21 +0100 Subject: [PATCH 24/52] tpm_crb: Convert ACPI driver to a platform one In all cases in which a struct acpi_driver is used for binding a driver to an ACPI device object, a corresponding platform device is created by the ACPI core and that device is regarded as a proper representation of underlying hardware. Accordingly, a struct platform_driver should be used by driver code to bind to that device. There are multiple reasons why drivers should not bind directly to ACPI device objects [1]. Overall, it is better to bind drivers to platform devices than to their ACPI companions, so convert the tpm_crb ACPI driver to a platform one. While this is not expected to alter functionality, it changes sysfs layout and so it will be visible to user space. Link: https://lore.kernel.org/all/2396510.ElGaqSPkdT@rafael.j.wysocki/ [1] Signed-off-by: Rafael J. Wysocki Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 6c25305c256e..7d1377e8e616 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #ifdef CONFIG_ARM64 #include @@ -602,13 +603,13 @@ static u64 crb_fixup_cmd_size(struct device *dev, struct resource *io_res, return io_res->end - start + 1; } -static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, +static int crb_map_io(struct device *dev, struct crb_priv *priv, struct acpi_table_tpm2 *buf) { + struct acpi_device *device = ACPI_COMPANION(dev); struct list_head acpi_resource_list; struct resource iores_array[TPM_CRB_MAX_RESOURCES + 1] = { {0} }; void __iomem *iobase_array[TPM_CRB_MAX_RESOURCES] = {NULL}; - struct device *dev = &device->dev; struct resource *iores; void __iomem **iobase_ptr; int i; @@ -782,12 +783,13 @@ static int crb_map_pluton(struct device *dev, struct crb_priv *priv, return 0; } -static int crb_acpi_add(struct acpi_device *device) +static int crb_acpi_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct acpi_device *device = ACPI_COMPANION(dev); struct acpi_table_tpm2 *buf; struct crb_priv *priv; struct tpm_chip *chip; - struct device *dev = &device->dev; struct tpm2_crb_smc *crb_smc; struct tpm2_crb_ffa *crb_ffa; struct tpm2_crb_pluton *crb_pluton; @@ -867,7 +869,7 @@ static int crb_acpi_add(struct acpi_device *device) priv->sm = sm; priv->hid = acpi_device_hid(device); - rc = crb_map_io(device, priv, buf); + rc = crb_map_io(dev, priv, buf); if (rc) goto out; @@ -901,12 +903,9 @@ out: return rc; } -static void crb_acpi_remove(struct acpi_device *device) +static void crb_acpi_remove(struct platform_device *pdev) { - struct device *dev = &device->dev; - struct tpm_chip *chip = dev_get_drvdata(dev); - - tpm_chip_unregister(chip); + tpm_chip_unregister(platform_get_drvdata(pdev)); } static const struct dev_pm_ops crb_pm = { @@ -919,19 +918,17 @@ static const struct acpi_device_id crb_device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, crb_device_ids); -static struct acpi_driver crb_acpi_driver = { - .name = "tpm_crb", - .ids = crb_device_ids, - .ops = { - .add = crb_acpi_add, - .remove = crb_acpi_remove, - }, - .drv = { +static struct platform_driver crb_acpi_driver = { + .probe = crb_acpi_probe, + .remove = crb_acpi_remove, + .driver = { + .name = "tpm_crb_acpi", + .acpi_match_table = crb_device_ids, .pm = &crb_pm, }, }; -module_acpi_driver(crb_acpi_driver); +module_platform_driver(crb_acpi_driver); MODULE_AUTHOR("Jarkko Sakkinen "); MODULE_DESCRIPTION("TPM2 Driver"); MODULE_VERSION("0.1"); From bb7a4e3b5f96d75756dab6459f073d4b2eedc7a0 Mon Sep 17 00:00:00 2001 From: Ethan Luna Date: Wed, 8 Apr 2026 11:37:47 +0300 Subject: [PATCH 25/52] tpm: i2c: atmel: fix block comment formatting Multiple block comments in tpm_i2c_atmel.c placed the closing '*/' on the same line as the comment text. This violates the kernel's preferred comment style, which requires the closing delimiter to appear on its line. Fix the formatting to improve readability and resolve checkpatch warnings. Signed-off-by: Ethan Luna Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_i2c_atmel.c | 34 +++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c index 4f229656a8e2..9fd73049821f 100644 --- a/drivers/char/tpm/tpm_i2c_atmel.c +++ b/drivers/char/tpm/tpm_i2c_atmel.c @@ -31,9 +31,11 @@ struct priv_data { size_t len; - /* This is the amount we read on the first try. 25 was chosen to fit a + /* + * This is the amount we read on the first try. 25 was chosen to fit a * fair number of read responses in the buffer so a 2nd retry can be - * avoided in small message cases. */ + * avoided in small message cases. + */ u8 buffer[sizeof(struct tpm_header) + 25]; }; @@ -58,7 +60,9 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, if (status < 0) return status; - /* The upper layer does not support incomplete sends. */ + /* + * The upper layer does not support incomplete sends. + */ if (status != len) return -E2BIG; @@ -76,9 +80,11 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) if (priv->len == 0) return -EIO; - /* Get the message size from the message header, if we didn't get the + /* + * Get the message size from the message header, if we didn't get the * whole message in read_status then we need to re-read the - * message. */ + * message. + */ expected_len = be32_to_cpu(hdr->length); if (expected_len > count) return -ENOMEM; @@ -111,15 +117,19 @@ static u8 i2c_atmel_read_status(struct tpm_chip *chip) struct i2c_client *client = to_i2c_client(chip->dev.parent); int rc; - /* The TPM fails the I2C read until it is ready, so we do the entire + /* + * The TPM fails the I2C read until it is ready, so we do the entire * transfer here and buffer it locally. This way the common code can - * properly handle the timeouts. */ + * properly handle the timeouts. + */ priv->len = 0; memset(priv->buffer, 0, sizeof(priv->buffer)); - /* Once the TPM has completed the command the command remains readable - * until another command is issued. */ + /* + * Once the TPM has completed the command the command remains readable + * until another command is issued. + */ rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer)); dev_dbg(&chip->dev, "%s: sts=%d", __func__, rc); @@ -172,9 +182,11 @@ static int i2c_atmel_probe(struct i2c_client *client) dev_set_drvdata(&chip->dev, priv); - /* There is no known way to probe for this device, and all version + /* + * There is no known way to probe for this device, and all version * information seems to be read via TPM commands. Thus we rely on the - * TPM startup process in the common code to detect the device. */ + * TPM startup process in the common code to detect the device. + */ return tpm_chip_register(chip); } From 666c1a2ca603d8314231200bf8bbb3a81bd64c6b Mon Sep 17 00:00:00 2001 From: Gunnar Kudrjavets Date: Wed, 8 Apr 2026 12:00:27 +0300 Subject: [PATCH 26/52] tpm: Fix auth session leak in tpm2_get_random() error path When tpm_buf_fill_hmac_session() fails inside the do-while loop in tpm2_get_random(), the function returns directly after destroying the buffer, without ending the auth session via tpm2_end_auth_session(). This leaks the TPM auth session resource. All other error paths within the loop correctly reach the 'out' label which calls both tpm_buf_destroy() and tpm2_end_auth_session(). Fix this by replacing the early return with a goto to the existing 'out' label, which already handles both cleanup operations. The redundant tpm_buf_destroy() call is removed since 'out' takes care of it. Cc: stable@vger.kernel.org # v6.19+ Fixes: 6e9722e9a7bf ("tpm2-sessions: Fix out of range indexing in name_size") Signed-off-by: Gunnar Kudrjavets Reviewed-by: Justinien Bouron Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm2-cmd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index e00f668f8c84..b11e6fa8b740 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -295,10 +295,8 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) } tpm_buf_append_u16(&buf, num_bytes); err = tpm_buf_fill_hmac_session(chip, &buf); - if (err) { - tpm_buf_destroy(&buf); - return err; - } + if (err) + goto out; err = tpm_transmit_cmd(chip, &buf, offsetof(struct tpm2_get_random_out, From f0f75a3d98b7959a8677b6363e23190f3018636b Mon Sep 17 00:00:00 2001 From: Gunnar Kudrjavets Date: Wed, 15 Apr 2026 03:00:03 +0300 Subject: [PATCH 27/52] tpm2-sessions: Fix missing tpm_buf_destroy() in tpm2_read_public() tpm2_read_public() calls tpm_buf_init() but fails to call tpm_buf_destroy() on two exit paths, leaking a page allocation: 1. When name_size() returns an error (unrecognized hash algorithm), the function returns directly without destroying the buffer. 2. On the success path, the buffer is never destroyed before returning. All other error paths in the function correctly call tpm_buf_destroy() before returning. Fix both by adding the missing tpm_buf_destroy() calls. Cc: stable@vger.kernel.org # v6.19+ Fixes: bda1cbf73c6e ("tpm2-sessions: Fix tpm2_read_public range checks") Signed-off-by: Gunnar Kudrjavets Reviewed-by: Justinien Bouron Reviewed-by: Paul Menzel Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm2-sessions.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c index 3b1cf1ca0420..c4da6fde748f 100644 --- a/drivers/char/tpm/tpm2-sessions.c +++ b/drivers/char/tpm/tpm2-sessions.c @@ -203,8 +203,10 @@ static int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name) rc = tpm_buf_read_u16(&buf, &offset); name_size_alg = name_size(&buf.data[offset]); - if (name_size_alg < 0) + if (name_size_alg < 0) { + tpm_buf_destroy(&buf); return name_size_alg; + } if (rc != name_size_alg) { tpm_buf_destroy(&buf); @@ -217,6 +219,7 @@ static int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name) } memcpy(name, &buf.data[offset], rc); + tpm_buf_destroy(&buf); return name_size_alg; } #endif /* CONFIG_TCG_TPM2_HMAC */ From c424d2664f08c77f08b4580b5f0cbaabf7c229b2 Mon Sep 17 00:00:00 2001 From: Gunnar Kudrjavets Date: Thu, 9 Apr 2026 17:20:54 +0000 Subject: [PATCH 28/52] tpm: Use kfree_sensitive() to free auth session in tpm_dev_release() tpm_dev_release() uses plain kfree() to free chip->auth, which contains sensitive cryptographic material including HMAC session keys, nonces, and passphrase data (struct tpm2_auth). Every other code path that frees this structure uses kfree_sensitive() to zero the memory before releasing it: both tpm2_end_auth_session() and tpm_buf_check_hmac_response() do so. The tpm_dev_release() path is the only one that does not, leaving key material in freed slab memory until it is eventually overwritten. Use kfree_sensitive() for consistency with the rest of the driver and to ensure session keys are scrubbed during device teardown. Cc: stable@vger.kernel.org # v6.10+ Fixes: 699e3efd6c64 ("tpm: Add HMAC session start and end functions") Signed-off-by: Gunnar Kudrjavets Reviewed-by: Justinien Bouron Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-chip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 0719577e584d..12b7394b34bd 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -247,7 +247,7 @@ static void tpm_dev_release(struct device *dev) kfree(chip->work_space.context_buf); kfree(chip->work_space.session_buf); #ifdef CONFIG_TCG_TPM2_HMAC - kfree(chip->auth); + kfree_sensitive(chip->auth); #endif kfree(chip); } From 6f1d4d2ecfcd1b577dc87350ea965fe81f272e83 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 22 Mar 2024 14:22:48 +0100 Subject: [PATCH 29/52] tpm: avoid -Wunused-but-set-variable Outside of the EFI tpm code, the TPM_MEMREMAP()/TPM_MEMUNMAP functions are defined as trivial macros, leading to the mapping_size variable ending up unused: In file included from drivers/char/tpm/tpm-sysfs.c:16: In file included from drivers/char/tpm/tpm.h:28: include/linux/tpm_eventlog.h:167:6: error: variable 'mapping_size' set but not used [-Werror,-Wunused-but-set-variable] 167 | int mapping_size; Turn the stubs into inline functions to avoid this warning. Cc: stable@vger.kernel.org # v5.3+ Fixes: c46f3405692d ("tpm: Reserve the TPM final events table") Signed-off-by: Arnd Bergmann Reviewed-by: Thorsten Blum Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- include/linux/tpm_eventlog.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/linux/tpm_eventlog.h b/include/linux/tpm_eventlog.h index 891368e82558..aff8ea2fa98e 100644 --- a/include/linux/tpm_eventlog.h +++ b/include/linux/tpm_eventlog.h @@ -131,11 +131,16 @@ struct tcg_algorithm_info { }; #ifndef TPM_MEMREMAP -#define TPM_MEMREMAP(start, size) NULL +static inline void *TPM_MEMREMAP(unsigned long start, size_t size) +{ + return NULL; +} #endif #ifndef TPM_MEMUNMAP -#define TPM_MEMUNMAP(start, size) do{} while(0) +static inline void TPM_MEMUNMAP(void *mapping, size_t size) +{ +} #endif /** From 0471921e2d1043dcc6de5cffb49dd37709521abe Mon Sep 17 00:00:00 2001 From: Jacqueline Wong Date: Wed, 15 Apr 2026 16:00:05 +0000 Subject: [PATCH 30/52] tpm: tpm_tis: add error logging for data transfer Add logging to more easily determine reason for transmit failure Cc: stable@vger.kernel.org # v6.6+ Fixes: 280db21e153d8 ("tpm_tis: Resend command to recover from data transfer errors") Signed-off-by: Jacqueline Wong Signed-off-by: Jordan Hand Link: https://lore.kernel.org/r/20260415160006.2275325-2-jacqwong@google.com Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index e2a1769081b1..acb91bf1e5f5 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -471,6 +471,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len) status = tpm_tis_status(chip); if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) { rc = -EIO; + dev_err(&chip->dev, "TPM_STS_DATA_EXPECT should be set. sts = 0x%08x\n", + status); goto out_err; } } @@ -491,6 +493,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len) status = tpm_tis_status(chip); if (!itpm && (status & TPM_STS_DATA_EXPECT) != 0) { rc = -EIO; + dev_err(&chip->dev, "TPM_STS_DATA_EXPECT should be unset. sts = 0x%08x\n", + status); goto out_err; } From 949692da7211572fac419b2986b6abc0cd1aeb76 Mon Sep 17 00:00:00 2001 From: Jacqueline Wong Date: Wed, 15 Apr 2026 16:00:06 +0000 Subject: [PATCH 31/52] tpm: tpm_tis: stop transmit if retries are exhausted tpm_tis_send_main() will attempt to retry sending data TPM_RETRY times. Currently, if those retries are exhausted, the driver will attempt to call execute. The TPM will be in the wrong state, leading to the operation simply timing out. Instead, if there is still an error after retries are exhausted, return that error immediately. Cc: stable@vger.kernel.org # v6.6+ Fixes: 280db21e153d8 ("tpm_tis: Resend command to recover from data transfer errors") Signed-off-by: Jacqueline Wong Signed-off-by: Jordan Hand Link: https://lore.kernel.org/r/20260415160006.2275325-3-jacqwong@google.com Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis_core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index acb91bf1e5f5..21d79ad3b164 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -556,11 +556,16 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len) break; else if (rc != -EAGAIN && rc != -EIO) /* Data transfer failed, not recoverable */ - return rc; + goto out_err; usleep_range(priv->timeout_min, priv->timeout_max); } + if (rc == -EAGAIN || rc == -EIO) { + dev_err(&chip->dev, "Exhausted %d tpm_tis_send_data retries\n", TPM_RETRY); + goto out_err; + } + /* go and do it */ rc = tpm_tis_write8(priv, TPM_STS(priv->locality), TPM_STS_GO); if (rc < 0) From 3ae6bafa104d93ddc525b8de547bf66b43fcaf10 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Tue, 21 Apr 2026 17:26:33 -0400 Subject: [PATCH 32/52] tools/power turbostat: Fix AMD RAPL regression on big systems turbostat.c:8688: rapl_perf_init: Assertion `next_domain < num_domains' failed. The initial fix for this regression was incomplete, as it did not handle multi-package systems with sparse core ids. Fixes: ef0e60083f76 ("tools/power turbostat: Fix AMD RAPL regression") Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index e9e8ef72395a..bea574d7aa68 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -5155,7 +5155,7 @@ static inline int get_rapl_num_domains(void) if (!platform->has_per_core_rapl) return topo.num_packages; - return topo.num_cores; + return GLOBAL_CORE_ID(topo.max_core_id, topo.num_packages) + 1; } static inline int get_rapl_domain_id(int cpu) From 869b93ba04088713596e68453c1146f52f713290 Mon Sep 17 00:00:00 2001 From: Yuho Choi Date: Sun, 19 Apr 2026 21:01:18 -0400 Subject: [PATCH 33/52] fbdev: offb: fix PCI device reference leak on probe failure offb_init_nodriver() gets a referenced PCI device with pci_get_device(). If pci_enable_device() fails, the function returns without dropping that reference. Release the PCI device reference before returning from the pci_enable_device() failure path. Fixes: 5bda8f7b5468 ("video: fbdev: offb: Call pci_enable_device() before using the PCI VGA device") Co-developed-by: Myeonghun Pak Signed-off-by: Myeonghun Pak Co-developed-by: Ijae Kim Signed-off-by: Ijae Kim Co-developed-by: Taegyu Kim Signed-off-by: Taegyu Kim Signed-off-by: Yuho Choi Signed-off-by: Helge Deller --- drivers/video/fbdev/offb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c index f85428e13996..166b2dff36f5 100644 --- a/drivers/video/fbdev/offb.c +++ b/drivers/video/fbdev/offb.c @@ -640,8 +640,13 @@ static void offb_init_nodriver(struct platform_device *parent, struct device_nod vid = be32_to_cpup(vidp); did = be32_to_cpup(didp); pdev = pci_get_device(vid, did, NULL); - if (!pdev || pci_enable_device(pdev)) + if (!pdev) return; + + if (pci_enable_device(pdev)) { + pci_dev_put(pdev); + return; + } } #endif /* kludge for valkyrie */ From 9b8a9a3a6f57edd02b7c8db14a316e6fab7fa772 Mon Sep 17 00:00:00 2001 From: Yuho Choi Date: Mon, 20 Apr 2026 01:19:26 -0400 Subject: [PATCH 34/52] fbdev: savage: fix probe-path EDID cleanup leaks When CONFIG_FB_SAVAGE_I2C is enabled, savagefb_probe() can build both an EDID-derived monspecs.modedb and a modelist from it before later failing. The normal success path frees monspecs.modedb after the initial mode selection, but the probe error path only deletes the I2C busses and misses the EDID-derived allocations. Free both the modelist and monspecs.modedb on the failed: unwind path. Co-developed-by: Myeonghun Pak Signed-off-by: Myeonghun Pak Co-developed-by: Ijae Kim Signed-off-by: Ijae Kim Co-developed-by: Taegyu Kim Signed-off-by: Taegyu Kim Signed-off-by: Yuho Choi Signed-off-by: Helge Deller --- drivers/video/fbdev/savage/savagefb_driver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c index ac41f8f37589..c2f79357c8da 100644 --- a/drivers/video/fbdev/savage/savagefb_driver.c +++ b/drivers/video/fbdev/savage/savagefb_driver.c @@ -2322,6 +2322,8 @@ static int savagefb_probe(struct pci_dev *dev, const struct pci_device_id *id) failed: #ifdef CONFIG_FB_SAVAGE_I2C savagefb_delete_i2c_busses(info); + fb_destroy_modelist(&info->modelist); + fb_destroy_modedb(info->monspecs.modedb); #endif fb_alloc_cmap(&info->cmap, 0, 0); savage_unmap_video(info); From b1aaf1110107dd17bee3618379cd35a816141c6c Mon Sep 17 00:00:00 2001 From: Ethan Carter Edwards Date: Sat, 18 Apr 2026 20:45:50 -0400 Subject: [PATCH 35/52] fbdev: atyfb: Fix spelling mistake "enfore" -> "enforce" Signed-off-by: Ethan Carter Edwards Signed-off-by: Helge Deller --- drivers/video/fbdev/aty/radeon_monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/aty/radeon_monitor.c b/drivers/video/fbdev/aty/radeon_monitor.c index df55e23b7a5a..621d13a1a1d9 100644 --- a/drivers/video/fbdev/aty/radeon_monitor.c +++ b/drivers/video/fbdev/aty/radeon_monitor.c @@ -654,7 +654,7 @@ static void radeon_fixup_panel_info(struct radeonfb_info *rinfo) { #ifdef CONFIG_PPC /* - * LCD Flat panels should use fixed dividers, we enfore that on + * LCD Flat panels should use fixed dividers, we enforce that on * PPC only for now... */ if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type == MT_LCD From d2386d9e3eb4c12f55f6131ab69cc65f13b5af80 Mon Sep 17 00:00:00 2001 From: Amit Barzilai Date: Mon, 20 Apr 2026 16:44:22 +0300 Subject: [PATCH 36/52] fbdev: cobalt_lcdfb: Request memory region Use devm_platform_get_and_ioremap_resource() instead of open-coding platform_get_resource() and devm_ioremap() separately. The helper requests the memory region before mapping it, which registers the range in /proc/iomem and prevents another driver from mapping the same registers. Assisted-by: Claude:claude-sonnet-4-6 Signed-off-by: Amit Barzilai Signed-off-by: Helge Deller --- drivers/video/fbdev/cobalt_lcdfb.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/video/fbdev/cobalt_lcdfb.c b/drivers/video/fbdev/cobalt_lcdfb.c index 308967b5096a..f7faa95fefd3 100644 --- a/drivers/video/fbdev/cobalt_lcdfb.c +++ b/drivers/video/fbdev/cobalt_lcdfb.c @@ -295,19 +295,13 @@ static int cobalt_lcdfb_probe(struct platform_device *dev) if (!info) return -ENOMEM; - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res) { + info->screen_base = devm_platform_get_and_ioremap_resource(dev, 0, &res); + if (IS_ERR(info->screen_base)) { framebuffer_release(info); - return -EBUSY; + return PTR_ERR(info->screen_base); } info->screen_size = resource_size(res); - info->screen_base = devm_ioremap(&dev->dev, res->start, - info->screen_size); - if (!info->screen_base) { - framebuffer_release(info); - return -ENOMEM; - } info->fbops = &cobalt_lcd_fbops; info->fix = cobalt_lcdfb_fix; From a40c0e815962b1f691d7ea12f7ddd42063c49f08 Mon Sep 17 00:00:00 2001 From: Amit Barzilai Date: Mon, 20 Apr 2026 16:44:23 +0300 Subject: [PATCH 37/52] fbdev: clps711x-fb: Request memory region for MMIO Use devm_platform_get_and_ioremap_resource() for resource 0 (the MMIO control register range) instead of open-coding platform_get_resource() and devm_ioremap() separately. The helper requests the memory region before mapping it, which registers the range in /proc/iomem and prevents another driver from mapping the same registers. This makes resource 0 consistent with resource 1 (the framebuffer), which already uses devm_platform_get_and_ioremap_resource(). Assisted-by: Claude:claude-sonnet-4-6 Signed-off-by: Amit Barzilai Signed-off-by: Helge Deller --- drivers/video/fbdev/clps711x-fb.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/video/fbdev/clps711x-fb.c b/drivers/video/fbdev/clps711x-fb.c index 5e61a349a4ab..7a7db7100499 100644 --- a/drivers/video/fbdev/clps711x-fb.c +++ b/drivers/video/fbdev/clps711x-fb.c @@ -216,12 +216,9 @@ static int clps711x_fb_probe(struct platform_device *pdev) cfb = info->par; platform_set_drvdata(pdev, info); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - goto out_fb_release; - cfb->base = devm_ioremap(dev, res->start, resource_size(res)); - if (!cfb->base) { - ret = -ENOMEM; + cfb->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(cfb->base)) { + ret = PTR_ERR(cfb->base); goto out_fb_release; } From 448aaf54d3ae1b73dfcf723c9f8a02c2116f3358 Mon Sep 17 00:00:00 2001 From: Hardik Phalet Date: Tue, 10 Mar 2026 12:30:27 +0000 Subject: [PATCH 38/52] fbdev: hgafb: Request memory region before ioremap The driver calls ioremap() on the HGA video memory at 0xb0000 without first reserving the physical address range. This leaves the kernel resource tree incomplete and can cause silent conflicts with other drivers claiming the same range. Add a devm_request_mem_region() call before ioremap() in hga_card_detect() to reserve the memory region. Signed-off-by: Hardik Phalet Reviewed-by: Thomas Zimmermann Signed-off-by: Helge Deller --- drivers/video/fbdev/hgafb.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/hgafb.c b/drivers/video/fbdev/hgafb.c index 14418aa3791a..d32fd1c5217c 100644 --- a/drivers/video/fbdev/hgafb.c +++ b/drivers/video/fbdev/hgafb.c @@ -276,7 +276,7 @@ static void hga_blank(int blank_mode) spin_unlock_irqrestore(&hga_reg_lock, flags); } -static int hga_card_detect(void) +static int hga_card_detect(struct platform_device *pdev) { int count = 0; void __iomem *p, *q; @@ -284,6 +284,11 @@ static int hga_card_detect(void) hga_vram_len = 0x08000; + if (!devm_request_mem_region(&pdev->dev, 0xb0000, hga_vram_len, "hgafb")) { + dev_err(&pdev->dev, "cannot reserve video memory at 0xb0000\n"); + return -EBUSY; + } + hga_vram = ioremap(0xb0000, hga_vram_len); if (!hga_vram) return -ENOMEM; @@ -568,7 +573,7 @@ static int hgafb_probe(struct platform_device *pdev) struct fb_info *info; int ret; - ret = hga_card_detect(); + ret = hga_card_detect(pdev); if (ret) return ret; From ce012c966b518c53475ba9a4e979242d7322d819 Mon Sep 17 00:00:00 2001 From: David Arcari Date: Tue, 21 Apr 2026 10:32:17 -0400 Subject: [PATCH 39/52] tools/power turbostat: Fix unrecognized option '-P' The '-P' short option (shorthand for --no-perf) is not present in the optstring of the second call to getopt_long_only(). This results in the "unrecognized option" error when the tool reaches the main parsing loop. Add 'P' to the second getopt_long_only() call to ensure it is consistently recognized. Fixes: a0e86c90b83c ("tools/power turbostat: Add --no-perf option") Signed-off-by: David Arcari Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index bea574d7aa68..d6b4fd17c5f3 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -11449,7 +11449,7 @@ void cmdline(int argc, char **argv) } optind = 0; - while ((opt = getopt_long_only(argc, argv, "+C:c:Dde:hi:Jn:N:o:qMST:v", long_options, &option_index)) != -1) { + while ((opt = getopt_long_only(argc, argv, "+C:c:Dde:hi:Jn:N:o:qMPST:v", long_options, &option_index)) != -1) { switch (opt) { case 'a': parse_add_command(optarg); From 2c52f942fcf21c8e09c7dac669fca591cec2692b Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 16 Apr 2026 16:17:31 -0400 Subject: [PATCH 40/52] tools/power turbostat: Fix --cpu-set 0 regression on HT systems "turbostat --cpu-set 0" appears to hang if cpu0 has an HT sibling. This is because the initialization code recognizes that it does not have to open perf files for the HT sibling, but the HT support in the collection code sees the HT sibling and tries to read from an uninitialized file descriptor, 0 (standard input). Access HT siblings only when they are in the allowed set. Fixes: a2b4d0f8bf07 ("tools/power turbostat: Favor cpu# over core#") Signed-off-by: Len Brown Reported-by: Artem Bityutskiy --- tools/power/x86/turbostat/turbostat.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index d6b4fd17c5f3..7f61f07ceb31 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -2427,11 +2427,17 @@ char *sys_lpi_file_debugfs = "/sys/kernel/debug/pmc_core/slp_s0_residency_usec"; int cpu_is_not_present(int cpu) { + if (cpu < 0) + return 1; + return !CPU_ISSET_S(cpu, cpu_present_setsize, cpu_present_set); } int cpu_is_not_allowed(int cpu) { + if (cpu < 0) + return 1; + return !CPU_ISSET_S(cpu, cpu_allowed_setsize, cpu_allowed_set); } @@ -2473,9 +2479,12 @@ int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pk int i; for (i = MAX_HT_ID; i > 0; --i) { /* ht_id 0 is self */ - if (cpus[cpu].ht_sibling_cpu_id[i] <= 0) + int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; + + if (cpu_is_not_allowed(sibling_cpu_id)) continue; - t = &thread_base[cpus[cpu].ht_sibling_cpu_id[i]]; + + t = &thread_base[sibling_cpu_id]; retval |= func(t, c, p); } @@ -6252,10 +6261,13 @@ int for_all_cpus_2(int (func) (struct thread_data *, struct core_data *, int i; for (i = MAX_HT_ID; i > 0; --i) { /* ht_id 0 is self */ - if (cpus[cpu].ht_sibling_cpu_id[i] <= 0) + int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; + + if (cpu_is_not_allowed(sibling_cpu_id)) continue; - t = &thread_base[cpus[cpu].ht_sibling_cpu_id[i]]; - t2 = &thread_base2[cpus[cpu].ht_sibling_cpu_id[i]]; + + t = &thread_base[sibling_cpu_id]; + t2 = &thread_base2[sibling_cpu_id]; retval |= func(t, c, p, t2, c2, p2); } From 08e11edd0e63b72651ed5eb9142430d1ca764923 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Tue, 21 Apr 2026 18:35:15 -0400 Subject: [PATCH 41/52] tools/power turbostat: Fix --cpu-set 1 regression on HT systems When the "--cpu-set" option limits turbostat to run on a higher numbered HT sibling, it exits upon dividing by zero. This is because the HT support handles higher numbered siblings at the same time as lower numbered siblings. But when that lower number sibling is dis-allowed, the higher numbered sibling is never processed. The result is a time delta of 0, which results in a divide by 0 for any of the "per-second" metrics. Enhance the HT enumeration code to record all siblings (up to SMT4). Consult this complete HT sibling list to determine when to process an HT sibling, and when to skip it. Fixes: a2b4d0f8bf07 ("tools/power turbostat: Favor cpu# over core#") Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 70 +++++++++++++++++++++------ 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 7f61f07ceb31..e609272ed80b 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -2449,6 +2449,22 @@ int cpu_is_not_allowed(int cpu) #define PER_THREAD_PARAMS struct thread_data *t, struct core_data *c, struct pkg_data *p +int has_allowed_lower_ht_sibling(int cpu) +{ + int i; + + for (i = 0; i <= cpus[cpu].ht_id; ++i) { + int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; + + if (sibling_cpu_id == cpu) + return 0; + + if (!cpu_is_not_allowed(sibling_cpu_id)) + return 1; + } + return 0; +} + int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pkg_data *), struct thread_data *thread_base, struct core_data *core_base, struct pkg_data *pkg_base) { @@ -2466,7 +2482,7 @@ int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pk if (cpu_is_not_allowed(cpu)) continue; - if (cpus[cpu].ht_id > 0) /* skip HT sibling */ + if (has_allowed_lower_ht_sibling(cpu)) /* skip HT sibling */ continue; t = &thread_base[cpu]; @@ -2475,12 +2491,18 @@ int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pk retval |= func(t, c, p); - /* Handle HT sibling now */ + /* Handle other HT siblings now */ int i; - for (i = MAX_HT_ID; i > 0; --i) { /* ht_id 0 is self */ + for (i = 0; i <= MAX_HT_ID; ++i) { int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; + if (sibling_cpu_id < 0) + break; + + if (sibling_cpu_id == cpu) + continue; + if (cpu_is_not_allowed(sibling_cpu_id)) continue; @@ -6178,11 +6200,11 @@ int set_thread_siblings(struct cpu_topology *thiscpu) int cpu = thiscpu->cpu_id; int offset = topo.max_cpu_num + 1; size_t size; - int thread_id = 0; + int ht_id = 0; thiscpu->put_ids = CPU_ALLOC((topo.max_cpu_num + 1)); if (thiscpu->ht_id < 0) - thiscpu->ht_id = thread_id++; + thiscpu->ht_id = 0; /* first CPU in core */ if (!thiscpu->put_ids) return -1; @@ -6206,13 +6228,9 @@ int set_thread_siblings(struct cpu_topology *thiscpu) sib_core = get_core_id(so); if (sib_core == thiscpu->core_id) { CPU_SET_S(so, size, thiscpu->put_ids); - if ((so != cpu) && (cpus[so].ht_id < 0)) { - cpus[so].ht_id = thread_id; - cpus[cpu].ht_sibling_cpu_id[thread_id] = so; - if (debug) - fprintf(stderr, "%s: cpu%d.ht_sibling_cpu_id[%d] = %d\n", __func__, cpu, thread_id, so); - thread_id += 1; - } + cpus[so].ht_id = ht_id; + cpus[cpu].ht_sibling_cpu_id[ht_id] = so; + ht_id += 1; } } } @@ -6245,7 +6263,7 @@ int for_all_cpus_2(int (func) (struct thread_data *, struct core_data *, if (cpu_is_not_allowed(cpu)) continue; - if (cpus[cpu].ht_id > 0) /* skip HT sibling */ + if (has_allowed_lower_ht_sibling(cpu)) /* skip HT sibling */ continue; t = &thread_base[cpu]; @@ -6260,9 +6278,15 @@ int for_all_cpus_2(int (func) (struct thread_data *, struct core_data *, /* Handle HT sibling now */ int i; - for (i = MAX_HT_ID; i > 0; --i) { /* ht_id 0 is self */ + for (i = 0; i <= MAX_HT_ID; ++i) { int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; + if (sibling_cpu_id < 0) + break; + + if (sibling_cpu_id == cpu) + continue; + if (cpu_is_not_allowed(sibling_cpu_id)) continue; @@ -9517,6 +9541,8 @@ void topology_probe(bool startup) cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); CPU_ZERO_S(cpu_present_setsize, cpu_present_set); for_all_proc_cpus(mark_cpu_present); + if (debug) + print_cpu_set("present set", cpu_present_set); /* * Allocate and initialize cpu_possible_set @@ -9527,6 +9553,8 @@ void topology_probe(bool startup) cpu_possible_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); CPU_ZERO_S(cpu_possible_setsize, cpu_possible_set); initialize_cpu_set_from_sysfs(cpu_possible_set, "/sys/devices/system/cpu", "possible"); + if (debug) + print_cpu_set("possible set", cpu_possible_set); /* * Allocate and initialize cpu_effective_set @@ -9537,6 +9565,8 @@ void topology_probe(bool startup) cpu_effective_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); CPU_ZERO_S(cpu_effective_setsize, cpu_effective_set); update_effective_set(startup); + if (debug) + print_cpu_set("effective set", cpu_effective_set); /* * Allocate and initialize cpu_allowed_set @@ -9580,6 +9610,8 @@ void topology_probe(bool startup) CPU_SET_S(i, cpu_allowed_setsize, cpu_allowed_set); } + if (debug) + print_cpu_set("allowed set", cpu_allowed_set); if (!CPU_COUNT_S(cpu_allowed_setsize, cpu_allowed_set)) err(-ENODEV, "No valid cpus found"); @@ -9683,12 +9715,18 @@ void topology_probe(bool startup) return; for (i = 0; i <= topo.max_cpu_num; ++i) { + int ht_id; + if (cpu_is_not_present(i)) continue; fprintf(outf, - "cpu %d pkg %d die %d l3 %d node %d lnode %d core %d thread %d\n", + "cpu %d pkg %d die %d l3 %d node %d lnode %d core %d ht_id %d", i, cpus[i].package_id, cpus[i].die_id, cpus[i].l3_id, cpus[i].physical_node_id, cpus[i].logical_node_id, cpus[i].core_id, cpus[i].ht_id); + fprintf(outf, " siblings"); + for (ht_id = 0; ht_id <= MAX_HT_ID; ++ht_id) + fprintf(outf, " %d", cpus[i].ht_sibling_cpu_id[ht_id]); + fprintf(outf, "\n"); } } @@ -9829,6 +9867,8 @@ void topology_update(void) topo.allowed_cores = 0; topo.allowed_packages = 0; for_all_cpus(update_topo, ODD_COUNTERS); + if (debug) + fprintf(stderr, "allowed_cpus %d allowed_cores %d allowed_packages %d\n", topo.allowed_cpus, topo.allowed_cores, topo.allowed_packages); } void setup_all_buffers(bool startup) From 092b76a3253fdd476e6d0626a094bf7b632f8eef Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 11 Mar 2026 11:00:35 +0200 Subject: [PATCH 42/52] tools/power turbostat: Cleanup print helper functions Make printer helper functions more readable by factoring out a local 'sep' variable. Remove the redundant parentheses around sprintf() calls. Remove an unnecessary cast to "unsigned int" by using the '%08llx' instead of '%08x'. No functional changes. [lenb: fix typos, simplify] Signed-off-by: Artem Bityutskiy Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index e609272ed80b..624f54ee1ad8 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -2866,31 +2866,38 @@ void bic_lookup(cpu_set_t *ret_set, char *name_list, enum show_hide_mode mode) static inline int print_name(int width, int *printed, char *delim, char *name, enum counter_type type, enum counter_format format) { UNUSED(type); + char *sep = (*printed)++ ? delim : ""; if (format == FORMAT_RAW && width >= 64) - return (sprintf(outp, "%s%-8s", ((*printed)++ ? delim : ""), name)); + return sprintf(outp, "%s%-8s", sep, name); else - return (sprintf(outp, "%s%s", ((*printed)++ ? delim : ""), name)); + return sprintf(outp, "%s%s", sep, name); } static inline int print_hex_value(int width, int *printed, char *delim, unsigned long long value) { + char *sep = (*printed)++ ? delim : ""; + if (width <= 32) - return (sprintf(outp, "%s%08x", ((*printed)++ ? delim : ""), (unsigned int)value)); + return sprintf(outp, "%s%08llx", sep, value); else - return (sprintf(outp, "%s%016llx", ((*printed)++ ? delim : ""), value)); + return sprintf(outp, "%s%016llx", sep, value); } static inline int print_decimal_value(int width, int *printed, char *delim, unsigned long long value) { + char *sep = (*printed)++ ? delim : ""; + UNUSED(width); - return (sprintf(outp, "%s%lld", ((*printed)++ ? delim : ""), value)); + return sprintf(outp, "%s%lld", sep, value); } static inline int print_float_value(int *printed, char *delim, double value) { - return (sprintf(outp, "%s%0.2f", ((*printed)++ ? delim : ""), value)); + char *sep = (*printed)++ ? delim : ""; + + return sprintf(outp, "%s%0.2f", sep, value); } void print_header(char *delim) From da828b6cafc103119b971290d44db5f33af7924e Mon Sep 17 00:00:00 2001 From: Len Brown Date: Tue, 24 Mar 2026 19:31:50 -0400 Subject: [PATCH 43/52] tools/power turbostat: Print core_id and apic_id in hex The core_id is based on a mask of the apic_id. Print them both in hex, rather than decimal, to make this relationship visibly clear. Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 624f54ee1ad8..b27227414dc7 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -3214,7 +3214,7 @@ int dump_counters(PER_THREAD_PARAMS) } if (c && is_cpu_first_thread_in_core(t, c)) { - outp += sprintf(outp, "core: %d\n", cpus[t->cpu_id].core_id); + outp += sprintf(outp, "core: 0x%x\n", cpus[t->cpu_id].core_id); outp += sprintf(outp, "c3: %016llX\n", c->c3); outp += sprintf(outp, "c6: %016llX\n", c->c6); outp += sprintf(outp, "c7: %016llX\n", c->c7); @@ -3423,16 +3423,16 @@ int format_counters(PER_THREAD_PARAMS) } if (DO_BIC(BIC_Core)) { if (c) - outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), cpus[t->cpu_id].core_id); + outp += sprintf(outp, "%s0x%x", (printed++ ? delim : ""), cpus[t->cpu_id].core_id); else outp += sprintf(outp, "%s-", (printed++ ? delim : "")); } if (DO_BIC(BIC_CPU)) outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->cpu_id); if (DO_BIC(BIC_APIC)) - outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->apic_id); + outp += sprintf(outp, "%s0x%x", (printed++ ? delim : ""), t->apic_id); if (DO_BIC(BIC_X2APIC)) - outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->x2apic_id); + outp += sprintf(outp, "%s0x%x", (printed++ ? delim : ""), t->x2apic_id); } if (DO_BIC(BIC_Avg_MHz)) From aea40f1e2d77a5581539d1ec6366c7dc7566321d Mon Sep 17 00:00:00 2001 From: Len Brown Date: Tue, 21 Apr 2026 18:36:31 -0400 Subject: [PATCH 44/52] tools/power turbostat: Show module_id column Get the "module_id" from the Linux topology "cluster_id". If the there is more than one id, show it by default. Module joins Die etc. in the "topology" group. Display in hex, as it is usually based mask of the APIC-id Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 38 +++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index b27227414dc7..f8e9aa8c9e54 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -191,6 +191,7 @@ struct msr_counter bic[] = { { 0x0, "Any%C0", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "GFX%C0", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "CPUGFX%", NULL, 0, 0, 0, NULL, 0 }, + { 0x0, "Module", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "Core", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "CPU", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "APIC", NULL, 0, 0, 0, NULL, 0 }, @@ -264,6 +265,7 @@ enum bic_names { BIC_Any_c0, BIC_GFX_c0, BIC_CPUGFX, + BIC_Module, BIC_Core, BIC_CPU, BIC_APIC, @@ -364,6 +366,7 @@ static void bic_groups_init(void) SET_BIC(BIC_Node, &bic_group_topology); SET_BIC(BIC_CoreCnt, &bic_group_topology); SET_BIC(BIC_PkgCnt, &bic_group_topology); + SET_BIC(BIC_Module, &bic_group_topology); SET_BIC(BIC_Core, &bic_group_topology); SET_BIC(BIC_CPU, &bic_group_topology); SET_BIC(BIC_Die, &bic_group_topology); @@ -2383,6 +2386,7 @@ struct platform_counters { struct cpu_topology { int cpu_id; int core_id; /* unique within a package */ + int module_id; int package_id; int die_id; int l3_id; @@ -2404,6 +2408,8 @@ struct topo_params { int allowed_cores; int max_cpu_num; int max_core_id; /* within a package */ + int min_module_id; /* system wide */ + int max_module_id; /* system wide */ int max_package_id; int max_die_id; int max_l3_id; @@ -2919,6 +2925,8 @@ void print_header(char *delim) outp += sprintf(outp, "%sL3", (printed++ ? delim : "")); if (DO_BIC(BIC_Node)) outp += sprintf(outp, "%sNode", (printed++ ? delim : "")); + if (DO_BIC(BIC_Module)) + outp += sprintf(outp, "%sModule", (printed++ ? delim : "")); if (DO_BIC(BIC_Core)) outp += sprintf(outp, "%sCore", (printed++ ? delim : "")); if (DO_BIC(BIC_CPU)) @@ -3388,6 +3396,8 @@ int format_counters(PER_THREAD_PARAMS) outp += sprintf(outp, "%s-", (printed++ ? delim : "")); if (DO_BIC(BIC_Node)) outp += sprintf(outp, "%s-", (printed++ ? delim : "")); + if (DO_BIC(BIC_Module)) + outp += sprintf(outp, "%s-", (printed++ ? delim : "")); if (DO_BIC(BIC_Core)) outp += sprintf(outp, "%s-", (printed++ ? delim : "")); if (DO_BIC(BIC_CPU)) @@ -3421,6 +3431,12 @@ int format_counters(PER_THREAD_PARAMS) else outp += sprintf(outp, "%s-", (printed++ ? delim : "")); } + if (DO_BIC(BIC_Module)) { + if (c) + outp += sprintf(outp, "%s0x%x", (printed++ ? delim : ""), cpus[t->cpu_id].module_id); + else + outp += sprintf(outp, "%s-", (printed++ ? delim : "")); + } if (DO_BIC(BIC_Core)) { if (c) outp += sprintf(outp, "%s0x%x", (printed++ ? delim : ""), cpus[t->cpu_id].core_id); @@ -6079,6 +6095,11 @@ int get_l3_id(int cpu) return parse_int_file("/sys/devices/system/cpu/cpu%d/cache/index3/id", cpu); } +int get_module_id(int cpu) +{ + return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/cluster_id", cpu); +} + int get_core_id(int cpu) { return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_id", cpu); @@ -9641,6 +9662,7 @@ void topology_probe(bool startup) * For online cpus * find max_core_id, max_package_id, num_cores (per system) */ + topo.min_module_id = 0x7FFFFFFF; for (i = 0; i <= topo.max_cpu_num; ++i) { int siblings; @@ -9672,6 +9694,13 @@ void topology_probe(bool startup) if (cpus[i].physical_node_id > topo.max_node_num) topo.max_node_num = cpus[i].physical_node_id; + /* get module information */ + cpus[i].module_id = get_module_id(i); + if (cpus[i].module_id > topo.max_module_id) + topo.max_module_id = cpus[i].module_id; + if (cpus[i].module_id < topo.min_module_id) + topo.min_module_id = cpus[i].module_id; + /* get core information */ cpus[i].core_id = get_core_id(i); if (cpus[i].core_id > max_core_id) @@ -9693,6 +9722,11 @@ void topology_probe(bool startup) if (!summary_only) BIC_PRESENT(BIC_Core); + if (debug > 1) + fprintf(outf, "min_module_id %d max_module_id %d\n", topo.min_module_id, topo.max_module_id); + if (!summary_only && (topo.min_module_id != topo.max_module_id)) + BIC_PRESENT(BIC_Module); + topo.num_die = topo.max_die_id + 1; if (debug > 1) fprintf(outf, "max_die_id %d, sizing for %d die\n", topo.max_die_id, topo.num_die); @@ -9727,9 +9761,9 @@ void topology_probe(bool startup) if (cpu_is_not_present(i)) continue; fprintf(outf, - "cpu %d pkg %d die %d l3 %d node %d lnode %d core %d ht_id %d", + "cpu %d pkg %d die %d l3 %d node %d lnode %d module 0x%x core %d ht_id %d", i, cpus[i].package_id, cpus[i].die_id, cpus[i].l3_id, - cpus[i].physical_node_id, cpus[i].logical_node_id, cpus[i].core_id, cpus[i].ht_id); + cpus[i].physical_node_id, cpus[i].logical_node_id, cpus[i].module_id, cpus[i].core_id, cpus[i].ht_id); fprintf(outf, " siblings"); for (ht_id = 0; ht_id <= MAX_HT_ID; ++ht_id) fprintf(outf, " %d", cpus[i].ht_sibling_cpu_id[ht_id]); From 58839fdbd441dc079800f2575013f2c438159d5a Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 22 Apr 2026 11:13:00 -0400 Subject: [PATCH 45/52] tools/power turbostat: Process HT siblings in CPU order On large systems with HT sibling cpu#'s more than 32 apart, HT siblings were processed and displayed in reverse order. This was due to how set_thread_siblings() parsed the sibling-bit-mask. Update set_thread_siblings to instead parse the sibling-list, like other cpu lists, and to thus order HT siblings by ascending CPU number, no matter the size of the system. Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 80 +++++++++++---------------- 1 file changed, 31 insertions(+), 49 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index f8e9aa8c9e54..d46878c63a80 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -6219,55 +6219,6 @@ static int parse_cpu_str(char *cpu_str, cpu_set_t *cpu_set, int cpu_set_size) return 0; } -int set_thread_siblings(struct cpu_topology *thiscpu) -{ - char path[80], character; - FILE *filep; - unsigned long map; - int so, shift, sib_core; - int cpu = thiscpu->cpu_id; - int offset = topo.max_cpu_num + 1; - size_t size; - int ht_id = 0; - - thiscpu->put_ids = CPU_ALLOC((topo.max_cpu_num + 1)); - if (thiscpu->ht_id < 0) - thiscpu->ht_id = 0; /* first CPU in core */ - if (!thiscpu->put_ids) - return -1; - - size = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); - CPU_ZERO_S(size, thiscpu->put_ids); - - sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings", cpu); - filep = fopen(path, "r"); - - if (!filep) { - warnx("%s: open failed", path); - return -1; - } - do { - offset -= BITMASK_SIZE; - if (fscanf(filep, "%lx%c", &map, &character) != 2) - err(1, "%s: failed to parse file", path); - for (shift = 0; shift < BITMASK_SIZE; shift++) { - if ((map >> shift) & 0x1) { - so = shift + offset; - sib_core = get_core_id(so); - if (sib_core == thiscpu->core_id) { - CPU_SET_S(so, size, thiscpu->put_ids); - cpus[so].ht_id = ht_id; - cpus[cpu].ht_sibling_cpu_id[ht_id] = so; - ht_id += 1; - } - } - } - } while (character == ','); - fclose(filep); - - return CPU_COUNT_S(size, thiscpu->put_ids); -} - /* * run func(thread, core, package) in topology order * skip non-present cpus @@ -9539,6 +9490,37 @@ int dir_filter(const struct dirent *dirp) return 0; } +int set_thread_siblings(struct cpu_topology *thiscpu) +{ + char path[80]; + int cpu = thiscpu->cpu_id; + size_t size; + int ht_id = 0; + int i; + + thiscpu->put_ids = CPU_ALLOC((topo.max_cpu_num + 1)); + if (thiscpu->ht_id < 0) + thiscpu->ht_id = 0; /* first CPU in core */ + if (!thiscpu->put_ids) + return -1; + + size = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); + CPU_ZERO_S(size, thiscpu->put_ids); + + sprintf(path, "/sys/devices/system/cpu/cpu%d/topology", cpu); + + initialize_cpu_set_from_sysfs(thiscpu->put_ids, path, "thread_siblings_list"); + + for (i = 0; i <= topo.max_cpu_num; ++i) + if (CPU_ISSET_S(i, size, thiscpu->put_ids)) { + cpus[i].ht_id = ht_id; + cpus[cpu].ht_sibling_cpu_id[ht_id] = i; + ht_id += 1; + } + + return (ht_id - 1); +} + void topology_probe(bool startup) { int i; From b488997b9cb006e175908b70fc0a2f3601a763d1 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Tue, 21 Apr 2026 18:39:20 -0400 Subject: [PATCH 46/52] tools/power turbostat: v2026.04.21 Since v2026.02.14 Display HT siblings in cpu# order. Add Module-ID column. Print Core-ID and APIC-ID in hex. Fix misc bugs. Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index d46878c63a80..920694c3c1ec 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -10608,7 +10608,7 @@ int get_and_dump_counters(void) void print_version() { - fprintf(outf, "turbostat version 2026.02.14 - Len Brown \n"); + fprintf(outf, "turbostat version 2026.04.21 - Len Brown \n"); } #define COMMAND_LINE_SIZE 2048 From 75f7c47ccd78c947cf1b6ddb18ea453ff0555716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 22 Apr 2026 17:10:27 +0200 Subject: [PATCH 47/52] kbuild: Never respect CONFIG_WERROR / W=e to fixdep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fixdep hostprog may be built multiple times during a single build. Once during the configuration phase and later during the regular phase. As only the regular build phase respects CONFIG_WERROR / W=e, the compiler flags might change between the phases, leading to rebuilds. Example, the rebuilds will happen twice on each invocation of the build: $ make allyesconfig prepare make[1]: Entering directory '/tmp/deleteme' HOSTCC scripts/basic/fixdep # # No change to .config # HOSTCC scripts/basic/fixdep DESCEND objtool INSTALL libsubcmd_headers make[1]: Leaving directory '/tmp/deleteme' Fix the compilation flags used for scripts/basic/ before scripts/Makefile.warn is evaluated to stop CONFIG_WERROR / W=e influencing the fixdep build to avoid the spurious rebuilds. Fixes: 7ded7d37e5f5 ("scripts/Makefile.extrawarn: Respect CONFIG_WERROR / W=e for hostprogs") Signed-off-by: Thomas Weißschuh Reviewed-by: Nathan Chancellor Link: https://patch.msgid.link/20260422-kbuild-scripts-basic-werror-v1-1-8c6912ff22e0@weissschuh.net Signed-off-by: Nicolas Schier --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 36d0a32fbe49..c4f76e4d77d0 100644 --- a/Makefile +++ b/Makefile @@ -655,6 +655,8 @@ export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o \ # Basic helpers built in scripts/basic/ PHONY += scripts_basic +scripts_basic: KBUILD_HOSTCFLAGS := $(KBUILD_HOSTCFLAGS) +scripts_basic: KBUILD_HOSTLDFLAGS := $(KBUILD_HOSTLDFLAGS) scripts_basic: $(Q)$(MAKE) $(build)=scripts/basic From 522567362b634015ca85b5460482ee0843feb105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Fri, 24 Apr 2026 16:34:52 +0100 Subject: [PATCH 48/52] clk: bcm: rpi: Mark VEC clock as CLK_IGNORE_UNUSED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Raspberry Pi 3B, the VEC clock is used by the VideoCore firmware display driver, which remains active until the vc4 driver loads and sends NOTIFY_DISPLAY_DONE. If this clock is disabled during boot, a bus lockup happens and the firmware becomes unresponsive, causing a complete system lockup. Mark the VEC clock with CLK_IGNORE_UNUSED so it survives the unused clock disablement and remains available until the vc4 driver takes over display management. Fixes: 672299736af6 ("clk: bcm: rpi: Manage clock rate in prepare/unprepare callbacks") Reported-by: Mark Brown Closes: https://lore.kernel.org/r/5f0bec08-f458-4fba-8bf3-06817a100c4c@sirena.org.uk Signed-off-by: Maíra Canal Link: https://patch.msgid.link/20260401111416.562279-2-mcanal@igalia.com Tested-by: Mark Brown Signed-off-by: Mark Brown Acked-by: Brian Masney # Active contributor to clk Reviewed-by: Stefan Wahren Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-raspberrypi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index df2d246eb6ef..f1a99de6de4f 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -160,6 +160,13 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = { [RPI_FIRMWARE_VEC_CLK_ID] = { .export = true, .minimize = true, + + /* + * If this clock is disabled during boot, it causes a bus + * lockup in RPi 3B. Therefore, make sure it's left enabled + * during boot. + */ + .flags = CLK_IGNORE_UNUSED, }, [RPI_FIRMWARE_DISP_CLK_ID] = { .export = true, From 25ff5848c05bc660739089cf9c6de4a166bd7932 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 15 Apr 2026 15:12:29 -0400 Subject: [PATCH 49/52] tools/power x86_energy_perf_policy: Enhances SoC Slider related checks When processor_thermal_soc_slider is loaded, its slider and offset modparams are visible. Check that the driver actually registered the profile named "SoC Slider" before reading or writing these modparams. n.b. This utility allows writing the Slider and Offset modparams even if the driver policy is not "balanced". Currently the processor_thermal_soc_slider consults those modparams only in "balanced" mode. Signed-off-by: Len Brown --- .../x86_energy_perf_policy.c | 142 +++++++++++++----- 1 file changed, 104 insertions(+), 38 deletions(-) diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c index 1f330c82d7c1..83e5adbcda69 100644 --- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c +++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c @@ -104,9 +104,14 @@ char platform_profile[64]; #define PATH_SOC_SLIDER_BALANCE "/sys/module/processor_thermal_soc_slider/parameters/slider_balance" #define PATH_SOC_SLIDER_OFFSET "/sys/module/processor_thermal_soc_slider/parameters/slider_offset" #define PATH_PLATFORM_PROFILE "/sys/class/platform-profile/platform-profile-0/profile" +#define PATH_PLATFORM_PROFILE_NAME "/sys/class/platform-profile/platform-profile-0/name" +#define POWER_SLIDER_NAME "SoC Power Slider" static int use_android_msr_path; +static unsigned int read_sysfs(const char *, char *, size_t); +static int sysfs_read_string(const char *, char *, size_t); + /* * maintain compatibility with original implementation, but don't document it: */ @@ -551,39 +556,91 @@ void print_version(void) printf("x86_energy_perf_policy 2025.11.22 Len Brown \n"); } +static int platform_profile_access(int mode) +{ + if (access(PATH_PLATFORM_PROFILE, mode)) { + if (debug) + fprintf(stderr, "Can not access %s\n", PATH_PLATFORM_PROFILE); + return 0; + } + + return 1; +} + +static int platform_profile_name_is(char *name) +{ + char buf[64]; + + if (sysfs_read_string(PATH_PLATFORM_PROFILE_NAME, buf, sizeof(buf)) != 0) { + if (debug) + fprintf(stderr, "Can not read %s\n", PATH_PLATFORM_PROFILE_NAME); + return 0; + } + + if (strncmp(buf, name, 16)) { + if (debug) + fprintf(stderr, "%s does not match '%s'\n", PATH_PLATFORM_PROFILE_NAME, name); + return 0; + } + + return 1; +} + +static int soc_slider_access(int mode) +{ + if (!platform_profile_access(R_OK)) + return 0; + + if (!platform_profile_name_is(POWER_SLIDER_NAME)) + return 0; + + if (access(PATH_SOC_SLIDER_BALANCE, mode)) { + if (debug) + fprintf(stderr, "Can not access %s\n", PATH_SOC_SLIDER_BALANCE); + return 0; + } + + if (access(PATH_SOC_SLIDER_OFFSET, mode)) { + if (debug) + fprintf(stderr, "Can not access %s\n", PATH_SOC_SLIDER_OFFSET); + return 0; + } + + return 1; +} + void cmdline(int argc, char **argv) { int opt; int option_index = 0; static struct option long_options[] = { - {"all", required_argument, 0, 'a'}, - {"cpu", required_argument, 0, 'c'}, - {"pkg", required_argument, 0, 'p'}, - {"debug", no_argument, 0, 'd'}, - {"hwp-desired", required_argument, 0, 'D'}, - {"epb", required_argument, 0, 'B'}, - {"force", no_argument, 0, 'f'}, - {"hwp-enable", no_argument, 0, 'e'}, - {"help", no_argument, 0, 'h'}, - {"hwp-epp", required_argument, 0, 'P'}, - {"hwp-min", required_argument, 0, 'm'}, - {"hwp-max", required_argument, 0, 'M'}, - {"read", no_argument, 0, 'r'}, - {"turbo-enable", required_argument, 0, 't'}, - {"hwp-use-pkg", required_argument, 0, 'u'}, - {"version", no_argument, 0, 'v'}, - {"hwp-window", required_argument, 0, 'w'}, - {"soc-slider-balance", required_argument, 0, 'S'}, - {"soc-slider-offset", required_argument, 0, 'O'}, - {"platform-profile", required_argument, 0, 'F'}, - {0, 0, 0, 0 } + { "all", required_argument, 0, 'a' }, + { "cpu", required_argument, 0, 'c' }, + { "pkg", required_argument, 0, 'p' }, + { "debug", no_argument, 0, 'd' }, + { "hwp-desired", required_argument, 0, 'D' }, + { "epb", required_argument, 0, 'B' }, + { "force", no_argument, 0, 'f' }, + { "hwp-enable", no_argument, 0, 'e' }, + { "help", no_argument, 0, 'h' }, + { "hwp-epp", required_argument, 0, 'P' }, + { "hwp-min", required_argument, 0, 'm' }, + { "hwp-max", required_argument, 0, 'M' }, + { "read", no_argument, 0, 'r' }, + { "turbo-enable", required_argument, 0, 't' }, + { "hwp-use-pkg", required_argument, 0, 'u' }, + { "version", no_argument, 0, 'v' }, + { "hwp-window", required_argument, 0, 'w' }, + { "soc-slider-balance", required_argument, 0, 'S' }, + { "soc-slider-offset", required_argument, 0, 'O' }, + { "platform-profile", required_argument, 0, 'F' }, + { 0, 0, 0, 0 } }; progname = argv[0]; - while ((opt = getopt_long_only(argc, argv, "+a:c:dD:E:e:f:m:M:rt:u:vw::S:O:F:", - long_options, &option_index)) != -1) { + while ((opt = getopt_long_only(argc, argv, "+a:c:dD:E:e:f:m:M:rt:u:vw::S:O:F:", long_options, &option_index)) != -1) { switch (opt) { case 'a': parse_cmdline_all(optarg); @@ -613,6 +670,8 @@ void cmdline(int argc, char **argv) case 'F': if (strlen(optarg) >= sizeof(platform_profile)) errx(1, "--platform-profile: value too long"); + if (!platform_profile_access(W_OK)) + errx(1, "Can not update platform-profile in '%s'", PATH_PLATFORM_PROFILE); strcpy(platform_profile, optarg); update_platform_profile = 1; break; @@ -625,6 +684,8 @@ void cmdline(int argc, char **argv) case 'O': if (parse_cmdline_int(optarg, &soc_slider_offset)) errx(1, "--soc-slider-offset: invalid value"); + if (!soc_slider_access(W_OK)) + errx(1, "Unable to write SOC Slider Offset"); update_soc_slider_offset = 1; break; case 'p': @@ -639,6 +700,8 @@ void cmdline(int argc, char **argv) case 'S': if (parse_cmdline_int(optarg, &soc_slider_balance)) errx(1, "--soc-slider-balance: invalid value"); + if (!soc_slider_access(W_OK)) + errx(1, "Unable to write SOC Slider-Balance in '%s'", PATH_SOC_SLIDER_BALANCE); update_soc_slider_balance = 1; break; case 't': @@ -814,7 +877,8 @@ static unsigned int write_sysfs(const char *path, char *buf, size_t buflen) numwritten = write(fd, buf, buflen - 1); if (numwritten < 1) { - perror("write failed\n"); + buf[strcspn(buf, "\n")] = '\0'; + warn("Write '%s' to '%s' failed", buf, path); close(fd); return -1; } @@ -972,27 +1036,30 @@ static int set_epb_sysfs(int cpu, int val) return (int)val; } -static int soc_slider_available(void) -{ - if (access(PATH_SOC_SLIDER_BALANCE, R_OK) && - access(PATH_SOC_SLIDER_OFFSET, R_OK) && - access(PATH_PLATFORM_PROFILE, R_OK)) - return 0; - - return 1; -} - static void print_soc_slider(void) { char buf[64]; - if (!soc_slider_available()) + if (!soc_slider_access(R_OK)) return; if (sysfs_read_string(PATH_SOC_SLIDER_BALANCE, buf, sizeof(buf)) == 0) printf("soc-slider-balance: %s\n", buf); + if (sysfs_read_string(PATH_SOC_SLIDER_OFFSET, buf, sizeof(buf)) == 0) printf("soc-slider-offset: %s\n", buf); +} + +static void print_platform_profile(void) +{ + char buf[64]; + + if (!platform_profile_access(R_OK)) + return; + + if (sysfs_read_string(PATH_PLATFORM_PROFILE_NAME, buf, sizeof(buf)) == 0) + printf("platform-profile-name: %s\n", buf); + if (sysfs_read_string(PATH_PLATFORM_PROFILE, buf, sizeof(buf)) == 0) printf("platform-profile: %s\n", buf); } @@ -1725,13 +1792,12 @@ int main(int argc, char **argv) return -EINVAL; /* display information only, no updates to settings */ - if (!update_epb && !update_turbo && !hwp_update_enabled() && - !update_soc_slider_balance && !update_soc_slider_offset && - !update_platform_profile) { + if (!update_epb && !update_turbo && !hwp_update_enabled() && !update_soc_slider_balance && !update_soc_slider_offset && !update_platform_profile) { if (cpu_selected_set) for_all_cpus_in_set(cpu_setsize, cpu_selected_set, print_cpu_msrs); print_soc_slider(); + print_platform_profile(); if (has_hwp_request_pkg) { if (pkg_selected_set == 0) From 18c5b9ea4ea4be5ed9b5b6add30a2a7911326224 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sat, 25 Apr 2026 12:10:54 -0400 Subject: [PATCH 50/52] tools/power x86_energy_perf_policy.8: Document SoC Slider Options x86_energy_perf_policy accesses the SoC Slider via standard user/kernel APIs to the processor_thermal_soc_slider driver. Machines that support SoC Slider largely use it instead of EPP, which may continue to exist in a diminished role, or vanish entirely. Signed-off-by: Len Brown --- .../x86_energy_perf_policy.8 | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 index 0aa981c18e56..836553e9a92c 100644 --- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 +++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 @@ -15,6 +15,8 @@ x86_energy_perf_policy \- Manage Energy vs. Performance Policy .br .RB "other: (\-\-force | \-\-hwp-enable | \-\-turbo-enable) value)" .br +.RB "soc-slider: --soc-slider-balance # | --soc-slider-offset # | --platform-profile " +.br .RB "value: # | default | performance | balance-performance | balance-power | power" .SH DESCRIPTION \fBx86_energy_perf_policy\fP @@ -154,6 +156,26 @@ level on this processor, specified in multiples of 100 MHz. in the sliding window that HWP uses to maintain average frequency. This parameter is meaningful only when the "desired" field above is non-zero. Default is 0, allowing the HW to choose. +.SH SOC SLIDER OPTIONS +.PP +Note that the Platform Profile Name must be "SoC Slider", and the +Platform Profile must be "balanced" for the --soc-slider-balance +and --soc-slider-offset options to take effect. +.PP +\fB--soc-slider-balance #\fP write numeric value to the SoC Slider. +Values range from 0 to 6. +Lower values result in higher performance, +and higher values improve energy efficiency. +Actual values are model specific. +.PP +\fB--soc-slider-offset #\fP write the numeric value to the Soc Slider Offset. +The slider offset is the maximum value that software allows the SoC to +autonomously add to the SoC Slider to improve energy efficiency. +The value 0 prohibits the SoC from autonomously changing the slider. +.PP +\fB--platform-profile "\fP set the platform profile to . +Available choices are in platform-profile-0/choices. The Soc Slider +driver currently supports "low-power", "balanced", and "performance". .SH OTHER OPTIONS .PP \fB-f, --force\fP writes the specified values without bounds checking. @@ -208,6 +230,10 @@ runs only as root. EPB: /sys/devices/system/cpu/cpu*/power/energy_perf_bias EPP: /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference MSR: /dev/cpu/*/msr +Platform Profile Name: /sys/class/platform-profile/platform-profile-0/name +Platform Profile: /sys/class/platform-profile/platform-profile-0/profile +SOC Slider Balanced: /sys/module/processor_thermal_soc_slider/parameters/slider_balance +SOC Slider Balanced Offset: /sys/module/processor_thermal_soc_slider/parameters/slider_offset .fi .SH "SEE ALSO" .nf From f1c35c73191b7d23ed4bbc660a7b9ed5b32614e0 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sat, 25 Apr 2026 13:26:16 -0400 Subject: [PATCH 51/52] tools/power x86_energy_perf_policy: Version 2026.04.25 Since v2025.11.22: Initial SoC Slider support SoC Slider is an SoC-wide power/performance policy setting. On SoC Slider systems, EPP plays a diminished role. Whitespace cleanup via: indent -npro -kr -i8 -ts8 -sob -l160 -ss -ncs -cp1 No functional changes Signed-off-by: Len Brown --- .../x86_energy_perf_policy.c | 161 +++++++----------- 1 file changed, 66 insertions(+), 95 deletions(-) diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c index 83e5adbcda69..0dc959e30076 100644 --- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c +++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c @@ -4,7 +4,7 @@ * policy preference bias on recent X86 processors. */ /* - * Copyright (c) 2010 - 2025 Intel Corporation. + * Copyright (c) 2010 - 2026 Intel Corporation. * Len Brown */ @@ -82,10 +82,10 @@ size_t cpu_setsize; char *proc_stat = "/proc/stat"; -unsigned int has_epb; /* MSR_IA32_ENERGY_PERF_BIAS */ -unsigned int has_hwp; /* IA32_PM_ENABLE, IA32_HWP_CAPABILITIES */ +unsigned int has_epb; /* MSR_IA32_ENERGY_PERF_BIAS */ +unsigned int has_hwp; /* IA32_PM_ENABLE, IA32_HWP_CAPABILITIES */ /* IA32_HWP_REQUEST, IA32_HWP_STATUS */ -unsigned int has_hwp_notify; /* IA32_HWP_INTERRUPT */ +unsigned int has_hwp_notify; /* IA32_HWP_INTERRUPT */ unsigned int has_hwp_activity_window; /* IA32_HWP_REQUEST[bits 41:32] */ unsigned int has_hwp_epp; /* IA32_HWP_REQUEST[bits 31:24] */ unsigned int has_hwp_request_pkg; /* IA32_HWP_REQUEST_PKG */ @@ -122,8 +122,7 @@ void usage(void) fprintf(stderr, "field: --all | --epb | --hwp-epp | --hwp-min | --hwp-max | --hwp-desired\n"); fprintf(stderr, "other: --hwp-enable | --turbo-enable (0 | 1) | --help | --force\n"); fprintf(stderr, "soc-slider: --soc-slider-balance # | --soc-slider-offset # | --platform-profile \n"); - fprintf(stderr, - "value: ( # | \"normal\" | \"performance\" | \"balance-performance\" | \"balance-power\"| \"power\")\n"); + fprintf(stderr, "value: ( # | \"normal\" | \"performance\" | \"balance-performance\" | \"balance-power\"| \"power\")\n"); fprintf(stderr, "--hwp-window usec\n"); fprintf(stderr, "Specify only Energy Performance BIAS (legacy usage):\n"); @@ -151,6 +150,7 @@ int ratio_2_msr_perf(int ratio) return msr_perf; } + int msr_perf_2_ratio(int msr_perf) { int ratio; @@ -159,8 +159,8 @@ int msr_perf_2_ratio(int msr_perf) if (!bdx_highest_ratio) return msr_perf; - d = (double)msr_perf * (double) bdx_highest_ratio / 255.0; - d = d + 0.5; /* round */ + d = (double)msr_perf * (double)bdx_highest_ratio / 255.0; + d = d + 0.5; /* round */ ratio = (int)d; if (debug) @@ -168,6 +168,7 @@ int msr_perf_2_ratio(int msr_perf) return ratio; } + int parse_cmdline_epb(int i) { if (!has_epb) @@ -214,6 +215,7 @@ int parse_cmdline_hwp_min(int i) } return i; } + /* * "power" changes hwp_max to cap.lowest * All others leave it at cap.highest @@ -233,6 +235,7 @@ int parse_cmdline_hwp_max(int i) } return i; } + /* * for --hwp-des, all strings leave it in autonomous mode * If you want to change it, you need to explicitly pick a value @@ -270,7 +273,7 @@ int parse_cmdline_hwp_window(int i) fprintf(stderr, "--hwp-window: 0 for auto; 1 - 1270000000 usec for window duration\n"); usage(); } - for (exponent = 0; ; ++exponent) { + for (exponent = 0;; ++exponent) { if (debug) printf("%d 10^%d\n", i, exponent); @@ -284,6 +287,7 @@ int parse_cmdline_hwp_window(int i) return (exponent << 7) | i; } + int parse_cmdline_hwp_epp(int i) { update_hwp_epp = 1; @@ -305,6 +309,7 @@ int parse_cmdline_hwp_epp(int i) } return i; } + int parse_cmdline_turbo(int i) { update_turbo = 1; @@ -524,7 +529,7 @@ void parse_cmdline_pkg(char *s) } } -void for_packages(unsigned long long pkg_set, int (func)(int)) +void for_packages(unsigned long long pkg_set, int (func) (int)) { int pkg_num; @@ -553,7 +558,7 @@ static int parse_cmdline_int(const char *s, int *out) void print_version(void) { - printf("x86_energy_perf_policy 2025.11.22 Len Brown \n"); + printf("x86_energy_perf_policy 2026.04.25 Len Brown \n"); } static int platform_profile_access(int mode) @@ -791,8 +796,7 @@ void err_on_hypervisor(void) free(buffer); if (hypervisor) - err(-1, - "not supported on this virtual machine"); + err(-1, "not supported on this virtual machine"); } int get_msr(int cpu, int offset, unsigned long long *msr) @@ -804,9 +808,7 @@ int get_msr(int cpu, int offset, unsigned long long *msr) sprintf(pathname, use_android_msr_path ? "/dev/msr%d" : "/dev/cpu/%d/msr", cpu); fd = open(pathname, O_RDONLY); if (fd < 0) - err(-1, "%s open failed, try chown or chmod +r %s, or run as root", - pathname, use_android_msr_path ? "/dev/msr*" : "/dev/cpu/*/msr"); - + err(-1, "%s open failed, try chown or chmod +r %s, or run as root", pathname, use_android_msr_path ? "/dev/msr*" : "/dev/cpu/*/msr"); retval = pread(fd, msr, sizeof(*msr), offset); if (retval != sizeof(*msr)) { @@ -830,8 +832,7 @@ int put_msr(int cpu, int offset, unsigned long long new_msr) sprintf(pathname, use_android_msr_path ? "/dev/msr%d" : "/dev/cpu/%d/msr", cpu); fd = open(pathname, O_RDWR); if (fd < 0) - err(-1, "%s open failed, try chown or chmod +r %s, or run as root", - pathname, use_android_msr_path ? "/dev/msr*" : "/dev/cpu/*/msr"); + err(-1, "%s open failed, try chown or chmod +r %s, or run as root", pathname, use_android_msr_path ? "/dev/msr*" : "/dev/cpu/*/msr"); retval = pwrite(fd, &new_msr, sizeof(new_msr), offset); if (retval != sizeof(new_msr)) @@ -863,7 +864,7 @@ static unsigned int read_sysfs(const char *path, char *buf, size_t buflen) buf[numread] = '\0'; close(fd); - return (unsigned int) numread; + return (unsigned int)numread; } static unsigned int write_sysfs(const char *path, char *buf, size_t buflen) @@ -885,7 +886,7 @@ static unsigned int write_sysfs(const char *path, char *buf, size_t buflen) close(fd); - return (unsigned int) numwritten; + return (unsigned int)numwritten; } static int sysfs_read_string(const char *path, char *buf, size_t buflen) @@ -918,9 +919,9 @@ void print_hwp_cap(int cpu, struct msr_hwp_cap *cap, char *str) if (cpu != -1) printf("cpu%d: ", cpu); - printf("HWP_CAP: low %d eff %d guar %d high %d\n", - cap->lowest, cap->efficient, cap->guaranteed, cap->highest); + printf("HWP_CAP: low %d eff %d guar %d high %d\n", cap->lowest, cap->efficient, cap->guaranteed, cap->highest); } + void read_hwp_cap(int cpu, struct msr_hwp_cap *cap, unsigned int msr_offset) { unsigned long long msr; @@ -942,9 +943,9 @@ void print_hwp_request(int cpu, struct msr_hwp_request *h, char *str) printf("%s", str); printf("HWP_REQ: min %d max %d des %d epp %d window 0x%x (%d*10^%dus) use_pkg %d\n", - h->hwp_min, h->hwp_max, h->hwp_desired, h->hwp_epp, - h->hwp_window, h->hwp_window & 0x7F, (h->hwp_window >> 7) & 0x7, h->hwp_use_pkg); + h->hwp_min, h->hwp_max, h->hwp_desired, h->hwp_epp, h->hwp_window, h->hwp_window & 0x7F, (h->hwp_window >> 7) & 0x7, h->hwp_use_pkg); } + void print_hwp_request_pkg(int pkg, struct msr_hwp_request *h, char *str) { printf("pkg%d: ", pkg); @@ -953,9 +954,9 @@ void print_hwp_request_pkg(int pkg, struct msr_hwp_request *h, char *str) printf("%s", str); printf("HWP_REQ_PKG: min %d max %d des %d epp %d window 0x%x (%d*10^%dus)\n", - h->hwp_min, h->hwp_max, h->hwp_desired, h->hwp_epp, - h->hwp_window, h->hwp_window & 0x7F, (h->hwp_window >> 7) & 0x7); + h->hwp_min, h->hwp_max, h->hwp_desired, h->hwp_epp, h->hwp_window, h->hwp_window & 0x7F, (h->hwp_window >> 7) & 0x7); } + void read_hwp_request_msr(int cpu, struct msr_hwp_request *hwp_req, unsigned int msr_offset) { unsigned long long msr; @@ -976,9 +977,7 @@ void write_hwp_request_msr(int cpu, struct msr_hwp_request *hwp_req, unsigned in if (debug > 1) printf("cpu%d: requesting min %d max %d des %d epp %d window 0x%0x use_pkg %d\n", - cpu, hwp_req->hwp_min, hwp_req->hwp_max, - hwp_req->hwp_desired, hwp_req->hwp_epp, - hwp_req->hwp_window, hwp_req->hwp_use_pkg); + cpu, hwp_req->hwp_min, hwp_req->hwp_max, hwp_req->hwp_desired, hwp_req->hwp_epp, hwp_req->hwp_window, hwp_req->hwp_use_pkg); msr |= HWP_MIN_PERF(ratio_2_msr_perf(hwp_req->hwp_min)); msr |= HWP_MAX_PERF(ratio_2_msr_perf(hwp_req->hwp_max)); @@ -1096,7 +1095,7 @@ int print_cpu_msrs(int cpu) epb = get_epb_sysfs(cpu); if (epb >= 0) - printf("cpu%d: EPB %u\n", cpu, (unsigned int) epb); + printf("cpu%d: EPB %u\n", cpu, (unsigned int)epb); if (!has_hwp) return 0; @@ -1124,17 +1123,13 @@ int print_pkg_msrs(int pkg) if (has_hwp_notify) { get_msr(first_cpu_in_pkg[pkg], MSR_HWP_INTERRUPT, &msr); fprintf(stderr, - "pkg%d: MSR_HWP_INTERRUPT: 0x%08llx (Excursion_Min-%sabled, Guaranteed_Perf_Change-%sabled)\n", - pkg, msr, - ((msr) & 0x2) ? "EN" : "Dis", - ((msr) & 0x1) ? "EN" : "Dis"); + "pkg%d: MSR_HWP_INTERRUPT: 0x%08llx (Excursion_Min-%sabled, Guaranteed_Perf_Change-%sabled)\n", + pkg, msr, ((msr) & 0x2) ? "EN" : "Dis", ((msr) & 0x1) ? "EN" : "Dis"); } get_msr(first_cpu_in_pkg[pkg], MSR_HWP_STATUS, &msr); fprintf(stderr, "pkg%d: MSR_HWP_STATUS: 0x%08llx (%sExcursion_Min, %sGuaranteed_Perf_Change)\n", - pkg, msr, - ((msr) & 0x4) ? "" : "No-", - ((msr) & 0x1) ? "" : "No-"); + pkg, msr, ((msr) & 0x4) ? "" : "No-", ((msr) & 0x1) ? "" : "No-"); return 0; } @@ -1148,6 +1143,7 @@ int ratio_2_sysfs_khz(int ratio) return ratio * bclk_khz; } + /* * If HWP is enabled and cpufreq sysfs attribtes are present, * then update via sysfs. The intel_pstate driver may modify (clip) @@ -1164,8 +1160,7 @@ void update_cpufreq_scaling_freq(int is_max, int cpu, unsigned int ratio) int retval; int khz; - sprintf(pathname, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_%s_freq", - cpu, is_max ? "max" : "min"); + sprintf(pathname, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_%s_freq", cpu, is_max ? "max" : "min"); fp = fopen(pathname, "w"); if (!fp) { @@ -1217,19 +1212,16 @@ int verify_hwp_req_self_consistency(int cpu, struct msr_hwp_request *req) { /* fail if min > max requested */ if (req->hwp_min > req->hwp_max) { - errx(1, "cpu%d: requested hwp-min %d > hwp_max %d", - cpu, req->hwp_min, req->hwp_max); + errx(1, "cpu%d: requested hwp-min %d > hwp_max %d", cpu, req->hwp_min, req->hwp_max); } /* fail if desired > max requestd */ if (req->hwp_desired && (req->hwp_desired > req->hwp_max)) { - errx(1, "cpu%d: requested hwp-desired %d > hwp_max %d", - cpu, req->hwp_desired, req->hwp_max); + errx(1, "cpu%d: requested hwp-desired %d > hwp_max %d", cpu, req->hwp_desired, req->hwp_max); } /* fail if desired < min requestd */ if (req->hwp_desired && (req->hwp_desired < req->hwp_min)) { - errx(1, "cpu%d: requested hwp-desired %d < requested hwp_min %d", - cpu, req->hwp_desired, req->hwp_min); + errx(1, "cpu%d: requested hwp-desired %d < requested hwp_min %d", cpu, req->hwp_desired, req->hwp_min); } return 0; @@ -1239,39 +1231,30 @@ int check_hwp_request_v_hwp_capabilities(int cpu, struct msr_hwp_request *req, s { if (update_hwp_max) { if (req->hwp_max > cap->highest) - errx(1, "cpu%d: requested max %d > capabilities highest %d, use --force?", - cpu, req->hwp_max, cap->highest); + errx(1, "cpu%d: requested max %d > capabilities highest %d, use --force?", cpu, req->hwp_max, cap->highest); if (req->hwp_max < cap->lowest) - errx(1, "cpu%d: requested max %d < capabilities lowest %d, use --force?", - cpu, req->hwp_max, cap->lowest); + errx(1, "cpu%d: requested max %d < capabilities lowest %d, use --force?", cpu, req->hwp_max, cap->lowest); } if (update_hwp_min) { if (req->hwp_min > cap->highest) - errx(1, "cpu%d: requested min %d > capabilities highest %d, use --force?", - cpu, req->hwp_min, cap->highest); + errx(1, "cpu%d: requested min %d > capabilities highest %d, use --force?", cpu, req->hwp_min, cap->highest); if (req->hwp_min < cap->lowest) - errx(1, "cpu%d: requested min %d < capabilities lowest %d, use --force?", - cpu, req->hwp_min, cap->lowest); + errx(1, "cpu%d: requested min %d < capabilities lowest %d, use --force?", cpu, req->hwp_min, cap->lowest); } if (update_hwp_min && update_hwp_max && (req->hwp_min > req->hwp_max)) - errx(1, "cpu%d: requested min %d > requested max %d", - cpu, req->hwp_min, req->hwp_max); + errx(1, "cpu%d: requested min %d > requested max %d", cpu, req->hwp_min, req->hwp_max); if (update_hwp_desired && req->hwp_desired) { if (req->hwp_desired > req->hwp_max) - errx(1, "cpu%d: requested desired %d > requested max %d, use --force?", - cpu, req->hwp_desired, req->hwp_max); + errx(1, "cpu%d: requested desired %d > requested max %d, use --force?", cpu, req->hwp_desired, req->hwp_max); if (req->hwp_desired < req->hwp_min) - errx(1, "cpu%d: requested desired %d < requested min %d, use --force?", - cpu, req->hwp_desired, req->hwp_min); + errx(1, "cpu%d: requested desired %d < requested min %d, use --force?", cpu, req->hwp_desired, req->hwp_min); if (req->hwp_desired < cap->lowest) - errx(1, "cpu%d: requested desired %d < capabilities lowest %d, use --force?", - cpu, req->hwp_desired, cap->lowest); + errx(1, "cpu%d: requested desired %d < capabilities lowest %d, use --force?", cpu, req->hwp_desired, cap->lowest); if (req->hwp_desired > cap->highest) - errx(1, "cpu%d: requested desired %d > capabilities highest %d, use --force?", - cpu, req->hwp_desired, cap->highest); + errx(1, "cpu%d: requested desired %d > capabilities highest %d, use --force?", cpu, req->hwp_desired, cap->highest); } return 0; @@ -1322,6 +1305,7 @@ int update_hwp_request_msr(int cpu) } return 0; } + int update_hwp_request_pkg_msr(int pkg) { struct msr_hwp_request req; @@ -1393,8 +1377,7 @@ int update_cpu_epb_sysfs(int cpu) set_epb_sysfs(cpu, new_epb); if (verbose) - printf("cpu%d: ENERGY_PERF_BIAS old: %d new: %d\n", - cpu, epb, (unsigned int) new_epb); + printf("cpu%d: ENERGY_PERF_BIAS old: %d new: %d\n", cpu, epb, (unsigned int)new_epb); return 0; } @@ -1410,7 +1393,7 @@ int update_cpu_msrs(int cpu) turbo_is_present_and_disabled = ((msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE) != 0); - if (turbo_update_value == 1) { + if (turbo_update_value == 1) { if (turbo_is_present_and_disabled) { msr &= ~MSR_IA32_MISC_ENABLE_TURBO_DISABLE; put_msr(cpu, MSR_IA32_MISC_ENABLE, msr); @@ -1479,6 +1462,7 @@ int set_max_cpu_pkg_num(int cpu) return 0; } + int mark_cpu_present(int cpu) { CPU_SET_S(cpu, cpu_setsize, cpu_present_set); @@ -1489,7 +1473,7 @@ int mark_cpu_present(int cpu) * run func(cpu) on every cpu in /proc/stat * return max_cpu number */ -int for_all_proc_cpus(int (func)(int)) +int for_all_proc_cpus(int (func) (int)) { FILE *fp; int cpu_num; @@ -1516,7 +1500,7 @@ int for_all_proc_cpus(int (func)(int)) return 0; } -void for_all_cpus_in_set(size_t set_size, cpu_set_t *cpu_set, int (func)(int)) +void for_all_cpus_in_set(size_t set_size, cpu_set_t *cpu_set, int (func) (int)) { int cpu_num; @@ -1524,7 +1508,8 @@ void for_all_cpus_in_set(size_t set_size, cpu_set_t *cpu_set, int (func)(int)) if (CPU_ISSET_S(cpu_num, set_size, cpu_set)) func(cpu_num); } -int for_all_cpus_in_set_and(size_t set_size, cpu_set_t *cpu_set, int (func)(int)) + +int for_all_cpus_in_set_and(size_t set_size, cpu_set_t *cpu_set, int (func) (int)) { int cpu_num; int retval = 1; @@ -1573,7 +1558,7 @@ void verify_hwp_is_enabled(void) { int retval; - if (!has_hwp) /* set in early_cpuid() */ + if (!has_hwp) /* set in early_cpuid() */ return; retval = for_all_cpus_in_set_and(cpu_setsize, cpu_selected_set, is_hwp_enabled_on_cpu); @@ -1590,21 +1575,18 @@ int req_update_bounds_check(void) return 0; /* fail if min > max requested */ - if ((update_hwp_max && update_hwp_min) && - (req_update.hwp_min > req_update.hwp_max)) { + if ((update_hwp_max && update_hwp_min) && (req_update.hwp_min > req_update.hwp_max)) { printf("hwp-min %d > hwp_max %d\n", req_update.hwp_min, req_update.hwp_max); return -EINVAL; } /* fail if desired > max requestd */ - if (req_update.hwp_desired && update_hwp_max && - (req_update.hwp_desired > req_update.hwp_max)) { + if (req_update.hwp_desired && update_hwp_max && (req_update.hwp_desired > req_update.hwp_max)) { printf("hwp-desired cannot be greater than hwp_max\n"); return -EINVAL; } /* fail if desired < min requestd */ - if (req_update.hwp_desired && update_hwp_min && - (req_update.hwp_desired < req_update.hwp_min)) { + if (req_update.hwp_desired && update_hwp_min && (req_update.hwp_desired < req_update.hwp_min)) { printf("hwp-desired cannot be less than hwp_min\n"); return -EINVAL; } @@ -1647,9 +1629,7 @@ void probe_dev_msr(void) } } -static void get_cpuid_or_exit(unsigned int leaf, - unsigned int *eax, unsigned int *ebx, - unsigned int *ecx, unsigned int *edx) +static void get_cpuid_or_exit(unsigned int leaf, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) { if (!__get_cpuid(leaf, eax, ebx, ecx, edx)) errx(1, "Processor not supported\n"); @@ -1703,8 +1683,7 @@ void parse_cpuid(void) genuine_intel = 1; if (debug) - fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ", - (char *)&ebx, (char *)&edx, (char *)&ecx); + fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ", (char *)&ebx, (char *)&edx, (char *)&ecx); get_cpuid_or_exit(1, &fms, &ebx, &ecx, &edx); family = (fms >> 8) & 0xf; @@ -1714,23 +1693,18 @@ void parse_cpuid(void) model += ((fms >> 16) & 0xf) << 4; if (debug) { - fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n", - max_level, family, model, stepping, family, model, stepping); + fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n", max_level, family, model, stepping, family, model, stepping); fprintf(stderr, "CPUID(1): %s %s %s %s %s %s %s %s\n", ecx & (1 << 0) ? "SSE3" : "-", ecx & (1 << 3) ? "MONITOR" : "-", ecx & (1 << 7) ? "EIST" : "-", ecx & (1 << 8) ? "TM2" : "-", - edx & (1 << 4) ? "TSC" : "-", - edx & (1 << 5) ? "MSR" : "-", - edx & (1 << 22) ? "ACPI-TM" : "-", - edx & (1 << 29) ? "TM" : "-"); + edx & (1 << 4) ? "TSC" : "-", edx & (1 << 5) ? "MSR" : "-", edx & (1 << 22) ? "ACPI-TM" : "-", edx & (1 << 29) ? "TM" : "-"); } if (!(edx & (1 << 5))) errx(1, "CPUID: no MSR"); - get_cpuid_or_exit(0x6, &eax, &ebx, &ecx, &edx); /* turbo_is_enabled already set */ /* has_hwp already set */ @@ -1750,12 +1724,9 @@ void parse_cpuid(void) turbo_is_enabled ? "" : "No-", has_hwp ? "" : "No-", has_hwp_notify ? "" : "No-", - has_hwp_activity_window ? "" : "No-", - has_hwp_epp ? "" : "No-", - has_hwp_request_pkg ? "" : "No-", - has_epb ? "" : "No-"); + has_hwp_activity_window ? "" : "No-", has_hwp_epp ? "" : "No-", has_hwp_request_pkg ? "" : "No-", has_epb ? "" : "No-"); - return; /* success */ + return; /* success */ } int main(int argc, char **argv) @@ -1765,7 +1736,7 @@ int main(int argc, char **argv) probe_dev_msr(); init_data_structures(); - early_cpuid(); /* initial cpuid parse before cmdline */ + early_cpuid(); /* initial cpuid parse before cmdline */ cmdline(argc, argv); @@ -1774,7 +1745,7 @@ int main(int argc, char **argv) parse_cpuid(); - /* If CPU-set and PKG-set are not initialized, default to all CPUs */ + /* If CPU-set and PKG-set are not initialized, default to all CPUs */ if ((cpu_selected_set == 0) && (pkg_selected_set == 0)) cpu_selected_set = cpu_present_set; From 254f49634ee16a731174d2ae34bc50bd5f45e731 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 26 Apr 2026 14:19:00 -0700 Subject: [PATCH 52/52] Linux 7.1-rc1 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 6c8a1b2e7c8a..e27c91ea56fc 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 7 -PATCHLEVEL = 0 +PATCHLEVEL = 1 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc1 NAME = Baby Opossum Posse # *DOCUMENTATION*