* [PATCH v4 1/4] hwmon: (pmbus) Add and export direct conversion calculation helpers
From: Stoyan Bogdanov @ 2026-05-22 8:23 UTC (permalink / raw)
To: jbrunet, linux, robh, krzk+dt, conor+dt, corbet, skhan
Cc: linux-hwmon, devicetree, linux-doc, linux-kernel, Stoyan Bogdanov
In-Reply-To: <20260522082349.2749970-1-sbogdanov@baylibre.com>
TPS25990 and upcoming TPS1689 need common computation APIs but
the current implementation is static to TPS25990. As a preparation for
TPS1689 support, split the math-only parts of pmbus_reg2data_direct() and
pmbus_data2reg_direct() into separate helper functions:
- pmbus_reg2data_direct_calc()
- pmbus_data2reg_direct_calc()
export them so the upcoming TPS1689 can use the same APIs.
This has no behavioral change on TPS25990 while allowing TPS1689
to use the same.
Signed-off-by: Stoyan Bogdanov <sbogdanov@baylibre.com>
---
drivers/hwmon/pmbus/pmbus.h | 2 ++
drivers/hwmon/pmbus/pmbus_core.c | 59 +++++++++++++++++++-------------
2 files changed, 38 insertions(+), 23 deletions(-)
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index 23e3eda58870..dd4fe7d9821d 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -578,5 +578,7 @@ DEFINE_GUARD(pmbus_lock, struct i2c_client *, pmbus_lock(_T), pmbus_unlock(_T))
int pmbus_update_fan(struct i2c_client *client, int page, int id,
u8 config, u8 mask, u16 command);
struct dentry *pmbus_get_debugfs_dir(struct i2c_client *client);
+s64 pmbus_reg2data_direct_calc(s64 val, s64 b, s32 m, s32 R);
+u16 pmbus_data2reg_direct_calc(s64 val, s64 b, s32 m, s32 R);
#endif /* PMBUS_H */
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index e8fdd799c71c..2eaac337eeab 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -817,6 +817,22 @@ static s64 pmbus_reg2data_linear(struct pmbus_data *data,
return val;
}
+s64 pmbus_reg2data_direct_calc(s64 val, s64 b, s32 m, s32 R)
+{
+ while (R > 0) {
+ val *= 10;
+ R--;
+ }
+ while (R < 0) {
+ val = div_s64(val + 5LL, 10L); /* round closest */
+ R++;
+ }
+
+ val = div_s64(val - b, m);
+ return val;
+}
+EXPORT_SYMBOL_NS_GPL(pmbus_reg2data_direct_calc, "PMBUS");
+
/*
* Convert direct sensor values to milli- or micro-units
* depending on sensor type.
@@ -824,7 +840,7 @@ static s64 pmbus_reg2data_linear(struct pmbus_data *data,
static s64 pmbus_reg2data_direct(struct pmbus_data *data,
struct pmbus_sensor *sensor)
{
- s64 b, val = (s16)sensor->data;
+ s64 b;
s32 m, R;
m = data->info->m[sensor->class];
@@ -848,17 +864,7 @@ static s64 pmbus_reg2data_direct(struct pmbus_data *data,
b *= 1000;
}
- while (R > 0) {
- val *= 10;
- R--;
- }
- while (R < 0) {
- val = div_s64(val + 5LL, 10L); /* round closest */
- R++;
- }
-
- val = div_s64(val - b, m);
- return val;
+ return pmbus_reg2data_direct_calc((s16)sensor->data, b, m, R);
}
/*
@@ -1057,6 +1063,23 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,
return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
}
+u16 pmbus_data2reg_direct_calc(s64 val, s64 b, s32 m, s32 R)
+{
+ val = val * m + b;
+
+ while (R > 0) {
+ val *= 10;
+ R--;
+ }
+ while (R < 0) {
+ val = div_s64(val + 5LL, 10L); /* round closest */
+ R++;
+ }
+
+ return (u16)clamp_val(val, S16_MIN, S16_MAX);
+}
+EXPORT_SYMBOL_NS_GPL(pmbus_data2reg_direct_calc, "PMBUS");
+
static u16 pmbus_data2reg_direct(struct pmbus_data *data,
struct pmbus_sensor *sensor, s64 val)
{
@@ -1078,18 +1101,8 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data,
R -= 3; /* Adjust R and b for data in milli-units */
b *= 1000;
}
- val = val * m + b;
- while (R > 0) {
- val *= 10;
- R--;
- }
- while (R < 0) {
- val = div_s64(val + 5LL, 10L); /* round closest */
- R++;
- }
-
- return (u16)clamp_val(val, S16_MIN, S16_MAX);
+ return pmbus_data2reg_direct_calc(val, b, m, R);
}
static u16 pmbus_data2reg_vid(struct pmbus_data *data,
--
2.43.0
^ permalink raw reply related
* [PATCH v4 2/4] hwmon: (pmbus/tps25990): Rework TPS25990 direct conversion handling
From: Stoyan Bogdanov @ 2026-05-22 8:23 UTC (permalink / raw)
To: jbrunet, linux, robh, krzk+dt, conor+dt, corbet, skhan
Cc: linux-hwmon, devicetree, linux-doc, linux-kernel, Stoyan Bogdanov
In-Reply-To: <20260522082349.2749970-1-sbogdanov@baylibre.com>
Rework the existing implementation of direct format conversion for
TPS25990 non-standard parameters to improve code reusability and
integration with the PMBus direct conversion helpers.
Changes include:
- Add an enum describing the supported parameters
- Add structure to hold m, b, R per-device coefficients
- Add data structures for pmbus_driver_info and local direct values
- Use the generic PMBus conversion helpers:
pmbus_reg2data_direct_calc()
pmbus_data2reg_direct_calc()
- Replace previously used defines with structured data
This reduces duplicated conversion logic and makes handling of
non-standard parameters more maintainable.
Signed-off-by: Stoyan Bogdanov <sbogdanov@baylibre.com>
---
drivers/hwmon/pmbus/tps25990.c | 197 +++++++++++++++++++++------------
1 file changed, 127 insertions(+), 70 deletions(-)
diff --git a/drivers/hwmon/pmbus/tps25990.c b/drivers/hwmon/pmbus/tps25990.c
index 05c6288ecafc..1e252844217b 100644
--- a/drivers/hwmon/pmbus/tps25990.c
+++ b/drivers/hwmon/pmbus/tps25990.c
@@ -36,17 +36,63 @@
#define TPS25990_UNLOCKED BIT(7)
#define TPS25990_8B_SHIFT 2
-#define TPS25990_VIN_OVF_NUM 525100
-#define TPS25990_VIN_OVF_DIV 10163
-#define TPS25990_VIN_OVF_OFF 155
-#define TPS25990_IIN_OCF_NUM 953800
-#define TPS25990_IIN_OCF_DIV 129278
-#define TPS25990_IIN_OCF_OFF 157
#define PK_MIN_AVG_RST_MASK (PK_MIN_AVG_RST_PEAK | \
PK_MIN_AVG_RST_AVG | \
PK_MIN_AVG_RST_MIN)
+enum chips {
+ tps25990,
+};
+
+enum tps25990_parameters {
+ TPS25990_VIN_OVF = 0, /* VIN over volatage fault */
+ TPS25990_IIN_OCF, /* IIN Over currect fault */
+ TPS25990_DIRECT_VALUES_COUNT,
+};
+
+struct tps25990_local_direct_value {
+ int m[TPS25990_DIRECT_VALUES_COUNT]; /* mantissa */
+ int b[TPS25990_DIRECT_VALUES_COUNT]; /* offset */
+ int R[TPS25990_DIRECT_VALUES_COUNT]; /* exponent */
+};
+
+struct tps25990_data {
+ struct pmbus_driver_info info;
+ struct tps25990_local_direct_value info_local;
+};
+
+static s64 tps25990_reg2data_direct(struct i2c_client *client, int param, s32 raw)
+{
+ struct pmbus_driver_info *info = i2c_get_clientdata(client);
+ struct tps25990_data *data = container_of(info, struct tps25990_data, info);
+ struct tps25990_local_direct_value *info_local = &data->info_local;
+ s64 b, val;
+ s32 m, R;
+
+ val = (s16)raw;
+ m = info_local->m[param];
+ b = info_local->b[param];
+ R = info_local->R[param];
+
+ return pmbus_reg2data_direct_calc(val, b, m, R);
+}
+
+static u16 tps25990_data2reg_direct(struct i2c_client *client, int param, s64 val)
+{
+ struct pmbus_driver_info *info = i2c_get_clientdata(client);
+ struct tps25990_data *data = container_of(info, struct tps25990_data, info);
+ struct tps25990_local_direct_value *info_local = &data->info_local;
+ s32 m, R;
+ s64 b;
+
+ m = info_local->m[param];
+ b = info_local->b[param];
+ R = info_local->R[param];
+
+ return pmbus_data2reg_direct_calc(val, b, m, R);
+}
+
/*
* Arbitrary default Rimon value: 1kOhm
* This correspond to an overcurrent limit of 55A, close to the specified limit
@@ -184,9 +230,7 @@ static int tps25990_read_word_data(struct i2c_client *client,
ret = pmbus_read_word_data(client, page, phase, reg);
if (ret < 0)
break;
- ret = DIV_ROUND_CLOSEST(ret * TPS25990_VIN_OVF_NUM,
- TPS25990_VIN_OVF_DIV);
- ret += TPS25990_VIN_OVF_OFF;
+ ret = tps25990_reg2data_direct(client, TPS25990_VIN_OVF, ret);
break;
case PMBUS_IIN_OC_FAULT_LIMIT:
@@ -198,9 +242,7 @@ static int tps25990_read_word_data(struct i2c_client *client,
ret = pmbus_read_byte_data(client, page, TPS25990_VIREF);
if (ret < 0)
break;
- ret = DIV_ROUND_CLOSEST(ret * TPS25990_IIN_OCF_NUM,
- TPS25990_IIN_OCF_DIV);
- ret += TPS25990_IIN_OCF_OFF;
+ ret = tps25990_reg2data_direct(client, TPS25990_IIN_OCF, ret);
break;
case PMBUS_VIRT_SAMPLES:
@@ -246,17 +288,13 @@ static int tps25990_write_word_data(struct i2c_client *client,
break;
case PMBUS_VIN_OV_FAULT_LIMIT:
- value -= TPS25990_VIN_OVF_OFF;
- value = DIV_ROUND_CLOSEST(((unsigned int)value) * TPS25990_VIN_OVF_DIV,
- TPS25990_VIN_OVF_NUM);
+ value = tps25990_data2reg_direct(client, TPS25990_VIN_OVF, value);
value = clamp_val(value, 0, 0xf);
ret = pmbus_write_word_data(client, page, reg, value);
break;
case PMBUS_IIN_OC_FAULT_LIMIT:
- value -= TPS25990_IIN_OCF_OFF;
- value = DIV_ROUND_CLOSEST(((unsigned int)value) * TPS25990_IIN_OCF_DIV,
- TPS25990_IIN_OCF_NUM);
+ value = tps25990_data2reg_direct(client, TPS25990_IIN_OCF, value);
value = clamp_val(value, 0, 0x3f);
ret = pmbus_write_byte_data(client, page, TPS25990_VIREF, value);
break;
@@ -337,63 +375,76 @@ static const struct regulator_desc tps25990_reg_desc[] = {
};
#endif
-static const struct pmbus_driver_info tps25990_base_info = {
- .pages = 1,
- .format[PSC_VOLTAGE_IN] = direct,
- .m[PSC_VOLTAGE_IN] = 5251,
- .b[PSC_VOLTAGE_IN] = 0,
- .R[PSC_VOLTAGE_IN] = -2,
- .format[PSC_VOLTAGE_OUT] = direct,
- .m[PSC_VOLTAGE_OUT] = 5251,
- .b[PSC_VOLTAGE_OUT] = 0,
- .R[PSC_VOLTAGE_OUT] = -2,
- .format[PSC_TEMPERATURE] = direct,
- .m[PSC_TEMPERATURE] = 140,
- .b[PSC_TEMPERATURE] = 32100,
- .R[PSC_TEMPERATURE] = -2,
- /*
- * Current and Power measurement depends on the ohm value
- * of Rimon. m is multiplied by 1000 below to have an integer
- * and -3 is added to R to compensate.
- */
- .format[PSC_CURRENT_IN] = direct,
- .m[PSC_CURRENT_IN] = 9538,
- .b[PSC_CURRENT_IN] = 0,
- .R[PSC_CURRENT_IN] = -6,
- .format[PSC_POWER] = direct,
- .m[PSC_POWER] = 4901,
- .b[PSC_POWER] = 0,
- .R[PSC_POWER] = -7,
- .func[0] = (PMBUS_HAVE_VIN |
- PMBUS_HAVE_VOUT |
- PMBUS_HAVE_VMON |
- PMBUS_HAVE_IIN |
- PMBUS_HAVE_PIN |
- PMBUS_HAVE_TEMP |
- PMBUS_HAVE_STATUS_VOUT |
- PMBUS_HAVE_STATUS_IOUT |
- PMBUS_HAVE_STATUS_INPUT |
- PMBUS_HAVE_STATUS_TEMP |
- PMBUS_HAVE_SAMPLES),
- .read_word_data = tps25990_read_word_data,
- .write_word_data = tps25990_write_word_data,
- .read_byte_data = tps25990_read_byte_data,
- .write_byte_data = tps25990_write_byte_data,
+static struct tps25990_local_direct_value tps25990_local_info[] = {
+ [tps25990] = {
+ .m[TPS25990_VIN_OVF] = 10163,
+ .b[TPS25990_VIN_OVF] = -30081,
+ .R[TPS25990_VIN_OVF] = -4,
+ .m[TPS25990_IIN_OCF] = 9538,
+ .b[TPS25990_IIN_OCF] = 0,
+ .R[TPS25990_IIN_OCF] = -6,
+ },
+};
+
+static struct pmbus_driver_info tps25990_base_info[] = {
+ [tps25990] = {
+ .pages = 1,
+ .format[PSC_VOLTAGE_IN] = direct,
+ .m[PSC_VOLTAGE_IN] = 5251,
+ .b[PSC_VOLTAGE_IN] = 0,
+ .R[PSC_VOLTAGE_IN] = -2,
+ .format[PSC_VOLTAGE_OUT] = direct,
+ .m[PSC_VOLTAGE_OUT] = 5251,
+ .b[PSC_VOLTAGE_OUT] = 0,
+ .R[PSC_VOLTAGE_OUT] = -2,
+ .format[PSC_TEMPERATURE] = direct,
+ .m[PSC_TEMPERATURE] = 140,
+ .b[PSC_TEMPERATURE] = 32100,
+ .R[PSC_TEMPERATURE] = -2,
+ /*
+ * Current and Power measurement depends on the ohm value
+ * of Rimon. m is multiplied by 1000 below to have an integer
+ * and -3 is added to R to compensate.
+ */
+ .format[PSC_CURRENT_IN] = direct,
+ .m[PSC_CURRENT_IN] = 9538,
+ .b[PSC_CURRENT_IN] = 0,
+ .R[PSC_CURRENT_IN] = -6,
+ .format[PSC_POWER] = direct,
+ .m[PSC_POWER] = 4901,
+ .b[PSC_POWER] = 0,
+ .R[PSC_POWER] = -7,
+ .func[0] = (PMBUS_HAVE_VIN |
+ PMBUS_HAVE_VOUT |
+ PMBUS_HAVE_VMON |
+ PMBUS_HAVE_IIN |
+ PMBUS_HAVE_PIN |
+ PMBUS_HAVE_TEMP |
+ PMBUS_HAVE_STATUS_VOUT |
+ PMBUS_HAVE_STATUS_IOUT |
+ PMBUS_HAVE_STATUS_INPUT |
+ PMBUS_HAVE_STATUS_TEMP |
+ PMBUS_HAVE_SAMPLES),
+ .read_word_data = tps25990_read_word_data,
+ .write_word_data = tps25990_write_word_data,
+ .read_byte_data = tps25990_read_byte_data,
+ .write_byte_data = tps25990_write_byte_data,
#if IS_ENABLED(CONFIG_SENSORS_TPS25990_REGULATOR)
- .reg_desc = tps25990_reg_desc,
- .num_regulators = ARRAY_SIZE(tps25990_reg_desc),
+ .reg_desc = tps25990_reg_desc,
+ .num_regulators = ARRAY_SIZE(tps25990_reg_desc),
#endif
+ },
};
static const struct i2c_device_id tps25990_i2c_id[] = {
- { "tps25990" },
+ { "tps25990", tps25990 },
{}
};
MODULE_DEVICE_TABLE(i2c, tps25990_i2c_id);
static const struct of_device_id tps25990_of_match[] = {
- { .compatible = "ti,tps25990" },
+ { .compatible = "ti,tps25990", .data = (void *)tps25990 },
{}
};
MODULE_DEVICE_TABLE(of, tps25990_of_match);
@@ -401,8 +452,9 @@ MODULE_DEVICE_TABLE(of, tps25990_of_match);
static int tps25990_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
- struct pmbus_driver_info *info;
+ struct tps25990_data *data;
const char *propname;
+ enum chips chip_id;
u32 rimon;
int ret;
@@ -415,15 +467,20 @@ static int tps25990_probe(struct i2c_client *client)
rimon = TPS25990_DEFAULT_RIMON;
}
- info = devm_kmemdup(dev, &tps25990_base_info, sizeof(*info), GFP_KERNEL);
- if (!info)
+ chip_id = (enum chips)(unsigned long)i2c_get_match_data(client);
+
+ data = devm_kzalloc(dev, sizeof(struct tps25990_data), GFP_KERNEL);
+ if (!data)
return -ENOMEM;
+ data->info = tps25990_base_info[chip_id];
+ data->info_local = tps25990_local_info[chip_id];
+
/* Adapt the current and power scale for each instance */
- tps25990_set_m(&info->m[PSC_CURRENT_IN], rimon);
- tps25990_set_m(&info->m[PSC_POWER], rimon);
+ tps25990_set_m(&data->info.m[PSC_CURRENT_IN], rimon);
+ tps25990_set_m(&data->info.m[PSC_POWER], rimon);
- return pmbus_do_probe(client, info);
+ return pmbus_do_probe(client, &data->info);
}
static struct i2c_driver tps25990_driver = {
--
2.43.0
^ permalink raw reply related
* [PATCH v4 3/4] dt-bindings: hwmon: pmbus/tps25990: Add TPS1689
From: Stoyan Bogdanov @ 2026-05-22 8:23 UTC (permalink / raw)
To: jbrunet, linux, robh, krzk+dt, conor+dt, corbet, skhan
Cc: linux-hwmon, devicetree, linux-doc, linux-kernel, Stoyan Bogdanov,
Krzysztof Kozlowski
In-Reply-To: <20260522082349.2749970-1-sbogdanov@baylibre.com>
Add device compatible support for TPS1689
Signed-off-by: Stoyan Bogdanov <sbogdanov@baylibre.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
.../devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml
index f4115870e450..63ccb67576df 100644
--- a/Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml
+++ b/Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml
@@ -5,18 +5,20 @@
$id: http://devicetree.org/schemas/hwmon/pmbus/ti,tps25990.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Texas Instruments TPS25990 Stackable eFuse
+title: Texas Instruments Stackable eFuses
maintainers:
- Jerome Brunet <jbrunet@baylibre.com>
description:
- The TI TPS25990 is an integrated, high-current circuit
+ The TI TPS25990 and TPS1689 are integrated, high-current circuit
protection and power management device with PMBUS interface
properties:
compatible:
- const: ti,tps25990
+ enum:
+ - ti,tps1689
+ - ti,tps25990
reg:
maxItems: 1
--
2.43.0
^ permalink raw reply related
* [PATCH v4 4/4] hwmon: (pmbus/tps25990): Add TPS1689 support
From: Stoyan Bogdanov @ 2026-05-22 8:23 UTC (permalink / raw)
To: jbrunet, linux, robh, krzk+dt, conor+dt, corbet, skhan
Cc: linux-hwmon, devicetree, linux-doc, linux-kernel, Stoyan Bogdanov
In-Reply-To: <20260522082349.2749970-1-sbogdanov@baylibre.com>
Extend the existing TPS25990 driver to support the TPS1689 eFuse,
as both devices share the same command interface and functionality.
Update the documentation to include TPS1689 support.
Signed-off-by: Stoyan Bogdanov <sbogdanov@baylibre.com>
---
Documentation/hwmon/tps25990.rst | 15 +++++---
drivers/hwmon/pmbus/tps25990.c | 66 +++++++++++++++++++++++++++++++-
2 files changed, 74 insertions(+), 7 deletions(-)
diff --git a/Documentation/hwmon/tps25990.rst b/Documentation/hwmon/tps25990.rst
index 04faec780d26..e8bc9a550bda 100644
--- a/Documentation/hwmon/tps25990.rst
+++ b/Documentation/hwmon/tps25990.rst
@@ -9,26 +9,31 @@ Supported chips:
Prefix: 'tps25990'
- * Datasheet
+ Datasheet: Publicly available at Texas Instruments website: https://www.ti.com/lit/gpn/tps25990
- Publicly available at Texas Instruments website: https://www.ti.com/lit/gpn/tps25990
+ * TI TPS1689
+
+ Prefix: 'tps1689'
+
+ Datasheet: Publicly available at Texas Instruments website: https://www.ti.com/lit/gpn/tps1689
Author:
Jerome Brunet <jbrunet@baylibre.com>
+ Stoyan Bogdanov <sbogdanov@baylibre.com>
Description
-----------
-This driver implements support for TI TPS25990 eFuse.
+This driver implements support for TI TPS25990 and TI TPS1689 eFuse chips.
This is an integrated, high-current circuit protection and power
management device with PMBUS interface
-Device compliant with:
+Devices are compliant with:
- PMBus rev 1.3 interface.
-Device supports direct format for reading input voltages,
+Devices supports direct format for reading input voltages,
output voltage, input current, input power and temperature.
Due to the specificities of the chip, all history reset attributes
diff --git a/drivers/hwmon/pmbus/tps25990.c b/drivers/hwmon/pmbus/tps25990.c
index 1e252844217b..720e134f1892 100644
--- a/drivers/hwmon/pmbus/tps25990.c
+++ b/drivers/hwmon/pmbus/tps25990.c
@@ -42,6 +42,7 @@
PK_MIN_AVG_RST_MIN)
enum chips {
+ tps1689,
tps25990,
};
@@ -286,7 +287,6 @@ static int tps25990_write_word_data(struct i2c_client *client,
value = clamp_val(value, 0, 0xff);
ret = pmbus_write_word_data(client, page, reg, value);
break;
-
case PMBUS_VIN_OV_FAULT_LIMIT:
value = tps25990_data2reg_direct(client, TPS25990_VIN_OVF, value);
value = clamp_val(value, 0, 0xf);
@@ -376,6 +376,14 @@ static const struct regulator_desc tps25990_reg_desc[] = {
#endif
static struct tps25990_local_direct_value tps25990_local_info[] = {
+ [tps1689] = {
+ .m[TPS25990_VIN_OVF] = 3984,
+ .b[TPS25990_VIN_OVF] = -63750,
+ .R[TPS25990_VIN_OVF] = -3,
+ .m[TPS25990_IIN_OCF] = 7111,
+ .b[TPS25990_IIN_OCF] = -2133,
+ .R[TPS25990_IIN_OCF] = -2,
+ },
[tps25990] = {
.m[TPS25990_VIN_OVF] = 10163,
.b[TPS25990_VIN_OVF] = -30081,
@@ -387,6 +395,59 @@ static struct tps25990_local_direct_value tps25990_local_info[] = {
};
static struct pmbus_driver_info tps25990_base_info[] = {
+ [tps1689] = {
+ .pages = 1,
+ .format[PSC_VOLTAGE_IN] = direct,
+ .m[PSC_VOLTAGE_IN] = 1166,
+ .b[PSC_VOLTAGE_IN] = 0,
+ .R[PSC_VOLTAGE_IN] = -2,
+ .format[PSC_VOLTAGE_OUT] = direct,
+ .m[PSC_VOLTAGE_OUT] = 1166,
+ .b[PSC_VOLTAGE_OUT] = 0,
+ .R[PSC_VOLTAGE_OUT] = -2,
+ .format[PSC_TEMPERATURE] = direct,
+ .m[PSC_TEMPERATURE] = 140,
+ .b[PSC_TEMPERATURE] = 32103,
+ .R[PSC_TEMPERATURE] = -2,
+ /*
+ * Current and Power measurement depends on the ohm value
+ * of Rimon. m is multiplied by 1000 below to have an integer
+ * and -3 is added to R to compensate.
+ */
+ .format[PSC_CURRENT_IN] = direct,
+ .m[PSC_CURRENT_IN] = 9548,
+ .b[PSC_CURRENT_IN] = 0,
+ .R[PSC_CURRENT_IN] = -6,
+ .format[PSC_CURRENT_OUT] = direct,
+ .m[PSC_CURRENT_OUT] = 24347,
+ .b[PSC_CURRENT_OUT] = 0,
+ .R[PSC_CURRENT_OUT] = -3,
+ .format[PSC_POWER] = direct,
+ .m[PSC_POWER] = 2775,
+ .b[PSC_POWER] = 0,
+ .R[PSC_POWER] = -4,
+ .func[0] = (PMBUS_HAVE_VIN |
+ PMBUS_HAVE_VOUT |
+ PMBUS_HAVE_VMON |
+ PMBUS_HAVE_IIN |
+ PMBUS_HAVE_PIN |
+ PMBUS_HAVE_TEMP |
+ PMBUS_HAVE_STATUS_VOUT |
+ PMBUS_HAVE_STATUS_IOUT |
+ PMBUS_HAVE_STATUS_INPUT |
+ PMBUS_HAVE_STATUS_TEMP |
+ PMBUS_HAVE_SAMPLES),
+
+ .read_word_data = tps25990_read_word_data,
+ .write_word_data = tps25990_write_word_data,
+ .read_byte_data = tps25990_read_byte_data,
+ .write_byte_data = tps25990_write_byte_data,
+
+#if IS_ENABLED(CONFIG_SENSORS_TPS25990_REGULATOR)
+ .reg_desc = tps25990_reg_desc,
+ .num_regulators = ARRAY_SIZE(tps25990_reg_desc),
+#endif
+ },
[tps25990] = {
.pages = 1,
.format[PSC_VOLTAGE_IN] = direct,
@@ -429,7 +490,6 @@ static struct pmbus_driver_info tps25990_base_info[] = {
.write_word_data = tps25990_write_word_data,
.read_byte_data = tps25990_read_byte_data,
.write_byte_data = tps25990_write_byte_data,
-
#if IS_ENABLED(CONFIG_SENSORS_TPS25990_REGULATOR)
.reg_desc = tps25990_reg_desc,
.num_regulators = ARRAY_SIZE(tps25990_reg_desc),
@@ -438,12 +498,14 @@ static struct pmbus_driver_info tps25990_base_info[] = {
};
static const struct i2c_device_id tps25990_i2c_id[] = {
+ { "tps1689", tps1689 },
{ "tps25990", tps25990 },
{}
};
MODULE_DEVICE_TABLE(i2c, tps25990_i2c_id);
static const struct of_device_id tps25990_of_match[] = {
+ { .compatible = "ti,tps1689", .data = (void *)tps1689 },
{ .compatible = "ti,tps25990", .data = (void *)tps25990 },
{}
};
--
2.43.0
^ permalink raw reply related
* Re: [PATCH] dcache: add fs.dentry-limit sysctl with negative-first reaper
From: Amir Goldstein @ 2026-05-22 8:27 UTC (permalink / raw)
To: NeilBrown
Cc: Ian Kent, Jan Kara, Horst Birthelmer, Miklos Szeredi,
Jonathan Corbet, Shuah Khan, Alexander Viro, Christian Brauner,
linux-doc, linux-kernel, linux-fsdevel, Horst Birthelmer
In-Reply-To: <177942337499.2234587.15757857859187727669@noble.neil.brown.name>
On Fri, May 22, 2026 at 6:16 AM NeilBrown <neilb@ownmail.net> wrote:
>
> On Wed, 20 May 2026, Amir Goldstein wrote:
> > On Wed, May 20, 2026 at 9:16 AM Ian Kent <raven@themaw.net> wrote:
> > >
> > > On 19/5/26 17:12, Jan Kara wrote:
> > > > On Mon 18-05-26 21:39:13, Ian Kent wrote:
> > > >> On 18/5/26 16:19, Jan Kara wrote:
> > > >>> Hi Ian,
> > > >>>
> > > >>> On Mon 18-05-26 10:55:43, Ian Kent wrote:
> > > >>>> On 18/5/26 07:55, NeilBrown wrote:
> > > >>>>> On Fri, 15 May 2026, Horst Birthelmer wrote:
> > > >>>>> According to the email you linked, a problem arises when a directory has
> > > >>>>> a great many negative children. Code which walks the list of children
> > > >>>>> (such as fsnotify) while holding a lock can suffer unpredictable delays
> > > >>>>> and result in long lock-hold times. So maybe a limit on negative
> > > >>>>> dentries for any parent is what we really want. That would be clumsy to
> > > >>>>> implement I imagine.
> > > >>>> But the notion of dropping the dentry in ->d_delete() on last dput() is
> > > >>>> simple enough but did see regressions (the only other place in the VFS
> > > >>>> besides dentry_kill() that the inode is unlinked from the dentry on
> > > >>>> dput()). I wonder if the regression was related to the test itself
> > > >>>> deliberately recreating deleted files and if that really is normal
> > > >>>> behaviour. By itself that should prevent almost all negative dentries
> > > >>>> being retained. Although file systems could do this as well (think XFS
> > > >>>> inode recycling) it should be reasonable to require it be left to the
> > > >>>> VFS.
> > > >>>>
> > > >>>> But even that's not enough given that, in my case, there would still be
> > > >>>> around 4 million dentries in the LRU cache and in fsnotify there are
> > > >>>> directory child traversals holding the parent i_lock "spinlock" that are
> > > >>>> going to cause problems.
> > > >>> Do you mean there are very many positive children of a directory?
> > > >> Didn't quantify that.
> > > >>
> > > >> The symptom is the "Spinlock held for more than ... seconds" occurring in
> > > >> the log. So there are certainly a lot of children in the list, but it's
> > > >> an assumption the ratio of positive to negative entries is roughly the
> > > >> same as the overall ratio in the dcache.
> > > > OK, but that's not necessarily true. I have seen these complaints from the
> > > > kernel but in all the cases I remember it was due to negative dentries
> > > > accumultating in a particular directory. There are certain apps such as
> > > > ElasticSearch which really do like creating huge amounts of negative
> > > > dentries in one directory - they use hashes as filenames and use directory
> > > > lookup instead of a DB table lookup and lookup lots of non-existent keys...
> > >
> > > Umm ... that's a good point, I hadn't paid much attention to ENOENT result
> > >
> > > lookups, I'll need to check on the like cycle of those, I think they do get
> > >
> > > hashed. That has to be the other source of negative dentries that I've
> > >
> > > neglected ...
> > >
> >
> > Yes, it has been claimed that some real life workloads create a lot of those.
> >
> > If we can keep those at the tail of the children list, it will be best
> > for the fsnotify
> > iteration, which only cares about positive dentries.
> >
> > > >
> > > >>>> so why is this traversal even retained in fsnotify?
> > > >>> Not sure which traversal you mean but if you set watch on a parent, you
> > > >>> have to walk all children to set PARENT_WATCHED flag so that you don't miss
> > > >>> events on children...
> > > >> Yes, that traversal is what I'm questioning ... again thanks.
> > > >>
> > > >> I think the function name is still fsnotify_set_children_dentry_flags()
> > > >> in recent kernels, the subject of commit 172e422ffea2 I mentioned above.
> > > > OK, thanks.
> > > >
> > > >> When you say miss events are you saying that accessing the parent dentry to
> > > >> work out if the child needs to respond to an event is quite expensive in the
> > > >> overall event processing context, that might make more sense to me ... or do
> > > >> I completely not yet understand the reasoning behind the need for the flag?
> > > > Close but not quite. The cost is the overhead of dget_parent() in
> > > > fsnotify_parent() which is often a couple of cache cold loads and atomic
> > > > instructions to find out we don't need to send any event for the current
> > > > write(2) or read(2) call. It gets worse if there are many IOs happening to
> > > > dentries in the same directory from multiple CPUs because instead of
> > > > cache-cold loads you get a cacheline contention on the parent.
> > > >
> > > >>>>> But what if we move dentries to the end of the list when they become
> > > >>>>> negative, and to the start of the list when they become positive? Then
> > > >>>>> code which walks the child list could simply abort on the first
> > > >>>>> negative.
> > > >>>>>
> > > >>>>> I doubt that would be quite as easy as it sounds, but it would at least
> > > >>>>> be more focused on the observed symptom rather than some whole-system
> > > >>>>> number which only vaguely correlates with the observed symptom.
> > > >>>>>
> > > >>>>> Maybe a completely different approach: change children-walking code to
> > > >>>>> drop and retake the lock (with appropriate validation) periodically.
> > > >>>>> What too would address the specific symptom.
> > > >>>> Another good question.
> > > >>>>
> > > >>>> I have assumed that dropping and re-taking the lock cannot be done but
> > > >>>> this is a question I would like answered as well. Dropping and re-taking
> > > >>>> lock would require, as Miklos pointed out to me off-list, recording the
> > > >>>> list position with say a cursor, introducing unwanted complexity when it
> > > >>>> would be better to accept the cost of a single extra access to the parent
> > > >>>> flags (which I assume is one reason to set the flag in the child).
> > > >>> The parent access is actually more expensive than you might think. Based on
> > > >>> experience with past fsnotify related performance regression I expect some
> > > >>> 20% performance hit for small tmpfs writes if you add unconditional parent
> > > >>> access to the write path.
> > > >> That sounds like a lot for what should be a memory access of an already in
> > > >> memory structure since the parent must be accessed to traverse the list of
> > > >> child entries. I clearly don't fully understand the implications of what
> > > >> I'm saying but there has been mention of another context ...
> > > > Parent dentry is of course in memory but often cache cold - you don't need
> > > > the parent to do e.g. write(2) to an already open file. You seem to be
> > > > somewhat confused about the child dentry list traversal (or maybe I'm
> > > > misunderstanding) - that happens only when placing the notification mark
> > > > but definitely not for each IO operation.
> > >
> > > LOL, confusion is a pretty common state of mind for me!
> > >
> > >
> > > I do get your point though and I am confusing the traversal with other
> > >
> > > operations. I think this answers the question I've been asking (maybe
> > >
> > > that wasn't obvious) about the reason for the traversal (ie. the reason
> > >
> > > to maintain a flag in the child).
> > >
> > >
> > > While I have looked at the code here I haven't absorbed it and I
> > >
> > > definitely don't understand it, your continued patience is appreciated
> > >
> > > and will be beneficial when I get time to look at it a bit closer. I
> > >
> > > do still need to use a notifications mechanism to match up with Miklos's
> > >
> > > statmount implementation to get the full benefit of that in user space,
> > >
> > > if I ever get a chance to work on that again.
> > >
> > >
> > > So it sounds like it would be worth while considering a traversal that's
> > >
> > > based on taking a reference on each dentry rather than a spinlock for
> > >
> > > the duration. It would be tricky though, for obvious reasons, like
> > >
> > > children added during the traversal, added overhead of getting the next
> > >
> > > entry reference, etc.
> >
> > Didn't look closely, but it feels like RCU traversal should be
> > possible if entries are added to the tail, or to the END_OF_POSITIVE
> > location.
> >
> > When we discussed the "negavites at tail" at LSFMM
> > it was said that managing the transitions positive<->negative
> > would be challenging, but I don't know that anyone tried to look closer at this.
>
> I had a quick look. Most users of d_sib walk from the parent->d_children
> with the parent ->d_lock held, so they shouldn't notice a movement in
> the list.
> The two exceptions I could find are d_walk() and the readdir code in
> libfs.c.
> I think the main problem case would be if they were holding a dentry as
> a cursor which transitioned when the parent d_lock is dropped and retaken.
>
> d_walk already needs to cope with a concurrent rename messing with
> its cursor so possibly something similar could be used to trigger a
> restart.
>
> libfs readdir walks from a DCACHE_DENTRY_CURSOR which will never
> transition and so won't move spontaneously. That is exactly as safe as
> walking from the parent.
>
> So I think d_walk() might need some help to avoid getting lost. It could
> probably simply check if its cursor changed ->d_inode between dropping
> ->d_lock and retaking it. If it did, then restart.
>
> It isn't clear to me that we can track a "end of positive" location. I
> think we would need to move negatives to the end and positives to the
> start. Can you see a down-side with doing that?
>
One of the intentions (that may be lost in this conversations) was to
avoid holding the parent inode lock over the entire children iteration in
fsnotify_set_children_dentry_flags().
This function only needs to go over all positive children.
That's why I thought about moving new positive to the end of positives.
Maybe this works if we keep positives at tail and negatives at head
and also have dentry shrinkers work on the negative dentries at the head
first.
Possibly, we can make sure to set DCACHE_FSNOTIFY_PARENT_WATCHED
if needed when making a dentry positive, to avoid some races.
NOTE that DCACHE_FSNOTIFY_PARENT_WATCHED can allow false
positives. It's an optimization flag that is auto cleared with
fsnotify_clear_child_dentry_flag() in case of false positive.
Also, it is possible to set DCACHE_FSNOTIFY_PARENT_WATCHED
*before* dentry is made positive, for example on start_creating()
because whether a negative dentry has DCACHE_FSNOTIFY_PARENT_WATCHED
or not is insignificant.
Thanks,
Amir.
^ permalink raw reply
* Re: [PATCH bpf-next v2] bpf, docs: add LOAD_ACQUIRE and STORE_RELEASE instructions
From: Alexis Lothoré @ 2026-05-22 8:35 UTC (permalink / raw)
To: David Vernet, Alexis Lothoré (eBPF Foundation)
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Song Liu, Yonghong Song, Jiri Olsa, Jonathan Corbet, Shuah Khan,
ebpf, Bastien Curutchet, Thomas Petazzoni, bpf, bpf, linux-doc,
linux-kernel
In-Reply-To: <iulf7fwwvfrvvspg4e5xyx3tcxe2yonfjllnze2phgfgpynrlh@kodf3fy3l32q>
Hi David,
On Thu May 21, 2026 at 4:17 AM CEST, David Vernet wrote:
> On Thu, May 21, 2026 at 12:09:11AM +0200, Alexis Lothoré (eBPF Foundation) wrote:
>
> Hi Alexis,
>
> Thanks for working on this.
>
>> Commit 880442305a39 ("bpf: Introduce load-acquire and store-release
>> instructions") instroduced the LOAD_ACQUIRE and STORE_RELEASE atomic
>
> introduced
>
>> instructions modifiers. Those are currently not described in the
>> documentation, despite being used in the verifier and the various JIT
>> compilers supporting them.
>>
>> Add the missing entries in the instruction set documentation.
>>
>> Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
>
> Alexei et al -- if you plan to do a subsequent RFC, it will influence
> how this document needs to be structured. [0] explains the process for
> adding new instructions. To quote:
>
>> Once a conformance group is registered with a set of instructions, no
>> further instructions can be added to that conformance group. A
>> specification should instead create a new conformance group that
>> includes the original conformance group, plus any newly added
>> instructions. Inclusion of the original conformance group is done via
>> the "includes" column of the BPF Instruction Conformance Groups
>> registry, and inclusion of newly added instructions is done via the
>> "groups" column of the BPF Instruction Set registry.
>
> So you would have to create a new conformance group for these new
> atomics -- you can't just add them to the existing one. In general it
> might be easier / advised to snapshot this file to RFC 9669 and create a
> new one for the new instructions to make it easier to tease this stuff
> apart later. If that's something you want, I'm happy to get us started
> with a skeleton file. Again, though, that's only necessary if you plan
> to submit a new document to the IETF WG.
>
> [0]: https://www.rfc-editor.org/rfc/rfc9669.html#name-adding-instructions
I don't know how heavy/long the process is to submit this kind of RFC
update, but your point makes it sound like it makes more sense to just
go directly for the proper way, ie adding the conformance group and then
adding those new ops in there, rather than updating the kernel doc as my
series is proposing, and then later reverting to a proper conformance
group.
--
Alexis Lothoré, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH v5 00/28] mtd: spi-nor: Enhance software protection
From: Tudor Ambarus @ 2026-05-22 9:07 UTC (permalink / raw)
To: Miquel Raynal, Pratyush Yadav, Michael Walle, Takahiro Kuwano,
Richard Weinberger, Vignesh Raghavendra, Jonathan Corbet,
Shuah Khan
Cc: Sean Anderson, Thomas Petazzoni, Steam Lin, linux-mtd,
linux-kernel, linux-doc, stable
In-Reply-To: <20260507-winbond-v6-18-rc1-spi-nor-swp-v5-0-93453e1a9597@bootlin.com>
Hi, Miquel,
Please consider sashiko's review feedback and let us know whether there's
going to be a v6 or this set is good as it is:
https://sashiko.dev/#/patchset/20260507-winbond-v6-18-rc1-spi-nor-swp-v5-0-93453e1a9597%40bootlin.com
Cheers,
ta
^ permalink raw reply
* Re: [PATCH v5 04/28] mtd: spi-nor: swp: Improve locking user experience
From: Tudor Ambarus @ 2026-05-22 9:10 UTC (permalink / raw)
To: Miquel Raynal, Pratyush Yadav, Michael Walle, Takahiro Kuwano,
Richard Weinberger, Vignesh Raghavendra, Jonathan Corbet,
Shuah Khan
Cc: Sean Anderson, Thomas Petazzoni, Steam Lin, linux-mtd,
linux-kernel, linux-doc, stable
In-Reply-To: <20260507-winbond-v6-18-rc1-spi-nor-swp-v5-4-93453e1a9597@bootlin.com>
On 5/7/26 7:46 PM, Miquel Raynal wrote:
> Fixes: 3dd8012a8eeb ("mtd: spi-nor: add TB (Top/Bottom) protect support")
> Cc: stable@kernel.org
Fixes shall be the first patches in the set.
^ permalink raw reply
* Re: [PATCH v5 12/28] mtd: spi-nor: swp: Rename a mask
From: Tudor Ambarus @ 2026-05-22 9:37 UTC (permalink / raw)
To: Miquel Raynal, Pratyush Yadav, Michael Walle, Takahiro Kuwano,
Richard Weinberger, Vignesh Raghavendra, Jonathan Corbet,
Shuah Khan
Cc: Sean Anderson, Thomas Petazzoni, Steam Lin, linux-mtd,
linux-kernel, linux-doc
In-Reply-To: <20260507-winbond-v6-18-rc1-spi-nor-swp-v5-12-93453e1a9597@bootlin.com>
Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>
^ permalink raw reply
* Re: [PATCH v5 13/28] mtd: spi-nor: swp: Create a TB intermediate variable
From: Tudor Ambarus @ 2026-05-22 9:39 UTC (permalink / raw)
To: Miquel Raynal, Pratyush Yadav, Michael Walle, Takahiro Kuwano,
Richard Weinberger, Vignesh Raghavendra, Jonathan Corbet,
Shuah Khan
Cc: Sean Anderson, Thomas Petazzoni, Steam Lin, linux-mtd,
linux-kernel, linux-doc
In-Reply-To: <20260507-winbond-v6-18-rc1-spi-nor-swp-v5-13-93453e1a9597@bootlin.com>
On 5/7/26 7:46 PM, Miquel Raynal wrote:
> Ease the future reuse of the tb (Top/Bottom) boolean by creating an
> intermediate variable.
Please squash this in the patch that needs it.
>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
> drivers/mtd/spi-nor/swp.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mtd/spi-nor/swp.c b/drivers/mtd/spi-nor/swp.c
> index 07269e09370a..540cd221c455 100644
> --- a/drivers/mtd/spi-nor/swp.c
> +++ b/drivers/mtd/spi-nor/swp.c
> @@ -62,6 +62,7 @@ static void spi_nor_get_locked_range_sr(struct spi_nor *nor, const u8 *sr, loff_
> u8 bp_mask = spi_nor_get_sr_bp_mask(nor);
> u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
> u8 bp, val = sr[0] & bp_mask;
> + bool tb = (nor->flags & SNOR_F_HAS_SR_TB) ? sr[0] & tb_mask : 0;
>
> if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3_BIT6)
> val = (val & ~SR_BP3_BIT6) | SR_BP3;
> @@ -81,7 +82,7 @@ static void spi_nor_get_locked_range_sr(struct spi_nor *nor, const u8 *sr, loff_
> if (*len > nor->params->size)
> *len = nor->params->size;
>
> - if (nor->flags & SNOR_F_HAS_SR_TB && sr[0] & tb_mask)
> + if (tb)
> *ofs = 0;
> else
> *ofs = nor->params->size - *len;
>
^ permalink raw reply
* Re: [PATCH v5 14/28] mtd: spi-nor: swp: Create helpers for building the SR register
From: Tudor Ambarus @ 2026-05-22 9:56 UTC (permalink / raw)
To: Miquel Raynal, Pratyush Yadav, Michael Walle, Takahiro Kuwano,
Richard Weinberger, Vignesh Raghavendra, Jonathan Corbet,
Shuah Khan
Cc: Sean Anderson, Thomas Petazzoni, Steam Lin, linux-mtd,
linux-kernel, linux-doc
In-Reply-To: <20260507-winbond-v6-18-rc1-spi-nor-swp-v5-14-93453e1a9597@bootlin.com>
On 5/7/26 7:46 PM, Miquel Raynal wrote:
> The status register contains 3 or 4 BP (Block Protect) bits, 0 or 1
> TB (Top/Bottom) bit, soon 0 or 1 CMP (Complement) bit. The last BP bit
> and the TB bit locations change between vendors. The whole logic of
> buildling the content of the status register based on some input
> conditions is used two times and soon will be used 4 times.
>
> Create dedicated helpers for these steps.
>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
> drivers/mtd/spi-nor/swp.c | 83 +++++++++++++++++++++++++++++------------------
> 1 file changed, 51 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/mtd/spi-nor/swp.c b/drivers/mtd/spi-nor/swp.c
> index 540cd221c455..8aa0fe297188 100644
> --- a/drivers/mtd/spi-nor/swp.c
> +++ b/drivers/mtd/spi-nor/swp.c
> @@ -125,6 +125,43 @@ static bool spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, u64 len,
> return spi_nor_check_lock_status_sr(nor, ofs, len, sr, false);
> }
>
> +static int spi_nor_sr_set_bp_mask(struct spi_nor *nor, u8 *sr, u8 pow)
> +{
> + u8 mask = spi_nor_get_sr_bp_mask(nor);
> + u8 val = pow << SR_BP_SHIFT;
> +
> + if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3)
> + val = (val & ~SR_BP3) | SR_BP3_BIT6;
> +
> + if (val & ~mask)
> + return -EINVAL;
> +
> + sr[0] = val;
As sashiko already noticed, I think too this should have been sr[0] |= val
^ permalink raw reply
* [PATCH] platform/x86: thinkpad_acpi: Add USB-C Security (USCS) support
From: Vishnu Sankar @ 2026-05-22 10:07 UTC (permalink / raw)
To: mpearson-lenovo, skhan, hmh, hansg, corbet, derekjohn.clark,
ilpo.jarvinen
Cc: linux-kernel, ibm-acpi-devel, linux-doc, platform-driver-x86,
vsankar, Vishnu Sankar
Newer ThinkPad systems expose a USB-C Security (Restricted Mode) feature.
When active, USB-C data connections are disabled while power delivery is
preserved. This is useful for kiosk and physically-secured deployments.
Hardware interface:
The HKEY device exposes a read-only ACPI method USCS():
Return value bit layout:
Bit 16 : Capability flag (1 = feature present on this SKU)
Bit 0 : Current state (0 = security OFF, 1 = security ON)
The sysfs attribute is read-only.
The Fn+U followed by Fn+S hotkey chord is the only way to toggle the
hardware state.
Hotkey:
Fn+U followed by Fn+S generates HKEY event 0x131e.
sysfs interface:
/sys/devices/platform/thinkpad_acpi/usb_c_security (read-only)
"enabled\n" -- data connections are currently blocked
"disabled\n" -- data connections are currently allowed
The attribute is hidden on SKUs where the USCS capability bit (bit 16)
is not set, so there is no ABI impact on unsupported hardware.
Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
---
.../admin-guide/laptops/thinkpad-acpi.rst | 24 ++++
drivers/platform/x86/lenovo/thinkpad_acpi.c | 115 ++++++++++++++++++
2 files changed, 139 insertions(+)
diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst b/Documentation/admin-guide/laptops/thinkpad-acpi.rst
index f874db31801d..db4588af0278 100644
--- a/Documentation/admin-guide/laptops/thinkpad-acpi.rst
+++ b/Documentation/admin-guide/laptops/thinkpad-acpi.rst
@@ -1543,6 +1543,30 @@ Values:
This setting can also be toggled via the Fn+doubletap hotkey.
+USB-C Security
+--------------
+
+sysfs: usb_c_security
+
+Reports the current state of the USB-C Security (Restricted Mode) feature
+on supported ThinkPad systems. When enabled, USB-C data connections are
+disabled while power delivery is preserved.
+
+The available command is::
+
+ cat /sys/devices/platform/thinkpad_acpi/usb_c_security
+
+Values:
+
+ * ``enabled`` - USB-C data connections are currently blocked
+ * ``disabled`` - USB-C data connections are currently allowed
+
+The attribute is read-only. The USB-C Security state can only be toggled
+via the Fn+U followed by Fn+S hotkey chord.
+
+The sysfs attribute is not created on platforms that do not support this
+feature.
+
Auxmac
------
diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c
index e1cee42a1683..889db802185a 100644
--- a/drivers/platform/x86/lenovo/thinkpad_acpi.c
+++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c
@@ -185,6 +185,7 @@ enum tpacpi_hkey_event_t {
TP_HKEY_EV_AMT_TOGGLE = 0x131a, /* Toggle AMT on/off */
TP_HKEY_EV_CAMERASHUTTER_TOGGLE = 0x131b, /* Toggle Camera Shutter */
TP_HKEY_EV_DOUBLETAP_TOGGLE = 0x131c, /* Toggle trackpoint doubletap on/off */
+ TP_HKEY_EV_USB_C_SECURITY = 0x131e, /* Toggle USB C Security ON/OFF */
TP_HKEY_EV_PROFILE_TOGGLE = 0x131f, /* Toggle platform profile in 2024 systems */
TP_HKEY_EV_PROFILE_TOGGLE2 = 0x1401, /* Toggle platform profile in 2025 + systems */
@@ -373,6 +374,8 @@ static struct {
u32 has_adaptive_kbd:1;
u32 kbd_lang:1;
u32 trackpoint_doubletap_enable:1;
+ u32 usbc_security_supported:1;
+ u32 usbc_security_enabled:1;
struct quirk_entry *quirks;
} tp_features;
@@ -11265,6 +11268,111 @@ static struct ibm_struct hwdd_driver_data = {
.name = "hwdd",
};
+/*************************************************************************
+ * USB-C Security subdriver
+ *
+ * HKEY.USCS(0) is a read-only ACPI method; its argument is ignored.
+ * It always returns:
+ * bit 16 - USB-C security capability present on this SKU or not
+ * bit 0 - USB-C Security state (enable or disable)
+ *
+ * Hotkey
+ * ------
+ * 0x131e (Fn+U, Fn+S): firmware toggles USBS before firing the event.
+ * The driver reads back the new state and notifies the sysfs attribute.
+ *
+ */
+
+/* USCS() return word bit layout */
+#define USCS_CAP_BIT BIT(16) /* capability: feature present on SKU */
+#define USCS_STATUS_BIT BIT(0) /* current security state */
+
+static DEFINE_MUTEX(usbc_security_mutex);
+
+/*
+ * usbc_security_query - read current USB-C security state via USCS()
+ * @enabled: out - true when security is ON (data connections blocked)
+ *
+ * Returns true if the feature is supported and query succeeded,
+ * false otherwise (feature absent or ACPI call failed).
+ */
+static bool usbc_security_query(bool *enabled)
+{
+ int status;
+
+ mutex_lock(&usbc_security_mutex);
+ if (!acpi_evalf(hkey_handle, &status, "USCS", "dd", 0)) {
+ mutex_unlock(&usbc_security_mutex);
+ return false;
+ }
+ mutex_unlock(&usbc_security_mutex);
+
+ if (!(status & USCS_CAP_BIT)) {
+ pr_debug("USCS cap bit absent (raw=0x%x)\n", status);
+ return false;
+ }
+
+ *enabled = !!(status & USCS_STATUS_BIT);
+ return true;
+}
+
+/* sysfs: /sys/devices/platform/thinkpad_acpi/usb_c_security ---------- */
+static ssize_t usb_c_security_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%s\n",
+ tp_features.usbc_security_enabled ? "enabled" : "disabled");
+}
+
+static DEVICE_ATTR_RO(usb_c_security);
+
+static struct attribute *usbc_security_attributes[] = {
+ &dev_attr_usb_c_security.attr,
+ NULL,
+};
+
+static umode_t usbc_security_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ return tp_features.usbc_security_supported ? attr->mode : 0;
+}
+
+static const struct attribute_group usbc_security_attr_group = {
+ .is_visible = usbc_security_attr_is_visible,
+ .attrs = usbc_security_attributes,
+};
+
+static int tpacpi_usbc_security_init(struct ibm_init_struct *iibm)
+{
+ bool enabled;
+
+ tp_features.usbc_security_supported =
+ usbc_security_query(&enabled);
+ tp_features.usbc_security_enabled = enabled;
+ return 0;
+}
+
+/* tpacpi_usbc_security_hotkey - handle Fn+U Fn+S hotkey (0x131e) */
+static bool tpacpi_usbc_security_hotkey(void)
+{
+ bool enabled;
+
+ if (!tp_features.usbc_security_supported)
+ return false;
+
+ if (!usbc_security_query(&enabled))
+ return false;
+
+ tp_features.usbc_security_enabled = enabled;
+ sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, "usb_c_security");
+ return true;
+}
+
+static struct ibm_struct usbc_security_driver_data = {
+ .name = "usbc_security",
+};
+
/* --------------------------------------------------------------------- */
static struct attribute *tpacpi_driver_attributes[] = {
@@ -11325,6 +11433,7 @@ static const struct attribute_group *tpacpi_groups[] = {
&dprc_attr_group,
&auxmac_attr_group,
&hwdd_attr_group,
+ &usbc_security_attr_group,
NULL,
};
@@ -11479,6 +11588,8 @@ static bool tpacpi_driver_event(const unsigned int hkey_event)
case TP_HKEY_EV_PROFILE_TOGGLE2:
platform_profile_cycle();
return true;
+ case TP_HKEY_EV_USB_C_SECURITY:
+ return tpacpi_usbc_security_hotkey();
}
return false;
@@ -11930,6 +12041,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
.init = tpacpi_hwdd_init,
.data = &hwdd_driver_data,
},
+ {
+ .init = tpacpi_usbc_security_init,
+ .data = &usbc_security_driver_data,
+ },
};
static int __init set_ibm_param(const char *val, const struct kernel_param *kp)
--
2.51.0
^ permalink raw reply related
* Re: [PATCH v2 03/14] mm: rename uffd-wp PTE accessors to uffd
From: Kiryl Shutsemau @ 2026-05-22 10:33 UTC (permalink / raw)
To: SeongJae Park
Cc: akpm, rppt, peterx, david, ljs, surenb, vbabka, Liam.Howlett, ziy,
corbet, skhan, seanjc, pbonzini, jthoughton, aarcange, usama.arif,
linux-mm, linux-kernel, linux-doc, linux-kselftest, kvm,
kernel-team
In-Reply-To: <20260514013127.148945-1-sj@kernel.org>
On Wed, May 13, 2026 at 06:31:27PM -0700, SeongJae Park wrote:
> On Fri, 8 May 2026 16:55:15 +0100 "Kiryl Shutsemau (Meta)" <kas@kernel.org> wrote:
>
> > Userfaultfd RWP will reuse the uffd-wp PTE bit to mark access-tracking
> > PTEs, alongside the write-protected ones it already marks. The bit's
> > meaning now depends on the VMA flag (WP or RWP), not on its name.
> >
> > Rename the kernel-internal names that describe the bit:
> >
> > - pte/pmd/huge_pte accessors (and swap variants)
> > - pgtable_supports_uffd() capability query
> > - SCAN_PTE_UFFD khugepaged enum
> >
> > The ftrace string emitted by mm_khugepaged_scan_pmd for this enum is
> > kept as "pte_uffd_wp" so existing trace-based tooling keeps matching.
> >
> > Pure mechanical rename -- no behavior change.
> >
> > Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
> > Assisted-by: Claude:claude-opus-4-6
> > Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
>
> Reviewed-by: SeongJae Park <sj@kernel.org>
Thanks!
> [...]
> > @@ -4934,10 +4934,10 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
> > softleaf = softleaf_from_pte(entry);
> > if (unlikely(softleaf_is_hwpoison(softleaf))) {
> > if (!userfaultfd_wp(dst_vma))
> > - entry = huge_pte_clear_uffd_wp(entry);
> > + entry = huge_pte_clear_uffd(entry);
> > set_huge_pte_at(dst, addr, dst_pte, entry, sz);
> > } else if (unlikely(softleaf_is_migration(softleaf))) {
> > - bool uffd_wp = pte_swp_uffd_wp(entry);
> > + bool uffd_wp = pte_swp_uffd(entry);
>
> Just curious. Is the variable name intentionally kept to avoid unnecessary
> change?
No, I've missed this. Will fix.
--
Kiryl Shutsemau / Kirill A. Shutemov
^ permalink raw reply
* Re: [PATCH v2 04/14] mm: add VM_UFFD_RWP VMA flag
From: Kiryl Shutsemau @ 2026-05-22 10:39 UTC (permalink / raw)
To: Mike Rapoport
Cc: akpm, peterx, david, ljs, surenb, vbabka, Liam.Howlett, ziy,
corbet, skhan, seanjc, pbonzini, jthoughton, aarcange, sj,
usama.arif, linux-mm, linux-kernel, linux-doc, linux-kselftest,
kvm, kernel-team
In-Reply-To: <agNZ-Q7A0rfY66gj@kernel.org>
On Tue, May 12, 2026 at 07:48:57PM +0300, Mike Rapoport wrote:
> On Fri, May 08, 2026 at 04:55:16PM +0100, Kiryl Shutsemau (Meta) wrote:
> > Preparatory patch for userfaultfd read-write protection (RWP). RWP
> > extends userfaultfd protection from plain write-protection (WP) to
> > full read-write protection: accesses to an RWP-protected range --
> > reads as well as writes -- trap through userfaultfd.
> >
> > RWP marks ranges by combining PAGE_NONE with the uffd PTE bit, so
> > the flag is only meaningful when both primitives exist. A new
> > CONFIG_USERFAULTFD_RWP Kconfig symbol auto-selects when CONFIG_64BIT,
> > CONFIG_ARCH_HAS_PTE_PROTNONE, and CONFIG_HAVE_ARCH_USERFAULTFD_WP
> > are all set; call sites that gate on the flag depend on the symbol.
> > Elsewhere VM_UFFD_RWP aliases VM_NONE and every downstream check
> > folds to dead code.
> >
> > Nothing sets the flag yet.
>
> And nothing check for it as well, am I right?
Yep.
> Worth noting here, IMHO.
Will do.
>
> > Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
> > Assisted-by: Claude:claude-opus-4-6
> > ---
> > Documentation/filesystems/proc.rst | 1 +
> > fs/proc/task_mmu.c | 3 +++
> > include/linux/mm.h | 28 +++++++++++++++++----------
> > include/linux/userfaultfd_k.h | 31 +++++++++++++++++++++++++-----
> > include/trace/events/mmflags.h | 7 +++++++
> > mm/Kconfig | 9 +++++++++
> > 6 files changed, 64 insertions(+), 15 deletions(-)
> >
> > diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
> > index 98f546e83cd2..fcf308dba311 100644
> > --- a/include/linux/userfaultfd_k.h
> > +++ b/include/linux/userfaultfd_k.h
> > @@ -21,10 +21,11 @@
> > #include <linux/hugetlb_inline.h>
> >
> > /* The set of all possible UFFD-related VM flags. */
> > -#define __VM_UFFD_FLAGS (VM_UFFD_MISSING | VM_UFFD_WP | VM_UFFD_MINOR)
> > +#define __VM_UFFD_FLAGS (VM_UFFD_MISSING | VM_UFFD_WP | VM_UFFD_MINOR | \
> > + VM_UFFD_RWP)
>
> Nit: can we keep mode bits together and protection bits together here and
> in the below changes?
Yep, make sense.
> Otherwise looks good to me
>
> Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Thanks!
--
Kiryl Shutsemau / Kirill A. Shutemov
^ permalink raw reply
* Re: [PATCH v2 04/14] mm: add VM_UFFD_RWP VMA flag
From: Kiryl Shutsemau @ 2026-05-22 10:54 UTC (permalink / raw)
To: SeongJae Park
Cc: akpm, rppt, peterx, david, ljs, surenb, vbabka, Liam.Howlett, ziy,
corbet, skhan, seanjc, pbonzini, jthoughton, aarcange, usama.arif,
linux-mm, linux-kernel, linux-doc, linux-kselftest, kvm,
kernel-team
In-Reply-To: <20260515002932.124892-1-sj@kernel.org>
On Thu, May 14, 2026 at 05:29:31PM -0700, SeongJae Park wrote:
> On Fri, 8 May 2026 16:55:16 +0100 "Kiryl Shutsemau (Meta)" <kas@kernel.org> wrote:
>
> > Preparatory patch for userfaultfd read-write protection (RWP). RWP
> > extends userfaultfd protection from plain write-protection (WP) to
> > full read-write protection: accesses to an RWP-protected range --
> > reads as well as writes -- trap through userfaultfd.
> >
> > RWP marks ranges by combining PAGE_NONE with the uffd PTE bit, so
> > the flag is only meaningful when both primitives exist. A new
> > CONFIG_USERFAULTFD_RWP Kconfig symbol auto-selects when CONFIG_64BIT,
> > CONFIG_ARCH_HAS_PTE_PROTNONE, and CONFIG_HAVE_ARCH_USERFAULTFD_WP
> > are all set; call sites that gate on the flag depend on the symbol.
> > Elsewhere VM_UFFD_RWP aliases VM_NONE and every downstream check
> > folds to dead code.
> >
> > Nothing sets the flag yet.
> >
> > Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
> > Assisted-by: Claude:claude-opus-4-6
>
> A silly but loud thought. Would it make more sense to put Signed-off-by: after
> Assisted-by: ?
I am not sure. I see it both ways in git log. And I don't have strong
opinion on the order here. Keeping as is.
> > ---
> > Documentation/filesystems/proc.rst | 1 +
> > fs/proc/task_mmu.c | 3 +++
> > include/linux/mm.h | 28 +++++++++++++++++----------
> > include/linux/userfaultfd_k.h | 31 +++++++++++++++++++++++++-----
> > include/trace/events/mmflags.h | 7 +++++++
> > mm/Kconfig | 9 +++++++++
> > 6 files changed, 64 insertions(+), 15 deletions(-)
> >
> > diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst
> > index db6167befb7b..db28207c5290 100644
> > --- a/Documentation/filesystems/proc.rst
> > +++ b/Documentation/filesystems/proc.rst
> > @@ -607,6 +607,7 @@ encoded manner. The codes are the following:
> > um userfaultfd missing tracking
> > uw userfaultfd wr-protect tracking
> > ui userfaultfd minor fault
> > + ur userfaultfd read-write-protect tracking
>
> Yet another silly but loud thought. My first feeling on this was that this
> reads like 'u'serfaultfd 'r'ead-protect. And was further thinking 'uf' for
> just 'u'seffaultfd 'f'ault or 'up' for 'u'serfault-'p'rotect might make sense.
> But ended up thinking this is too trivial and ain't really matter.
I will keep it. It's "u" + the first distinguishing letter of the mode
name. r distinguishes RWP from WP cleanly.
> [...]
> > diff --git a/mm/Kconfig b/mm/Kconfig
> > index e8bf1e9e6ad9..ccf534a8cbc9 100644
> > --- a/mm/Kconfig
> > +++ b/mm/Kconfig
> > @@ -1347,6 +1347,15 @@ config HAVE_ARCH_USERFAULTFD_MINOR
> > help
> > Arch has userfaultfd minor fault support
> >
> > +config USERFAULTFD_RWP
> > + def_bool y
> > + depends on 64BIT && ARCH_HAS_PTE_PROTNONE && HAVE_ARCH_USERFAULTFD_WP
> > + help
> > + Userfaultfd read-write protection (UFFDIO_RWPROTECT) delivers a
>
> Seems UFFDIO_RWPROTECT will be introduced later. Would it make more sense to
> add this config together with the patch?
Okay, I will move later in the patchset.
> > + userfaultfd notification on every access -- read or write -- to a
> > + protected range, letting userspace observe the working set of a
> > + process.
> > +
> > menuconfig USERFAULTFD
> > bool "Enable userfaultfd() system call"
> > depends on MMU
> > --
> > 2.51.2
> >
> >
>
> None of my comments is a blocker.
>
> Reviewed-by: SeongJae Park <sj@kernel.org>
Thanks!
--
Kiryl Shutsemau / Kirill A. Shutemov
^ permalink raw reply
* Re: [PATCH net-next v3 01/14] virtchnl: create 'include/linux/intel' and move necessary header files
From: Alexander Lobakin @ 2026-05-22 11:08 UTC (permalink / raw)
To: Jakub Kicinski, Larysa Zaremba
Cc: Tony Nguyen, davem, pabeni, edumazet, andrew+netdev, netdev,
przemyslaw.kitszel, sridhar.samudrala, anjali.singhai,
michal.swiatkowski, maciej.fijalkowski, emil.s.tantilov,
madhu.chittim, joshua.a.hay, jacob.e.keller,
jayaprakash.shanmugam, jiri, horms, corbet, richardcochran,
linux-doc, tatyana.e.nikolova, krzysztof.czurylo, jgg, leon,
linux-rdma, Samuel Salin, Aleksandr Loktionov
In-Reply-To: <20260521065609.248c7009@kernel.org>
From: Jakub Kicinski <kuba@kernel.org>
Date: Thu, 21 May 2026 06:56:09 -0700
> On Thu, 21 May 2026 11:28:50 +0200 Larysa Zaremba wrote:
>> On Wed, May 20, 2026 at 05:52:01PM -0700, Jakub Kicinski wrote:
>>> On Fri, 15 May 2026 15:44:25 -0700 Tony Nguyen wrote:
>>>> include/linux/intel is vacant
>>>
>>> I don't see any other vendor directory under include/linux
>>
>> There are at least
>>
>> include/linux/mlx4, include/linux/mlx5 and include/linux/bnxt.
>>
>> Those are per-driver and not per-vendor, but intel ethernet has too many drivers
>> to have separate folders for them.
>>
>> I just do not think this creates a precedent neccessarily.
>
> You just said the other ones are for specific drivers.
Right, but according to your earlier suggestion they belong to
include/net, not include/linux.
My understanding is that they're under include/linux, not include/net as
mlx5 is not only about Ethernet, but also RDMA etc. The same applies to
Intel's headers.
What's your position after all this? Still include/net/intel? This
commit is about stopping scattering Intel headers all over include/linux
and set one place for them.
>
>> Folder structure is for you to decide as a maintainer, but it would be nice to
>> have known about such doubts earlier.
>
> I'd love to know if you any suggestions for improving the process.
> Otherwise please keep your venting off list.
I think Larysa just wanted to say that you disliked this commit after
the series went through several iterations on IWL and 3 iterations here,
nothing more. It's not about the overall process.
I also had a couple such moments in the past, but well, a review or a
comment can happen (and are valid) anytime before the patch is taken to
the tree, sometimes even afterwards and then we send fixups.
Thanks,
Olek
^ permalink raw reply
* Re: [PATCH v12 5/6] iio: adc: ad4691: add oversampling support
From: Jonathan Cameron @ 2026-05-22 11:16 UTC (permalink / raw)
To: Sabau, Radu bogdan
Cc: Lars-Peter Clausen, Hennerich, Michael, David Lechner, Sa, Nuno,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Uwe Kleine-König, Liam Girdwood, Mark Brown, Linus Walleij,
Bartosz Golaszewski, Philipp Zabel, Jonathan Corbet, Shuah Khan,
linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-pwm@vger.kernel.org,
linux-gpio@vger.kernel.org, linux-doc@vger.kernel.org
In-Reply-To: <LV9PR03MB8414CA3DB26235605C9323E5F70E2@LV9PR03MB8414.namprd03.prod.outlook.com>
On Thu, 21 May 2026 11:32:42 +0000
"Sabau, Radu bogdan" <Radu.Sabau@analog.com> wrote:
> > -----Original Message-----
> > From: Radu Sabau via B4 Relay <devnull+radu.sabau.analog.com@kernel.org>
> > Sent: Tuesday, May 19, 2026 3:20 PM
>
> ...
>
> >
> > + iio_for_each_active_channel(indio_dev, bit) {
> > + ret = regmap_write(st->regmap,
> > AD4691_ACC_DEPTH_IN(bit), st->osr[bit]);
>
> Unfortunately enough, I think a v13 will come, too...
>
> Had a look again on what Sashiko had to say, and seeing the sampling frequency
> shared_by_all comment again made me have a deeper look see how the code could
> be commented so he wouldn't complain about this anymore, and...
>
> Perhaps he is a bit right after all. I found a section stating that in standard
> sequencer mode (which the driver uses right now), all the channels actually use
> the ACC_DEPTH_IN0 for osr, and so changing ACC_DEPTH_INn for other channels
> doesn't really do much. And so I tested this selecting both voltage0 and voltage1
> for sampling with osr4 for voltage0 and osr1 for voltage1 and with a 100kHz osc freq
> indeed DR fell after approximately 80us which points out both channels were actually
> using OSR of 4. Perhaps the OSR should be shared by all and therefore the
> sampling frequency would also be shared by all, right?
I kind of lost track on the modes. What are the chances we later move to or add
support for a mode where the different OSRs do matter? If that's a possibility
we should avoid ABI change by allowing for it from the start.
Then if we are in this mode, they'll have separate controls but change any, changes
them all, if we are in a different mode that connection breaks.
If that's the case, just throw in a comment saying something to the effect this
may change.
It's not wrong ABI to do this, it's just less intuitive for users which is why
we prefer the shared_by stuff where there isn't a disadvantage. That is at most
a hint to what actually happens. A simple example is where different
channels have one OSR field but they aren't the same - i.e. channel 1 is twice
the OSR of channel 2. Hence we can't share the attribute but any change effects
both.
Jonathan
>
> The usage of internal_osc_freq and pre-computed freq values depending on osr would
> stay the same since those are still correct anyway.
>
> What's your opinion on this?
> Radu
>
^ permalink raw reply
* Re: [PATCH v12 1/6] dt-bindings: iio: adc: add AD4691 family
From: Jonathan Cameron @ 2026-05-22 11:23 UTC (permalink / raw)
To: Radu Sabau via B4 Relay
Cc: radu.sabau, Lars-Peter Clausen, Michael Hennerich, David Lechner,
Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Uwe Kleine-König, Liam Girdwood, Mark Brown,
Linus Walleij, Bartosz Golaszewski, Philipp Zabel,
Jonathan Corbet, Shuah Khan, linux-iio, devicetree, linux-kernel,
linux-pwm, linux-gpio, linux-doc, Conor Dooley
In-Reply-To: <20260519-ad4692-multichannel-sar-adc-driver-v12-1-5b335162aa51@analog.com>
On Tue, 19 May 2026 15:20:22 +0300
Radu Sabau via B4 Relay <devnull+radu.sabau.analog.com@kernel.org> wrote:
> From: Radu Sabau <radu.sabau@analog.com>
>
> Add DT bindings for the Analog Devices AD4691 family of multichannel
> SAR ADCs (AD4691, AD4692, AD4693, AD4694).
>
> The binding describes the hardware connections:
>
> - Power domains: avdd-supply (required), vio-supply, ref-supply or
> refin-supply (external reference; the REFIN path enables the
> internal reference buffer). Digital core VDD is supplied either
> externally via vdd-supply, or generated by the on-chip LDO fed
> from ldo-in-supply; the two are mutually exclusive and one must
> be present.
>
> - Optional PWM on the CNV pin selects CNV Burst Mode; when absent,
> Manual Mode is assumed with CNV tied to SPI CS.
>
> - An optional reset GPIO (reset-gpios) for hardware reset.
>
> - Up to four GP pins (gp0..gp3) usable as interrupt sources,
> identified in firmware via interrupt-names "gp0".."gp3".
>
> - gpio-controller with #gpio-cells = <2> for GP pin GPIO usage.
>
> - #trigger-source-cells = <1>: one cell selecting the GP pin number
> (0-3) used as the SPI offload trigger source.
>
> Two binding examples are provided: CNV Burst Mode with SPI offload
> (DMA data acquisition driven by DATA_READY on a GP pin), and Manual
> Mode for CPU-driven triggered-buffer or single-shot capture.
Doesn't really matter, but why include so much detail that is easy enough
seen in the binding? If there is information we need to capture it better
be in the binding!
Not actually worth the effort of changing it though - more something
for future reference (unless someone else is asking for this levle
of detail).
>
> The four variants are not compatible with each other: AD4691/AD4692 have
> 16 analog input channels while AD4693/AD4694 have 8, and AD4691/AD4693
> top out at 500 kSPS while AD4692/AD4694 reach 1 MSPS. These differences
> in channel count and maximum sample rate require distinct compatible
> strings so the driver can select the correct channel configuration and
> rate limits.
This bit indeed belongs here.
>
> Acked-by: Conor Dooley <conor.dooley@microchip.com>
> Signed-off-by: Radu Sabau <radu.sabau@analog.com>
> ---
^ permalink raw reply
* Re: [PATCH v12 2/6] iio: adc: ad4691: add initial driver for AD4691 family
From: Jonathan Cameron @ 2026-05-22 11:35 UTC (permalink / raw)
To: Radu Sabau via B4 Relay
Cc: radu.sabau, Lars-Peter Clausen, Michael Hennerich, David Lechner,
Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Uwe Kleine-König, Liam Girdwood, Mark Brown,
Linus Walleij, Bartosz Golaszewski, Philipp Zabel,
Jonathan Corbet, Shuah Khan, linux-iio, devicetree, linux-kernel,
linux-pwm, linux-gpio, linux-doc
In-Reply-To: <20260519-ad4692-multichannel-sar-adc-driver-v12-2-5b335162aa51@analog.com>
On Tue, 19 May 2026 15:20:23 +0300
Radu Sabau via B4 Relay <devnull+radu.sabau.analog.com@kernel.org> wrote:
> From: Radu Sabau <radu.sabau@analog.com>
>
> Add support for the Analog Devices AD4691 family of high-speed,
> low-power multichannel SAR ADCs: AD4691 (16-ch, 500 kSPS),
> AD4692 (16-ch, 1 MSPS), AD4693 (8-ch, 500 kSPS) and
> AD4694 (8-ch, 1 MSPS).
>
> The driver implements a custom regmap layer over raw SPI to handle the
> device's mixed 1/2/3/4-byte register widths and uses the standard IIO
> read_raw/write_raw interface for single-channel reads.
>
> The chip idles in Autonomous Mode so that single-shot read_raw can use
> the internal oscillator without disturbing the hardware configuration.
>
> Three voltage supply domains are managed: avdd (required), vio, and a
> reference supply on either the REF pin (ref-supply, external buffer)
> or the REFIN pin (refin-supply, uses the on-chip reference buffer;
> REFBUF_EN is set accordingly). Hardware reset is performed by asserting
> the reset-gpios GPIO line for at least 300 µs then deasserting it;
> a software reset via SPI_CONFIG_A is used as fallback when no reset
> GPIO is provided.
>
> Accumulator channel masking for single-shot reads uses ACC_MASK_REG via
> an ADDR_DESCENDING SPI write, which covers both mask bytes in a single
> 16-bit transfer.
>
> IIO_CHAN_INFO_SAMP_FREQ is exposed as info_mask_separate. The oscillator
> is shared hardware — writing any channel's sampling_frequency attribute
> sets it for all others — but per-channel attributes are used throughout
> the series to avoid an ABI change when per-channel oversampling ratios
> are introduced in a later commit, at which point the effective output
> rate (osc_freq / osr[N]) becomes genuinely per-channel.
>
> Reviewed-by: David Lechner <dlechner@baylibre.com>
> Signed-off-by: Radu Sabau <radu.sabau@analog.com>
One really small thing given you mention you'll be doing a v13.
> diff --git a/drivers/iio/adc/ad4691.c b/drivers/iio/adc/ad4691.c
> new file mode 100644
> index 000000000000..2d58df862142
> --- /dev/null
> +++ b/drivers/iio/adc/ad4691.c
> +static int ad4691_reset(struct ad4691_state *st)
> +{
> + struct device *dev = regmap_get_device(st->regmap);
> + struct reset_control *rst;
> + int ret;
> +
> + rst = devm_reset_control_get_optional_exclusive(dev, NULL);
> + if (IS_ERR(rst))
> + return dev_err_probe(dev, PTR_ERR(rst), "Failed to get reset\n");
> +
> + if (rst) {
> + /*
> + * Assert the reset line to guarantee a clean reset pulse on
> + * every probe, including driver reloads where the line may
> + * already be deasserted (reset_control_put() does not
> + * re-assert on release). tRESETL (minimum pulse width) = 10 ns
> + * (Table 5); kernel function-call overhead alone exceeds this,
> + * so no explicit delay is needed between assert and deassert.
> + */
> + reset_control_assert(rst);
> + ret = reset_control_deassert(rst);
> + if (ret)
> + return ret;
Really trivial but seems like this could be refactored to share the sleep
code + perhaps more usefully the comment.
} else {
/* No hardware reset available, fall back to software reset. */
ret = regmap_write(st->regmap, AD4691_SPI_CONFIG_A_REG, AD4691_SW_RESET);
if (ret)
return ret;
}
/*
* Wait tHWR = 300 µs (Table 5) for the device to complete its
* internal reset sequence before accepting SPI commands.
*/
fsleep(300);
return 0;
}
> + /*
> + * Wait tHWR = 300 µs (Table 5) for the device to complete its
> + * internal reset sequence before accepting SPI commands.
> + */
> + fsleep(300);
> + return 0;
> + }
> +
> + /* No hardware reset available, fall back to software reset. */
> + ret = regmap_write(st->regmap, AD4691_SPI_CONFIG_A_REG, AD4691_SW_RESET);
> + if (ret)
> + return ret;
> + /*
> + * Wait tSWR = 300 µs (Table 5) for the device to complete its
> + * internal reset sequence before accepting SPI commands.
> + */
> + fsleep(300);
> + return 0;
> +}
^ permalink raw reply
* RE: [PATCH v12 5/6] iio: adc: ad4691: add oversampling support
From: Sabau, Radu bogdan @ 2026-05-22 11:38 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Lars-Peter Clausen, Hennerich, Michael, David Lechner, Sa, Nuno,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Uwe Kleine-König, Liam Girdwood, Mark Brown, Linus Walleij,
Bartosz Golaszewski, Philipp Zabel, Jonathan Corbet, Shuah Khan,
linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-pwm@vger.kernel.org,
linux-gpio@vger.kernel.org, linux-doc@vger.kernel.org
In-Reply-To: <20260522121628.21bf03f9@jic23-huawei>
> -----Original Message-----
> From: Jonathan Cameron <jic23@kernel.org>
> Sent: Friday, May 22, 2026 2:16 PM
...
> > >
> > > + iio_for_each_active_channel(indio_dev, bit) {
> > > + ret = regmap_write(st->regmap,
> > > AD4691_ACC_DEPTH_IN(bit), st->osr[bit]);
> >
> > Unfortunately enough, I think a v13 will come, too...
> >
> > Had a look again on what Sashiko had to say, and seeing the sampling
> frequency
> > shared_by_all comment again made me have a deeper look see how the
> code could
> > be commented so he wouldn't complain about this anymore, and...
> >
> > Perhaps he is a bit right after all. I found a section stating that in standard
> > sequencer mode (which the driver uses right now), all the channels actually
> use
> > the ACC_DEPTH_IN0 for osr, and so changing ACC_DEPTH_INn for other
> channels
> > doesn't really do much. And so I tested this selecting both voltage0 and
> voltage1
> > for sampling with osr4 for voltage0 and osr1 for voltage1 and with a 100kHz
> osc freq
> > indeed DR fell after approximately 80us which points out both channels were
> actually
> > using OSR of 4. Perhaps the OSR should be shared by all and therefore the
> > sampling frequency would also be shared by all, right?
>
> I kind of lost track on the modes. What are the chances we later move to or
> add
> support for a mode where the different OSRs do matter? If that's a possibility
> we should avoid ABI change by allowing for it from the start.
>
> Then if we are in this mode, they'll have separate controls but change any,
> changes
> them all, if we are in a different mode that connection breaks.
> If that's the case, just throw in a comment saying something to the effect this
> may change.
>
> It's not wrong ABI to do this, it's just less intuitive for users which is why
> we prefer the shared_by stuff where there isn't a disadvantage. That is at
> most
> a hint to what actually happens. A simple example is where different
> channels have one OSR field but they aren't the same - i.e. channel 1 is twice
> the OSR of channel 2. Hence we can't share the attribute but any change
> effects
> both.
>
Hi Jonathan,
I don't think a mode where different OSR will matter will be added in the future. Better
yet, this advanced sequencer functionality is not really mode dependent and is actually
something that allows you to manually rearrange channels and samples in the
sequence, and unless this functionality is active (it is not by default nor is it used by
the driver, since we use the standard sequencer).
Personally, I don't see any reason to have this advanced sequencer stuff implemented
since DR is only falling at the end of the sequence no matter if it is standard config or not,
the only "disadvantage" to say so is that the standard sequencer uses the same OSR field
for all channels. But that advanced sequencer stuff would only complicate the buffer
enable/disable functions even more, which I don't think it's worth the effort.
So, with this in mind. Letting the driver use standard sequencer would ultimately mean
that the osr would be the same for all the channels, and then effective rate the same for
all channels, which I suggest having it like that from initial driver patch to the end, so no
ABI change mid-patch series. This change will simplify the driver.
Radu
^ permalink raw reply
* Re: [PATCH v2 05/14] mm: add MM_CP_UFFD_RWP change_protection() flag
From: Kiryl Shutsemau @ 2026-05-22 11:44 UTC (permalink / raw)
To: Mike Rapoport
Cc: akpm, peterx, david, ljs, surenb, vbabka, Liam.Howlett, ziy,
corbet, skhan, seanjc, pbonzini, jthoughton, aarcange, sj,
usama.arif, linux-mm, linux-kernel, linux-doc, linux-kselftest,
kvm, kernel-team
In-Reply-To: <agNZE49m8Pkn8CeW@kernel.org>
On Tue, May 12, 2026 at 07:45:07PM +0300, Mike Rapoport wrote:
> On Fri, May 08, 2026 at 04:55:17PM +0100, Kiryl Shutsemau (Meta) wrote:
> > Preparatory patch. Add the change_protection() primitive that
> > userfaultfd RWP will use.
> >
> > An RWP-protected PTE is PAGE_NONE with the uffd PTE bit set. The
> > PROT_NONE half makes the CPU fault on any access; the uffd bit
> > distinguishes an RWP fault from a plain mprotect(PROT_NONE) or NUMA
> > hinting fault. MM_CP_UFFD_WP and MM_CP_UFFD_RWP share the same PTE
> > bit, so the two cannot be used together on the same range.
> >
> > Two new change_protection() flags:
> >
> > MM_CP_UFFD_RWP install PAGE_NONE and set the uffd bit
> > MM_CP_UFFD_RWP_RESOLVE restore vma->vm_page_prot, clear the uffd bit
> >
> > Both are wired through change_pte_range(), change_huge_pmd(), and
> > hugetlb_change_protection() so anon, shmem, THP, and hugetlb all
> > share the same semantics.
> >
> > Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
> > Assisted-by: Claude:claude-opus-4-6
> > ---
> > include/linux/mm.h | 5 +++++
> > include/linux/userfaultfd_k.h | 1 -
> > mm/huge_memory.c | 20 ++++++++++++------
> > mm/hugetlb.c | 25 ++++++++++++++++------
> > mm/mprotect.c | 40 +++++++++++++++++++++++++++++------
> > 5 files changed, 71 insertions(+), 20 deletions(-)
> >
> > diff --git a/include/linux/mm.h b/include/linux/mm.h
> > index 3f53d1e978c0..2b65416bb760 100644
> > --- a/include/linux/mm.h
> > +++ b/include/linux/mm.h
> > @@ -3291,6 +3291,11 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen);
> > #define MM_CP_UFFD_WP_RESOLVE (1UL << 3) /* Resolve wp */
> > #define MM_CP_UFFD_WP_ALL (MM_CP_UFFD_WP | \
> > MM_CP_UFFD_WP_RESOLVE)
> > +/* Whether this change is for uffd RWP */
> > +#define MM_CP_UFFD_RWP (1UL << 4) /* do rwp */
> > +#define MM_CP_UFFD_RWP_RESOLVE (1UL << 5) /* Resolve rwp */
>
> Nit: any reason except copy/paset to use different case in "do rwp" and
> "Resolve rwp"? ;-)
copy/paste it is. Will use "resolve rwp"
> > +#define MM_CP_UFFD_RWP_ALL (MM_CP_UFFD_RWP | \
> > + MM_CP_UFFD_RWP_RESOLVE)
> >
> > bool can_change_pte_writable(struct vm_area_struct *vma, unsigned long addr,
> > pte_t pte);
> > diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
> > index fcf308dba311..3725e61a7041 100644
> > --- a/include/linux/userfaultfd_k.h
> > +++ b/include/linux/userfaultfd_k.h
> > @@ -397,7 +397,6 @@ static inline bool userfaultfd_huge_pmd_wp(struct vm_area_struct *vma,
> > return false;
> > }
> >
> > -
> > static inline bool userfaultfd_armed(struct vm_area_struct *vma)
> > {
> > return false;
> > diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> > index d88fcccd386d..2537dca63c6c 100644
> > --- a/mm/huge_memory.c
> > +++ b/mm/huge_memory.c
> > @@ -2665,6 +2665,8 @@ int change_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
> > spinlock_t *ptl;
> > pmd_t oldpmd, entry;
> > bool prot_numa = cp_flags & MM_CP_PROT_NUMA;
> > + bool uffd_rwp = cp_flags & MM_CP_UFFD_RWP;
> > + bool uffd_rwp_resolve = cp_flags & MM_CP_UFFD_RWP_RESOLVE;
> > bool uffd_wp = cp_flags & MM_CP_UFFD_WP;
> > bool uffd_wp_resolve = cp_flags & MM_CP_UFFD_WP_RESOLVE;
>
> It looks like uffd_wp* are always ORed with uffd_rwp, we could fold this to
> e.g.
>
> bool uffd_prot = cp_flags & (MM_CP_UFFD_WP | MM_CP_UFFD_RWP);
Makes sense.
> > int ret = 1;
> > @@ -2679,11 +2681,18 @@ int change_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
> > return 0;
> >
> > if (thp_migration_supported() && pmd_is_valid_softleaf(*pmd)) {
> > - change_non_present_huge_pmd(mm, addr, pmd, uffd_wp,
> > - uffd_wp_resolve);
> > + change_non_present_huge_pmd(mm, addr, pmd,
> > + uffd_wp || uffd_rwp,
> > + uffd_wp_resolve || uffd_rwp_resolve);
> > goto unlock;
> > }
> >
> > + /* Already in the desired state */
> > + if (prot_numa && pmd_protnone(*pmd))
> > + goto unlock;
> > + if (uffd_rwp && pmd_protnone(*pmd) && pmd_uffd(*pmd))
> > + goto unlock;
> > +
> > if (prot_numa) {
> >
> > /*
> > @@ -2694,9 +2703,6 @@ int change_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
> > if (is_huge_zero_pmd(*pmd))
> > goto unlock;
> >
> > - if (pmd_protnone(*pmd))
> > - goto unlock;
> > -
> > if (!folio_can_map_prot_numa(pmd_folio(*pmd), vma,
> > vma_is_single_threaded_private(vma)))
> > goto unlock;
> > @@ -2725,9 +2731,9 @@ int change_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
> > oldpmd = pmdp_invalidate_ad(vma, addr, pmd);
> >
> > entry = pmd_modify(oldpmd, newprot);
> > - if (uffd_wp)
> > + if (uffd_wp || uffd_rwp)
> > entry = pmd_mkuffd(entry);
> > - else if (uffd_wp_resolve)
> > + else if (uffd_wp_resolve || uffd_rwp_resolve)
> > /*
> > * Leave the write bit to be handled by PF interrupt
> > * handler, then things like COW could be properly
> > diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> > index 61cda9992043..63f6b19418b9 100644
> > --- a/mm/hugetlb.c
> > +++ b/mm/hugetlb.c
> > @@ -6434,6 +6436,11 @@ long hugetlb_change_protection(struct vm_area_struct *vma,
> >
> > ptep = hugetlb_walk(vma, address, psize);
> > if (!ptep) {
> > + /*
> > + * uffd_wp installs a pte marker on the unpopulated
> > + * entry; RWP does not install markers so the
>
> Nit: uffd_rwp
Ack.
>
> > + * allocation is unnecessary for it.
> > + */
> > if (!uffd_wp) {
> > address |= last_addr_mask;
> > continue;
> > diff --git a/mm/mprotect.c b/mm/mprotect.c
> > index 8340c8b228c6..23e71f68cf7a 100644
> > --- a/mm/mprotect.c
> > +++ b/mm/mprotect.c
> > @@ -216,6 +216,8 @@ static long change_softleaf_pte(struct vm_area_struct *vma,
> > {
> > const bool uffd_wp = cp_flags & MM_CP_UFFD_WP;
> > const bool uffd_wp_resolve = cp_flags & MM_CP_UFFD_WP_RESOLVE;
> > + const bool uffd_rwp = cp_flags & MM_CP_UFFD_RWP;
> > + const bool uffd_rwp_resolve = cp_flags & MM_CP_UFFD_RWP_RESOLVE;
>
> And here a single pair of bools should be enough I think.
Yep.
>
> > softleaf_t entry = softleaf_from_pte(oldpte);
> > pte_t newpte;
> >
> > @@ -256,7 +258,7 @@ static long change_softleaf_pte(struct vm_area_struct *vma,
> > * to unprotect it, drop it; the next page
> > * fault will trigger without uffd trapping.
> > */
> > - if (uffd_wp_resolve) {
> > + if (uffd_wp_resolve || uffd_rwp_resolve) {
> > pte_clear(vma->vm_mm, addr, pte);
> > return 1;
> > }
> > @@ -265,9 +267,9 @@ static long change_softleaf_pte(struct vm_area_struct *vma,
> > newpte = oldpte;
> > }
> >
> > - if (uffd_wp)
> > + if (uffd_wp || uffd_rwp)
> > newpte = pte_swp_mkuffd(newpte);
> > - else if (uffd_wp_resolve)
> > + else if (uffd_wp_resolve || uffd_rwp_resolve)
> > newpte = pte_swp_clear_uffd(newpte);
> >
> > if (!pte_same(oldpte, newpte)) {
>
> --
> Sincerely yours,
> Mike.
--
Kiryl Shutsemau / Kirill A. Shutemov
^ permalink raw reply
* Re: [PATCH v12 3/6] iio: adc: ad4691: add triggered buffer support
From: Jonathan Cameron @ 2026-05-22 11:46 UTC (permalink / raw)
To: Radu Sabau via B4 Relay
Cc: radu.sabau, Lars-Peter Clausen, Michael Hennerich, David Lechner,
Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Uwe Kleine-König, Liam Girdwood, Mark Brown,
Linus Walleij, Bartosz Golaszewski, Philipp Zabel,
Jonathan Corbet, Shuah Khan, linux-iio, devicetree, linux-kernel,
linux-pwm, linux-gpio, linux-doc
In-Reply-To: <20260519-ad4692-multichannel-sar-adc-driver-v12-3-5b335162aa51@analog.com>
On Tue, 19 May 2026 15:20:24 +0300
Radu Sabau via B4 Relay <devnull+radu.sabau.analog.com@kernel.org> wrote:
> From: Radu Sabau <radu.sabau@analog.com>
>
> Add buffered capture support using the IIO triggered buffer framework.
>
> CNV Burst Mode: the GP pin identified by interrupt-names in the device
> tree is configured as DATA_READY output. The IRQ handler stops
> conversions and fires the IIO trigger; the trigger handler executes a
> pre-built SPI message that reads all active channels from the AVG_IN
> accumulator registers and then resets accumulator state and restarts
> conversions for the next cycle.
>
> Manual Mode: CNV is tied to SPI CS so each transfer simultaneously
> reads the previous result and starts the next conversion (pipelined
> N+1 scheme). At preenable time a pre-built, optimised SPI message of
> N+1 transfers is constructed (N channel reads plus one NOOP to drain
> the pipeline). The trigger handler executes the message in a single
> spi_sync() call and collects the results. An external trigger (e.g.
> iio-trig-hrtimer) is required to drive the trigger at the desired
> sample rate.
>
> Both modes share the same trigger handler and push a complete scan —
> one big-endian 16-bit (__be16) slot per active channel, densely packed
> in scan_index order, followed by a timestamp.
>
> The CNV Burst Mode sampling frequency (PWM period) is exposed as a
> buffer-level attribute via IIO_DEVICE_ATTR.
>
> Signed-off-by: Radu Sabau <radu.sabau@analog.com>
I didn't spot anything in my read through and most of what Sashiko
is commenting on is wrong or not a driver specific problem
(the trigger leak is a core problem)
One small thing Sashiko did pick up on though that I think could be a little nicer.
You may well already have this in hand as I know you are checking there
as well!
> +static void ad4691_read_scan(struct iio_dev *indio_dev, s64 ts)
> +{
> + struct ad4691_state *st = iio_priv(indio_dev);
> +
> + guard(mutex)(&st->lock);
> +
> + spi_sync(st->spi, &st->scan_msg);
One thing from sashiko. If this fails we shouldn't push data and we should
make it clear somewhere (rate limited print or similar).
> +
> + /*
> + * rx_buf pointers in scan_xfers point directly into scan.vals, so no
> + * copy is needed. The scan_msg already includes a STATE_RESET at the
> + * end (appended in preenable), so no explicit reset is needed here.
> + */
> + iio_push_to_buffers_with_ts(indio_dev, st->vals, sizeof(st->vals), ts);
> +}
^ permalink raw reply
* Re: [PATCH v2 08/14] userfaultfd: add UFFDIO_REGISTER_MODE_RWP and UFFDIO_RWPROTECT plumbing
From: Kiryl Shutsemau @ 2026-05-22 11:50 UTC (permalink / raw)
To: Mike Rapoport
Cc: akpm, peterx, david, ljs, surenb, vbabka, Liam.Howlett, ziy,
corbet, skhan, seanjc, pbonzini, jthoughton, aarcange, sj,
usama.arif, linux-mm, linux-kernel, linux-doc, linux-kselftest,
kvm, kernel-team
In-Reply-To: <agNhTvqeOD1eo8mD@kernel.org>
On Tue, May 12, 2026 at 08:20:14PM +0300, Mike Rapoport wrote:
> On Fri, May 08, 2026 at 04:55:20PM +0100, Kiryl Shutsemau (Meta) wrote:
> > Add the userspace interface for read-write protection tracking:
> >
> > - UFFDIO_REGISTER_MODE_RWP register a range for RWP tracking
> > - UFFD_FEATURE_RWP capability bit
> > - UFFDIO_RWPROTECT install / remove RWP on a range
> >
> > Registration sets VM_UFFD_RWP on the VMA. Combining MODE_WP with
> > MODE_RWP is rejected because both modes claim the uffd PTE bit.
> >
> > UFFDIO_RWPROTECT is the bidirectional counterpart of
> > UFFDIO_WRITEPROTECT:
> >
> > - MODE_RWP change_protection() with MM_CP_UFFD_RWP
> > installs PAGE_NONE and sets the uffd bit on
> > present PTEs
> > - !MODE_RWP change_protection() with MM_CP_UFFD_RWP_RESOLVE
> > restores vma->vm_page_prot and clears the bit
> >
> > userfaultfd_clear_vma() runs the same resolve pass on unregister so
> > RWP state cannot outlive the uffd.
> >
> > Re-registering a range must not drop a mode that installs per-PTE
> > markers (WP or RWP); doing so returns -EBUSY. This also closes a
> > pre-existing window where re-registering without MODE_WP would strand
> > uffd-wp markers: before, those caused extra write-faults but were
> > otherwise benign; with RWP preservation in place, a subsequent
> > mprotect() on a VM_UFFD_RWP VMA would silently promote the stale
> > markers to RWP.
> >
> > The feature is not yet advertised. UFFDIO_REGISTER_MODE_RWP,
> > UFFD_FEATURE_RWP, and _UFFDIO_RWPROTECT are intentionally absent from
> > UFFD_API_REGISTER_MODES, UFFD_API_FEATURES, and UFFD_API_RANGE_IOCTLS,
> > so UFFDIO_API masks them out and the register-mode validator rejects
> > the bit. The follow-up patch adds fault dispatch and exposes the UAPI.
> >
> > Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
> > Assisted-by: Claude:claude-opus-4-6
>
> Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Thanks!
>
> with a comment below
>
> > ---
> > Documentation/admin-guide/mm/userfaultfd.rst | 10 ++
> > fs/userfaultfd.c | 84 +++++++++++++++++
> > include/linux/userfaultfd_k.h | 2 +
> > include/uapi/linux/userfaultfd.h | 19 ++++
> > mm/userfaultfd.c | 97 +++++++++++++++++++-
> > 5 files changed, 209 insertions(+), 3 deletions(-)
> >
> > + /*
> > + * Pre-scan the range: validate every spanned VMA before applying
> > + * any change_protection() so a partial failure cannot leave the
> > + * process with only a prefix of the range re-protected.
> > + */
> > + err = -ENOENT;
> > + for_each_vma_range(vmi, dst_vma, end) {
> > + if (!userfaultfd_rwp(dst_vma))
> > + return -ENOENT;
> > +
> > + if (is_vm_hugetlb_page(dst_vma)) {
> > + unsigned long page_mask;
> > +
> > + page_mask = vma_kernel_pagesize(dst_vma) - 1;
> > + if ((start & page_mask) || (len & page_mask))
> > + return -EINVAL;
> > + }
> > + err = 0;
> > + }
> > + if (err)
> > + return err;
>
> It's an interesting way to say "no VMA found in range" :)
> I think bool found and
>
> if (!found)
> return -ENOENT;
>
> looks more readable.
Fair enough. Will do.
--
Kiryl Shutsemau / Kirill A. Shutemov
^ permalink raw reply
* Re: [PATCH v2 09/14] mm/userfaultfd: add RWP fault delivery and expose UFFDIO_REGISTER_MODE_RWP
From: Kiryl Shutsemau @ 2026-05-22 11:51 UTC (permalink / raw)
To: Mike Rapoport
Cc: akpm, peterx, david, ljs, surenb, vbabka, Liam.Howlett, ziy,
corbet, skhan, seanjc, pbonzini, jthoughton, aarcange, sj,
usama.arif, linux-mm, linux-kernel, linux-doc, linux-kselftest,
kvm, kernel-team
In-Reply-To: <agNjXmuEHSaWKrv9@kernel.org>
On Tue, May 12, 2026 at 08:29:02PM +0300, Mike Rapoport wrote:
> On Fri, May 08, 2026 at 04:55:21PM +0100, Kiryl Shutsemau (Meta) wrote:
> > Wire the fault side of read-write protection tracking and turn the
> > userspace interface on.
> >
> > An RWP-protected PTE is PAGE_NONE with the uffd bit set. The
> > PROT_NONE triggers a fault on any access; the uffd bit distinguishes
> > it from plain mprotect(PROT_NONE) or NUMA hinting.
> >
> > Fault dispatch, per level:
> >
> > PTE handle_pte_fault() -> do_uffd_rwp()
> > PMD __handle_mm_fault() -> do_huge_pmd_uffd_rwp()
> > hugetlb hugetlb_fault() -> hugetlb_handle_userfault()
> >
> > The RWP branches gate on userfaultfd_pte_rwp() / userfaultfd_huge_pmd_rwp()
> > (VM_UFFD_RWP plus the uffd bit) and fall through to do_numa_page() /
> > do_huge_pmd_numa_page() otherwise. Each delivers a
> > UFFD_PAGEFAULT_FLAG_RWP message through handle_userfault(); the handler
> > resolves it with UFFDIO_RWPROTECT clearing MODE_RWP.
> >
> > userfaultfd_must_wait() and userfaultfd_huge_must_wait() add matching
> > protnone+uffd waiters so sync-mode fault handlers block correctly.
> >
> > Expose the UAPI:
> >
> > UFFDIO_REGISTER_MODE_RWP -> UFFD_API_REGISTER_MODES
> > UFFD_FEATURE_RWP -> UFFD_API_FEATURES
> > _UFFDIO_RWPROTECT -> UFFD_API_RANGE_IOCTLS
> > UFFD_API_RANGE_IOCTLS_BASIC
> >
> > UFFD_FEATURE_RWP is masked out at UFFDIO_API time when PROT_NONE is
> > not available or VM_UFFD_RWP aliases VM_NONE (32-bit), so userspace
> > never sees an advertised-but-broken feature.
> >
> > Works on anonymous, shmem, and hugetlb memory.
> >
> > Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
> > Assisted-by: Claude:claude-opus-4-6
>
> A small nit below, other than that
>
> Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Thanks!
> > @@ -347,6 +359,14 @@ static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
> > */
> > if (!pte_write(ptent) && (reason & VM_UFFD_WP))
> > goto out;
> > + /*
> > + * PTE is still RW-protected (protnone with uffd bit), wait for
> > + * userspace to resolve. Plain PROT_NONE without the marker is not
> > + * an RWP fault.
> > + */
> > + if (pte_protnone(ptent) && pte_uffd(ptent) &&
> > + (reason & VM_UFFD_RWP))
>
> Nit: this fits even in 80-chars line
Ack.
--
Kiryl Shutsemau / Kirill A. Shutemov
^ permalink raw reply
* Re: [PATCH v12 0/6] iio: adc: ad4691: add driver for AD4691 multichannel SAR ADC family
From: Jonathan Cameron @ 2026-05-22 11:51 UTC (permalink / raw)
To: Radu Sabau via B4 Relay
Cc: radu.sabau, Lars-Peter Clausen, Michael Hennerich, David Lechner,
Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Uwe Kleine-König, Liam Girdwood, Mark Brown,
Linus Walleij, Bartosz Golaszewski, Philipp Zabel,
Jonathan Corbet, Shuah Khan, linux-iio, devicetree, linux-kernel,
linux-pwm, linux-gpio, linux-doc, Conor Dooley
In-Reply-To: <20260519-ad4692-multichannel-sar-adc-driver-v12-0-5b335162aa51@analog.com>
On Tue, 19 May 2026 15:20:21 +0300
Radu Sabau via B4 Relay <devnull+radu.sabau.analog.com@kernel.org> wrote:
> This series adds support for the Analog Devices AD4691 family of
> high-speed, low-power multichannel successive approximation register
> (SAR) ADCs with an SPI-compatible serial interface.
>
> The family includes:
> - AD4691: 16-channel, 500 kSPS
> - AD4692: 16-channel, 1 MSPS
> - AD4693: 8-channel, 500 kSPS
> - AD4694: 8-channel, 1 MSPS
>
> The devices support two operating modes, auto-detected from the device
> tree:
> - CNV Burst Mode: external PWM drives CNV independently of SPI;
> DATA_READY on a GP pin signals end of conversion
> - Manual Mode: CNV tied to SPI CS; each SPI transfer reads
> the previous conversion result and starts the
> next (pipelined N+1 scheme)
>
> A new driver is warranted rather than extending ad4695: the AD4691
> data path uses an accumulator-register model — results are read from
> AVG_IN registers, with ACC_MASK, ADC_SETUP, DEVICE_SETUP, and
> GPIO_MODE registers controlling the sequencer — none of which exist
> in AD4695. CNV Burst Mode (PWM drives CNV independently of SPI) and
> Manual Mode (pipelined N+1 transfers) also have no equivalent in
> AD4695's command-embedded single-cycle protocol.
>
> The series is structured as follows:
> 1/6 - DT bindings (YAML schema) and MAINTAINERS entry
> 2/6 - Initial driver: register map via custom regmap callbacks,
> IIO read_raw/write_raw, both operating modes, single-channel
> reads via internal oscillator (Autonomous Mode)
> 3/6 - Triggered buffer support: IRQ-driven (DATA_READY on a GP pin
> selected via interrupt-names) for CNV Burst Mode; external IIO
> trigger for Manual Mode to handle the pipelined N+1 SPI protocol
> 4/6 - SPI Engine offload support: DMA-backed high-throughput
> capture path using the SPI offload subsystem
> 5/6 - Per-channel oversampling ratio support for CNV Burst Mode
> 6/6 - Driver documentation (Documentation/iio/ad4691.rst)
>
> Datasheets:
> https://www.analog.com/en/products/ad4691.html
> https://www.analog.com/en/products/ad4692.html
> https://www.analog.com/en/products/ad4693.html
> https://www.analog.com/en/products/ad4694.html
>
> Signed-off-by: Radu Sabau <radu.sabau@analog.com>
I only plan to check the bit you've called out for v13. Series looks very
nice to me. Hopefully I'll remember that and not reread the whole thing
again! FWIW I'll be offline from end of today until Tuesday so it won't
get queued up until then at the earliest.
Jonathan
^ 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