* Re: [PATCH 2/2] thermal/drivers/mediatek/lvts_thermal: Improve some memory allocation
From: Dan Carpenter @ 2024-04-08 8:09 UTC (permalink / raw)
To: Christophe JAILLET
Cc: Rafael J. Wysocki, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Matthias Brugger, AngeloGioacchino Del Regno, linux-kernel,
kernel-janitors, linux-pm, linux-arm-kernel, linux-mediatek
In-Reply-To: <8cb69f245311a348164b0b5ca3dbc59386746035.1712520052.git.christophe.jaillet@wanadoo.fr>
On Sun, Apr 07, 2024 at 10:01:49PM +0200, Christophe JAILLET wrote:
> diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c
> index 3003dc350766..b133f731c5ba 100644
> --- a/drivers/thermal/mediatek/lvts_thermal.c
> +++ b/drivers/thermal/mediatek/lvts_thermal.c
> @@ -204,7 +204,7 @@ static const struct debugfs_reg32 lvts_regs[] = {
>
> static int lvts_debugfs_init(struct device *dev, struct lvts_domain *lvts_td)
> {
> - struct debugfs_regset32 *regset;
> + struct debugfs_regset32 *regsets;
> struct lvts_ctrl *lvts_ctrl;
> struct dentry *dentry;
> char name[64];
> @@ -214,8 +214,14 @@ static int lvts_debugfs_init(struct device *dev, struct lvts_domain *lvts_td)
> if (IS_ERR(lvts_td->dom_dentry))
> return 0;
>
> + regsets = devm_kcalloc(dev, lvts_td->num_lvts_ctrl,
> + sizeof(*regsets), GFP_KERNEL);
> + if (!regsets)
> + return 0;
I understand that this preserved the behavior from the original code,
but the original code was wrong. This should return -ENOMEM.
> +
> for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
>
> + struct debugfs_regset32 *regset = ®sets[i];
> lvts_ctrl = &lvts_td->lvts_ctrl[i];
The blank line should come after the declaration.
regards,
dan carpenter
^ permalink raw reply
* Re: [PATCH v2 1/6] media: platform: cros-ec: provide ID table for avoiding fallback match
From: Hans Verkuil @ 2024-04-08 7:36 UTC (permalink / raw)
To: Tzung-Bi Shih, bleung, groeck, linus.walleij, brgl, mchehab, sre
Cc: chrome-platform, pmalani, linux-gpio, linux-media, linux-pm, krzk,
Krzysztof Kozlowski
In-Reply-To: <20240401030052.2887845-2-tzungbi@kernel.org>
On 01/04/2024 05:00, Tzung-Bi Shih wrote:
> Instead of using fallback driver name match, provide ID table[1] for the
> primary match.
>
> [1]: https://elixir.bootlin.com/linux/v6.8/source/drivers/base/platform.c#L1353
>
> Reviewed-by: Benson Leung <bleung@chromium.org>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
Looks OK, I'll queue this patch up for v6.10.
Regards,
Hans
> ---
> Changes from v1:
> - No code changes.
> - Add R-b tags.
>
> drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
> index 48ed2993d2f0..8fbbb4091455 100644
> --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
> +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
> @@ -8,6 +8,7 @@
>
> #include <linux/kernel.h>
> #include <linux/module.h>
> +#include <linux/mod_devicetable.h>
> #include <linux/platform_device.h>
> #include <linux/dmi.h>
> #include <linux/pci.h>
> @@ -573,6 +574,12 @@ static void cros_ec_cec_remove(struct platform_device *pdev)
> }
> }
>
> +static const struct platform_device_id cros_ec_cec_id[] = {
> + { DRV_NAME, 0 },
> + {}
> +};
> +MODULE_DEVICE_TABLE(platform, cros_ec_cec_id);
> +
> static struct platform_driver cros_ec_cec_driver = {
> .probe = cros_ec_cec_probe,
> .remove_new = cros_ec_cec_remove,
> @@ -580,6 +587,7 @@ static struct platform_driver cros_ec_cec_driver = {
> .name = DRV_NAME,
> .pm = &cros_ec_cec_pm_ops,
> },
> + .id_table = cros_ec_cec_id,
> };
>
> module_platform_driver(cros_ec_cec_driver);
> @@ -587,4 +595,3 @@ module_platform_driver(cros_ec_cec_driver);
> MODULE_DESCRIPTION("CEC driver for ChromeOS ECs");
> MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
> MODULE_LICENSE("GPL");
> -MODULE_ALIAS("platform:" DRV_NAME);
^ permalink raw reply
* [PATCH v2] PM: s2idle: Make sure CPUs will wakeup directly on resume
From: Anna-Maria Behnsen @ 2024-04-08 7:02 UTC (permalink / raw)
To: linux-kernel
Cc: Rafael J . Wysocki, Pavel Machek, Len Brown, Ulf Hansson,
linux-pm, Frederic Weisbecker, Thomas Gleixner, x86,
Mario Limonciello, stable
In-Reply-To: <20240405083410.4896-1-anna-maria@linutronix.de>
s2idle works like a regular suspend with freezing processes and freezing
devices. All CPUs except the control CPU go into idle. Once this is
completed the control CPU kicks all other CPUs out of idle, so that they
reenter the idle loop and then enter s2idle state. The control CPU then
issues an swait() on the suspend state and therefore enters the idle loop
as well.
Due to being kicked out of idle, the other CPUs leave their NOHZ states,
which means the tick is active and the corresponding hrtimer is programmed
to the next jiffie.
On entering s2idle the CPUs shut down their local clockevent device to
prevent wakeups. The last CPU which enters s2idle shuts down its local
clockevent and freezes timekeeping.
On resume, one of the CPUs receives the wakeup interrupt, unfreezes
timekeeping and its local clockevent and starts the resume process. At that
point all other CPUs are still in s2idle with their clockevents switched
off. They only resume when they are kicked by another CPU or after resuming
devices and then receiving a device interrupt.
That means there is no guarantee that all CPUs will wakeup directly on
resume. As a consequence there is no guarantee that timers which are queued
on those CPUs and should expire directly after resume, are handled. Also
timer list timers which are remotely queued to one of those CPUs after
resume will not result in a reprogramming IPI as the tick is
active. Queueing a hrtimer will also not result in a reprogramming IPI
because the first hrtimer event is already in the past.
The recent introduction of the timer pull model (7ee988770326 ("timers:
Implement the hierarchical pull model")) amplifies this problem, if the
current migrator is one of the non woken up CPUs. When a non pinned timer
list timer is queued and the queuing CPU goes idle, it relies on the still
suspended migrator CPU to expire the timer which will happen by chance.
The problem exists since commit 8d89835b0467 ("PM: suspend: Do not pause
cpuidle in the suspend-to-idle path"). There the cpuidle_pause() call which
in turn invoked a wakeup for all idle CPUs was moved to a later point in
the resume process. This might not be reached or reached very late because
it waits on a timer of a still suspended CPU.
Address this by kicking all CPUs out of idle after the control CPU returns
from swait() so that they resume their timers and restore consistent system
state.
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218641
Fixes: 8d89835b0467 ("PM: suspend: Do not pause cpuidle in the suspend-to-idle path")
Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Mario Limonciello <mario.limonciello@amd.com>
Cc: stable@kernel.org
---
v2: Fix typos in commit message
---
kernel/power/suspend.c | 6 ++++++
1 file changed, 6 insertions(+)
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -106,6 +106,12 @@ static void s2idle_enter(void)
swait_event_exclusive(s2idle_wait_head,
s2idle_state == S2IDLE_STATE_WAKE);
+ /*
+ * Kick all CPUs to ensure that they resume their timers and restore
+ * consistent system state.
+ */
+ wake_up_all_idle_cpus();
+
cpus_read_unlock();
raw_spin_lock_irq(&s2idle_lock);
^ permalink raw reply
* [PATCH 1/2] dt-bindings: power: supply: ltc3350-charger: Add bindings
From: Mike Looijmans @ 2024-04-08 6:49 UTC (permalink / raw)
To: linux-pm
Cc: Mike Looijmans, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
Sebastian Reichel, devicetree, linux-kernel
In-Reply-To: <1b153bce-a66a-45ee-a5c6-963ea6fb1c82.949ef384-8293-46b8-903f-40a477c056ae.3bc97c8f-843d-4e46-84f9-469b7ba2489d@emailsignatures365.codetwo.com>
The LTC3350 is a backup power controller that can charge and monitor
a series stack of one to four supercapacitors.
Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
---
.../bindings/power/supply/ltc3350.yaml | 55 +++++++++++++++++++
1 file changed, 55 insertions(+)
create mode 100644 Documentation/devicetree/bindings/power/supply/ltc3350.yaml
diff --git a/Documentation/devicetree/bindings/power/supply/ltc3350.yaml b/Documentation/devicetree/bindings/power/supply/ltc3350.yaml
new file mode 100644
index 000000000000..607a62fd25ba
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/ltc3350.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) 2024 Topic Embedded Products
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/supply/ltc3350.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Linear Technology (Analog Devices) LTC3350 Supercap Charger
+
+maintainers:
+ - Mike Looijmans <mike.looijmans@topic.nl>
+
+description: |
+ The LTC3350 is a High Current Supercapacitor Backup Controller and System
+ Monitor.
+ Specifications about the charger can be found at:
+ https://www.analog.com/en/products/ltc3350.html
+
+properties:
+ compatible:
+ enum:
+ - lltc,ltc3350
+
+ reg:
+ maxItems: 1
+ description: I2C address of the charger.
+
+ lltc,rsnsc-micro-ohms:
+ description: Capacitor charger sense resistor in microohm.
+ minimum: 1000
+
+ lltc,rsnsi-micro-ohms:
+ description: Input current sense resistor in microohm.
+ minimum: 1000
+
+required:
+ - compatible
+ - reg
+ - lltc,rsnsc-micro-ohms
+ - lltc,rsnsi-micro-ohms
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ charger: battery-charger@9 {
+ compatible = "lltc,ltc3350";
+ reg = <0x9>;
+ lltc,rsnsc-micro-ohms = <10000>;
+ lltc,rsnsi-micro-ohms = <10000>;
+ };
+ };
--
2.34.1
Met vriendelijke groet / kind regards,
Mike Looijmans
System Expert
TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands
T: +31 (0) 499 33 69 69
E: mike.looijmans@topic.nl
W: www.topic.nl
Please consider the environment before printing this e-mail
^ permalink raw reply related
* [PATCH 2/2] power: supply: ltc3350-charger: Add driver
From: Mike Looijmans @ 2024-04-08 6:49 UTC (permalink / raw)
To: linux-pm; +Cc: Mike Looijmans, Sebastian Reichel, linux-kernel
In-Reply-To: <20240408064905.20298-1-mike.looijmans@topic.nl>
The LTC3350 is a backup power controller that can charge and monitor
a series stack of one to four supercapacitors.
Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
---
drivers/power/supply/Kconfig | 10 +
drivers/power/supply/Makefile | 1 +
drivers/power/supply/ltc3350-charger.c | 720 +++++++++++++++++++++++++
3 files changed, 731 insertions(+)
create mode 100644 drivers/power/supply/ltc3350-charger.c
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 3e31375491d5..7cb1a66e522d 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -514,6 +514,16 @@ config CHARGER_LT3651
Say Y to include support for the Analog Devices (Linear Technology)
LT3651 battery charger which reports its status via GPIO lines.
+config CHARGER_LTC3350
+ tristate "LTC3350 Supercapacitor Backup Controller and System Monitor"
+ depends on I2C
+ select REGMAP_I2C
+ select I2C_SMBUS
+ help
+ Say Y to include support for the Analog Devices (Linear Technology)
+ LTC3350 Supercapacitor Backup Controller and System Monitor connected
+ to I2C.
+
config CHARGER_LTC4162L
tristate "LTC4162-L charger"
depends on I2C
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 58b567278034..a8d618e4ac91 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o
obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
obj-$(CONFIG_CHARGER_LT3651) += lt3651-charger.o
+obj-$(CONFIG_CHARGER_LTC3350) += ltc3350-charger.o
obj-$(CONFIG_CHARGER_LTC4162L) += ltc4162-l-charger.o
obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o
diff --git a/drivers/power/supply/ltc3350-charger.c b/drivers/power/supply/ltc3350-charger.c
new file mode 100644
index 000000000000..b3a23447ebf4
--- /dev/null
+++ b/drivers/power/supply/ltc3350-charger.c
@@ -0,0 +1,720 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Analog Devices (Linear Technology) LTC3350
+ * High Current Supercapacitor Backup Controller and System Monitor
+ * Copyright (C) 2024, Topic Embedded Products
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/power_supply.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+/* Registers (names based on what datasheet uses) */
+#define LTC3350_REG_CLR_ALARMS 0x00
+#define LTC3350_REG_MSK_ALARMS 0x01
+#define LTC3350_REG_MSK_MON_STATUS 0x02
+#define LTC3350_REG_CAP_ESR_PER 0x04
+#define LTC3350_REG_VCAPFB_DAC 0x05
+#define LTC3350_REG_VSHUNT 0x06
+#define LTC3350_REG_CAP_UV_LVL 0x07
+#define LTC3350_REG_CAP_OV_LVL 0x08
+#define LTC3350_REG_GPI_UV_LVL 0x09
+#define LTC3350_REG_GPI_OV_LVL 0x0A
+#define LTC3350_REG_VIN_UV_LVL 0x0B
+#define LTC3350_REG_VIN_OV_LVL 0x0C
+#define LTC3350_REG_VCAP_UV_LVL 0x0D
+#define LTC3350_REG_VCAP_OV_LVL 0x0E
+#define LTC3350_REG_VOUT_UV_LVL 0x0F
+#define LTC3350_REG_VOUT_OV_LVL 0x10
+#define LTC3350_REG_IIN_OC_LVL 0x11
+#define LTC3350_REG_ICHG_UC_LVL 0x12
+#define LTC3350_REG_DTEMP_COLD_LVL 0x13
+#define LTC3350_REG_DTEMP_HOT_LVL 0x14
+#define LTC3350_REG_ESR_HI_LVL 0x15
+#define LTC3350_REG_CAP_LO_LVL 0x16
+#define LTC3350_REG_CTL_REG 0x17
+#define LTC3350_REG_NUM_CAPS 0x1A
+#define LTC3350_REG_CHRG_STATUS 0x1B
+#define LTC3350_REG_MON_STATUS 0x1C
+#define LTC3350_REG_ALARM_REG 0x1D
+#define LTC3350_REG_MEAS_CAP 0x1E
+#define LTC3350_REG_MEAS_ESR 0x1F
+#define LTC3350_REG_MEAS_VCAP1 0x20
+#define LTC3350_REG_MEAS_VCAP2 0x21
+#define LTC3350_REG_MEAS_VCAP3 0x22
+#define LTC3350_REG_MEAS_VCAP4 0x23
+#define LTC3350_REG_MEAS_GPI 0x24
+#define LTC3350_REG_MEAS_VIN 0x25
+#define LTC3350_REG_MEAS_VCAP 0x26
+#define LTC3350_REG_MEAS_VOUT 0x27
+#define LTC3350_REG_MEAS_IIN 0x28
+#define LTC3350_REG_MEAS_ICHG 0x29
+#define LTC3350_REG_MEAS_DTEMP 0x2A
+
+/* LTC3350_REG_CLR_ALARMS, LTC3350_REG_MASK_ALARMS, LTC3350_REG_ALARM_REG */
+#define LTC3350_MSK_CAP_UV BIT(0) /* capacitor undervoltage alarm */
+#define LTC3350_MSK_CAP_OV BIT(1) /* capacitor overvoltage alarm */
+#define LTC3350_MSK_GPI_UV BIT(2) /* GPI undervoltage alarm */
+#define LTC3350_MSK_GPI_OV BIT(3) /* GPI overvoltage alarm */
+#define LTC3350_MSK_VIN_UV BIT(4) /* VIN undervoltage alarm */
+#define LTC3350_MSK_VIN_OV BIT(5) /* VIN overvoltage alarm */
+#define LTC3350_MSK_VCAP_UV BIT(6) /* VCAP undervoltage alarm */
+#define LTC3350_MSK_VCAP_OV BIT(7) /* VCAP overvoltage alarm */
+#define LTC3350_MSK_VOUT_UV BIT(8) /* VOUT undervoltage alarm */
+#define LTC3350_MSK_VOUT_OV BIT(9) /* VOUT overvoltage alarm */
+#define LTC3350_MSK_IIN_OC BIT(10) /* input overcurrent alarm */
+#define LTC3350_MSK_ICHG_UC BIT(11) /* charge undercurrent alarm */
+#define LTC3350_MSK_DTEMP_COLD BIT(12) /* die temperature cold alarm */
+#define LTC3350_MSK_DTEMP_HOT BIT(13) /* die temperature hot alarm */
+#define LTC3350_MSK_ESR_HI BIT(14) /* ESR high alarm */
+#define LTC3350_MSK_CAP_LO BIT(15) /* capacitance low alarm */
+
+/* LTC3350_REG_MSK_MON_STATUS masks */
+#define LTC3350_MSK_MON_CAPESR_ACTIVE BIT(0)
+#define LTC3350_MSK_MON_CAPESR_SCHEDULED BIT(1)
+#define LTC3350_MSK_MON_CAPESR_PENDING BIT(2)
+#define LTC3350_MSK_MON_CAP_DONE BIT(3)
+#define LTC3350_MSK_MON_ESR_DONE BIT(4)
+#define LTC3350_MSK_MON_CAP_FAILED BIT(5)
+#define LTC3350_MSK_MON_ESR_FAILED BIT(6)
+#define LTC3350_MSK_MON_POWER_FAILED BIT(8)
+#define LTC3350_MSK_MON_POWER_RETURNED BIT(9)
+
+/* LTC3350_REG_CTL_REG */
+/* Begin a capacitance and ESR measurement when possible */
+#define LTC3350_CTL_STRT_CAPESR BIT(0)
+/* A one in this bit location enables the input buffer on the GPI pin */
+#define LTC3350_CTL_GPI_BUFFER_EN BIT(1)
+/* Stops an active capacitance/ESR measurement */
+#define LTC3350_CTL_STOP_CAPESR BIT(2)
+/* Increases capacitor measurement resolution by 100x for smaller capacitors */
+#define LTC3350_CTL_CAP_SCALE BIT(3)
+
+/* LTC3350_REG_CHRG_STATUS */
+#define LTC3350_CHRG_STEPDOWN BIT(0) /* Synchronous controller in step-down mode (charging) */
+#define LTC3350_CHRG_STEPUP BIT(1) /* Synchronous controller in step-up mode (backup) */
+#define LTC3350_CHRG_CV BIT(2) /* The charger is in constant voltage mode */
+#define LTC3350_CHRG_UVLO BIT(3) /* The charger is in undervoltage lockout */
+#define LTC3350_CHRG_INPUT_ILIM BIT(4) /* The charger is in input current limit */
+#define LTC3350_CHRG_CAPPG BIT(5) /* The capacitor voltage is above power good threshold */
+#define LTC3350_CHRG_SHNT BIT(6) /* The capacitor manager is shunting */
+#define LTC3350_CHRG_BAL BIT(7) /* The capacitor manager is balancing */
+#define LTC3350_CHRG_DIS BIT(8) /* Charger disabled for capacitance measurement */
+#define LTC3350_CHRG_CI BIT(9) /* The charger is in constant current mode */
+#define LTC3350_CHRG_PFO BIT(11) /* Input voltage is below PFI threshold */
+
+/* LTC3350_REG_MON_STATUS */
+#define LTC3350_MON_CAPESR_ACTIVE BIT(0) /* Capacitance/ESR measurement in progress */
+#define LTC3350_MON_CAPESR_SCHEDULED BIT(1) /* Waiting programmed time */
+#define LTC3350_MON_CAPESR_PENDING BIT(2) /* Waiting for satisfactory conditions */
+#define LTC3350_MON_CAP_DONE BIT(3) /* Capacitance measurement has completed */
+#define LTC3350_MON_ESR_DONE BIT(4) /* ESR Measurement has completed */
+#define LTC3350_MON_CAP_FAILED BIT(5) /* Last capacitance measurement failed */
+#define LTC3350_MON_ESR_FAILED BIT(6) /* Last ESR measurement failed */
+#define LTC3350_MON_POWER_FAILED BIT(8) /* Unable to charge */
+#define LTC3350_MON_POWER_RETURNED BIT(9) /* Able to charge */
+
+
+struct ltc3350_info {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct power_supply *charger;
+ u32 rsnsc; /* Series resistor that sets charge current, microOhm */
+ u32 rsnsi; /* Series resistor to measure input current, microOhm */
+};
+
+/*
+ * About LTC3350 "alarm" functions: Setting a bit in the LTC3350_REG_MSK_ALARMS
+ * register enables the alarm. The alarm will trigger an SMBALERT only once.
+ * To reset the alarm, write a "1" bit to LTC3350_REG_CLR_ALARMS. Then the alarm
+ * will trigger another SMBALERT when conditions are met (may be immediately).
+ * After writing to one of the corresponding level registers, enable the alarm,
+ * so that a UEVENT triggers when the alarm goes off.
+ */
+static void ltc3350_enable_alarm(struct ltc3350_info *info, unsigned int reg)
+{
+ unsigned int mask;
+
+ /* Register locations correspond to alarm mask bits */
+ mask = BIT(reg - LTC3350_REG_CAP_UV_LVL);
+ /* Clear the alarm bit so it may trigger again */
+ regmap_write(info->regmap, LTC3350_REG_CLR_ALARMS, mask);
+ /* Enable the alarm */
+ regmap_update_bits(info->regmap, LTC3350_REG_MSK_ALARMS, mask, mask);
+}
+
+/* Convert enum value to POWER_SUPPLY_STATUS value */
+static int ltc3350_state_decode(unsigned int value)
+{
+ if (value & LTC3350_CHRG_STEPUP)
+ return POWER_SUPPLY_STATUS_DISCHARGING; /* running on backup */
+
+ if (value & LTC3350_CHRG_PFO)
+ return POWER_SUPPLY_STATUS_NOT_CHARGING;
+
+ if (value & LTC3350_CHRG_STEPDOWN) {
+ /* The chip remains in CV mode indefinitely, hence "full" */
+ if (value & LTC3350_CHRG_CV)
+ return POWER_SUPPLY_STATUS_FULL;
+
+ return POWER_SUPPLY_STATUS_CHARGING;
+ }
+
+ /* Not in step down? Must be full then (never seen this) */
+ return POWER_SUPPLY_STATUS_FULL;
+};
+
+static int ltc3350_get_status(struct ltc3350_info *info, union power_supply_propval *val)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->regmap, LTC3350_REG_CHRG_STATUS, ®val);
+ if (ret)
+ return ret;
+
+ val->intval = ltc3350_state_decode(regval);
+
+ return 0;
+}
+
+static int ltc3350_charge_status_decode(unsigned int value)
+{
+ if (!(value & LTC3350_CHRG_STEPDOWN))
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
+
+ /* constant voltage is "topping off" */
+ if (value & LTC3350_CHRG_CV)
+ return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+
+ /* input limiter */
+ if (value & LTC3350_CHRG_INPUT_ILIM)
+ return POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE;
+
+ /* constant current is "fast" */
+ if (value & LTC3350_CHRG_CI)
+ return POWER_SUPPLY_CHARGE_TYPE_FAST;
+
+ return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+}
+
+static int ltc3350_get_charge_type(struct ltc3350_info *info, union power_supply_propval *val)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->regmap, LTC3350_REG_CHRG_STATUS, ®val);
+ if (ret)
+ return ret;
+
+ val->intval = ltc3350_charge_status_decode(regval);
+
+ return 0;
+}
+
+static int ltc3350_get_online(struct ltc3350_info *info, union power_supply_propval *val)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->regmap, LTC3350_REG_MON_STATUS, ®val);
+ if (ret)
+ return ret;
+
+ /* indicates if input voltage is sufficient to charge */
+ val->intval = !!(regval & LTC3350_MON_POWER_RETURNED);
+
+ return 0;
+}
+
+static int ltc3350_get_input_voltage(struct ltc3350_info *info, union power_supply_propval *val)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->regmap, LTC3350_REG_MEAS_VIN, ®val);
+ if (ret)
+ return ret;
+
+ /* 2.21mV/LSB */
+ val->intval = regval * 2210;
+
+ return 0;
+}
+
+static int ltc3350_get_input_current(struct ltc3350_info *info, union power_supply_propval *val)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->regmap, LTC3350_REG_MEAS_IIN, ®val);
+ if (ret)
+ return ret;
+
+ /* 1.983µV/RSNSI amperes per LSB */
+ ret = regval * 19830;
+ ret /= info->rsnsi;
+ ret *= 100;
+
+ val->intval = ret;
+
+ return 0;
+}
+
+static int ltc3350_get_icharge(struct ltc3350_info *info, union power_supply_propval *val)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->regmap, LTC3350_REG_MEAS_ICHG, ®val);
+ if (ret)
+ return ret;
+
+ /* 1.983µV/RSNSC amperes per LSB */
+ ret = regval * 19830;
+ ret /= info->rsnsc;
+ ret *= 100;
+
+ val->intval = ret;
+
+ return 0;
+}
+
+static int ltc3350_get_icharge_max(struct ltc3350_info *info, union power_supply_propval *val)
+{
+ /* I_CHG(MAX) = 32mV / RSNSC (Ampere) */
+ val->intval = 3200000000U / (info->rsnsc / 10);
+
+ return 0;
+}
+
+static int ltc3350_get_iin_max(struct ltc3350_info *info, union power_supply_propval *val)
+{
+ /* I_IN(MAX) = 32mV / RSNSI (Ampere) */
+ val->intval = 3200000000U / (info->rsnsi / 10);
+
+ return 0;
+}
+
+
+static int ltc3350_get_die_temp(struct ltc3350_info *info, unsigned int reg,
+ union power_supply_propval *val)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->regmap, reg, ®val);
+ if (ret)
+ return ret;
+
+ /* 0.028°C per LSB – 251.4°C */
+ ret = 280 * regval;
+ ret /= 100; /* Centidegrees scale */
+ ret -= 25140;
+ val->intval = ret;
+
+ return 0;
+}
+
+static int ltc3350_set_die_temp(struct ltc3350_info *info, unsigned int reg, int val)
+{
+ unsigned int regval;
+ int ret;
+
+ /* 0.028°C per LSB – 251.4°C */
+ regval = val + 25140;
+ regval *= 100;
+ regval /= 280;
+
+ ret = regmap_write(info->regmap, reg, regval);
+ if (ret)
+ return ret;
+
+ ltc3350_enable_alarm(info, reg);
+ return 0;
+}
+
+/* Custom properties */
+
+static ssize_t ltc3350_attr_show(struct device *dev,
+ struct device_attribute *attr, char *buf,
+ unsigned int reg, unsigned int scale)
+{
+ struct power_supply *psy = to_power_supply(dev);
+ struct ltc3350_info *info = power_supply_get_drvdata(psy);
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->regmap, reg, ®val);
+ if (ret)
+ return ret;
+
+ regval *= scale; /* Scale is in 10 μV units */
+ regval /= 10;
+
+ return sprintf(buf, "%u\n", regval);
+}
+
+static ssize_t ltc3350_attr_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count,
+ unsigned int reg, unsigned int scale)
+{
+ struct power_supply *psy = to_power_supply(dev);
+ struct ltc3350_info *info = power_supply_get_drvdata(psy);
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ val *= 10;
+ val = DIV_ROUND_CLOSEST(val, scale); /* Scale is in 10 μV units */
+
+ ret = regmap_write(info->regmap, reg, val);
+ if (ret)
+ return ret;
+
+ /* When writing to one of the LVL registers, update the alarm mask */
+ if (reg >= LTC3350_REG_CAP_UV_LVL && reg <= LTC3350_REG_CAP_LO_LVL)
+ ltc3350_enable_alarm(info, reg);
+
+ return count;
+}
+
+#define LTC3350_DEVICE_ATTR_RO(_name, _reg, _scale) \
+static ssize_t _name##_show(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return ltc3350_attr_show(dev, attr, buf, _reg, _scale); \
+} \
+static DEVICE_ATTR_RO(_name)
+
+#define LTC3350_DEVICE_ATTR_RW(_name, _reg, _scale) \
+static ssize_t _name##_show(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return ltc3350_attr_show(dev, attr, buf, _reg, _scale); \
+} \
+static ssize_t _name##_store(struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ return ltc3350_attr_store(dev, attr, buf, count, _reg, _scale); \
+} \
+static DEVICE_ATTR_RW(_name)
+
+/* Shunt voltage, 183.5μV per LSB */
+LTC3350_DEVICE_ATTR_RW(vshunt, LTC3350_REG_VSHUNT, 1835);
+
+/* Single capacitor voltages, 183.5μV per LSB */
+LTC3350_DEVICE_ATTR_RO(vcap1, LTC3350_REG_MEAS_VCAP1, 1835);
+LTC3350_DEVICE_ATTR_RO(vcap2, LTC3350_REG_MEAS_VCAP2, 1835);
+LTC3350_DEVICE_ATTR_RO(vcap3, LTC3350_REG_MEAS_VCAP3, 1835);
+LTC3350_DEVICE_ATTR_RO(vcap4, LTC3350_REG_MEAS_VCAP4, 1835);
+LTC3350_DEVICE_ATTR_RW(cap_uv, LTC3350_REG_CAP_UV_LVL, 1835);
+LTC3350_DEVICE_ATTR_RW(cap_ov, LTC3350_REG_CAP_OV_LVL, 1835);
+
+/* General purpose input, 183.5μV per LSB */
+LTC3350_DEVICE_ATTR_RO(gpi, LTC3350_REG_MEAS_GPI, 1835);
+LTC3350_DEVICE_ATTR_RW(gpi_uv, LTC3350_REG_GPI_UV_LVL, 1835);
+LTC3350_DEVICE_ATTR_RW(gpi_ov, LTC3350_REG_GPI_OV_LVL, 1835);
+
+/* Input voltage, 2.21mV per LSB */
+LTC3350_DEVICE_ATTR_RO(vin, LTC3350_REG_MEAS_VIN, 22100);
+LTC3350_DEVICE_ATTR_RW(vin_uv, LTC3350_REG_VIN_UV_LVL, 22100);
+LTC3350_DEVICE_ATTR_RW(vin_ov, LTC3350_REG_VIN_OV_LVL, 22100);
+
+/* Capacitor stack voltage, 1.476 mV per LSB */
+LTC3350_DEVICE_ATTR_RO(vcap, LTC3350_REG_MEAS_VCAP, 14760);
+LTC3350_DEVICE_ATTR_RW(vcap_uv, LTC3350_REG_VCAP_UV_LVL, 14760);
+LTC3350_DEVICE_ATTR_RW(vcap_ov, LTC3350_REG_VCAP_OV_LVL, 14760);
+
+/* Output, 2.21mV per LSB */
+LTC3350_DEVICE_ATTR_RO(vout, LTC3350_REG_MEAS_VOUT, 22100);
+LTC3350_DEVICE_ATTR_RW(vout_uv, LTC3350_REG_VOUT_UV_LVL, 22100);
+LTC3350_DEVICE_ATTR_RW(vout_ov, LTC3350_REG_VOUT_OV_LVL, 22100);
+
+static ssize_t num_caps_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct power_supply *psy = to_power_supply(dev);
+ struct ltc3350_info *info = power_supply_get_drvdata(psy);
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->regmap, LTC3350_REG_NUM_CAPS, ®val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", regval + 1);
+}
+static DEVICE_ATTR_RO(num_caps);
+
+static ssize_t charge_status_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct power_supply *psy = to_power_supply(dev);
+ struct ltc3350_info *info = power_supply_get_drvdata(psy);
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->regmap, LTC3350_REG_CHRG_STATUS, ®val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "0x%x\n", regval);
+}
+static DEVICE_ATTR_RO(charge_status);
+
+static struct attribute *ltc3350_sysfs_entries[] = {
+ &dev_attr_vshunt.attr,
+ &dev_attr_vcap1.attr,
+ &dev_attr_vcap2.attr,
+ &dev_attr_vcap3.attr,
+ &dev_attr_vcap4.attr,
+ &dev_attr_cap_uv.attr,
+ &dev_attr_cap_ov.attr,
+ &dev_attr_gpi.attr,
+ &dev_attr_gpi_uv.attr,
+ &dev_attr_gpi_ov.attr,
+ &dev_attr_vin_uv.attr,
+ &dev_attr_vin_ov.attr,
+ &dev_attr_vcap.attr,
+ &dev_attr_vcap_uv.attr,
+ &dev_attr_vcap_ov.attr,
+ &dev_attr_vin.attr,
+ &dev_attr_vin_uv.attr,
+ &dev_attr_vin_ov.attr,
+ &dev_attr_vout.attr,
+ &dev_attr_vout_uv.attr,
+ &dev_attr_vout_ov.attr,
+ &dev_attr_num_caps.attr,
+ &dev_attr_charge_status.attr,
+ NULL,
+};
+
+static const struct attribute_group ltc3350_attr_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = ltc3350_sysfs_entries,
+};
+
+static const struct attribute_group *ltc3350_attr_groups[] = {
+ <c3350_attr_group,
+ NULL,
+};
+
+static int ltc3350_get_property(struct power_supply *psy, enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct ltc3350_info *info = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ return ltc3350_get_status(info, val);
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ return ltc3350_get_charge_type(info, val);
+ case POWER_SUPPLY_PROP_ONLINE:
+ return ltc3350_get_online(info, val);
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ return ltc3350_get_input_voltage(info, val);
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ return ltc3350_get_input_current(info, val);
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ return ltc3350_get_icharge(info, val);
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+ return ltc3350_get_icharge_max(info, val);
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ return ltc3350_get_iin_max(info, val);
+ case POWER_SUPPLY_PROP_TEMP:
+ return ltc3350_get_die_temp(info, LTC3350_REG_MEAS_DTEMP, val);
+ case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
+ return ltc3350_get_die_temp(info, LTC3350_REG_DTEMP_COLD_LVL, val);
+ case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
+ return ltc3350_get_die_temp(info, LTC3350_REG_DTEMP_HOT_LVL, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ltc3350_set_property(struct power_supply *psy, enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct ltc3350_info *info = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
+ return ltc3350_set_die_temp(info, LTC3350_REG_DTEMP_COLD_LVL, val->intval);
+ case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
+ return ltc3350_set_die_temp(info, LTC3350_REG_DTEMP_HOT_LVL, val->intval);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ltc3350_property_is_writeable(struct power_supply *psy, enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
+ case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* Charger power supply property routines */
+static enum power_supply_property ltc3350_properties[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
+ POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
+};
+
+static const struct power_supply_desc ltc3350_desc = {
+ .name = "ltc3350",
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .properties = ltc3350_properties,
+ .num_properties = ARRAY_SIZE(ltc3350_properties),
+ .get_property = ltc3350_get_property,
+ .set_property = ltc3350_set_property,
+ .property_is_writeable = ltc3350_property_is_writeable,
+};
+
+static bool ltc3350_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+ /* all registers up to this one are writeable */
+ return reg < LTC3350_REG_NUM_CAPS;
+}
+
+static bool ltc3350_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ /* read-only status registers and self-clearing register */
+ return reg > LTC3350_REG_NUM_CAPS || reg == LTC3350_REG_CLR_ALARMS;
+}
+
+static const struct regmap_config ltc3350_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+ .writeable_reg = ltc3350_is_writeable_reg,
+ .volatile_reg = ltc3350_is_volatile_reg,
+ .max_register = LTC3350_REG_MEAS_DTEMP,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static int ltc3350_probe(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct device *dev = &client->dev;
+ struct ltc3350_info *info;
+ struct power_supply_config ltc3350_config = {};
+ int ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_err(dev, "No support for SMBUS_WORD_DATA\n");
+ return -ENODEV;
+ }
+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->client = client;
+ i2c_set_clientdata(client, info);
+
+ info->regmap = devm_regmap_init_i2c(client, <c3350_regmap_config);
+ if (IS_ERR(info->regmap)) {
+ dev_err(dev, "Failed to initialize register map\n");
+ return PTR_ERR(info->regmap);
+ }
+
+ ret = device_property_read_u32(dev, "lltc,rsnsc-micro-ohms",
+ &info->rsnsc);
+ if (ret) {
+ dev_err(dev, "Missing lltc,rsnsc-micro-ohms property\n");
+ return ret;
+ }
+ if (!info->rsnsc)
+ return -EINVAL;
+
+ ret = device_property_read_u32(dev, "lltc,rsnsi-micro-ohms",
+ &info->rsnsi);
+ if (ret) {
+ dev_err(dev, "Missing lltc,rsnsi-micro-ohms property\n");
+ return ret;
+ }
+ if (!info->rsnsi)
+ return -EINVAL;
+
+ /* Clear and disable all interrupt sources*/
+ ret = regmap_write(info->regmap, LTC3350_REG_CLR_ALARMS, 0xFFFF);
+ if (ret) {
+ dev_err(dev, "Failed to write configuration\n");
+ return ret;
+ }
+ regmap_write(info->regmap, LTC3350_REG_MSK_ALARMS, 0);
+ regmap_write(info->regmap, LTC3350_REG_MSK_MON_STATUS, 0);
+
+ ltc3350_config.of_node = dev->of_node;
+ ltc3350_config.drv_data = info;
+ ltc3350_config.attr_grp = ltc3350_attr_groups;
+
+ info->charger = devm_power_supply_register(dev, <c3350_desc,
+ <c3350_config);
+ if (IS_ERR(info->charger)) {
+ dev_err(dev, "Failed to register charger\n");
+ return PTR_ERR(info->charger);
+ }
+
+ /* Enable interrupts on status changes */
+ regmap_write(info->regmap, LTC3350_REG_MSK_MON_STATUS,
+ LTC3350_MON_POWER_FAILED | LTC3350_MON_POWER_RETURNED);
+
+ return 0;
+}
+
+static void ltc3350_alert(struct i2c_client *client, enum i2c_alert_protocol type,
+ unsigned int flag)
+{
+ struct ltc3350_info *info = i2c_get_clientdata(client);
+
+ if (type != I2C_PROTOCOL_SMBUS_ALERT)
+ return;
+
+ power_supply_changed(info->charger);
+}
+
+static const struct i2c_device_id ltc3350_i2c_id_table[] = {
+ { "ltc3350", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, ltc3350_i2c_id_table);
+
+static const struct of_device_id ltc3350_of_match[] = {
+ { .compatible = "lltc,ltc3350", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ltc3350_of_match);
+
+static struct i2c_driver ltc3350_driver = {
+ .probe = ltc3350_probe,
+ .alert = ltc3350_alert,
+ .id_table = ltc3350_i2c_id_table,
+ .driver = {
+ .name = "ltc3350-charger",
+ .of_match_table = of_match_ptr(ltc3350_of_match),
+ },
+};
+module_i2c_driver(ltc3350_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
+MODULE_DESCRIPTION("LTC3350 charger driver");
--
2.34.1
Met vriendelijke groet / kind regards,
Mike Looijmans
System Expert
TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands
T: +31 (0) 499 33 69 69
E: mike.looijmans@topic.nl
W: www.topic.nl
Please consider the environment before printing this e-mail
^ permalink raw reply related
* Re: [PATCH] power: supply: cros_usbpd: Don't show messages for no charging ports found
From: Tzung-Bi Shih @ 2024-04-08 6:29 UTC (permalink / raw)
To: Mario Limonciello
Cc: Benson Leung, Guenter Roeck, Sebastian Reichel,
open list:CHROMEOS EC SUBDRIVERS,
open list:POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS, open list,
Dustin L . Howett, Mario Limonciello
In-Reply-To: <20240406191734.137797-1-superm1@gmail.com>
On Sat, Apr 06, 2024 at 02:17:34PM -0500, Mario Limonciello wrote:
> From: Mario Limonciello <mario.limonciello@amd.com>
>
> Framework 13 and 16 don't use cros_usbpd but do use cros_ec. The following
> sequence of messages is totally unnecessary.
In the case, the EC firmware shouldn't report the feature. See [1].
[1]: https://elixir.bootlin.com/linux/v6.8/source/drivers/mfd/cros_ec_dev.c#L106
^ permalink raw reply
* [PATCH] powercap: intel_rapl: Add support for ArrowLake-H platform
From: Zhang Rui @ 2024-04-08 4:05 UTC (permalink / raw)
To: rafael.j.wysocki; +Cc: linux-kernel, linux-pm
Add support for ArrowLake-H platform.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
drivers/powercap/intel_rapl_common.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/powercap/intel_rapl_common.c b/drivers/powercap/intel_rapl_common.c
index a28d54fd5222..c02851c73751 100644
--- a/drivers/powercap/intel_rapl_common.c
+++ b/drivers/powercap/intel_rapl_common.c
@@ -1263,6 +1263,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = {
X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, &rapl_defaults_spr_server),
X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X, &rapl_defaults_spr_server),
X86_MATCH_INTEL_FAM6_MODEL(LUNARLAKE_M, &rapl_defaults_core),
+ X86_MATCH_INTEL_FAM6_MODEL(ARROWLAKE_H, &rapl_defaults_core),
X86_MATCH_INTEL_FAM6_MODEL(ARROWLAKE, &rapl_defaults_core),
X86_MATCH_INTEL_FAM6_MODEL(LAKEFIELD, &rapl_defaults_core),
--
2.34.1
^ permalink raw reply related
* [PATCH V2 3/3] powercap: intel_rapl_tpmi: Enable PMU support
From: Zhang Rui @ 2024-04-08 3:51 UTC (permalink / raw)
To: rafael.j.wysocki; +Cc: linux-kernel, linux-pm, srinivas.pandruvada
In-Reply-To: <20240408035141.248644-1-rui.zhang@intel.com>
Enable RAPL PMU support for TPMI RAPL driver.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
drivers/powercap/intel_rapl_tpmi.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/powercap/intel_rapl_tpmi.c b/drivers/powercap/intel_rapl_tpmi.c
index f6b7f085977c..947544e4d229 100644
--- a/drivers/powercap/intel_rapl_tpmi.c
+++ b/drivers/powercap/intel_rapl_tpmi.c
@@ -302,6 +302,8 @@ static int intel_rapl_tpmi_probe(struct auxiliary_device *auxdev,
goto err;
}
+ rapl_package_add_pmu(trp->rp);
+
auxiliary_set_drvdata(auxdev, trp);
return 0;
@@ -314,6 +316,7 @@ static void intel_rapl_tpmi_remove(struct auxiliary_device *auxdev)
{
struct tpmi_rapl_package *trp = auxiliary_get_drvdata(auxdev);
+ rapl_package_remove_pmu(trp->rp);
rapl_remove_package(trp->rp);
trp_release(trp);
}
--
2.34.1
^ permalink raw reply related
* [PATCH V2 2/3] powercap: intel_rapl: Introduce APIs for PMU support
From: Zhang Rui @ 2024-04-08 3:51 UTC (permalink / raw)
To: rafael.j.wysocki; +Cc: linux-kernel, linux-pm, srinivas.pandruvada
In-Reply-To: <20240408035141.248644-1-rui.zhang@intel.com>
Introduce two new APIs rapl_package_add_pmu()/rapl_package_remove_pmu().
RAPL driver can invoke these APIs to expose its supported energy
counters via perf PMU. The new RAPL PMU is fully compatible with current
MSR RAPL PMU, including using the same PMU name and events
name/id/unit/scale, etc.
For example, use below command
perf stat -e power/energy-pkg/ -e power/energy-ram/ -e power/energy-cores/ FOO
to get the energy consumption for events in the "perf list" output.
This does not introduce any conflict because TPMI RAPL is the only user
of these APIs currently, and it never co-exists with MSR RAPL.
Note that, TPMI RAPL is probed dynamically, and the events supported by
each TPMI RAPL device can be different. Thus, for a new RAPL Package
device that wants PMU support,
1. if PMU has not been registered yet, register the PMU with events
supported by current RAPL Package device
2. if PMU has been registered and no new events support is needed, do
nothing
2. or else, unregister current PMU and re-register the PMU with events
supported by all probed RAPL Package devices that need PMU support.
For example, on a dual-package system using TPMI RAPL, it is possible
that Package 1 behaves as TPMI domain root and supports Psys domain.
In this case, register PMU without Psys event when probing Package 0,
and re-register the PMU with Psys event when probing Package 1.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
drivers/powercap/intel_rapl_common.c | 537 +++++++++++++++++++++++++++
include/linux/intel_rapl.h | 23 ++
2 files changed, 560 insertions(+)
diff --git a/drivers/powercap/intel_rapl_common.c b/drivers/powercap/intel_rapl_common.c
index 1f4a7aa12d77..f51012f023b0 100644
--- a/drivers/powercap/intel_rapl_common.c
+++ b/drivers/powercap/intel_rapl_common.c
@@ -15,6 +15,8 @@
#include <linux/list.h>
#include <linux/log2.h>
#include <linux/module.h>
+#include <linux/nospec.h>
+#include <linux/perf_event.h>
#include <linux/platform_device.h>
#include <linux/powercap.h>
#include <linux/processor.h>
@@ -1506,6 +1508,541 @@ static int rapl_detect_domains(struct rapl_package *rp)
return 0;
}
+#ifdef CONFIG_PERF_EVENTS
+
+/* Support for RAPL PMU */
+
+struct rapl_pmu {
+ struct pmu pmu;
+ u64 timer_ms;
+ cpumask_t cpu_mask;
+ unsigned long domain_map; /* Events supported by all registered RAPL packages */
+ bool registered;
+};
+
+static struct rapl_pmu rapl_pmu;
+
+/* PMU helpers */
+static int get_pmu_cpu(struct rapl_package *rp)
+{
+ int cpu;
+
+ if (!rp->has_pmu)
+ return nr_cpu_ids;
+
+ if (rp->lead_cpu >= 0)
+ return rp->lead_cpu;
+
+ /* TPMI RAPL uses any CPU in the package for PMU */
+ for_each_online_cpu(cpu)
+ if (topology_physical_package_id(cpu) == rp->id)
+ return cpu;
+
+ return nr_cpu_ids;
+}
+
+static bool is_rp_pmu_cpu(struct rapl_package *rp, int cpu)
+{
+ if (!rp->has_pmu)
+ return false;
+
+ if (rp->lead_cpu >= 0)
+ return cpu == rp->lead_cpu;
+
+ /* TPMI RAPL uses any CPU in the package for PMU */
+ return topology_physical_package_id(cpu) == rp->id;
+}
+
+static struct rapl_package_pmu_data *event_to_pmu_data(struct perf_event *event)
+{
+ struct rapl_package *rp = event->pmu_private;
+
+ return &rp->pmu_data;
+}
+
+/* PMU event callbacks */
+
+/* Return 0 for unsupported events or failed read */
+static u64 event_read_counter(struct perf_event *event)
+{
+ struct rapl_package *rp = event->pmu_private;
+ u64 val;
+ int ret;
+
+ if (event->hw.idx < 0)
+ return 0;
+
+ ret = rapl_read_data_raw(&rp->domains[event->hw.idx], ENERGY_COUNTER, false, &val);
+ return ret ? 0 : val;
+}
+
+static void __rapl_pmu_event_start(struct perf_event *event)
+{
+ struct rapl_package_pmu_data *data = event_to_pmu_data(event);
+
+ if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+ return;
+
+ event->hw.state = 0;
+
+ list_add_tail(&event->active_entry, &data->active_list);
+
+ local64_set(&event->hw.prev_count, event_read_counter(event));
+ if (++data->n_active == 1)
+ hrtimer_start(&data->hrtimer, data->timer_interval,
+ HRTIMER_MODE_REL_PINNED);
+}
+
+static void rapl_pmu_event_start(struct perf_event *event, int mode)
+{
+ struct rapl_package_pmu_data *data = event_to_pmu_data(event);
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&data->lock, flags);
+ __rapl_pmu_event_start(event);
+ raw_spin_unlock_irqrestore(&data->lock, flags);
+}
+
+static u64 rapl_event_update(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct rapl_package_pmu_data *data = event_to_pmu_data(event);
+ u64 prev_raw_count, new_raw_count;
+ s64 delta, sdelta;
+
+again:
+ prev_raw_count = local64_read(&hwc->prev_count);
+ new_raw_count = event_read_counter(event);
+
+ if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+ new_raw_count) != prev_raw_count)
+ goto again;
+
+ /*
+ * Now we have the new raw value and have updated the prev
+ * timestamp already. We can now calculate the elapsed delta
+ * (event-)time and add that to the generic event.
+ */
+ delta = new_raw_count - prev_raw_count;
+
+ /*
+ * Scale delta to smallest unit (2^-32)
+ * users must then scale back: count * 1/(1e9*2^32) to get Joules
+ * or use ldexp(count, -32).
+ * Watts = Joules/Time delta
+ */
+ sdelta = delta * data->scale[event->hw.flags];
+
+ local64_add(sdelta, &event->count);
+
+ return new_raw_count;
+}
+
+static void rapl_pmu_event_stop(struct perf_event *event, int mode)
+{
+ struct rapl_package_pmu_data *data = event_to_pmu_data(event);
+ struct hw_perf_event *hwc = &event->hw;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&data->lock, flags);
+
+ /* Mark event as deactivated and stopped */
+ if (!(hwc->state & PERF_HES_STOPPED)) {
+ WARN_ON_ONCE(data->n_active <= 0);
+ if (--data->n_active == 0)
+ hrtimer_cancel(&data->hrtimer);
+
+ list_del(&event->active_entry);
+
+ WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+ hwc->state |= PERF_HES_STOPPED;
+ }
+
+ /* Check if update of sw counter is necessary */
+ if ((mode & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+ /*
+ * Drain the remaining delta count out of a event
+ * that we are disabling:
+ */
+ rapl_event_update(event);
+ hwc->state |= PERF_HES_UPTODATE;
+ }
+
+ raw_spin_unlock_irqrestore(&data->lock, flags);
+}
+
+static int rapl_pmu_event_add(struct perf_event *event, int mode)
+{
+ struct rapl_package_pmu_data *data = event_to_pmu_data(event);
+ struct hw_perf_event *hwc = &event->hw;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&data->lock, flags);
+
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+ if (mode & PERF_EF_START)
+ __rapl_pmu_event_start(event);
+
+ raw_spin_unlock_irqrestore(&data->lock, flags);
+
+ return 0;
+}
+
+static void rapl_pmu_event_del(struct perf_event *event, int flags)
+{
+ rapl_pmu_event_stop(event, PERF_EF_UPDATE);
+}
+
+/*
+ * RAPL energy status counters
+ */
+enum perf_rapl_events {
+ PERF_RAPL_PP0 = 0, /* all cores */
+ PERF_RAPL_PKG, /* entire package */
+ PERF_RAPL_RAM, /* DRAM */
+ PERF_RAPL_PP1, /* gpu */
+ PERF_RAPL_PSYS, /* psys */
+};
+#define RAPL_EVENT_MASK GENMASK(7, 0)
+
+static int event_to_domain(int event)
+{
+ switch (event) {
+ case PERF_RAPL_PP0:
+ return RAPL_DOMAIN_PP0;
+ case PERF_RAPL_PKG:
+ return RAPL_DOMAIN_PACKAGE;
+ case PERF_RAPL_RAM:
+ return RAPL_DOMAIN_DRAM;
+ case PERF_RAPL_PP1:
+ return RAPL_DOMAIN_PP1;
+ case PERF_RAPL_PSYS:
+ return RAPL_DOMAIN_PLATFORM;
+ default:
+ return RAPL_DOMAIN_MAX;
+ }
+}
+
+static int rapl_pmu_event_init(struct perf_event *event)
+{
+ struct rapl_package *pos, *rp = NULL;
+ u64 cfg = event->attr.config & RAPL_EVENT_MASK;
+ int domain, idx;
+
+ /* Only look at RAPL events */
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ /* Check only supported bits are set */
+ if (event->attr.config & ~RAPL_EVENT_MASK)
+ return -EINVAL;
+
+ if (event->cpu < 0)
+ return -EINVAL;
+
+ /* Find out which Package the event belongs to */
+ list_for_each_entry(pos, &rapl_packages, plist) {
+ if (is_rp_pmu_cpu(pos, event->cpu)) {
+ rp = pos;
+ break;
+ }
+ }
+ if (!rp)
+ return -ENODEV;
+
+ /* Find out which RAPL Domain the event belongs to */
+ domain = event_to_domain(cfg - 1);
+ if (domain >= RAPL_DOMAIN_MAX)
+ return -EINVAL;
+
+ event->event_caps |= PERF_EV_CAP_READ_ACTIVE_PKG;
+ event->pmu_private = rp; /* Which package */
+ event->hw.flags = domain; /* Which domain */
+
+ event->hw.idx = -1;
+ /* Find out the index in rp->domains[] to get domain pointer */
+ for (idx = 0; idx < rp->nr_domains; idx++) {
+ if (rp->domains[idx].id == domain) {
+ event->hw.idx = idx;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void rapl_pmu_event_read(struct perf_event *event)
+{
+ rapl_event_update(event);
+}
+
+static enum hrtimer_restart rapl_hrtimer_handle(struct hrtimer *hrtimer)
+{
+ struct rapl_package_pmu_data *data =
+ container_of(hrtimer, struct rapl_package_pmu_data, hrtimer);
+ struct perf_event *event;
+ unsigned long flags;
+
+ if (!data->n_active)
+ return HRTIMER_NORESTART;
+
+ raw_spin_lock_irqsave(&data->lock, flags);
+
+ list_for_each_entry(event, &data->active_list, active_entry)
+ rapl_event_update(event);
+
+ raw_spin_unlock_irqrestore(&data->lock, flags);
+
+ hrtimer_forward_now(hrtimer, data->timer_interval);
+
+ return HRTIMER_RESTART;
+}
+
+/* PMU sysfs attributes */
+
+/*
+ * There are no default events, but we need to create "events" group (with
+ * empty attrs) before updating it with detected events.
+ */
+static struct attribute *attrs_empty[] = {
+ NULL,
+};
+
+static struct attribute_group pmu_events_group = {
+ .name = "events",
+ .attrs = attrs_empty,
+};
+
+static ssize_t cpumask_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rapl_package *rp;
+ int cpu;
+
+ cpus_read_lock();
+ cpumask_clear(&rapl_pmu.cpu_mask);
+
+ /* Choose a cpu for each RAPL Package */
+ list_for_each_entry(rp, &rapl_packages, plist) {
+ cpu = get_pmu_cpu(rp);
+ if (cpu < nr_cpu_ids)
+ cpumask_set_cpu(cpu, &rapl_pmu.cpu_mask);
+ }
+ cpus_read_unlock();
+
+ return cpumap_print_to_pagebuf(true, buf, &rapl_pmu.cpu_mask);
+}
+
+static DEVICE_ATTR_RO(cpumask);
+
+static struct attribute *pmu_cpumask_attrs[] = {
+ &dev_attr_cpumask.attr,
+ NULL
+};
+
+static struct attribute_group pmu_cpumask_group = {
+ .attrs = pmu_cpumask_attrs,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-7");
+static struct attribute *pmu_format_attr[] = {
+ &format_attr_event.attr,
+ NULL
+};
+
+static struct attribute_group pmu_format_group = {
+ .name = "format",
+ .attrs = pmu_format_attr,
+};
+
+static const struct attribute_group *pmu_attr_groups[] = {
+ &pmu_events_group,
+ &pmu_cpumask_group,
+ &pmu_format_group,
+ NULL
+};
+
+#define RAPL_EVENT_ATTR_STR(_name, v, str) \
+static struct perf_pmu_events_attr event_attr_##v = { \
+ .attr = __ATTR(_name, 0444, perf_event_sysfs_show, NULL), \
+ .event_str = str, \
+}
+
+RAPL_EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01");
+RAPL_EVENT_ATTR_STR(energy-pkg, rapl_pkg, "event=0x02");
+RAPL_EVENT_ATTR_STR(energy-ram, rapl_ram, "event=0x03");
+RAPL_EVENT_ATTR_STR(energy-gpu, rapl_gpu, "event=0x04");
+RAPL_EVENT_ATTR_STR(energy-psys, rapl_psys, "event=0x05");
+
+RAPL_EVENT_ATTR_STR(energy-cores.unit, rapl_unit_cores, "Joules");
+RAPL_EVENT_ATTR_STR(energy-pkg.unit, rapl_unit_pkg, "Joules");
+RAPL_EVENT_ATTR_STR(energy-ram.unit, rapl_unit_ram, "Joules");
+RAPL_EVENT_ATTR_STR(energy-gpu.unit, rapl_unit_gpu, "Joules");
+RAPL_EVENT_ATTR_STR(energy-psys.unit, rapl_unit_psys, "Joules");
+
+RAPL_EVENT_ATTR_STR(energy-cores.scale, rapl_scale_cores, "2.3283064365386962890625e-10");
+RAPL_EVENT_ATTR_STR(energy-pkg.scale, rapl_scale_pkg, "2.3283064365386962890625e-10");
+RAPL_EVENT_ATTR_STR(energy-ram.scale, rapl_scale_ram, "2.3283064365386962890625e-10");
+RAPL_EVENT_ATTR_STR(energy-gpu.scale, rapl_scale_gpu, "2.3283064365386962890625e-10");
+RAPL_EVENT_ATTR_STR(energy-psys.scale, rapl_scale_psys, "2.3283064365386962890625e-10");
+
+#define RAPL_EVENT_GROUP(_name, domain) \
+static struct attribute *pmu_attr_##_name[] = { \
+ &event_attr_rapl_##_name.attr.attr, \
+ &event_attr_rapl_unit_##_name.attr.attr, \
+ &event_attr_rapl_scale_##_name.attr.attr, \
+ NULL \
+}; \
+static umode_t is_visible_##_name(struct kobject *kobj, struct attribute *attr, int event) \
+{ \
+ return rapl_pmu.domain_map & BIT(domain) ? attr->mode : 0; \
+} \
+static struct attribute_group pmu_group_##_name = { \
+ .name = "events", \
+ .attrs = pmu_attr_##_name, \
+ .is_visible = is_visible_##_name, \
+}
+
+RAPL_EVENT_GROUP(cores, RAPL_DOMAIN_PP0);
+RAPL_EVENT_GROUP(pkg, RAPL_DOMAIN_PACKAGE);
+RAPL_EVENT_GROUP(ram, RAPL_DOMAIN_DRAM);
+RAPL_EVENT_GROUP(gpu, RAPL_DOMAIN_PP1);
+RAPL_EVENT_GROUP(psys, RAPL_DOMAIN_PLATFORM);
+
+static const struct attribute_group *pmu_attr_update[] = {
+ &pmu_group_cores,
+ &pmu_group_pkg,
+ &pmu_group_ram,
+ &pmu_group_gpu,
+ &pmu_group_psys,
+ NULL
+};
+
+static int rapl_pmu_update(struct rapl_package *rp)
+{
+ int ret;
+
+ /* Return if PMU already covers all events supported by current RAPL Package */
+ if (rapl_pmu.registered && !(rp->domain_map & (~rapl_pmu.domain_map)))
+ return 0;
+
+ /* Unregister previous registered PMU */
+ if (rapl_pmu.registered) {
+ perf_pmu_unregister(&rapl_pmu.pmu);
+ memset(&rapl_pmu.pmu, 0, sizeof(struct pmu));
+ }
+
+ rapl_pmu.domain_map |= rp->domain_map;
+
+ memset(&rapl_pmu.pmu, 0, sizeof(struct pmu));
+ rapl_pmu.pmu.attr_groups = pmu_attr_groups;
+ rapl_pmu.pmu.attr_update = pmu_attr_update;
+ rapl_pmu.pmu.task_ctx_nr = perf_invalid_context;
+ rapl_pmu.pmu.event_init = rapl_pmu_event_init;
+ rapl_pmu.pmu.add = rapl_pmu_event_add;
+ rapl_pmu.pmu.del = rapl_pmu_event_del;
+ rapl_pmu.pmu.start = rapl_pmu_event_start;
+ rapl_pmu.pmu.stop = rapl_pmu_event_stop;
+ rapl_pmu.pmu.read = rapl_pmu_event_read;
+ rapl_pmu.pmu.module = THIS_MODULE;
+ rapl_pmu.pmu.capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT;
+ ret = perf_pmu_register(&rapl_pmu.pmu, "power", -1);
+ if (ret)
+ pr_warn("Failed to register PMU\n");
+
+ rapl_pmu.registered = !ret;
+
+ return ret;
+}
+
+int rapl_package_add_pmu(struct rapl_package *rp)
+{
+ struct rapl_package_pmu_data *data = &rp->pmu_data;
+ int idx;
+ int ret;
+
+ if (rp->has_pmu)
+ return -EEXIST;
+
+ guard(cpus_read_lock)();
+
+ for (idx = 0; idx < rp->nr_domains; idx++) {
+ struct rapl_domain *rd = &rp->domains[idx];
+ int domain = rd->id;
+ u64 val;
+
+ if (!test_bit(domain, &rp->domain_map))
+ continue;
+
+ /*
+ * The RAPL PMU granularity is 2^-32 Joules
+ * data->scale[]: times of 2^-32 Joules for each ENERGY COUNTER increase
+ */
+ val = rd->energy_unit * (1ULL << 32);
+ do_div(val, ENERGY_UNIT_SCALE * 1000000);
+ data->scale[domain] = val;
+
+ if (!rapl_pmu.timer_ms) {
+ struct rapl_primitive_info *rpi = get_rpi(rp, ENERGY_COUNTER);
+
+ /*
+ * Calculate the timer rate:
+ * Use reference of 200W for scaling the timeout to avoid counter
+ * overflows.
+ *
+ * max_count = rpi->mask >> rpi->shift + 1
+ * max_energy_pj = max_count * rd->energy_unit
+ * max_time_sec = (max_energy_pj / 1000000000) / 200w
+ *
+ * rapl_pmu.timer_ms = max_time_sec * 1000 / 2
+ */
+ val = (rpi->mask >> rpi->shift) + 1;
+ val *= rd->energy_unit;
+ do_div(val, 1000000 * 200 * 2);
+ rapl_pmu.timer_ms = val;
+
+ pr_info("%llu ms ovfl timer\n", rapl_pmu.timer_ms);
+ }
+
+ pr_info("Domain %s: hw unit %lld * 2^-32 Joules\n", rd->name, data->scale[domain]);
+ }
+
+ /* Initialize per package PMU data */
+ raw_spin_lock_init(&data->lock);
+ INIT_LIST_HEAD(&data->active_list);
+ data->timer_interval = ms_to_ktime(rapl_pmu.timer_ms);
+ hrtimer_init(&data->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ data->hrtimer.function = rapl_hrtimer_handle;
+
+ ret = rapl_pmu_update(rp);
+ if (!ret)
+ rp->has_pmu = true;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rapl_package_add_pmu);
+
+void rapl_package_remove_pmu(struct rapl_package *rp)
+{
+ struct rapl_package *pos;
+
+ if (!rp->has_pmu)
+ return;
+
+ guard(cpus_read_lock)();
+
+ list_for_each_entry(pos, &rapl_packages, plist) {
+ /* PMU is still needed */
+ if (pos->has_pmu)
+ return;
+ }
+
+ perf_pmu_unregister(&rapl_pmu.pmu);
+ memset(&rapl_pmu, 0, sizeof(struct rapl_pmu));
+}
+EXPORT_SYMBOL_GPL(rapl_package_remove_pmu);
+#endif
+
/* called from CPU hotplug notifier, hotplug lock held */
void rapl_remove_package_cpuslocked(struct rapl_package *rp)
{
diff --git a/include/linux/intel_rapl.h b/include/linux/intel_rapl.h
index f3196f82fd8a..38e43dbb3dac 100644
--- a/include/linux/intel_rapl.h
+++ b/include/linux/intel_rapl.h
@@ -158,6 +158,17 @@ struct rapl_if_priv {
void *rpi;
};
+#ifdef CONFIG_PERF_EVENTS
+struct rapl_package_pmu_data {
+ u64 scale[RAPL_DOMAIN_MAX];
+ raw_spinlock_t lock;
+ int n_active;
+ struct list_head active_list;
+ ktime_t timer_interval;
+ struct hrtimer hrtimer;
+};
+#endif
+
/* maximum rapl package domain name: package-%d-die-%d */
#define PACKAGE_DOMAIN_NAME_LENGTH 30
@@ -176,6 +187,10 @@ struct rapl_package {
struct cpumask cpumask;
char name[PACKAGE_DOMAIN_NAME_LENGTH];
struct rapl_if_priv *priv;
+#ifdef CONFIG_PERF_EVENTS
+ bool has_pmu;
+ struct rapl_package_pmu_data pmu_data;
+#endif
};
struct rapl_package *rapl_find_package_domain_cpuslocked(int id, struct rapl_if_priv *priv,
@@ -188,4 +203,12 @@ struct rapl_package *rapl_find_package_domain(int id, struct rapl_if_priv *priv,
struct rapl_package *rapl_add_package(int id, struct rapl_if_priv *priv, bool id_is_cpu);
void rapl_remove_package(struct rapl_package *rp);
+#ifdef CONFIG_PERF_EVENTS
+int rapl_package_add_pmu(struct rapl_package *rp);
+void rapl_package_remove_pmu(struct rapl_package *rp);
+#else
+static inline int rapl_package_add_pmu(struct rapl_package *rp) { return 0; }
+static inline void rapl_package_remove_pmu(struct rapl_package *rp) { }
+#endif
+
#endif /* __INTEL_RAPL_H__ */
--
2.34.1
^ permalink raw reply related
* [PATCH V2 1/3] powercap: intel_rapl: Sort header files
From: Zhang Rui @ 2024-04-08 3:51 UTC (permalink / raw)
To: rafael.j.wysocki; +Cc: linux-kernel, linux-pm, srinivas.pandruvada
In-Reply-To: <20240408035141.248644-1-rui.zhang@intel.com>
Sort header files alphabetically.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
drivers/powercap/intel_rapl_common.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/powercap/intel_rapl_common.c b/drivers/powercap/intel_rapl_common.c
index a28d54fd5222..1f4a7aa12d77 100644
--- a/drivers/powercap/intel_rapl_common.c
+++ b/drivers/powercap/intel_rapl_common.c
@@ -5,27 +5,27 @@
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/bitmap.h>
#include <linux/cleanup.h>
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/intel_rapl.h>
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/list.h>
-#include <linux/types.h>
-#include <linux/device.h>
-#include <linux/slab.h>
#include <linux/log2.h>
-#include <linux/bitmap.h>
-#include <linux/delay.h>
-#include <linux/sysfs.h>
-#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/powercap.h>
-#include <linux/suspend.h>
-#include <linux/intel_rapl.h>
#include <linux/processor.h>
-#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
-#include <asm/iosf_mbi.h>
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
+#include <asm/iosf_mbi.h>
/* bitmasks for RAPL MSRs, used by primitive access functions */
#define ENERGY_STATUS_MASK 0xffffffff
--
2.34.1
^ permalink raw reply related
* [PATCH V2 0/3] powercap: Introduce TPMI RAPL PMU support
From: Zhang Rui @ 2024-04-08 3:51 UTC (permalink / raw)
To: rafael.j.wysocki; +Cc: linux-kernel, linux-pm, srinivas.pandruvada
RAPL energy counter MSRs are exposed via perf PMU. But this is done by
separate code which is not part of RAPL framework, and it cannot be
reused by other RAPL Interface drivers like TPMI RAPL.
Introduce two new APIs for PMU support in RAPL framework. This allows
TPMI RAPL PMU support and also makes it possible for future cleanups of
MSR RAPL PMU code.
Changes since V1:
- remove the MSR RAPL PMU conversion because it is a separate work that
can be done later.
- instead of using a flag to indicate the need of PMU support, introduce
two APIs for the RAPL Interface driver to invoke explicitly.
- minor code/comments/changelog improvements.
thanks,
rui
----------------------------------------------------------------
Zhang Rui (3):
powercap: intel_rapl: Sort header files
powercap: intel_rapl: Introduce APIs for PMU support
powercap: intel_rapl_tpmi: Enable PMU support
drivers/powercap/intel_rapl_common.c | 561 ++++++++++++++++++++++++++++++++++-
drivers/powercap/intel_rapl_tpmi.c | 3 +
include/linux/intel_rapl.h | 23 ++
3 files changed, 575 insertions(+), 12 deletions(-)
^ permalink raw reply
* Re: [RFC PATCH 1/1] clk: sunxi-ng: h6-r: add GPU power domain
From: Stephen Boyd @ 2024-04-08 3:33 UTC (permalink / raw)
To: Andre Przywara, Chen-Yu Tsai, Jernej Skrabec, Michael Turquette,
Samuel Holland, Ulf Hansson
Cc: linux-clk, linux-pm, linux-arm-kernel, linux-sunxi
In-Reply-To: <20240225160616.15001-2-andre.przywara@arm.com>
Quoting Andre Przywara (2024-02-25 08:06:16)
> diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
> index 02b28cfc5525e..363fb7a71e9f5 100644
> --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
> +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
> @@ -217,6 +219,86 @@ static const struct sunxi_ccu_desc sun50i_h616_r_ccu_desc = {
[...]
> +static int sun50i_h616_register_ppu(struct platform_device *pdev,
> + void __iomem *base)
> +{
> + struct device *dev = &pdev->dev;
> + struct genpd_onecell_data *ppu;
> + struct sun50i_h616_ppu_pd *pd;
> + int ret;
> +
> + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
> + if (!pd)
> + return -ENOMEM;
> +
> + ppu = devm_kzalloc(dev, sizeof(*ppu), GFP_KERNEL);
> + if (!ppu)
> + return -ENOMEM;
> +
> + ppu->domains = devm_kzalloc(dev, sizeof(*ppu->domains), GFP_KERNEL);
> + if (!ppu->domains)
> + return -ENOMEM;
> +
> + ppu->num_domains = 1;
> + pd->genpd.name = "GPU";
> + pd->genpd.power_off = sun50i_h616_ppu_pd_power_off;
> + pd->genpd.power_on = sun50i_h616_ppu_pd_power_on;
> + pd->base = base;
> +
> + ret = pm_genpd_init(&pd->genpd, NULL, !sun50i_h616_ppu_power_status(pd));
> + if (ret) {
> + dev_warn(dev, "Failed to add GPU power domain: %d\n", ret);
> + return ret;
> + }
> +
> + ppu->domains[0] = &pd->genpd;
> + ret = of_genpd_add_provider_onecell(dev->of_node, ppu);
Is this provider removed somewhere when probe fails or the driver is
removed? It looks like the rest of the driver uses devm during probe.
^ permalink raw reply
* [Bug 217931] amd-pstate lacks crucial features: CPU frequency and boost control
From: bugzilla-daemon @ 2024-04-08 3:27 UTC (permalink / raw)
To: linux-pm
In-Reply-To: <bug-217931-137361@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=217931
--- Comment #59 from Perry Yuan(AMD) (Perry.Yuan@amd.com) ---
(In reply to Artem S. Tashkinov from comment #56)
> Here's my report for 6.8.4 and Ryzen 7 7840HS:
>
> 1. Setting scaling_max_freq works, cool, but you cannot go below 544MHz. You
> can set 400MHz but the CPU will continue to jump to 544MHz, not a big deal.
>
> 2. Setting scaling_min_freq sort of works, the CPU _prefers_ to stay at this
> specified frequency but occasionally drops to 400MHz. Then, the CPU doesn't
> totally respect it, i.e. for values below 1.4GHz it stays around 1397MHz.
> The relationship is not linear, setting 4GHz results in the CPU preferring
> 3766Mhz. Or 2GHz -> 1982MHz. Not a big deal. Unlikely anyone would want to
> set the lowest frequency.
>
> 3. /sys/devices/system/cpu/amd_pstate/cpb_boost is missing altogether:
>
> # find /sys -iname '*boost*'
> [nothing]
>
> So, my only remaining question is where's boost support? Or it's not
> supported for all Zen CPUs?
>
> Thanks a lot for your work regardless!
1. please try to apply the two patches for your cpb testing.
https://lore.kernel.org/lkml/cover.1711335714.git.perry.yuan@amd.com/
https://lore.kernel.org/lkml/Zfqv3ckVU4km+RLr@BLR-5CG11610CF.amd.com/
2. are you testing under EPP driver mode? the 400MHz is the lowest freq,
however it dose not mean the CPU will be keeping at 400MHz, it will wake up and
idle and bump up frequency shortly according to the workload. you need to
know, when the Core is idle, kernel will not get the realtime frequency by
APERF/MPERF, cpufreq just show the lowest freq as 400MHz. It is not an issue.
There is one idle frequency defined by power firmware, it is 1.4GHz for some
client system, the lowest active frequency is not 400MHz, it is 1.4GHz. so you
have no need to worry the 1.4GHz or 400MHz, it is not a problem.
3. the invalid max frequency value issue is caused by wrong highest perf value
defined by pstate driver, I have been working a solution to fix that. with EPP
driver mode, it will not cause any performance problem, just a little
uncomfortable to see the wrong value listed.
Perry.
--
You may reply to this email to add a comment.
You are receiving this mail because:
You are the assignee for the bug.
^ permalink raw reply
* Re: [PATCH] intel_idle: Add RaptorLake support
From: Zhang, Rui @ 2024-04-08 2:01 UTC (permalink / raw)
To: peter.laszlo2@gmail.com
Cc: lenb@kernel.org, jacob.jun.pan@linux.intel.com,
smarter3@gmail.com, Kumar, Vinay, linux-kernel@vger.kernel.org,
noltari@gmail.com, Bityutskiy, Artem, linux-pm@vger.kernel.org
In-Reply-To: <BCBB0027-F0E9-42EE-BB43-D50091D9115F@gmail.com>
On Sun, 2024-04-07 at 19:37 +0200, László Péter wrote:
>
>
> > On 20 Aug 2023, at 11:20, Zhang, Rui <rui.zhang@intel.com> wrote:
> >
> > This is still work in progress because there are still some open
> > questions that we cannot answer from our measurement, and the table
> > is
> > not finalized yet.
> >
> > thanks,
> > rui
> >
> >
>
> Hi,
>
> I also just stumbled upon this patch series as I was wondering about
> the lack of specific support for RaptorLake in intel_idle. The
> AlderLake specific part of the intel_idle.c code mentions that "On
> AlderLake C1 has to be disabled if C1E is enabled, and vice versa ….
> By default we enable C1E and disable C1 by marking it with...”.
> Without a patch on RaptorLake (which I assume works the same way)
> this cannot be controlled with the preferred_cstates kernel
> parameter.
That is true, but that only applies when you have a custom table which
expose C1 and C1E as two separate states.
The default behavior (intel_idle + _CST c-states) doesn't have this
issue. We will just follow the system default.
> Also on my NUC 13 Pro i5-1340P the latency for C10 looks
> suspiciously large compared to the AlderLake cstates table.
Does this bring any real issue in your case?
We do have finished a series of evaluation on RPL, but we didn't find
obvious PnP benefit by introducing a custom table. That is why we
stopped shipping one for RPL.
If you find any real case that this impacts, it would be nice to share
your proposal and test data.
thanks,
rui
^ permalink raw reply
* [Bug 218686] Fail to set energy_performance_preference of amd processor on asus ga403uv
From: bugzilla-daemon @ 2024-04-08 1:48 UTC (permalink / raw)
To: linux-pm
In-Reply-To: <bug-218686-137361@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=218686
al0uette@outlook.com changed:
What |Removed |Added
----------------------------------------------------------------------------
Kernel Version| |6.8.x, 6.9.0-rc1
--
You may reply to this email to add a comment.
You are receiving this mail because:
You are the assignee for the bug.
^ permalink raw reply
* [PATCH next] cpupfreq: tegra124: eliminate uses of of_node_put()
From: Javier Carrasco @ 2024-04-07 20:15 UTC (permalink / raw)
To: Rafael J. Wysocki, Viresh Kumar, Thierry Reding, Jonathan Hunter,
Julia Lawall
Cc: linux-pm, linux-tegra, linux-kernel, Javier Carrasco
Make use of the __free() cleanup handler to automatically free nodes
when they get out of scope. Only the probe function is affected by this
modification.
Given that this mechanism requires the node to be initialized, its
initialization and the value check have been moved to the top of the
function.
After removing uses of of_node_put(), the jump to out_put_np is no
longer necessary.
Suggested-by: Julia Lawall <julia.lawall@inria.fr>
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
---
This patch is a proof of concept to remove uses of of_node_put() in
cpufreq, which can be replaced with the clenaup handler introduced with
54da6a092431 ("locking: Introduce __cleanup() based infrastructure").
This change provides a scope-based cleanup mechanism to avoid potential
memory leaks that can appear if of_node_put() is not used correctly.
The patch is based on the latest linux-next tag (next-20240405).
---
drivers/cpufreq/tegra124-cpufreq.c | 19 ++++++-------------
1 file changed, 6 insertions(+), 13 deletions(-)
diff --git a/drivers/cpufreq/tegra124-cpufreq.c b/drivers/cpufreq/tegra124-cpufreq.c
index aae951d4e77c..514146d98bca 100644
--- a/drivers/cpufreq/tegra124-cpufreq.c
+++ b/drivers/cpufreq/tegra124-cpufreq.c
@@ -52,12 +52,15 @@ static int tegra124_cpu_switch_to_dfll(struct tegra124_cpufreq_priv *priv)
static int tegra124_cpufreq_probe(struct platform_device *pdev)
{
+ struct device_node *np __free(device_node) = of_cpu_device_node_get(0);
struct tegra124_cpufreq_priv *priv;
- struct device_node *np;
struct device *cpu_dev;
struct platform_device_info cpufreq_dt_devinfo = {};
int ret;
+ if (!np)
+ return -ENODEV;
+
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -66,15 +69,9 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev)
if (!cpu_dev)
return -ENODEV;
- np = of_cpu_device_node_get(0);
- if (!np)
- return -ENODEV;
-
priv->cpu_clk = of_clk_get_by_name(np, "cpu_g");
- if (IS_ERR(priv->cpu_clk)) {
- ret = PTR_ERR(priv->cpu_clk);
- goto out_put_np;
- }
+ if (IS_ERR(priv->cpu_clk))
+ return PTR_ERR(priv->cpu_clk);
priv->dfll_clk = of_clk_get_by_name(np, "dfll");
if (IS_ERR(priv->dfll_clk)) {
@@ -110,8 +107,6 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
- of_node_put(np);
-
return 0;
out_put_pllp_clk:
@@ -122,8 +117,6 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev)
clk_put(priv->dfll_clk);
out_put_cpu_clk:
clk_put(priv->cpu_clk);
-out_put_np:
- of_node_put(np);
return ret;
}
---
base-commit: 8568bb2ccc278f344e6ac44af6ed010a90aa88dc
change-id: 20240407-cpufreq_of_node_put-0d1972a33561
Best regards,
--
Javier Carrasco <javier.carrasco.cruz@gmail.com>
^ permalink raw reply related
* [PATCH 2/2] thermal/drivers/mediatek/lvts_thermal: Improve some memory allocation
From: Christophe JAILLET @ 2024-04-07 20:01 UTC (permalink / raw)
To: Rafael J. Wysocki, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: linux-kernel, kernel-janitors, Christophe JAILLET, linux-pm,
linux-arm-kernel, linux-mediatek
In-Reply-To: <42a87fb9837f1760d1ad4eb7162a7536785dc6f5.1712520052.git.christophe.jaillet@wanadoo.fr>
lvts_debugfs_init() is called with lvts_td->num_lvts_ctrl being 2, 3 or 4.
sizeof(struct debugfs_regset32) is small. 32 byres on a x86_64.
So, given the overhead of devm_kzalloc(), it is better to allocate all
needed regset at once.
The overhead of devm_kzalloc() is 40 bytes on a x86_64, and because of
rounding in memory allocation, it leads to:
2 * (32 + 40) = 2 * 72 --> 2 96 bytes allocations for a total of 192 bytes
3 * (32 + 40) = 3 * 72 --> 3 96 bytes allocations for a total of 288 bytes
4 * (32 + 40) = 4 * 72 --> 4 96 bytes allocations for a total of 384 bytes
using a single devm_kcalloc():
2 * 32 + 40 = 104 --> 1 allocation for a total of 128
3 * 32 + 40 = 136 --> 1 allocation for a total of 192
4 * 32 + 40 = 168 --> 1 allocation for a total of 192
So, this saves both a few bytes and reduce memory fragmentation.
Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
---
Compile tested-only
---
drivers/thermal/mediatek/lvts_thermal.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c
index 3003dc350766..b133f731c5ba 100644
--- a/drivers/thermal/mediatek/lvts_thermal.c
+++ b/drivers/thermal/mediatek/lvts_thermal.c
@@ -204,7 +204,7 @@ static const struct debugfs_reg32 lvts_regs[] = {
static int lvts_debugfs_init(struct device *dev, struct lvts_domain *lvts_td)
{
- struct debugfs_regset32 *regset;
+ struct debugfs_regset32 *regsets;
struct lvts_ctrl *lvts_ctrl;
struct dentry *dentry;
char name[64];
@@ -214,8 +214,14 @@ static int lvts_debugfs_init(struct device *dev, struct lvts_domain *lvts_td)
if (IS_ERR(lvts_td->dom_dentry))
return 0;
+ regsets = devm_kcalloc(dev, lvts_td->num_lvts_ctrl,
+ sizeof(*regsets), GFP_KERNEL);
+ if (!regsets)
+ return 0;
+
for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
+ struct debugfs_regset32 *regset = ®sets[i];
lvts_ctrl = &lvts_td->lvts_ctrl[i];
sprintf(name, "controller%d", i);
@@ -223,10 +229,6 @@ static int lvts_debugfs_init(struct device *dev, struct lvts_domain *lvts_td)
if (IS_ERR(dentry))
continue;
- regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
- if (!regset)
- continue;
-
regset->base = lvts_ctrl->base;
regset->regs = lvts_regs;
regset->nregs = ARRAY_SIZE(lvts_regs);
--
2.44.0
^ permalink raw reply related
* [PATCH 1/2] thermal/drivers/mediatek/lvts_thermal: Make debugfs related fields more consistent
From: Christophe JAILLET @ 2024-04-07 20:01 UTC (permalink / raw)
To: Rafael J. Wysocki, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: linux-kernel, kernel-janitors, Christophe JAILLET, linux-pm,
linux-arm-kernel, linux-mediatek
The debugfs code is only generated if CONFIG_MTK_LVTS_THERMAL_DEBUGFS is
defined.
So 'dom_dentry' should be included in the 'struct lvts_domain' with the
same condition, instead of CONFIG_DEBUG_FS.
Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
---
Compile tested-only
---
drivers/thermal/mediatek/lvts_thermal.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c
index fd4bd650c77a..3003dc350766 100644
--- a/drivers/thermal/mediatek/lvts_thermal.c
+++ b/drivers/thermal/mediatek/lvts_thermal.c
@@ -150,7 +150,7 @@ struct lvts_domain {
void __iomem *base;
size_t calib_len;
u8 *calib;
-#ifdef CONFIG_DEBUG_FS
+#ifdef CONFIG_MTK_LVTS_THERMAL_DEBUGFS
struct dentry *dom_dentry;
#endif
};
--
2.44.0
^ permalink raw reply related
* [Bug 218689] AMD_Pstate_EPP Ryzen 7000 issues. Freezing and static sound
From: bugzilla-daemon @ 2024-04-07 19:41 UTC (permalink / raw)
To: linux-pm
In-Reply-To: <bug-218689-137361@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=218689
--- Comment #6 from Christopher Bii (kbii.chris@gmail.com) ---
if there were* to be a hardware issue^^^
--
You may reply to this email to add a comment.
You are receiving this mail because:
You are the assignee for the bug.
^ permalink raw reply
* [Bug 218689] AMD_Pstate_EPP Ryzen 7000 issues. Freezing and static sound
From: bugzilla-daemon @ 2024-04-07 19:40 UTC (permalink / raw)
To: linux-pm
In-Reply-To: <bug-218689-137361@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=218689
--- Comment #5 from Christopher Bii (kbii.chris@gmail.com) ---
(In reply to Artem S. Tashkinov from comment #4)
> If I were you, I'd definitely post your issue here:
>
> https://www.reddit.com/r/AMDHelp/
>
> and here
>
> https://community.amd.com/t5/support-forums/ct-p/supprtforums
I have attempted to post on both early on but to no avail. CPU, CPU cooler,
nvme and the rest we're all removed and put back. Absolutely nothing wrong with
them.
Even if there were to be a hardware issue, which I think is ruled out at this
point. It would not perfectly explain how the issue completely goes away when
the driver/governor is changed.
The CPU benchmarks perfect scores. Another observation I had was that under
full load with that I suspect to be the faulty driver, there is no issue.
Disabling c6 in bios does not fix the issue. I will try the other driver when I
disable _PC register to see if it fixed the issue. This was something I had
tried also but I cannot fully remember whether the issue persisted or not.
The CPU benchmarks perfectly, outperforming the average on geekbench (I am
cheating since I am on the superior linux). I believe I tested the issue on
windows also, it was definitely the same until I upgraded the drivers and all.
Issue nearly completely disappeared.
I am yet to try on 6.8.4, I will try the different drivers and see whether
there is any difference.
--
You may reply to this email to add a comment.
You are receiving this mail because:
You are the assignee for the bug.
^ permalink raw reply
* [Bug 218689] AMD_Pstate_EPP Ryzen 7000 issues. Freezing and static sound
From: bugzilla-daemon @ 2024-04-07 19:12 UTC (permalink / raw)
To: linux-pm
In-Reply-To: <bug-218689-137361@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=218689
Artem S. Tashkinov (aros@gmx.com) changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |aros@gmx.com
--- Comment #4 from Artem S. Tashkinov (aros@gmx.com) ---
If I were you, I'd definitely post your issue here:
https://www.reddit.com/r/AMDHelp/
and here
https://community.amd.com/t5/support-forums/ct-p/supprtforums
--
You may reply to this email to add a comment.
You are receiving this mail because:
You are the assignee for the bug.
^ permalink raw reply
* [Bug 218689] AMD_Pstate_EPP Ryzen 7000 issues. Freezing and static sound
From: bugzilla-daemon @ 2024-04-07 19:07 UTC (permalink / raw)
To: linux-pm
In-Reply-To: <bug-218689-137361@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=218689
Artem S. Tashkinov (aros@gmx.com) changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |mario.limonciello@amd.com
--- Comment #3 from Artem S. Tashkinov (aros@gmx.com) ---
amd-pstate has been the default CPU driver for quite some time now in many
distros and your report is the first of this kind. And since most Linux users
use AMD CPUs it becomes even more bizarre.
I still smell something is wrong with your setup hardware wise only I don't
understand what exactly.
What other options I can think of:
1. CPU dies sometimes can be faulty as well. This is extremely unlikely but
does happen.
2. Thermal paste/CPU cooler issues.
3. PSU issues.
I'm quite sure replacing the CPU is not on your mind yet, but I'd at least make
sure that the thermal paste is applied properly (and you've not forgotten to
remove the plastic for your cooler) and that the PSU CPU power connector is
attached properly.
And then if you're keen to check thermal paste application, please remove the
die from the motherboard socket and check that all the CPU pins are intact.
Again, I'm 99.999% sure it's a hardware issue.
I'll CC Mario because he knows a lot more about AMD hardware, so probably he
could add something.
--
You may reply to this email to add a comment.
You are receiving this mail because:
You are the assignee for the bug.
^ permalink raw reply
* [Bug 218689] AMD_Pstate_EPP Ryzen 7000 issues. Freezing and static sound
From: bugzilla-daemon @ 2024-04-07 18:11 UTC (permalink / raw)
To: linux-pm
In-Reply-To: <bug-218689-137361@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=218689
--- Comment #2 from Christopher Bii (kbii.chris@gmail.com) ---
(In reply to Artem S. Tashkinov from comment #1)
> This is extremely unlikely to be caused by the CPU driver.
>
> Please try resetting your BIOS settings and not using any XMP memory
> profiles first.
Few things I have done:
- Reset bios to defaults
- Updated Bios
- Downgraded bios
- Disable xmp profile
- Set/unset typical idle usage
- Tweaked nearly every setting in the bios over 2 weeks
- Replaced motherboard
- Replaced ram
Kernel params passed:
no_rcucbs=0-$numcores
idle=nomwait
iommu=soft
acpi=off
Absolutely nothing worked.
I had tried testing around different governors but had never tried using the
passive amd_pstate mode. The one thing that caught my attention was the
asynchronous power management parameter being off. This to me seems like the
most plausible cause of the stuttering.
The one thing I am absolutely certain of though, change the cpufreq driver and
governor 100% makes a difference. Exact cause needs to be further investigated.
--
You may reply to this email to add a comment.
You are receiving this mail because:
You are the assignee for the bug.
^ permalink raw reply
* Re: [PATCH] intel_idle: Add RaptorLake support
From: László Péter @ 2024-04-07 17:37 UTC (permalink / raw)
To: Zhang, Rui
Cc: smarter3@gmail.com, linux-pm@vger.kernel.org,
jacob.jun.pan@linux.intel.com, noltari@gmail.com, lenb@kernel.org,
linux-kernel@vger.kernel.org, Bityutskiy, Artem, Kumar, Vinay
In-Reply-To: <7e2c1da24b48217045e8ad95b739ec96cdce5931.camel@intel.com>
> On 20 Aug 2023, at 11:20, Zhang, Rui <rui.zhang@intel.com> wrote:
>
> This is still work in progress because there are still some open
> questions that we cannot answer from our measurement, and the table is
> not finalized yet.
>
> thanks,
> rui
>
>
Hi,
I also just stumbled upon this patch series as I was wondering about the lack of specific support for RaptorLake in intel_idle. The AlderLake specific part of the intel_idle.c code mentions that "On AlderLake C1 has to be disabled if C1E is enabled, and vice versa …. By default we enable C1E and disable C1 by marking it with...”. Without a patch on RaptorLake (which I assume works the same way) this cannot be controlled with the preferred_cstates kernel parameter. Also on my NUC 13 Pro i5-1340P the latency for C10 looks suspiciously large compared to the AlderLake cstates table.
grep . /sys/devices/system/cpu/cpu0/cpuidle/state*/desc
/sys/devices/system/cpu/cpu0/cpuidle/state0/desc:CPUIDLE CORE POLL IDLE
/sys/devices/system/cpu/cpu0/cpuidle/state1/desc:ACPI FFH MWAIT 0x0
/sys/devices/system/cpu/cpu0/cpuidle/state2/desc:ACPI FFH MWAIT 0x21
/sys/devices/system/cpu/cpu0/cpuidle/state3/desc:ACPI FFH MWAIT 0x60
grep . /sys/devices/system/cpu/cpu0/cpuidle/state*/latency
/sys/devices/system/cpu/cpu0/cpuidle/state0/latency:0
/sys/devices/system/cpu/cpu0/cpuidle/state1/latency:1
/sys/devices/system/cpu/cpu0/cpuidle/state2/latency:127
/sys/devices/system/cpu/cpu0/cpuidle/state3/latency:1048
Thanks,
Peter
^ permalink raw reply
* Re: [PATCH v4 1/4] include/linux/suspend.h: Only show pm_pr_dbg messages at suspend/resume
From: Randy Dunlap @ 2024-04-07 15:32 UTC (permalink / raw)
To: xiongxin, mario.limonciello, Rafael Wysocki, hdegoede,
linus.walleij
Cc: Basavaraj.Natikar, Shyam-sundar.S-k, linux-pm, linux-acpi,
linux-kernel, platform-driver-x86, linux-gpio
In-Reply-To: <20230602073025.22884-1-mario.limonciello@amd.com>
On 4/7/24 5:49 AM, xiongxin wrote:
> From: Mario Limonciello <mario.limonciello@amd.com>
>
> All uses in the kernel are currently already oriented around
> suspend/resume. As some other parts of the kernel may also use these
> messages in functions that could also be used outside of
> suspend/resume, only enable in suspend/resume path.
>
> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
> ---
> v3->v4:
> * add back do/while as it wasn't pointless. It fixes a warning.
> ---
> include/linux/suspend.h | 8 +++++---
> kernel/power/main.c | 6 ++++++
> 2 files changed, 11 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/suspend.h b/include/linux/suspend.h
> index 1a0426e6761c..74f406c53ac0 100644
> --- a/include/linux/suspend.h
> +++ b/include/linux/suspend.h
> @@ -555,6 +555,7 @@ static inline void unlock_system_sleep(unsigned int flags) {}
> #ifdef CONFIG_PM_SLEEP_DEBUG
> extern bool pm_print_times_enabled;
> extern bool pm_debug_messages_on;
> +extern bool pm_debug_messages_should_print(void);
> static inline int pm_dyn_debug_messages_on(void)
> {
> #ifdef CONFIG_DYNAMIC_DEBUG
> @@ -568,14 +569,14 @@ static inline int pm_dyn_debug_messages_on(void)
> #endif
> #define __pm_pr_dbg(fmt, ...) \
> do { \
> - if (pm_debug_messages_on) \
> + if (pm_debug_messages_should_print()) \
> printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \
> else if (pm_dyn_debug_messages_on()) \
> pr_debug(fmt, ##__VA_ARGS__); \
> } while (0)
> #define __pm_deferred_pr_dbg(fmt, ...) \
> do { \
> - if (pm_debug_messages_on) \
> + if (pm_debug_messages_should_print()) \
> printk_deferred(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \
> } while (0)
> #else
> @@ -593,7 +594,8 @@ static inline int pm_dyn_debug_messages_on(void)
> /**
> * pm_pr_dbg - print pm sleep debug messages
> *
> - * If pm_debug_messages_on is enabled, print message.
> + * If pm_debug_messages_on is enabled and the system is entering/leaving
> + * suspend, print message.
> * If pm_debug_messages_on is disabled and CONFIG_DYNAMIC_DEBUG is enabled,
> * print message only from instances explicitly enabled on dynamic debug's
> * control.
> diff --git a/kernel/power/main.c b/kernel/power/main.c
> index 3113ec2f1db4..daa535012e51 100644
> --- a/kernel/power/main.c
> +++ b/kernel/power/main.c
> @@ -556,6 +556,12 @@ power_attr_ro(pm_wakeup_irq);
>
> bool pm_debug_messages_on __read_mostly;
>
> +bool pm_debug_messages_should_print(void)
> +{
> + return pm_debug_messages_on && pm_suspend_target_state != PM_SUSPEND_ON;
>
>> hibernate processes also mostly use the pm_pr_dbg() function, which
>> results in hibernate processes only being able to output such logs
>> through dynamic debug, which is unfriendly to kernels without
>> CONFIG_DYNAMIC_DEBUG configuration.
This part of the patch doesn't look so good. ^^^^^^^^^^^^^^^^^^^^
>
> +}
> +EXPORT_SYMBOL_GPL(pm_debug_messages_should_print);
> +
> static ssize_t pm_debug_messages_show(struct kobject *kobj,
> struct kobj_attribute *attr, char *buf)
> {
>
--
#Randy
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox