Linux Documentation
 help / color / mirror / Atom feed
* [PATCH 4/4] docs: iio: ade9000: document ADE9078 support
From: Antoniu Miclaus @ 2026-07-20 11:07 UTC (permalink / raw)
  To: Antoniu Miclaus, Nuno Sá, Michael Hennerich,
	Jonathan Cameron, David Lechner, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Corbet, Shuah Khan, Marcelo Schmitt,
	Radu Sabau, Jorge Marques, Matti Vaittinen, Jonathan Santos,
	Jishnu Prakash, linux-iio, linux, devicetree, linux-kernel,
	linux-doc
In-Reply-To: <20260720110754.7674-1-antoniu.miclaus@analog.com>

Add the ADE9078 to the list of supported devices and note that the
dip/swell voltage events are only available on the ADE9000.

Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
---
 Documentation/iio/ade9000.rst | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/Documentation/iio/ade9000.rst b/Documentation/iio/ade9000.rst
index c9ff702a4251..72737b5ec59c 100644
--- a/Documentation/iio/ade9000.rst
+++ b/Documentation/iio/ade9000.rst
@@ -1,24 +1,30 @@
 .. SPDX-License-Identifier: GPL-2.0
 
-===============
-ADE9000 driver
-===============
+======================
+ADE9000/ADE9078 driver
+======================
 
-This driver supports Analog Device's ADE9000 energy measurement IC on SPI bus.
+This driver supports Analog Device's ADE9000 and ADE9078 energy measurement
+ICs on SPI bus.
 
 1. Supported devices
 ====================
 
 * `ADE9000 <https://www.analog.com/media/en/technical-documentation/data-sheets/ADE9000.pdf>`_
-
-The ADE9000 is a highly accurate, fully integrated, multiphase energy and power
-quality monitoring device. Superior analog performance and a digital signal
-processing (DSP) core enable accurate energy monitoring over a wide dynamic
-range. An integrated high end reference ensures low drift over temperature
-with a combined drift of less than ±25 ppm/°C maximum for the entire channel
-including a programmable gain amplifier (PGA) and an analog-to-digital
+* `ADE9078 <https://www.analog.com/media/en/technical-documentation/data-sheets/ADE9078.pdf>`_
+
+The ADE9000 and ADE9078 are highly accurate, fully integrated, multiphase energy
+and power quality monitoring devices. Superior analog performance and a digital
+signal processing (DSP) core enable accurate energy monitoring over a wide
+dynamic range. An integrated high end reference ensures low drift over
+temperature with a combined drift of less than ±25 ppm/°C maximum for the entire
+channel including a programmable gain amplifier (PGA) and an analog-to-digital
 converter (ADC).
 
+The ADE9078 does not provide the on-chip dip/swell (sag) detection available on
+the ADE9000, so the RMS voltage swell/dip events described below are only
+available on the ADE9000.
+
 2. Device attributes
 ====================
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH 3/4] iio: adc: ade9000: add support for ADE9078
From: Antoniu Miclaus @ 2026-07-20 11:07 UTC (permalink / raw)
  To: Antoniu Miclaus, Nuno Sá, Michael Hennerich,
	Jonathan Cameron, David Lechner, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Corbet, Shuah Khan, Marcelo Schmitt,
	Radu Sabau, Jorge Marques, Matti Vaittinen, Jonathan Santos,
	Jishnu Prakash, linux-iio, linux, devicetree, linux-kernel,
	linux-doc
In-Reply-To: <20260720110754.7674-1-antoniu.miclaus@analog.com>

The ADE9078 is a polyphase energy metering device that is register
compatible with the ADE9000. The main differences relevant to the driver
are the absence of the on-chip dip/swell detection and slightly different
full-scale ADC codes.

Add a dedicated channel table that omits the swell/dip voltage events and
a matching chip_info describing the ADE9078 full-scale codes. The RMS
voltage channel macro is split into a shared base and two variants so the
event-less table can reuse the common definition.

Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
---
 drivers/iio/adc/Kconfig   |  14 ++---
 drivers/iio/adc/ade9000.c | 121 +++++++++++++++++++++++++-------------
 2 files changed, 86 insertions(+), 49 deletions(-)

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index d1b198cb8a80..33f2c281b1aa 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -573,20 +573,20 @@ config AD9467
 	  called ad9467.
 
 config ADE9000
-	tristate "Analog Devices ADE9000 Multiphase Energy, and Power Quality Monitoring IC Driver"
+	tristate "Analog Devices ADE9000/ADE9078 Multiphase Energy, and Power Quality Monitoring IC Driver"
 	depends on SPI
 	select REGMAP_SPI
 	select IIO_BUFFER
 	select IIO_KFIFO_BUF
 	help
-	  Say yes here to build support for the Analog Devices ADE9000,
-	  a highly accurate, multiphase energy and power quality monitoring
-	  integrated circuit.
+	  Say yes here to build support for the Analog Devices ADE9000 and
+	  ADE9078, highly accurate, multiphase energy and power quality
+	  monitoring integrated circuits.
 
-	  The device features high-precision analog-to-digital converters
+	  The devices feature high-precision analog-to-digital converters
 	  and digital signal processing to compute RMS values, power factor,
-	  frequency, and harmonic analysis. It supports SPI communication
-	  and provides buffered data output through the IIO framework.
+	  frequency, and harmonic analysis. They support SPI communication
+	  and provide buffered data output through the IIO framework.
 
 	  To compile this driver as a module, choose M here: the module will
 	  be called ade9000.
diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c
index 38a5c7e043b3..0de55b7ad1ea 100644
--- a/drivers/iio/adc/ade9000.c
+++ b/drivers/iio/adc/ade9000.c
@@ -502,7 +502,7 @@ static const struct iio_chan_spec_ext_info ade9000_ext_info[] = {
 	.scan_index = -1						\
 }
 
-#define ADE9000_ALTVOLTAGE_RMS_CHANNEL(num) {				\
+#define ADE9000_ALTVOLTAGE_RMS_CHANNEL_BASE(num)			\
 	.type = IIO_ALTVOLTAGE,						\
 	.channel = num,							\
 	.address = ADE9000_ADDR_ADJUST(ADE9000_REG_AVRMS, num),		\
@@ -512,9 +512,18 @@ static const struct iio_chan_spec_ext_info ade9000_ext_info[] = {
 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
 			      BIT(IIO_CHAN_INFO_SCALE) |		\
 			      BIT(IIO_CHAN_INFO_CALIBBIAS),		\
+	.scan_index = -1
+
+/* With swell/dip (sag) events - ADE9000 only */
+#define ADE9000_ALTVOLTAGE_RMS_CHANNEL(num) {				\
+	ADE9000_ALTVOLTAGE_RMS_CHANNEL_BASE(num),			\
 	.event_spec = ade9000_rms_voltage_events,			\
 	.num_event_specs = ARRAY_SIZE(ade9000_rms_voltage_events),	\
-	.scan_index = -1						\
+}
+
+/* Without swell/dip events - parts lacking DIP_LVL/SWELL_LVL hardware */
+#define ADE9000_ALTVOLTAGE_RMS_CHANNEL_NO_EVENTS(num) {			\
+	ADE9000_ALTVOLTAGE_RMS_CHANNEL_BASE(num),			\
 }
 
 #define ADE9000_POWER_ACTIVE_CHANNEL(num) {				\
@@ -598,48 +607,65 @@ static const struct iio_chan_spec_ext_info ade9000_ext_info[] = {
 	.scan_index = -1						\
 }
 
-static const struct iio_chan_spec ade9000_channels[] = {
-	/* Phase A channels */
-	ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_A_NR),
-	ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_A_NR),
-	ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_A_NR),
-	ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_A_NR),
-	ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR),
-	ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR),
-	ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_A_NR),
-	ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AWATTHR_LO),
-	ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AVAHR_LO),
-	ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AFVARHR_LO),
-	ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_A_NR),
-	/* Phase B channels */
-	ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_B_NR),
-	ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_B_NR),
-	ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_B_NR),
-	ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_B_NR),
-	ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR),
-	ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR),
-	ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_B_NR),
-	ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BWATTHR_LO),
-	ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BVAHR_LO),
-	ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BFVARHR_LO),
-	ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_B_NR),
-	/* Phase C channels */
-	ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_C_NR),
-	ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_C_NR),
-	ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_C_NR),
-	ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_C_NR),
-	ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR),
-	ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR),
-	ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_C_NR),
-	ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CWATTHR_LO),
-	ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CVAHR_LO),
-	ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CFVARHR_LO),
-	ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_C_NR),
-};
+/*
+ * Declare a full channel array. @altvoltage_rms picks the RMS voltage channel
+ * variant so parts without dip/swell hardware (e.g. ADE9078) omit those events.
+ */
+#define ADE9000_DECLARE_CHANNELS(_name, altvoltage_rms)			      \
+	static const struct iio_chan_spec _name[] = {			      \
+		/* Phase A channels */					      \
+		ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_A_NR),		      \
+		ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_A_NR),		      \
+		ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_A_NR),	      \
+		altvoltage_rms(ADE9000_PHASE_A_NR),			      \
+		ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR),	      \
+		ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR),	      \
+		ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_A_NR),	      \
+		ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR,	      \
+					      ADE9000_REG_AWATTHR_LO),	      \
+		ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_A_NR,	      \
+						ADE9000_REG_AVAHR_LO),	      \
+		ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR,	      \
+						ADE9000_REG_AFVARHR_LO),      \
+		ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_A_NR),	      \
+		/* Phase B channels */					      \
+		ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_B_NR),		      \
+		ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_B_NR),		      \
+		ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_B_NR),	      \
+		altvoltage_rms(ADE9000_PHASE_B_NR),			      \
+		ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR),	      \
+		ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR),	      \
+		ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_B_NR),	      \
+		ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR,	      \
+					      ADE9000_REG_BWATTHR_LO),	      \
+		ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_B_NR,	      \
+						ADE9000_REG_BVAHR_LO),	      \
+		ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR,	      \
+						ADE9000_REG_BFVARHR_LO),      \
+		ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_B_NR),	      \
+		/* Phase C channels */					      \
+		ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_C_NR),		      \
+		ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_C_NR),		      \
+		ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_C_NR),	      \
+		altvoltage_rms(ADE9000_PHASE_C_NR),			      \
+		ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR),	      \
+		ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR),	      \
+		ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_C_NR),	      \
+		ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR,	      \
+					      ADE9000_REG_CWATTHR_LO),	      \
+		ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_C_NR,	      \
+						ADE9000_REG_CVAHR_LO),	      \
+		ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR,	      \
+						ADE9000_REG_CFVARHR_LO),      \
+		ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_C_NR),	      \
+	}
+
+ADE9000_DECLARE_CHANNELS(ade9000_channels, ADE9000_ALTVOLTAGE_RMS_CHANNEL);
+ADE9000_DECLARE_CHANNELS(ade9078_channels, ADE9000_ALTVOLTAGE_RMS_CHANNEL_NO_EVENTS);
 
 /*
- * Full-scale codes referred from the datasheet. These are the digital codes
- * produced when the ADC inputs are at full scale.
+ * Full-scale codes referred from the respective datasheets. These are the
+ * digital codes produced when the ADC inputs are at full scale.
  */
 static const struct ade9000_chip_info ade9000_chip_info = {
 	.name = "ade9000",
@@ -650,6 +676,15 @@ static const struct ade9000_chip_info ade9000_chip_info = {
 	.pcf_full_scale_codes = 74770000,
 };
 
+static const struct ade9000_chip_info ade9078_chip_info = {
+	.name = "ade9078",
+	.channels = ade9078_channels,
+	.num_channels = ARRAY_SIZE(ade9078_channels),
+	.rms_full_scale_codes = 52866837,
+	.watt_full_scale_codes = 20823646,
+	.pcf_full_scale_codes = 74680000,
+};
+
 static const struct reg_sequence ade9000_initialization_sequence[] = {
 	{ ADE9000_REG_PGA_GAIN, ADE9000_PGA_GAIN },
 	{ ADE9000_REG_CONFIG0, ADE9000_CONFIG0 },
@@ -1800,12 +1835,14 @@ static int ade9000_probe(struct spi_device *spi)
 
 static const struct spi_device_id ade9000_id[] = {
 	{ .name = "ade9000", .driver_data = (kernel_ulong_t)&ade9000_chip_info },
+	{ .name = "ade9078", .driver_data = (kernel_ulong_t)&ade9078_chip_info },
 	{ }
 };
 MODULE_DEVICE_TABLE(spi, ade9000_id);
 
 static const struct of_device_id ade9000_of_match[] = {
 	{ .compatible = "adi,ade9000", .data = &ade9000_chip_info },
+	{ .compatible = "adi,ade9078", .data = &ade9078_chip_info },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, ade9000_of_match);
-- 
2.43.0


^ permalink raw reply related

* [PATCH 2/4] dt-bindings: iio: adc: adi,ade9000: add adi,ade9078 compatible
From: Antoniu Miclaus @ 2026-07-20 11:07 UTC (permalink / raw)
  To: Antoniu Miclaus, Nuno Sá, Michael Hennerich,
	Jonathan Cameron, David Lechner, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Corbet, Shuah Khan, Marcelo Schmitt,
	Radu Sabau, Jorge Marques, Matti Vaittinen, Jonathan Santos,
	Jishnu Prakash, linux-iio, linux, devicetree, linux-kernel,
	linux-doc
In-Reply-To: <20260720110754.7674-1-antoniu.miclaus@analog.com>

The ADE9078 is a polyphase energy metering device from the same family as
the ADE9000. It is register-compatible with the ADE9000 but does not
provide the on-chip dip/swell detection and is limited to a 10 MHz SPI
clock.

Add the new compatible along with a conditional constraint lowering the
maximum spi-max-frequency for the ADE9078.

Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
---
 .../bindings/iio/adc/adi,ade9000.yaml         | 30 ++++++++++++++-----
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml
index f22eba0250ee..1e940e8c7297 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml
@@ -5,21 +5,23 @@
 $id: http://devicetree.org/schemas/iio/adc/adi,ade9000.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Analog Devices ADE9000 High Performance, Polyphase Energy Metering
+title: Analog Devices ADE9000/ADE9078 High Performance, Polyphase Energy Metering
 
 maintainers:
   - Antoniu Miclaus <antoniu.miclaus@analog.com>
 
 description: |
-  The ADE9000 is a highly accurate, fully integrated, multiphase energy and power
-  quality monitoring device. Superior analog performance and a digital signal
-  processing (DSP) core enable accurate energy monitoring over a wide dynamic
-  range. An integrated high end reference ensures low drift over temperature
-  with a combined drift of less than ±25 ppm/°C maximum for the entire channel
-  including a programmable gain amplifier (PGA) and an analog-to-digital
-  converter (ADC).
+  The ADE9000 and ADE9078 are highly accurate, fully integrated, multiphase
+  energy and power quality monitoring devices. Superior analog performance and a
+  digital signal processing (DSP) core enable accurate energy monitoring over a
+  wide dynamic range. An integrated high end reference ensures low drift over
+  temperature with a combined drift of less than ±25 ppm/°C maximum for the
+  entire channel including a programmable gain amplifier (PGA) and an
+  analog-to-digital converter (ADC). The ADE9078 does not provide the on-chip
+  dip/swell detection available on the ADE9000.
 
   https://www.analog.com/media/en/technical-documentation/data-sheets/ADE9000.pdf
+  https://www.analog.com/media/en/technical-documentation/data-sheets/ADE9078.pdf
 
 $ref: /schemas/spi/spi-peripheral-props.yaml#
 
@@ -27,6 +29,7 @@ properties:
   compatible:
     enum:
       - adi,ade9000
+      - adi,ade9078
 
   reg:
     maxItems: 1
@@ -67,6 +70,17 @@ required:
   - reg
   - vdd-supply
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: adi,ade9078
+    then:
+      properties:
+        spi-max-frequency:
+          maximum: 10000000
+
 unevaluatedProperties: false
 
 examples:
-- 
2.43.0


^ permalink raw reply related

* [PATCH 1/4] iio: adc: ade9000: introduce chip_info structure
From: Antoniu Miclaus @ 2026-07-20 11:07 UTC (permalink / raw)
  To: Antoniu Miclaus, Nuno Sá, Michael Hennerich,
	Jonathan Cameron, David Lechner, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Corbet, Shuah Khan, Marcelo Schmitt,
	Radu Sabau, Jorge Marques, Matti Vaittinen, Jonathan Santos,
	Jishnu Prakash, linux-iio, linux, devicetree, linux-kernel,
	linux-doc
In-Reply-To: <20260720110754.7674-1-antoniu.miclaus@analog.com>

The driver currently hardcodes the device name and the full-scale ADC
codes used to derive the IIO scale attributes. In preparation for
supporting additional parts of the ADE9000 family, move these
part-specific values into a new struct ade9000_chip_info and retrieve it
via spi_get_device_match_data() at probe time.

The channel table and its size are also referenced through the chip_info
so that parts with a different channel layout can be added without
touching the probe path.

No functional change intended for the ADE9000.

Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
---
 drivers/iio/adc/ade9000.c | 63 +++++++++++++++++++++++++++++----------
 1 file changed, 47 insertions(+), 16 deletions(-)

diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c
index b80cdd8ad982..38a5c7e043b3 100644
--- a/drivers/iio/adc/ade9000.c
+++ b/drivers/iio/adc/ade9000.c
@@ -242,14 +242,6 @@
 #define ADE9000_LAST_PAGE_BIT		BIT(15)
 #define ADE9000_MIDDLE_PAGE_BIT		BIT(7)
 
-/*
- * Full scale Codes referred from Datasheet. Respective digital codes are
- * produced when ADC inputs are at full scale.
- */
-#define ADE9000_RMS_FULL_SCALE_CODES	52866837
-#define ADE9000_WATT_FULL_SCALE_CODES	20694066
-#define ADE9000_PCF_FULL_SCALE_CODES	74770000
-
 /* Phase and channel definitions */
 #define ADE9000_PHASE_A_NR		0
 #define ADE9000_PHASE_B_NR		1
@@ -290,7 +282,29 @@ enum ade9000_wfb_cfg {
 #define ADE9000_ADDR_ADJUST(addr, chan)					\
 	(((chan) == 0 ? 0 : (chan) == 1 ? 2 : 4) << 4 | (addr))
 
+/**
+ * struct ade9000_chip_info - part-specific configuration
+ * @name: IIO device name reported to userspace
+ * @channels: channel specification for this part
+ * @num_channels: number of entries in @channels
+ * @rms_full_scale_codes: digital code produced at full-scale RMS input
+ * @watt_full_scale_codes: digital code produced at full-scale power input
+ * @pcf_full_scale_codes: digital code produced at full-scale xI_PCF/xV_PCF input
+ *
+ * The full-scale codes are taken from the respective datasheets and are used to
+ * derive the IIO scale of the raw measurement channels.
+ */
+struct ade9000_chip_info {
+	const char *name;
+	const struct iio_chan_spec *channels;
+	unsigned int num_channels;
+	unsigned int rms_full_scale_codes;
+	unsigned int watt_full_scale_codes;
+	unsigned int pcf_full_scale_codes;
+};
+
 struct ade9000_state {
+	const struct ade9000_chip_info *info;
 	struct completion reset_completion;
 	struct mutex lock; /* Protects SPI transactions */
 	u8 wf_src;
@@ -623,6 +637,19 @@ static const struct iio_chan_spec ade9000_channels[] = {
 	ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_C_NR),
 };
 
+/*
+ * Full-scale codes referred from the datasheet. These are the digital codes
+ * produced when the ADC inputs are at full scale.
+ */
+static const struct ade9000_chip_info ade9000_chip_info = {
+	.name = "ade9000",
+	.channels = ade9000_channels,
+	.num_channels = ARRAY_SIZE(ade9000_channels),
+	.rms_full_scale_codes = 52866837,
+	.watt_full_scale_codes = 20694066,
+	.pcf_full_scale_codes = 74770000,
+};
+
 static const struct reg_sequence ade9000_initialization_sequence[] = {
 	{ ADE9000_REG_PGA_GAIN, ADE9000_PGA_GAIN },
 	{ ADE9000_REG_CONFIG0, ADE9000_CONFIG0 },
@@ -1064,7 +1091,7 @@ static int ade9000_read_raw(struct iio_dev *indio_dev,
 			case ADE9000_REG_CI_PCF:
 			case ADE9000_REG_CV_PCF:
 				*val = 1;
-				*val2 = ADE9000_PCF_FULL_SCALE_CODES;
+				*val2 = st->info->pcf_full_scale_codes;
 				return IIO_VAL_FRACTIONAL;
 			case ADE9000_REG_AIRMS:
 			case ADE9000_REG_AVRMS:
@@ -1073,14 +1100,14 @@ static int ade9000_read_raw(struct iio_dev *indio_dev,
 			case ADE9000_REG_CIRMS:
 			case ADE9000_REG_CVRMS:
 				*val = 1;
-				*val2 = ADE9000_RMS_FULL_SCALE_CODES;
+				*val2 = st->info->rms_full_scale_codes;
 				return IIO_VAL_FRACTIONAL;
 			default:
 				return -EINVAL;
 			}
 		case IIO_POWER:
 			*val = 1;
-			*val2 = ADE9000_WATT_FULL_SCALE_CODES;
+			*val2 = st->info->watt_full_scale_codes;
 			return IIO_VAL_FRACTIONAL;
 		default:
 			break;
@@ -1692,6 +1719,10 @@ static int ade9000_probe(struct spi_device *spi)
 
 	st = iio_priv(indio_dev);
 
+	st->info = spi_get_device_match_data(spi);
+	if (!st->info)
+		return -ENODEV;
+
 	regmap = devm_regmap_init(dev, NULL, st, &ade9000_regmap_config);
 	if (IS_ERR(regmap))
 		return dev_err_probe(dev, PTR_ERR(regmap), "Unable to allocate ADE9000 regmap");
@@ -1726,7 +1757,7 @@ static int ade9000_probe(struct spi_device *spi)
 	if (ret)
 		return ret;
 
-	indio_dev->name = "ade9000";
+	indio_dev->name = st->info->name;
 	indio_dev->info = &ade9000_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->setup_ops = &ade9000_buffer_ops;
@@ -1736,8 +1767,8 @@ static int ade9000_probe(struct spi_device *spi)
 		return dev_err_probe(&spi->dev, ret,
 				     "Failed to get and enable vdd regulator\n");
 
-	indio_dev->channels = ade9000_channels;
-	indio_dev->num_channels = ARRAY_SIZE(ade9000_channels);
+	indio_dev->channels = st->info->channels;
+	indio_dev->num_channels = st->info->num_channels;
 
 	ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
 					  &ade9000_buffer_ops);
@@ -1768,13 +1799,13 @@ static int ade9000_probe(struct spi_device *spi)
 };
 
 static const struct spi_device_id ade9000_id[] = {
-	{ .name = "ade9000" },
+	{ .name = "ade9000", .driver_data = (kernel_ulong_t)&ade9000_chip_info },
 	{ }
 };
 MODULE_DEVICE_TABLE(spi, ade9000_id);
 
 static const struct of_device_id ade9000_of_match[] = {
-	{ .compatible = "adi,ade9000" },
+	{ .compatible = "adi,ade9000", .data = &ade9000_chip_info },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, ade9000_of_match);
-- 
2.43.0


^ permalink raw reply related

* [PATCH 0/4] iio: adc: ade9000: add support for ADE9078
From: Antoniu Miclaus @ 2026-07-20 11:07 UTC (permalink / raw)
  To: Antoniu Miclaus, Nuno Sá, Michael Hennerich,
	Jonathan Cameron, David Lechner, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Corbet, Shuah Khan, Marcelo Schmitt,
	Radu Sabau, Jorge Marques, Matti Vaittinen, Jonathan Santos,
	Jishnu Prakash, linux-iio, linux, devicetree, linux-kernel,
	linux-doc

The ADE9078 is a polyphase energy metering device from the same family as
the ADE9000 and is register compatible with it. The main differences
relevant to the driver are the absence of the on-chip dip/swell detection,
a lower maximum SPI clock (10 MHz), and slightly different full-scale ADC
codes.

This series adds support for the ADE9078 to the existing ade9000 driver.
It first refactors the driver to move the part-specific values (device
name, channel table, and full-scale codes) into a chip_info structure
retrieved via device match data, then adds the new device tree compatible
and the ADE9078 support itself, and finally updates the documentation.

Antoniu Miclaus (4):
  iio: adc: ade9000: introduce chip_info structure
  dt-bindings: iio: adc: adi,ade9000: add adi,ade9078 compatible
  iio: adc: ade9000: add support for ADE9078
  docs: iio: ade9000: document ADE9078 support

 .../bindings/iio/adc/adi,ade9000.yaml         |  30 ++-
 Documentation/iio/ade9000.rst                 |  28 +--
 drivers/iio/adc/Kconfig                       |  14 +-
 drivers/iio/adc/ade9000.c                     | 178 ++++++++++++------
 4 files changed, 169 insertions(+), 81 deletions(-)

-- 
2.43.0


^ permalink raw reply

* Re: [PATCH 01/15] drm/exynos: remove dependency on DRM simple helpers
From: Thomas Zimmermann @ 2026-07-20 11:05 UTC (permalink / raw)
  To: Diogo Silva, Jingoo Han, Inki Dae, Seung-Woo Kim, Kyungmin Park,
	David Airlie, Simona Vetter, Krzysztof Kozlowski, Peter Griffin,
	Alim Akhtar, Laurent Pinchart, Tomi Valkeinen, Maarten Lankhorst,
	Maxime Ripard, Michal Simek, Thierry Reding, Mikko Perttunen,
	Jonathan Hunter, Stefan Agner, Alison Wang, Anitha Chrisanthus,
	David Airlie, Gerd Hoffmann, Dmitry Osipenko, Gurchetan Singh,
	Chia-I Wu, Jyri Sarha, Liu Ying, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Chun-Kuang Hu,
	Philipp Zabel, Matthias Brugger, AngeloGioacchino Del Regno,
	Geert Uytterhoeven, Xinliang Liu, Sumit Semwal, Yongqin Liu,
	John Stultz, Liviu Dudau, Neil Armstrong, Kevin Hilman,
	Jerome Brunet, Martin Blumenstingl, Jonathan Corbet, Shuah Khan
  Cc: dri-devel, linux-arm-kernel, linux-samsung-soc, linux-kernel,
	linux-tegra, virtualization, imx, linux-mediatek,
	linux-renesas-soc, linux-amlogic, linux-doc
In-Reply-To: <20260719-drm_simple_encoder_init-v1-1-a78c509e3062@gmail.com>

Hi

Am 19.07.26 um 01:35 schrieb Diogo Silva:
> The simple KMS helpers are deprecated because they only add an
> intermediate layer between drivers and atomic modesetting.
>
> Open-code drm_simple_encoder_init() by calling drm_encoder_init()
> directly and providing driver-local drm_encoder_funcs.
> Also check the return value from drm_encoder_init() to avoid silent
> failures.
>
> Signed-off-by: Diogo Silva <diogompaissilva@gmail.com>
> ---
>   drivers/gpu/drm/exynos/exynos_dp.c       | 13 +++++++++++--
>   drivers/gpu/drm/exynos/exynos_drm_dpi.c  | 14 ++++++++++++--
>   drivers/gpu/drm/exynos/exynos_drm_dsi.c  | 11 +++++++++--
>   drivers/gpu/drm/exynos/exynos_drm_vidi.c | 14 ++++++++++++--
>   drivers/gpu/drm/exynos/exynos_hdmi.c     | 15 +++++++++++++--
>   5 files changed, 57 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> index b80540328150..1598892c602b 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -24,11 +24,11 @@
>   #include <drm/drm_bridge.h>
>   #include <drm/drm_bridge_connector.h>
>   #include <drm/drm_crtc.h>
> +#include <drm/drm_encoder.h>
>   #include <drm/drm_of.h>
>   #include <drm/drm_panel.h>
>   #include <drm/drm_print.h>
>   #include <drm/drm_probe_helper.h>
> -#include <drm/drm_simple_kms_helper.h>
>   #include <drm/exynos_drm.h>
>   
>   #include "exynos_drm_crtc.h"
> @@ -79,6 +79,10 @@ static void exynos_dp_nop(struct drm_encoder *encoder)
>   	/* do nothing */
>   }
>   
> +static const struct drm_encoder_funcs exynos_dp_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
>   static const struct drm_encoder_helper_funcs exynos_dp_encoder_helper_funcs = {
>   	.mode_set = exynos_dp_mode_set,
>   	.enable = exynos_dp_nop,
> @@ -95,7 +99,12 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
>   
>   	dp->drm_dev = drm_dev;
>   
> -	drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS);
> +	ret = drm_encoder_init(drm_dev, encoder, &exynos_dp_encoder_funcs,
> +			       DRM_MODE_ENCODER_TMDS, NULL);
> +	if (ret) {
> +		dev_err(dp->dev, "Failed to initialize encoder\n");

Preferably use drm_err and drm_dev.

> +		return ret;
> +	}
>   
>   	drm_encoder_helper_add(encoder, &exynos_dp_encoder_helper_funcs);
>   
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> index 0dc36df6ada3..4e42a1da81d1 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> @@ -12,10 +12,10 @@
>   #include <linux/regulator/consumer.h>
>   
>   #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_encoder.h>
>   #include <drm/drm_panel.h>
>   #include <drm/drm_print.h>
>   #include <drm/drm_probe_helper.h>
> -#include <drm/drm_simple_kms_helper.h>
>   
>   #include <video/of_videomode.h>
>   #include <video/videomode.h>
> @@ -140,6 +140,10 @@ static void exynos_dpi_disable(struct drm_encoder *encoder)
>   	}
>   }
>   
> +static const struct drm_encoder_funcs exynos_dpi_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
>   static const struct drm_encoder_helper_funcs exynos_dpi_encoder_helper_funcs = {
>   	.mode_set = exynos_dpi_mode_set,
>   	.enable = exynos_dpi_enable,
> @@ -194,7 +198,13 @@ int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder)
>   {
>   	int ret;
>   
> -	drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS);
> +	ret = drm_encoder_init(dev, encoder, &exynos_dpi_encoder_funcs,
> +			       DRM_MODE_ENCODER_TMDS, NULL);
> +	if (ret) {
> +		DRM_DEV_ERROR(encoder_to_dpi(encoder)->dev,

It just failed to init the encoder, so better not use it here. The 
device should be the same as passed to the function via 'dev'.

> +			      "failed to create encoder ret = %d\n", ret);
> +		return ret;
> +	}
>   
>   	drm_encoder_helper_add(encoder, &exynos_dpi_encoder_helper_funcs);
>   
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index c4d098ab7863..6b7561ac9bb0 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -13,7 +13,7 @@
>   
>   #include <drm/bridge/samsung-dsim.h>
>   #include <drm/drm_probe_helper.h>
> -#include <drm/drm_simple_kms_helper.h>
> +#include <drm/drm_encoder.h>
>   
>   #include "exynos_drm_crtc.h"
>   #include "exynos_drm_drv.h"
> @@ -22,6 +22,10 @@ struct exynos_dsi {
>   	struct drm_encoder encoder;
>   };
>   
> +static const struct drm_encoder_funcs exynos_drm_dsi_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
>   static irqreturn_t exynos_dsi_te_irq_handler(struct samsung_dsim *dsim)
>   {
>   	struct exynos_dsi *dsi = dsim->priv;
> @@ -79,7 +83,10 @@ static int exynos_dsi_bind(struct device *dev, struct device *master, void *data
>   	struct drm_device *drm_dev = data;
>   	int ret;
>   
> -	drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS);
> +	ret = drm_encoder_init(drm_dev, encoder, &exynos_drm_dsi_encoder_funcs,
> +			       DRM_MODE_ENCODER_TMDS, NULL);
> +	if (ret)
> +		return ret;
>   
>   	ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);
>   	if (ret < 0)
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
> index 67bbf9b8bc0e..59dea853d364 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
> @@ -13,10 +13,10 @@
>   
>   #include <drm/drm_atomic_helper.h>
>   #include <drm/drm_edid.h>
> +#include <drm/drm_encoder.h>
>   #include <drm/drm_framebuffer.h>
>   #include <drm/drm_print.h>
>   #include <drm/drm_probe_helper.h>
> -#include <drm/drm_simple_kms_helper.h>
>   #include <drm/drm_vblank.h>
>   #include <drm/exynos_drm.h>
>   
> @@ -403,6 +403,10 @@ static void exynos_vidi_disable(struct drm_encoder *encoder)
>   {
>   }
>   
> +static const struct drm_encoder_funcs exynos_vidi_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
>   static const struct drm_encoder_helper_funcs exynos_vidi_encoder_helper_funcs = {
>   	.mode_set = exynos_vidi_mode_set,
>   	.enable = exynos_vidi_enable,
> @@ -445,7 +449,13 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
>   		return PTR_ERR(ctx->crtc);
>   	}
>   
> -	drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS);
> +	ret = drm_encoder_init(drm_dev, encoder, &exynos_vidi_encoder_funcs,
> +			       DRM_MODE_ENCODER_TMDS, NULL);
> +	if (ret) {
> +		DRM_DEV_ERROR(dev, "failed to initialize encoder ret = %d\n",
> +			      ret);

Again, you rather want drm_err() with drm_dev here.

I've briefly looked over the series and many patches seem affected. 
Please prefer drm_ logging functions and DRM devices over the plain 
device equivalents.

Best regards
Thomas


> +		return ret;
> +	}
>   
>   	drm_encoder_helper_add(encoder, &exynos_vidi_encoder_helper_funcs);
>   
> diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
> index 09b2cabb236f..f44586ce0fdf 100644
> --- a/drivers/gpu/drm/exynos/exynos_hdmi.c
> +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
> @@ -36,9 +36,9 @@
>   #include <drm/drm_atomic_helper.h>
>   #include <drm/drm_bridge.h>
>   #include <drm/drm_edid.h>
> +#include <drm/drm_encoder.h>
>   #include <drm/drm_print.h>
>   #include <drm/drm_probe_helper.h>
> -#include <drm/drm_simple_kms_helper.h>
>   
>   #include "exynos_drm_crtc.h"
>   #include "regs-hdmi.h"
> @@ -1575,6 +1575,11 @@ static void hdmi_disable(struct drm_encoder *encoder)
>   	mutex_unlock(&hdata->mutex);
>   }
>   
> +static const struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
> +
>   static const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
>   	.mode_fixup	= hdmi_mode_fixup,
>   	.enable		= hdmi_enable,
> @@ -1862,7 +1867,13 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
>   
>   	hdata->phy_clk.enable = hdmiphy_clk_enable;
>   
> -	drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS);
> +	ret = drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
> +			       DRM_MODE_ENCODER_TMDS, NULL);
> +	if (ret) {
> +		DRM_DEV_ERROR(dev, "failed to initialize encoder ret = %d\n",
> +			      ret);
> +		return ret;
> +	}
>   
>   	drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
>   
>

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, (HRB 36809, AG Nürnberg)



^ permalink raw reply

* PING [PATCH v3] cgroup/cpu: document cpu.stat.local and clarify cpu.stat behavior
From: Shaojie Sun @ 2026-07-20 10:09 UTC (permalink / raw)
  To: tj
  Cc: mkoutny, cgroups, corbet, cui.tao, hannes, linux-doc,
	linux-kernel, skhan, sunshaojie
In-Reply-To: <20260629060636.200118-1-sunshaojie@kylinos.cn>

Hi Tejun and Michal,

Just a gentle ping on this documentation patch. It received an Acked-by from Michal about
three weeks ago. Any chance this could be picked up for the next merge window, or is there
anything else needed from my side?

The commit in linux-next is: 171569f8ee6724a4113a0100fea6ff83d9b70c6a

Thanks,
Shaojie Sun

^ permalink raw reply

* Re: [PATCH V11 0/9] famfs: port into fuse
From: Amir Goldstein @ 2026-07-20 10:07 UTC (permalink / raw)
  To: John Groves
  Cc: John Groves, Miklos Szeredi, Dan Williams, Bernd Schubert,
	Alison Schofield, John Groves, Jonathan Corbet, Shuah Khan,
	Vishal Verma, Dave Jiang, Matthew Wilcox, Jan Kara,
	Alexander Viro, David Hildenbrand, Christian Brauner,
	Darrick J . Wong, Randy Dunlap, Jeff Layton, Jonathan Cameron,
	Stefan Hajnoczi, Joanne Koong, Josef Bacik, Bagas Sanjaya,
	Chen Linxuan, James Morse, Fuad Tabba, Sean Christopherson,
	Shivank Garg, Ackerley Tng, Gregory Price, Andrew Morton,
	Namjae Jeon, Lorenzo Stoakes, Aravind Ramesh, Ajay Joshi,
	venkataravis@micron.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, nvdimm@lists.linux.dev,
	linux-cxl@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	fuse-devel@lists.linux.dev
In-Reply-To: <0100019f7d9fbe81-6cb16662-2522-47ea-a152-fab0ee3d9b35-000000@email.amazonses.com>

On Mon, Jul 20, 2026 at 5:44 AM John Groves <john@jagalactic.com> wrote:
>
> From: John Groves <john@groves.net>
>
> This has been quite a gauntlet so far. Some requests were made but eventually
> ruled out (e.g. using BPF for fault handling).

I'm sorry John, but this patch set is not what I was hoping to see.
I don't know if we are miscommunicating or if it is something else.
I will try to do my best to explain again.

I say miscommunication when looking at your comment in reply to [1]:
"First, a scope check. This patch touches only the daxdev registration -
GET_FMAP, struct fuse_famfs_fmap_header, and the simple/interleave
extent structs in include/uapi/linux/fuse.h are untouched. I'm reading
that as tacit agreement to GET_FMAP and its ABI. Can you confirm? If so
the large piece is settled and this is really just about how a daxdev
gets registered."

This was a wrong assumption on your part, it was NOT confirmed and
I even responded to it with a mini tantrum.

I feel that you may have not gotten Miklos' second patch [2] at all, because
you have not responded to it.
Maybe because it was sent only to your work email?

>
> Concrete requests (demands?) from the fuse community included the following:
> - Pass daxdevs into the kernel via an ioctl rather than a new fuse
>   message/response

Look at this patch by Miklos:
[1] https://lore.kernel.org/fuse-devel/20260529134302.1989958-1-mszeredi@redhat.com/

Look more closely at the diffstat:
 7 files changed, 123 insertions(+), 294 deletions(-)

It's not about this ioctl, it's about infrastructure reuse.
It's about the fact that there is NOTHING special about dax_devlist;
and no reason not to manage it via backing_files_map.

The reason you stated was that you want userspace to determine the
daxdev_index/backing_id - fine, no problem - this is why I asked that
you pass it the desired backing_id in the ioctl.
In fact I think that all fuse backing_ids would be better assigned by user space
so the extension of padding => backing_id is not unique to famfs.

And the best part is that this request requires no changes to your userspace.
You already bite the bullet and maintain the new/old uapi but changing the
kernel implementation does not require this burden from you, so to be honest
I really don't understand why you did not follow Miklos' suggestion.

> - Lose the famfs interleaved extent format. I have complied with this request.
>   It makes some things worse, but we'll discuss that later.
>

I am really not aware of a request to lose the interleaved extent format.
How can this patch [2] from Miklos which reimplements this format as a generic
uapi be mistaken for a request to lose this format?

> There has also been a desire from the fuse community for famfs to use an
> experimental implementation of virtual backing-devs from Darrick. I'm leaving
> this out as a potential future optimization - although Darrick has announced
> that he (and $employer) intend to abandon that work, so it's not clear whether
> that will become viable.

Forgive me John, but I am having a hard time following the logic of
this statement.
How are Darrick's future plans about fuse iomap even remotely related?

In this patch Miklos has ALREADY IMPLEMENTED
"striped "virtual" backing devices (idea from Darrick)"
[2] https://lore.kernel.org/linux-fsdevel/20260601152327.2069787-1-mszeredi@redhat.com/

An idea does not die when employers change priorities.

The diffstat is also impressive:
 6 files changed, 219 insertions(+), 300 deletions(-)

Especially when considering the fact that the insertions are generic code
that could be useful to fuse passthrough regardless of famfs.

Let me recap the former review requests as I understand them:

1. Use ioctl instead of GET_DAXDEV
2. Use backing files infra for daxdev table
3. Use ioctl instead of GET_FMAP
4. Use backing files infra for fmaps

Request #1 was fulfilled in the v11 patch set.
Other requests were not fulfilled and with no explanation why,
not one that I could find anyway.

Perhaps requests 2-4 were lost in the spam folder and/or lost
in translation, so I will repeat my question from review of [1]:

Are there any other *technical* problems that you can point out
with the patches that Miklos posted (including FUSE_DEV_IOC_STRIPE_OPEN)?

Thanks,
Amir.

^ permalink raw reply

* Re: [RFC PATCH v3 1/3] mm/damon: introduce DAMOS_SPLIT action
From: Lian Wang @ 2026-07-20 10:02 UTC (permalink / raw)
  To: Gutierrez Asier
  Cc: Lian Wang, damon, linux-mm, sj, akpm, linux-kernel, david, ljs,
	liam, vbabka, rppt, surenb, mhocko, npache, ziy, baolin.wang,
	ryan.roberts, daichaobing, wangkefeng.wang, zengheng4, kasong,
	corbet, skhan, linux-doc, linux-kselftest, lianux.wang,
	kunwu.chan
In-Reply-To: <e01fa50e-b9a7-4c0b-ba70-6088b8d6ddfd@huawei-partners.com>

On Mon, 20 Jul 2026 12:47:23 +0300 Gutierrez Asier <gutierrez.asier@huawei-partners.com> wrote:

> 
> 
> On 7/20/2026 6:03 AM, Lian Wang wrote:
> > Add a new DAMOS action, DAMOS_SPLIT, that splits large folios in the
> > target region down to a smaller order.  A new per-scheme field and sysfs
> > file, target_order, selects the split target: 0 for order-0 base pages,
> > or 2..HPAGE_PMD_ORDER-1 for a smaller mTHP order (order-1 is rejected at
> > store time since anonymous THPs cannot be split to order-1).
> > 
> > Unlike DAMOS_COLLAPSE which builds large folios, splitting only dismantles
> > them; it allocates nothing, copies nothing, and no THP admission policy
> > applies.  khugepaged deliberately refuses to collapse a folio to a
> > smaller order, leaving the shrink direction to callers like this one.
> > 
> > This patch adds the DAMOS_SPLIT action, the ``order`` field (placed in
> > the existing union alongside target_nid and migrate_dests), its sysfs
> > interface, and documentation.  The vaddr operations set handler is added
> > in the next patch.
> > 
> > Link: https://lore.kernel.org/20260605161422.213817-9-npache@redhat.com/
> >  ("mm/khugepaged: skip collapsing mTHP to smaller orders")

Hi Asier,

Thanks for the review.  All three points noted -- will address them
in the next revision along with feedback from David and others.

Thanks,
Lian Wang

^ permalink raw reply

* Re: [External] [PATCH v5 4/8] riscv_cbqri: Add capacity controller probe and allocation device ops
From: yunhui cui @ 2026-07-20  9:56 UTC (permalink / raw)
  To: Drew Fustini
  Cc: Adrien Ricciardi, Alexandre Ghiti, Atish Kumar Patra, Atish Patra,
	Babu Moger, Ben Horgan, Borislav Petkov, Chen Pei, Conor Dooley,
	Conor Dooley, Dave Hansen, Dave Martin, Fenghua Yu, Gong Shuai,
	Gong Shuai, guo.wenjia23, James Morse, Kornel Dulęba,
	Krzysztof Kozlowski, liu.qingtao2, Liu Zhiwei, Palmer Dabbelt,
	Paul Walmsley, Peter Newman, Radim Krčmář,
	Reinette Chatre, Rob Herring, Samuel Holland,
	Sebastian Andrzej Siewior, Tony Luck, Vasudevan Srinivasan,
	Ved Shanbhogue, Weiwei Li, Zhanpeng Zhang, linux-kernel,
	linux-riscv, x86, devicetree, linux-rt-devel, linux-doc
In-Reply-To: <20260714-dfustini-atl-sc-cbqri-dt-v5-4-b0ae7e9c932e@kernel.org>

Hi Drew,

On Wed, Jul 15, 2026 at 8:24 AM Drew Fustini <fustini@kernel.org> wrote:
>
> Add support for the RISC-V CBQRI capacity controller. A platform driver
> passes a cbqri_controller_info descriptor together with the cache level
> to riscv_cbqri_register_cc_dt(), which probes the controller and adds it
> to the controller list.
>
> Assisted-by: Claude:claude-opus-4-8
> Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> Signed-off-by: Drew Fustini <fustini@kernel.org>
> ---
>  MAINTAINERS                      |   3 +
>  drivers/resctrl/Kconfig          |  13 +
>  drivers/resctrl/Makefile         |   3 +
>  drivers/resctrl/cbqri_devices.c  | 563 +++++++++++++++++++++++++++++++++++++++
>  drivers/resctrl/cbqri_internal.h | 122 +++++++++
>  include/linux/riscv_cbqri.h      |  45 ++++
>  6 files changed, 749 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a0a4b41f02c5..064a6ae2823e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -23365,6 +23365,9 @@ L:      linux-riscv@lists.infradead.org
>  S:     Supported
>  F:     arch/riscv/include/asm/qos.h
>  F:     arch/riscv/kernel/qos.c
> +F:     drivers/resctrl/cbqri_devices.c
> +F:     drivers/resctrl/cbqri_internal.h
> +F:     include/linux/riscv_cbqri.h
>
>  RISC-V RPMI AND MPXY DRIVERS
>  M:     Rahul Pathak <rahul@summations.net>
> diff --git a/drivers/resctrl/Kconfig b/drivers/resctrl/Kconfig
> index 672abea3b03c..92b9c82cf9f3 100644
> --- a/drivers/resctrl/Kconfig
> +++ b/drivers/resctrl/Kconfig
> @@ -29,3 +29,16 @@ config ARM64_MPAM_RESCTRL_FS
>         default y if ARM64_MPAM_DRIVER && RESCTRL_FS
>         select RESCTRL_RMID_DEPENDS_ON_CLOSID
>         select RESCTRL_ASSIGN_FIXED
> +
> +menuconfig RISCV_CBQRI
> +       bool "RISC-V CBQRI support"
> +       depends on RISCV && RISCV_ISA_SSQOSID
> +       help
> +         Capacity and Bandwidth QoS Register Interface (CBQRI) support for
> +         RISC-V cache QoS resources. CBQRI exposes cache capacity
> +         allocation through the resctrl filesystem at /sys/fs/resctrl when
> +         RESCTRL_FS is also enabled.
> +
> +if RISCV_CBQRI
> +
> +endif

Should this empty if/endif block go in patch [8/8] instead?

> diff --git a/drivers/resctrl/Makefile b/drivers/resctrl/Makefile
> index 4f6d0e81f9b8..4d8a2c4b5627 100644
> --- a/drivers/resctrl/Makefile
> +++ b/drivers/resctrl/Makefile
> @@ -3,3 +3,6 @@ mpam-y                                          += mpam_devices.o
>  mpam-$(CONFIG_ARM64_MPAM_RESCTRL_FS)           += mpam_resctrl.o
>
>  ccflags-$(CONFIG_ARM64_MPAM_DRIVER_DEBUG)      += -DDEBUG
> +
> +obj-$(CONFIG_RISCV_CBQRI)                      += cbqri.o
> +cbqri-y                                                += cbqri_devices.o
> diff --git a/drivers/resctrl/cbqri_devices.c b/drivers/resctrl/cbqri_devices.c
> new file mode 100644
> index 000000000000..3e1df660920e
> --- /dev/null
> +++ b/drivers/resctrl/cbqri_devices.c
> @@ -0,0 +1,563 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
> +
> +#include <linux/bitfield.h>
> +#include <linux/cleanup.h>
> +#include <linux/riscv_cbqri.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/ioport.h>
> +#include <linux/list.h>
> +#include <linux/mutex.h>
> +#include <linux/printk.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +
> +#include <asm/csr.h>
> +
> +#include "cbqri_internal.h"
> +
> +LIST_HEAD(cbqri_controllers);
> +
> +/*
> + * Serializes cbqri_controllers mutations against a concurrent insert under
> + * asynchronous driver probing, and against the boot-time walk in the resctrl
> + * glue. Runtime cpuhp walks happen after registration has settled.
> + */
> +DEFINE_MUTEX(cbqri_controllers_lock);
> +
> +/*
> + * CBQRI registers are 64-bit, but the spec only guarantees single-copy
> + * atomicity for naturally aligned 4-byte accesses. Read the two halves and
> + * reconstruct, so the driver does not rely on native 64-bit MMIO.
> + *
> + * The halves are not sampled atomically, but a tear is harmless. The fields
> + * that change while an operation runs, BUSY (bit 39) and STATUS (bits
> + * 38:32), are in the high half and read by the single high readl(). The low
> + * half (OP/AT/RCID) is software-written and constant for the operation.
> + */
> +static u64 cbqri_readq(void __iomem *addr)
> +{
> +       u32 lo = readl(addr);
> +       u32 hi = readl(addr + 4);
> +
> +       return (u64)hi << 32 | lo;
> +}
> +
> +/* Set capacity block mask (cc_block_mask) */
> +static void cbqri_set_cbm(struct cbqri_controller *ctrl, u64 cbm)
> +{
> +       /*
> +        * cbqri_probe_cc() rejects ncblks > 32, so the mask fits the low word.
> +        * Per CBQRI 3.5 the cc_block_mask bits above NCBLKS are read-only zero,
> +        * so the upper word needs no write.
> +        */
> +       writel(lower_32_bits(cbm), ctrl->base + CBQRI_CC_BLOCK_MASK_OFF);
> +}
> +
> +/*
> + * Clear cc_cunits so a CONFIG_LIMIT on a CUNITS-capable controller imposes no
> + * capacity-unit limit. resctrl models only the block mask. On controllers
> + * with cc_capabilities.CUNITS == 0 the register is read-only zero, so there is
> + * nothing to do.
> + */
> +static void cbqri_clear_cunits(struct cbqri_controller *ctrl)
> +{
> +       if (ctrl->cc.cunits) {
> +               writel(0, ctrl->base + CBQRI_CC_CUNITS_OFF);
> +               writel(0, ctrl->base + CBQRI_CC_CUNITS_OFF + 4);
> +       }
> +}
> +
> +static int cbqri_wait_busy_flag(struct cbqri_controller *ctrl, int reg_offset,
> +                               u64 *regp)
> +{
> +       u64 reg;
> +       int ret;
> +
> +       /*
> +        * Sleeping poll: caller holds ctrl->lock as a sleeping mutex, so
> +        * 10us/1ms is safe under PREEMPT_RT.
> +        */
> +       ret = read_poll_timeout(cbqri_readq, reg,
> +                               !FIELD_GET(CBQRI_CONTROL_REGISTERS_BUSY_MASK, reg),
> +                               10, 1000, false, ctrl->base + reg_offset);
> +       if (ret)
> +               return ret;
> +       if (regp)
> +               *regp = reg;
> +       return 0;
> +}
> +
> +/*
> + * Perform capacity allocation control operation on capacity controller.
> + * Caller must hold ctrl->lock.
> + */
> +static int cbqri_cc_alloc_op(struct cbqri_controller *ctrl, int operation,
> +                            int rcid, u32 at)
> +{
> +       int reg_offset = CBQRI_CC_ALLOC_CTL_OFF;
> +       int status;
> +       u64 reg;
> +
> +       lockdep_assert_held(&ctrl->lock);
> +
> +       if (cbqri_wait_busy_flag(ctrl, reg_offset, &reg) < 0) {
> +               pr_err_ratelimited("BUSY timeout before starting operation\n");
> +               return -EIO;
> +       }
> +       FIELD_MODIFY(CBQRI_CONTROL_REGISTERS_OP_MASK, &reg, operation);
> +       FIELD_MODIFY(CBQRI_CONTROL_REGISTERS_RCID_MASK, &reg, rcid);
> +
> +       /*
> +        * CBQRI Table 1: AT 0=Data, 1=Code. Program AT on controllers
> +        * that report supports_alloc_at_code. On controllers that don't,
> +        * AT is reserved-zero and the op acts on both halves.
> +        */
> +       reg &= ~CBQRI_CONTROL_REGISTERS_AT_MASK;
> +       if (ctrl->cc.supports_alloc_at_code)
> +               reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_AT_MASK, at);
> +
> +       writel(lower_32_bits(reg), ctrl->base + reg_offset);
> +
> +       if (cbqri_wait_busy_flag(ctrl, reg_offset, &reg) < 0) {
> +               pr_err_ratelimited("BUSY timeout during operation\n");
> +               return -EIO;
> +       }
> +
> +       status = FIELD_GET(CBQRI_CONTROL_REGISTERS_STATUS_MASK, reg);
> +       if (status != CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS) {
> +               pr_err_ratelimited("operation %d failed: status=%d\n", operation, status);
> +               return -EIO;
> +       }
> +
> +       return 0;
> +}
> +
> +/*
> + * Apply a capacity block mask and verify via CONFIG_LIMIT + READ_LIMIT.
> + *
> + * AT-capable controllers with CDP off need a second CONFIG_LIMIT on the
> + * other AT half (the spec encodes AT only as 0=Data / 1=Code, there is
> + * no "both halves" value). CDP-on issues separate per-type writes from
> + * resctrl, so a single CONFIG_LIMIT per call is correct.
> + */
> +int cbqri_apply_cache_config(struct cbqri_controller *ctrl, u32 closid,
> +                            const struct cbqri_cc_config *cfg)
> +{
> +       bool need_at_mirror;
> +       u64 saved_cbm = 0;
> +       int err = 0;
> +       u64 reg;
> +
> +       mutex_lock(&ctrl->lock);
> +
> +       need_at_mirror = ctrl->cc.supports_alloc_at_code && !cfg->cdp_enabled;
> +
> +       /*
> +        * Capture the cfg->at half CBM before any write so a partial
> +        * AT-mirror failure can revert and keep the two halves consistent.
> +        * Pre-clear cc_block_mask so a silent firmware no-op (status
> +        * SUCCESS but staging not updated) shows as a zero readback
> +        * rather than carrying stale data from a prior op.
> +        */
> +       if (need_at_mirror) {
> +               cbqri_set_cbm(ctrl, 0);
> +               err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT,
> +                                       closid, cfg->at);
> +               if (err < 0)
> +                       goto out;
> +               saved_cbm = cbqri_readq(ctrl->base + CBQRI_CC_BLOCK_MASK_OFF);
> +       }
> +
> +       /* Set capacity block mask (cc_block_mask) */
> +       cbqri_set_cbm(ctrl, cfg->cbm);
> +       cbqri_clear_cunits(ctrl);
> +
> +       /* Capacity config limit operation for the AT half implied by cfg->at */
> +       err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT,
> +                               closid, cfg->at);
> +       if (err < 0)
> +               goto out;
> +
> +       /*
> +        * CDP-off mirror: on AT-capable controllers, also program the
> +        * other AT half with the same mask so the two halves stay in sync.
> +        */
> +       if (need_at_mirror) {
> +               u32 other = (cfg->at == CBQRI_CONTROL_REGISTERS_AT_CODE) ?
> +                           CBQRI_CONTROL_REGISTERS_AT_DATA :
> +                           CBQRI_CONTROL_REGISTERS_AT_CODE;
> +
> +               cbqri_set_cbm(ctrl, cfg->cbm);
> +               cbqri_clear_cunits(ctrl);
> +               err = cbqri_cc_alloc_op(ctrl,
> +                                       CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT,
> +                                       closid, other);
> +               if (err < 0) {
> +                       int rerr;
> +
> +                       /*
> +                        * Best-effort revert of the cfg->at half so the two
> +                        * halves stay in sync. A schemata read sees only one
> +                        * half, so silent divergence would otherwise report
> +                        * the new value as if the write had succeeded.
> +                        */
> +                       cbqri_set_cbm(ctrl, saved_cbm);
> +                       cbqri_clear_cunits(ctrl);
> +                       rerr = cbqri_cc_alloc_op(ctrl,
> +                                                CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT,
> +                                                closid, cfg->at);
> +                       if (rerr < 0)
> +                               pr_err_ratelimited("AT-mirror revert failed (err=%d), AT halves diverged\n",
> +                                                  rerr);
> +                       goto out;
> +               }
> +       }
> +
> +       /* Clear cc_block_mask before read limit to verify op works */
> +       cbqri_set_cbm(ctrl, 0);
> +
> +       /* Perform a capacity read limit operation to verify blockmask */
> +       err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT,
> +                               closid, cfg->at);
> +       if (err < 0)
> +               goto out;
> +
> +       /*
> +        * Read capacity blockmask and narrow to u32 to match resctrl's CBM
> +        * width. cbqri_probe_cc() rejects ncblks > 32 so the upper bits are
> +        * reserved zero.
> +        */
> +       reg = cbqri_readq(ctrl->base + CBQRI_CC_BLOCK_MASK_OFF);
> +       if (lower_32_bits(reg) != cfg->cbm) {
> +               pr_err_ratelimited("CBM verify mismatch (reg=%llx != cbm=%llx)\n",
> +                                  reg, cfg->cbm);
> +               err = -EIO;
> +       }
> +
> +out:
> +       mutex_unlock(&ctrl->lock);
> +       return err;
> +}
> +
> +/*
> + * Read the configured CBM for closid on the at half via READ_LIMIT.
> + * Pre-clears cc_block_mask before the op so a silent firmware no-op
> + * (status SUCCESS but staging not updated) is detectable in cbm_out.
> + */
> +int cbqri_read_cache_config(struct cbqri_controller *ctrl, u32 closid,
> +                           u32 at, u32 *cbm_out)
> +{
> +       int err;
> +
> +       mutex_lock(&ctrl->lock);
> +       cbqri_set_cbm(ctrl, 0);
> +       err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, closid, at);
> +       if (err == 0) {
> +               /*
> +                * resctrl exposes the CBM as a u32 and cbqri_probe_cc() rejects
> +                * ncblks > 32, so the mask fits the low 32-bit word of the
> +                * cc_block_mask register.
> +                */
> +               *cbm_out = readl(ctrl->base + CBQRI_CC_BLOCK_MASK_OFF);
> +       }
> +       mutex_unlock(&ctrl->lock);
> +       return err;
> +}
> +
> +static int cbqri_probe_feature(struct cbqri_controller *ctrl, int reg_offset,
> +                              int operation, int *status, bool *access_type_supported)
> +{
> +       const u64 active_mask = CBQRI_CONTROL_REGISTERS_OP_MASK |
> +                               CBQRI_CONTROL_REGISTERS_AT_MASK |
> +                               CBQRI_CONTROL_REGISTERS_RCID_MASK;
> +       u64 reg, saved_reg;
> +       int at;
> +
> +       /*
> +        * Default the output to false so the status==0 (feature not
> +        * implemented) path returns a deterministic value to the caller
> +        * rather than leaving an uninitialized bool.
> +        */
> +       *access_type_supported = false;
> +
> +       /* Keep the initial register value to preserve the WPRI fields */
> +       reg = cbqri_readq(ctrl->base + reg_offset);
> +       saved_reg = reg;
> +
> +       /* Drain any in-flight firmware op before issuing our own write. */
> +       if (cbqri_wait_busy_flag(ctrl, reg_offset, &saved_reg) < 0) {
> +               pr_err("BUSY timeout before probe operation\n");
> +               return -EIO;
> +       }
> +
> +       /*
> +        * Execute the requested operation with all active fields
> +        * (OP/AT/RCID) zeroed except OP itself. Every bit not in
> +        * active_mask is WPRI and gets carried over from saved_reg.
> +        */
> +       reg = (saved_reg & ~active_mask) |
> +             FIELD_PREP(CBQRI_CONTROL_REGISTERS_OP_MASK, operation);
> +       writel(lower_32_bits(reg), ctrl->base + reg_offset);
> +       if (cbqri_wait_busy_flag(ctrl, reg_offset, &reg) < 0) {
> +               pr_err_ratelimited("BUSY timeout during operation\n");
> +               return -EIO;
> +       }
> +
> +       /* Get the operation status */
> +       *status = FIELD_GET(CBQRI_CONTROL_REGISTERS_STATUS_MASK, reg);
> +
> +       /*
> +        * Check for the AT support if the register is implemented
> +        * (if not, the status value will remain 0)
> +        */
> +       if (*status != 0) {
> +               /*
> +                * Re-issue operation with AT=CODE so the controller
> +                * latches AT=CODE on supported hardware (or resets it to 0
> +                * on hardware that doesn't). OP must be a defined CBQRI op
> +                * here. OP=0 is a no-op and would silently disable CDP.
> +                */
> +               reg = (saved_reg & ~active_mask) |
> +                     FIELD_PREP(CBQRI_CONTROL_REGISTERS_OP_MASK, operation) |
> +                     FIELD_PREP(CBQRI_CONTROL_REGISTERS_AT_MASK,
> +                                CBQRI_CONTROL_REGISTERS_AT_CODE);
> +               writel(lower_32_bits(reg), ctrl->base + reg_offset);
> +               if (cbqri_wait_busy_flag(ctrl, reg_offset, &reg) < 0) {
> +                       pr_err("BUSY timeout setting AT field\n");
> +                       return -EIO;
> +               }
> +
> +               /*
> +                * If the AT field value has been reset to zero,
> +                * then the AT support is not present
> +                */
> +               at = FIELD_GET(CBQRI_CONTROL_REGISTERS_AT_MASK, reg);
> +               if (at == CBQRI_CONTROL_REGISTERS_AT_CODE)
> +                       *access_type_supported = true;
> +       }
> +
> +       /*
> +        * Restore the original register value.
> +        * Clear OP to avoid re-triggering the probe op.
> +        */
> +       saved_reg &= ~CBQRI_CONTROL_REGISTERS_OP_MASK;
> +       writel(lower_32_bits(saved_reg), ctrl->base + reg_offset);
> +       if (cbqri_wait_busy_flag(ctrl, reg_offset, NULL) < 0) {
> +               pr_err("BUSY timeout restoring register value\n");
> +               return -EIO;
> +       }
> +
> +       return 0;
> +}
> +
> +static int cbqri_probe_cc(struct cbqri_controller *ctrl)
> +{
> +       int err, status;
> +       int ver_major, ver_minor;
> +       u64 reg;
> +
> +       reg = cbqri_readq(ctrl->base + CBQRI_CC_CAPABILITIES_OFF);
> +       if (reg == 0)
> +               return -ENODEV;
> +
> +       ver_minor = FIELD_GET(CBQRI_CC_CAPABILITIES_VER_MINOR_MASK, reg);
> +       ver_major = FIELD_GET(CBQRI_CC_CAPABILITIES_VER_MAJOR_MASK, reg);
> +       ctrl->cc.ncblks = FIELD_GET(CBQRI_CC_CAPABILITIES_NCBLKS_MASK, reg);
> +
> +       pr_debug("version=%d.%d ncblks=%d cache_level=%d\n",
> +                ver_major, ver_minor,
> +                ctrl->cc.ncblks, ctrl->cache.cache_level);
> +
> +       /*
> +        * NCBLKS == 0 would divide-by-zero in the schemata math while
> +        * ctrl->lock is held.
> +        */
> +       if (!ctrl->cc.ncblks) {
> +               pr_warn("CC at %pa has 0 capacity blocks, skipping\n",
> +                       &ctrl->addr);
> +               return -ENODEV;
> +       }
> +
> +       if (ctrl->cc.ncblks > 32) {
> +               pr_warn("CC at %pa has ncblks=%u > 32 (resctrl CBM is u32), skipping\n",
> +                       &ctrl->addr, ctrl->cc.ncblks);
> +               return -ENODEV;
> +       }
> +
> +       /*
> +        * On a CUNITS-capable controller, CONFIG_LIMIT also consumes cc_cunits,
> +        * whose reset value is unspecified. The driver clears it to 0 (no limit)
> +        * on every CONFIG_LIMIT, so cc_cunits at 0x28 must be within the mapping.
> +        */
> +       ctrl->cc.cunits = FIELD_GET(CBQRI_CC_CAPABILITIES_CUNITS_MASK, reg);
> +       if (ctrl->cc.cunits && ctrl->size < CBQRI_CC_CUNITS_OFF + 8) {
> +               pr_warn("CC at %pa supports CUNITS but maps only %pa, skipping\n",
> +                       &ctrl->addr, &ctrl->size);
> +               return -ENODEV;
> +       }
> +
> +       /* Probe allocation features */
> +       err = cbqri_probe_feature(ctrl, CBQRI_CC_ALLOC_CTL_OFF,
> +                                 CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT,
> +                                 &status, &ctrl->cc.supports_alloc_at_code);
> +       if (err)
> +               return err;
> +
> +       if (status == CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS)
> +               ctrl->alloc_capable = true;
> +
> +       return 0;
> +}
> +
> +static int cbqri_probe_controller(struct cbqri_controller *ctrl)
> +{
> +       int err;
> +
> +       pr_debug("controller info: type=%d addr=%pa size=%pa max-rcid=%u\n",
> +                ctrl->type, &ctrl->addr, &ctrl->size, ctrl->rcid_count);
> +
> +       if (!ctrl->addr) {
> +               pr_warn("controller has invalid addr=0x0, skipping\n");
> +               return -EINVAL;
> +       }
> +
> +       if (ctrl->size < CBQRI_CTRL_MIN_REG_SPAN) {
> +               pr_warn("controller at %pa: size %pa < minimum 0x%x, skipping\n",
> +                       &ctrl->addr, &ctrl->size, CBQRI_CTRL_MIN_REG_SPAN);
> +               return -EINVAL;
> +       }
> +
> +       if (!request_mem_region(ctrl->addr, ctrl->size, "cbqri_controller")) {
> +               pr_err("request_mem_region failed for %pa\n", &ctrl->addr);
> +               return -EBUSY;
> +       }
> +
> +       ctrl->base = ioremap(ctrl->addr, ctrl->size);
> +       if (!ctrl->base) {
> +               pr_err("ioremap failed for %pa\n", &ctrl->addr);
> +               err = -ENOMEM;
> +               goto err_release;
> +       }
> +
> +       switch (ctrl->type) {
> +       case CBQRI_CONTROLLER_TYPE_CAPACITY:
> +               err = cbqri_probe_cc(ctrl);
> +               break;
> +       default:
> +               pr_err("unknown controller type %d\n", ctrl->type);
> +               err = -ENODEV;
> +               break;
> +       }
> +
> +       if (err)
> +               goto err_iounmap;
> +
> +       return 0;
> +
> +err_iounmap:
> +       iounmap(ctrl->base);
> +       ctrl->base = NULL;
> +err_release:
> +       release_mem_region(ctrl->addr, ctrl->size);
> +       return err;
> +}
> +
> +void cbqri_controller_destroy(struct cbqri_controller *ctrl)
> +{
> +       /*
> +        * cbqri_probe_controller() clears ctrl->base on its error paths and
> +        * releases the mem region itself, so reach into both only when
> +        * destroy is rolling back a successful probe.
> +        */
> +       if (ctrl->base) {
> +               iounmap(ctrl->base);
> +               release_mem_region(ctrl->addr, ctrl->size);
> +       }
> +       kfree(ctrl);
> +}
> +
> +/**
> + * riscv_cbqri_register_cc_dt() - register a DT-described capacity controller
> + * @info:        registration descriptor. info->cache_id is used as the
> + *               resctrl domain id. info->type must be CAPACITY.
> + * @cache_level: cache level (2 or 3) the controller backs, mapped to the
> + *               resctrl L2/L3 resource by the resctrl glue.
> + *
> + * The cache level and id (info->cache_id) are supplied directly by the
> + * caller, which resolves them from cacheinfo. Domain membership is resolved
> + * per CPU at hotplug, so no cpu mask is stored. There is no firmware table
> + * to resolve any of this from.
> + *
> + * Return: 0 on success, or a negative errno on failure.
> + */
> +int riscv_cbqri_register_cc_dt(const struct cbqri_controller_info *info,
> +                              u32 cache_level)
> +{
> +       struct cbqri_controller *ctrl;
> +       int err;
> +
> +       if (!info->addr) {
> +               pr_warn("skipping controller with invalid addr=0x0\n");
> +               return -EINVAL;
> +       }
> +
> +       if (info->type != CBQRI_CONTROLLER_TYPE_CAPACITY) {
> +               pr_warn("register_cc_dt called with non-capacity type %u\n",
> +                       info->type);
> +               return -EINVAL;
> +       }
> +
> +       ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
> +       if (!ctrl)
> +               return -ENOMEM;
> +
> +       mutex_init(&ctrl->lock);
> +
> +       ctrl->addr = info->addr;
> +       ctrl->size = info->size;
> +       ctrl->type = info->type;
> +       ctrl->rcid_count = info->rcid_count;
> +
> +       /*
> +        * SRMCFG encodes RCID in 12 bits. Reject an out-of-range count rather
> +        * than silently truncating in every FIELD_PREP(SRMCFG_RCID_MASK, closid)
> +        * on the schedule-in fast path.
> +        */
> +       if (ctrl->rcid_count > FIELD_MAX(SRMCFG_RCID_MASK) + 1) {
> +               pr_warn("CC at %pa has RCID count %u beyond the 12-bit SRMCFG field, skipping\n",
> +                       &ctrl->addr, ctrl->rcid_count);
> +               cbqri_controller_destroy(ctrl);
> +               return -EINVAL;
> +       }
> +
> +       ctrl->cache.cache_id = info->cache_id;
> +       ctrl->cache.cache_level = cache_level;
> +
> +       err = cbqri_probe_controller(ctrl);
> +       if (err) {
> +               cbqri_controller_destroy(ctrl);
> +               return err;
> +       }
> +
> +       /*
> +        * Allocation capability comes from the capabilities register probed
> +        * above, not from device tree. rcid_count only bounds the RCID range,
> +        * so a controller the hardware reports as alloc-capable but described
> +        * with no RCID count cannot be driven. Reject that inconsistency. A
> +        * monitoring-only controller (not alloc_capable) needs no RCID count.
> +        */
> +       if (ctrl->alloc_capable && !ctrl->rcid_count) {
> +               pr_warn("CC at %pa is alloc-capable but has no RCID count, skipping\n",
> +                       &ctrl->addr);
> +               cbqri_controller_destroy(ctrl);
> +               return -EINVAL;
> +       }
> +
> +       guard(mutex)(&cbqri_controllers_lock);
> +       list_add_tail(&ctrl->list, &cbqri_controllers);
> +       return 0;
> +}
> diff --git a/drivers/resctrl/cbqri_internal.h b/drivers/resctrl/cbqri_internal.h
> new file mode 100644
> index 000000000000..77429f39f874
> --- /dev/null
> +++ b/drivers/resctrl/cbqri_internal.h
> @@ -0,0 +1,122 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef _DRIVERS_RESCTRL_CBQRI_INTERNAL_H
> +#define _DRIVERS_RESCTRL_CBQRI_INTERNAL_H
> +
> +#include <linux/bitfield.h>
> +#include <linux/riscv_cbqri.h>
> +#include <linux/list.h>
> +#include <linux/mutex.h>
> +#include <linux/types.h>
> +
> +/* Capacity Controller (CC) MMIO register offsets. */
> +#define CBQRI_CC_CAPABILITIES_OFF 0
> +#define CBQRI_CC_ALLOC_CTL_OFF   24
> +#define CBQRI_CC_BLOCK_MASK_OFF  32
> +
> +/*
> + * Per CBQRI 3.5 the block-mask width BMW is the smallest multiple of 64 bits
> + * that holds NCBLKS, so cc_cunits sits at 32 + BMW/8 bytes. This constant is
> + * valid only while NCBLKS <= 64. cbqri_probe_cc() rejects ncblks > 32 before
> + * it reads cc_capabilities.CUNITS, forcing BMW to 64 bits, one 8-byte block
> + * mask, and cc_cunits at 0x28. Raising that cap above 64 would require
> + * computing 32 + roundup(ncblks, 64) / 8 instead of a constant.
> + */
> +#define CBQRI_CC_CUNITS_OFF      40
> +
> +/*
> + * Highest base register offset (cc_block_mask at 0x20) plus its 8-byte width.
> + * cbqri_probe_controller() rejects smaller mappings. cc_cunits at 0x28 is
> + * optional and only required when cc_capabilities.CUNITS is set, which
> + * cbqri_probe_cc() checks against the mapping size separately.
> + */
> +#define CBQRI_CTRL_MIN_REG_SPAN  0x28u
> +
> +#define CBQRI_CC_CAPABILITIES_VER_MINOR_MASK  GENMASK_ULL(3, 0)
> +#define CBQRI_CC_CAPABILITIES_VER_MAJOR_MASK  GENMASK_ULL(7, 4)
> +#define CBQRI_CC_CAPABILITIES_NCBLKS_MASK     GENMASK_ULL(23, 8)
> +#define CBQRI_CC_CAPABILITIES_CUNITS_MASK     BIT_ULL(25)
> +
> +/*
> + * CC control registers are 64-bit, but the CBQRI spec only guarantees
> + * single-copy atomicity for naturally aligned 4-byte accesses. They are read
> + * as two 32-bit halves (cbqri_readq) reconstructed into a u64 for field
> + * extraction, and written via the low 32-bit half, so the driver does not
> + * depend on native 64-bit MMIO. Keep every field mask GENMASK_ULL so
> + * FIELD_MODIFY() or ~mask on the reconstructed u64 never zero-extends a
> + * 32-bit mask and clobbers STATUS/BUSY/WPRI in bits 63:32.
> + */
> +#define CBQRI_CONTROL_REGISTERS_OP_MASK      GENMASK_ULL(4, 0)
> +#define CBQRI_CONTROL_REGISTERS_AT_MASK      GENMASK_ULL(7, 5)
> +/* AT field values (CBQRI Table 1): data vs code half for CDP */
> +#define CBQRI_CONTROL_REGISTERS_AT_DATA      0
> +#define CBQRI_CONTROL_REGISTERS_AT_CODE      1
> +#define CBQRI_CONTROL_REGISTERS_RCID_MASK    GENMASK_ULL(19, 8)
> +#define CBQRI_CONTROL_REGISTERS_STATUS_MASK  GENMASK_ULL(38, 32)
> +#define CBQRI_CONTROL_REGISTERS_BUSY_MASK    GENMASK_ULL(39, 39)
> +
> +#define CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT 1
> +#define CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT   2
> +#define CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS  1
> +
> +/* Capacity Controller hardware capabilities */
> +struct riscv_cbqri_capacity_caps {
> +       u16 ncblks;
> +       bool supports_alloc_at_code;
> +       /* cc_capabilities.CUNITS: controller enforces a capacity-unit limit */
> +       bool cunits;
> +};
> +
> +/**
> + * struct cbqri_cc_config - desired capacity allocation state for one rcid
> + * @cbm:         capacity block mask
> + * @at:          AT half the @cbm applies to (CBQRI_CONTROL_REGISTERS_AT_DATA
> + *               or CBQRI_CONTROL_REGISTERS_AT_CODE)
> + * @cdp_enabled: when false and the controller supports AT, mirror @cbm
> + *               into the other AT half so both stay in sync
> + */
> +struct cbqri_cc_config {
> +       u64  cbm;
> +       u32  at;
> +       bool cdp_enabled;
> +};
> +
> +struct cbqri_controller {
> +       void __iomem *base;
> +       /*
> +        * Serializes the write-then-poll-busy MMIO sequences on this
> +        * controller. Each CBQRI op may busy-wait up to 1 ms on slow
> +        * firmware, so use a sleeping mutex to keep preemption enabled.
> +        * All resctrl-arch entry points run in process context.
> +        */
> +       struct mutex lock;
> +
> +       struct riscv_cbqri_capacity_caps cc;
> +
> +       bool alloc_capable;
> +
> +       phys_addr_t addr;
> +       phys_addr_t size;
> +       enum cbqri_controller_type type;
> +       u32 rcid_count;
> +
> +       struct list_head list;
> +
> +       struct cache_controller {
> +               u32 cache_level;
> +               /* Cache id used as the resctrl domain id */
> +               u32 cache_id;
> +       } cache;
> +};
> +
> +extern struct list_head cbqri_controllers;
> +extern struct mutex cbqri_controllers_lock;
> +
> +void cbqri_controller_destroy(struct cbqri_controller *ctrl);
> +
> +int cbqri_apply_cache_config(struct cbqri_controller *ctrl, u32 closid,
> +                            const struct cbqri_cc_config *cfg);
> +
> +int cbqri_read_cache_config(struct cbqri_controller *ctrl, u32 closid,
> +                           u32 at, u32 *cbm_out);
> +
> +#endif /* _DRIVERS_RESCTRL_CBQRI_INTERNAL_H */
> diff --git a/include/linux/riscv_cbqri.h b/include/linux/riscv_cbqri.h
> new file mode 100644
> index 000000000000..e6b3febbed89
> --- /dev/null
> +++ b/include/linux/riscv_cbqri.h
> @@ -0,0 +1,45 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Public registration API for the RISC-V Capacity and Bandwidth QoS
> + * Register Interface (CBQRI) core. Discovery layers (device tree
> + * platform drivers) call riscv_cbqri_register_cc_dt() to hand a capacity
> + * controller descriptor to the core, which owns all subsequent state.
> + */
> +#ifndef _LINUX_RISCV_CBQRI_H
> +#define _LINUX_RISCV_CBQRI_H
> +
> +#include <linux/types.h>
> +
> +enum cbqri_controller_type {
> +       CBQRI_CONTROLLER_TYPE_CAPACITY,
> +};
> +
> +/**
> + * struct cbqri_controller_info - registration descriptor
> + * @addr:        MMIO base address of the controller's register interface
> + * @size:        size of the MMIO region
> + * @type:        controller type (capacity)
> + * @rcid_count:  number of supported RCIDs
> + * @cache_id:    cache id used as the resctrl domain id
> + */
> +struct cbqri_controller_info {
> +       phys_addr_t                     addr;
> +       phys_addr_t                     size;
> +       enum cbqri_controller_type      type;
> +       u32                             rcid_count;
> +       u32                             cache_id;
> +};
> +
> +#if IS_ENABLED(CONFIG_RISCV_CBQRI)
> +int riscv_cbqri_register_cc_dt(const struct cbqri_controller_info *info,
> +                              u32 cache_level);
> +#else
> +static inline int
> +riscv_cbqri_register_cc_dt(const struct cbqri_controller_info *info,
> +                          u32 cache_level)
> +{
> +       return -ENODEV;
> +}
> +#endif
> +
> +#endif /* _LINUX_RISCV_CBQRI_H */
>
> --
> 2.43.0
>

Thanks,
Yunhui

^ permalink raw reply

* Re: [RFC PATCH v3 0/3] mm/damon: introduce DAMOS_SPLIT action
From: Lian Wang @ 2026-07-20  9:56 UTC (permalink / raw)
  To: david
  Cc: damon, linux-mm, sj, akpm, linux-kernel, ljs, liam, vbabka, rppt,
	surenb, mhocko, npache, ziy, baolin.wang, ryan.roberts,
	daichaobing, wangkefeng.wang, gutierrez.asier, zengheng4, kasong,
	corbet, skhan, linux-doc, linux-kselftest, lianux.mm, lianux.wang,
	kunwu.chan
In-Reply-To: <59292ba2-e0cc-4e50-bb26-be9c15843a41@kernel.org>

Hi David,

On 7/20/2026 10:44 AM, David Hildenbrand (Arm) wrote:
> you give no real motivation and evaluation why this is required or
> why this gives the user any benefit.
> A SPLIT with an explicit order is not really want we want and it
> does not fit the existing primitives.

Thank you for the direct feedback.  Let me explain where this came
from -- the cover letter should have included this context.

This started from a real problem at Sangfor.  The scenario is:

  KVM-QEMU virtualization on Kunpeng 920, with KVM guest memory
  backed by tmpfs shared mappings (THP=always on the host).  An
  Oracle database runs inside the VM.  DAMON monitors the KVM
  process on the host to measure the hot-memory ratio.

  The KVM process allocates and uses a large amount of memory.
  Under the same workload, DAMON reports a significantly higher
  hot-memory ratio with THP enabled versus THP disabled.  Direct
  tmpfs write tests inside the VM -- touching at 4K and 2M
  strides -- show a clear gap between the two cases.

  DAMON parameters used:

    operations=vaddr
    monitoring_attrs/nr_regions/min=500
    monitoring_attrs/nr_regions/max=2000
    monitoring_attrs/intervals/sample_us=500000
    monitoring_attrs/intervals/aggr_us=20000000
    monitoring_attrs/intervals/update_us=60000000
    schemes/0/action=stat
    schemes/0/access_pattern/nr_accesses/min=1
    schemes/0/access_pattern/nr_accesses/max=max

The underlying issue is that under PMD-mapped THP, DAMON's monitoring
granularity is coarser than the actual working set -- a single
Accessed bit covers 512 base pages.  Before SJ's probe infrastructure
arrives, there is a gap: DAMON cannot distinguish hot sub-pages from
cold ones within a single THP.

Split is one possible mechanism to bridge that gap -- by dismantling
the PMD mapping, each base page gets its own PTE Accessed bit and
DAMON recovers fine-grain monitoring.  It is not intended to be a
permanent API, and certainly not "the opposite of collapse".

I did not write this scenario into the cover letter because our test
results do not yet show a clear quantitative benefit worth claiming,
and I did not want to oversell.  Without the context, I understand it
looks like I randomly proposed a new primitive -- that was not the
intention.

SJ acknowledged [1] that the monitoring problem under THP is real.
My RFC is a concrete proposal to start the discussion.  If split with
an explicit order is not the right primitive, I would appreciate your
thoughts on what the correct DAMOS abstraction for this should be.

[1] https://lore.kernel.org/20260620203915.82947-1-sj@kernel.org/

Thanks,
Lian Wang

^ permalink raw reply

* Re: [RFC PATCH v1 1/8] misc/arm-cla: Add driver skeleton and documentation
From: Ryan Roberts @ 2026-07-20  9:54 UTC (permalink / raw)
  To: Arnd Bergmann, Greg Kroah-Hartman, Catalin Marinas, Will Deacon,
	Mark Rutland, Jean-Philippe Brucker, Oded Gabbay, Jonathan Corbet
  Cc: linux-kernel, linux-arm-kernel, dri-devel, linux-doc
In-Reply-To: <2732dc3b-e3b0-4df6-9b63-f0de4eaca993@app.fastmail.com>

On 17/07/2026 17:10, Arnd Bergmann wrote:
> On Fri, Jul 17, 2026, at 17:44, Ryan Roberts wrote:
>> On 17/07/2026 14:49, Arnd Bergmann wrote:
>>> On Fri, Jul 17, 2026, at 12:47, Ryan Roberts wrote:
>>> This sounds a lot like st64bv or st64bv0, passing an 8-word payload and returning
>>> a single word per accelerator operation with shared addressing.
>>
>> We're actually passing 9 words here; 8 DATA words plus the LAUNCH word. CLA
>> supports only 64 bit aligned and sized accesses (other accesses are RAZ/WI) so
>> they have to be written as 9x64bit stores. Then poll using 64bit loads.
>>
>>>
>>> Why are there now two interfaces to do the same thing?
>>
>> Good question. This is how the HW operates.
>>
>>>
>>> Can a user process use st64bv to do the four steps in a
>>> single instruction?
>>
>> No, unfortunately not.
>>
> 
> Ok
> 
>>> Can a CPU start multiple asynchronous operations concurrently?
>>
>> Yes; STATUS indicates READY while it can accept more asynchronous operations
>> ("comamnds").
> 
> How does userspace know which operations have already completed
> then? (not worried about this bit, just trying to understand)

There is nothing architected in the CLA to determine this; You can determine
READY (i.e. can accept new commands) and IDLE (i.e. completed all previously
submitted commands). If you want to know when a specific command completed
without having to wait for all commands to complete, then you need extra
knowledge of the specific accelerator.

> 
>>> Do these continue to run if the starting process is scheduled out
>>> and another process also tries to use CLA?
>>
>> Yes; the driver manages assignment of a CLA to a process context completely
>> separately from the thread scheduler's decisions about which threads run on
>> which CPUs and when. If another process is scheduled onto the CPU and it
>> attempts to access it's VA for the CLA, it will fault into the driver's handler
>> and be put to sleep until the driver decides to reassign the CLA.
> 
> This part does sound dangerous, not in the sense that I think it's
> fundamentally broken, but in the complexity it adds.

Can you describe more about the complexity you see here? The intention is to
_reduce_ complexity by not coupling with the CPU scheduler.

> 
> I wonder if it's feasible to simplify this by always canceling
> any ongoing CLA operations during switch_mm():

The advice I've had so far is to avoid at all costs, coupling the CLA context
switch with the CPU context switch; there are concerns about the latency
impliciaitons for the CLA context switch and also a desire not to couple the CLA
device driver with arch code.

> 
> Is there an upper bound on how long a single operation can take,
> or a guarantee that an operation at least provides a partial result
> in hardware?

For the compute accelerator we have, operations are gauranteed to complete in
finite time, but that time could technically be very large. In practice
operations for known use cases range from a few microseconds to ~10 milliseconds.

As I described in a previous response, the accelerator does not support full
save/restore so if it is interrupted while running an operation, the operation
appears aborted when the state is next restored. Due to forward progress
concerns, we are looking at the possibility of a grace period (of the order of a
few milliseconds) during CLA reassignment. I'm pretty sure we wouldn't want to
insert that into the (non-preemptible) CPU context switch path...

> 
> From your earlier descriptions, it sounds like the CPU is usually
> assumed to wait for completion with WFE anyway, so from the
> scheduler's perspective, the thread is active while waiting for
> the accelerator to complete a job (even if from hardware side
> the CPU is powered down during WFE).

In practice the CPU will have some parallel work to prepare the next
operation(s) for submission, but yes, eventually it will enter a polling loop
waiting for accelarator completion with WFE.

> 
> If this is how it generally operates, and the accelerator jobs
> are usually fast, forcing the CLA TTBR0 to be the same as the
> CPU TTBR0 would avoid the entire problem of unmapping the registers
> on context switch, but instead let this hook into the same place
> as the corresponding iommu_mm_data switch on x86, which seems> to handle this
more nicely.
>

I agree this feels like a much simpler model on the surface but because the jobs
are not always fast and because the accelerator doesn't support full
save/restore, I don't think this approach flies in practice.

Thanks,
Ryan


>> I'm not sure what you mean by "Which instruction specifically causes the fault".
>> A fault occurs within the accelerator if it tries to access a virtual address
>> that is not mapped by the page table or if the permissions of the mapping are
>> not sufficient, etc... The fact that the accelerator has faulted is reported to
>> the SW that is polling the accelerator's STATUS register within user space. That
>> SW is expected to trigger fault handling by the usual kernel mechanisms by
>> accessing the VA. Then it issues a RESOLVE operation to tell the accelerator it
>> can continue.
> 
> Got it now. I had assumed that the page fault is delivered asynchronously
> to the kernel without user space getting involved. In this case, I think
> the interface is actually cleaner, though it does add a little bit
> of overhead for userspace having to decipher the status. 
>  
>>>> +User space software is expected to create a thread to drive each CLA it is
>>>> +using, and for each thread to be pinned to the CLA's local CPU.
>>>
>>> What happens if multiple processes have the same chardev open and
>>> each mmap() that, e.g. after a fork()? Does each process see its
>>> own virtual instance of the accelerator and interact with it through
>>> the same physical MMIO register range but its own process address space,
>>> or do you have to rely on the registers being mapped only into a
>>> single mm_struct to prevent a process from messing with another process
>>> data?
>>
>> The driver maintains a cla_ctx for each {file description, mm_struct} pair. So
>> in this case, even though the file description is shared between the parent and
>> child processes, they still have distinct mm_structs so still have separate
>> contexts allowing the driver to virtualize access correctly.
> 
> Ok, got it.
> 
>      Arnd


^ permalink raw reply

* Re: [RFC PATCH v3 1/3] mm/damon: introduce DAMOS_SPLIT action
From: Gutierrez Asier @ 2026-07-20  9:47 UTC (permalink / raw)
  To: Lian Wang, damon, linux-mm
  Cc: sj, akpm, linux-kernel, david, ljs, liam, vbabka, rppt, surenb,
	mhocko, npache, ziy, baolin.wang, ryan.roberts, daichaobing,
	wangkefeng.wang, zengheng4, kasong, corbet, skhan, linux-doc,
	linux-kselftest, lianux.wang, kunwu.chan
In-Reply-To: <20260720030327.80153-2-lianux.mm@gmail.com>



On 7/20/2026 6:03 AM, Lian Wang wrote:
> Add a new DAMOS action, DAMOS_SPLIT, that splits large folios in the
> target region down to a smaller order.  A new per-scheme field and sysfs
> file, target_order, selects the split target: 0 for order-0 base pages,
> or 2..HPAGE_PMD_ORDER-1 for a smaller mTHP order (order-1 is rejected at
> store time since anonymous THPs cannot be split to order-1).
> 
> Unlike DAMOS_COLLAPSE which builds large folios, splitting only dismantles
> them; it allocates nothing, copies nothing, and no THP admission policy
> applies.  khugepaged deliberately refuses to collapse a folio to a
> smaller order, leaving the shrink direction to callers like this one.
> 
> This patch adds the DAMOS_SPLIT action, the ``order`` field (placed in
> the existing union alongside target_nid and migrate_dests), its sysfs
> interface, and documentation.  The vaddr operations set handler is added
> in the next patch.
> 
> Link: https://lore.kernel.org/20260605161422.213817-9-npache@redhat.com/
>  ("mm/khugepaged: skip collapsing mTHP to smaller orders")
> 
> 
> 
> Co-developed-by: Kunwu Chan <kunwu.chan@linux.dev>
> Signed-off-by: Kunwu Chan <kunwu.chan@linux.dev>
> Signed-off-by: Lian Wang (Processmission) <lianux.mm@gmail.com>
> ---
>  .../ABI/testing/sysfs-kernel-mm-damon         |  7 +++
>  Documentation/mm/damon/design.rst             |  5 ++
>  include/linux/damon.h                         | 15 ++++--
>  mm/damon/core.c                               |  2 +
>  mm/damon/sysfs-schemes.c                      | 48 +++++++++++++++++++
>  tools/testing/selftests/damon/sysfs.py        | 11 +++--
>  6 files changed, 79 insertions(+), 9 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-kernel-mm-damon b/Documentation/ABI/testing/sysfs-kernel-mm-damon
> index 907a504fb64c..ee8e260a631c 100644
> --- a/Documentation/ABI/testing/sysfs-kernel-mm-damon
> +++ b/Documentation/ABI/testing/sysfs-kernel-mm-damon
> @@ -265,6 +265,13 @@ Contact:	SJ Park <sj@kernel.org>
>  Description:	Action's target NUMA node id.  Supported by only relevant
>  		actions.
>  
> +What:		/sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/target_order
> +Date:		Jul 2026
> +Contact:	SJ Park <sj@kernel.org>
Shouldn't this point to your email address?
> +Description:	Target folio order for the ``split`` action.  Large folios in
> +		the target region are split down to this order.  Valid values
> +		are 0 (order-0 base pages) and 2..HPAGE_PMD_ORDER-1.
> +
>  What:		/sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/apply_interval_us
>  Date:		Sep 2023
>  Contact:	SJ Park <sj@kernel.org>
> diff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst
> index aed6cb1cf483..87a801954b1b 100644
> --- a/Documentation/mm/damon/design.rst
> +++ b/Documentation/mm/damon/design.rst
> @@ -549,6 +549,11 @@ that supports each action are as below.
>     Supported by ``vaddr`` and ``fvaddr`` operations set. When
>     TRANSPARENT_HUGEPAGE is disabled, the application of the action will just
>     fail.
> + - ``split``: Split each large folio in the region down to the order specified
> +   by the scheme's ``target_order`` (``0`` for order-0 base pages, or
> +   ``2..HPAGE_PMD_ORDER-1``).  Supported by ``vaddr`` and ``fvaddr`` operations
> +   set. When TRANSPARENT_HUGEPAGE is disabled, the application of the action
> +   will just fail.
>   - ``lru_prio``: Prioritize the region on its LRU lists.
>     Supported by ``paddr`` operations set.
>   - ``lru_deprio``: Deprioritize the region on its LRU lists.
> diff --git a/include/linux/damon.h b/include/linux/damon.h
> index f69442a9d431..88b61b900a36 100644
> --- a/include/linux/damon.h
> +++ b/include/linux/damon.h
> @@ -110,6 +110,7 @@ struct damon_target {
>   * @DAMOS_HUGEPAGE:	Call ``madvise()`` for the region with MADV_HUGEPAGE.
>   * @DAMOS_NOHUGEPAGE:	Call ``madvise()`` for the region with MADV_NOHUGEPAGE.
>   * @DAMOS_COLLAPSE:	Call ``madvise()`` for the region with MADV_COLLAPSE.
> + * @DAMOS_SPLIT:	Split each large folio in the region to a smaller order.
>   * @DAMOS_LRU_PRIO:	Prioritize the region on its LRU lists.
>   * @DAMOS_LRU_DEPRIO:	Deprioritize the region on its LRU lists.
>   * @DAMOS_MIGRATE_HOT:  Migrate the regions prioritizing warmer regions.
> @@ -130,6 +131,7 @@ enum damos_action {
>  	DAMOS_HUGEPAGE,
>  	DAMOS_NOHUGEPAGE,
>  	DAMOS_COLLAPSE,
> +	DAMOS_SPLIT,
>  	DAMOS_LRU_PRIO,
>  	DAMOS_LRU_DEPRIO,
>  	DAMOS_MIGRATE_HOT,
> @@ -582,10 +584,15 @@ struct damos {
>  	struct damos_quota quota;
>  	struct damos_watermarks wmarks;
>  	union {
> -		struct {
> -			int target_nid;
> -			struct damos_migrate_dests migrate_dests;
> -		};
> +		int target_nid;
> +		struct damos_migrate_dests migrate_dests;
Shouldn't we keep target_nid and migrate_dests together using a
struct, as in the initial code?
> +		/*
> +		 * @order: target folio order for DAMOS_SPLIT.
> +		 * Split large folios down to this order.  0 for
> +		 * order-0 base pages, 2..HPAGE_PMD_ORDER-1 for
> +		 * smaller mTHP.  Order-1 is rejected.
> +		 */
> +		unsigned int order;
>  	};
>  	struct list_head core_filters;
>  	struct list_head ops_filters;
> diff --git a/mm/damon/core.c b/mm/damon/core.c
> index 806a67d02a6e..394c62455ad5 100644
> --- a/mm/damon/core.c
> +++ b/mm/damon/core.c
> @@ -693,6 +693,7 @@ struct damos *damon_new_scheme(struct damos_access_pattern *pattern,
>  		return NULL;
>  	scheme->pattern = *pattern;
>  	scheme->action = action;
> +	scheme->order = 0;
>  	scheme->apply_interval_us = apply_interval_us;
>  	/*
>  	 * next_apply_sis will be set when kdamond starts.  While kdamond is
> @@ -1446,6 +1447,7 @@ static int damos_commit(struct damos *dst, struct damos *src)
>  
>  	dst->pattern = src->pattern;
>  	dst->action = src->action;
> +	dst->order = src->order;
>  	dst->apply_interval_us = src->apply_interval_us;
>  
>  	err = damos_commit_quota(&dst->quota, &src->quota);
> diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
> index 32f495a96b17..725ed81ccf6c 100644
> --- a/mm/damon/sysfs-schemes.c
> +++ b/mm/damon/sysfs-schemes.c
> @@ -4,7 +4,9 @@
>   */
>  
>  #include <linux/slab.h>
> +#include <linux/mm.h>
>  #include <linux/numa.h>
> +#include <linux/huge_mm.h>
>  
>  #include "sysfs-common.h"
>  
> @@ -2260,6 +2262,7 @@ struct damon_sysfs_scheme {
>  	struct damon_sysfs_stats *stats;
>  	struct damon_sysfs_scheme_regions *tried_regions;
>  	int target_nid;
> +	unsigned int target_order;
>  	struct damos_sysfs_dests *dests;
>  };
>  
> @@ -2293,6 +2296,10 @@ static struct damos_sysfs_action_name damos_sysfs_action_names[] = {
>  		.action = DAMOS_COLLAPSE,
>  		.name = "collapse",
>  	},
> +	{
> +		.action = DAMOS_SPLIT,
> +		.name = "split",
> +	},
>  	{
>  		.action = DAMOS_LRU_PRIO,
>  		.name = "lru_prio",
> @@ -2326,6 +2333,7 @@ static struct damon_sysfs_scheme *damon_sysfs_scheme_alloc(
>  	scheme->action = action;
>  	scheme->apply_interval_us = apply_interval_us;
>  	scheme->target_nid = NUMA_NO_NODE;
> +	scheme->target_order = 0;
>  	return scheme;
>  }
>  
> @@ -2645,6 +2653,40 @@ static ssize_t target_nid_store(struct kobject *kobj,
>  	return err ? err : count;
>  }
>  
> +static ssize_t target_order_show(struct kobject *kobj,
> +		struct kobj_attribute *attr, char *buf)
> +{
> +	struct damon_sysfs_scheme *scheme = container_of(kobj,
> +			struct damon_sysfs_scheme, kobj);
> +
> +	return sysfs_emit(buf, "%u\n", scheme->target_order);
> +}
> +
> +static ssize_t target_order_store(struct kobject *kobj,
> +		struct kobj_attribute *attr, const char *buf, size_t count)
> +{
> +	struct damon_sysfs_scheme *scheme = container_of(kobj,
> +			struct damon_sysfs_scheme, kobj);
> +	unsigned int val;
> +	int err;
Move the variable declaration to the top of the function.
> +
> +	err = kstrtouint(buf, 0, &val);
> +	if (err)
> +		return err;
> +
> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> +	/* Valid split targets: 0 (order-0 base pages) or 2..HPAGE_PMD_ORDER-1. */
> +	if (val != 0 && (val < 2 || val >= HPAGE_PMD_ORDER))
> +		return -EINVAL;
> +#else
> +	if (val != 0)
> +		return -EINVAL;
> +#endif
> +
> +	scheme->target_order = val;
> +	return count;
> +}
> +
>  static void damon_sysfs_scheme_release(struct kobject *kobj)
>  {
>  	kfree(container_of(kobj, struct damon_sysfs_scheme, kobj));
> @@ -2659,10 +2701,14 @@ static struct kobj_attribute damon_sysfs_scheme_apply_interval_us_attr =
>  static struct kobj_attribute damon_sysfs_scheme_target_nid_attr =
>  		__ATTR_RW_MODE(target_nid, 0600);
>  
> +static struct kobj_attribute damon_sysfs_scheme_target_order_attr =
> +		__ATTR_RW_MODE(target_order, 0600);
> +
>  static struct attribute *damon_sysfs_scheme_attrs[] = {
>  	&damon_sysfs_scheme_action_attr.attr,
>  	&damon_sysfs_scheme_apply_interval_us_attr.attr,
>  	&damon_sysfs_scheme_target_nid_attr.attr,
> +	&damon_sysfs_scheme_target_order_attr.attr,
>  	NULL,
>  };
>  ATTRIBUTE_GROUPS(damon_sysfs_scheme);
> @@ -3011,6 +3057,8 @@ static struct damos *damon_sysfs_mk_scheme(
>  	if (!scheme)
>  		return NULL;
>  
> +	scheme->order = sysfs_scheme->target_order;
> +
>  	err = damos_sysfs_add_quota_score(sysfs_quotas->goals, &scheme->quota);
>  	if (err) {
>  		damon_destroy_scheme(scheme);
> diff --git a/tools/testing/selftests/damon/sysfs.py b/tools/testing/selftests/damon/sysfs.py
> index 3ffa054b6386..49d3c319dfd8 100755
> --- a/tools/testing/selftests/damon/sysfs.py
> +++ b/tools/testing/selftests/damon/sysfs.py
> @@ -131,11 +131,12 @@ def assert_scheme_committed(scheme, dump):
>              'hugepage': 3,
>              'nohugepage': 4,
>              'collapse': 5,
> -            'lru_prio': 6,
> -            'lru_deprio': 7,
> -            'migrate_hot': 8,
> -            'migrate_cold': 9,
> -            'stat': 10,
> +            'split': 6,
> +            'lru_prio': 7,
> +            'lru_deprio': 8,
> +            'migrate_hot': 9,
> +            'migrate_cold': 10,
> +            'stat': 11,
>              }
>      assert_true(dump['action'] == action_val[scheme.action], 'action', dump)
>      assert_true(dump['apply_interval_us'] == scheme. apply_interval_us,
> 

-- 
Asier Gutierrez
Huawei


^ permalink raw reply

* Re: [RFC PATCH v3 0/3] mm/damon: introduce DAMOS_SPLIT action
From: David Hildenbrand (Arm) @ 2026-07-20  9:44 UTC (permalink / raw)
  To: Lian Wang, damon, linux-mm
  Cc: sj, akpm, linux-kernel, ljs, liam, vbabka, rppt, surenb, mhocko,
	npache, ziy, baolin.wang, ryan.roberts, daichaobing,
	wangkefeng.wang, gutierrez.asier, zengheng4, kasong, corbet,
	skhan, linux-doc, linux-kselftest, lianux.wang, kunwu.chan
In-Reply-To: <20260720030327.80153-1-lianux.mm@gmail.com>

On 7/20/26 04:03, Lian Wang wrote:
> DAMOS_SPLIT splits large folios in a target region down to a
> configured target order, using the existing split_folio_to_order().
> No new core-mm code or exported symbols are introduced.
> 
> Based on mm-unstable at 61cccb8363fc ("mm/swap, PM: hibernate:
> atomically replace hibernation pin").
> 
> Different addresses within a PMD-mapped folio resolve to the same
> PMD Accessed bit.  Accesses to a small part of the folio can
> therefore coarsen DAMON's observed hot set relative to the actual
> working set.
> 
> DAMOS already provides promotion actions (HUGEPAGE, COLLAPSE) but
> has no corresponding demotion action.  DAMOS_SPLIT fills this gap.
> It is a mechanism, not a policy -- it does not decide which folios
> to split.  Selection is left to DAMON's existing access patterns,
> filters, and future probe/PMU signals.
> 
> target_order selects the split target: 0 for order-0 base pages,
> or a supported smaller mTHP order.  Both anonymous and file-backed
> folios are supported.  The locking follows split_huge_pages_in_pid()
> in mm/huge_memory.c.
> 
> Tests
> =====
> 
> damos_split.py (VM + Kunpeng 920):
>   anon THP -> order-0 split: PASS
> 
> sangfor_exp.py (Kunpeng 920, tmpfs, 4096 MiB):
> 
>   - Created a 4 GiB PMD-mapped tmpfs workload.
>   - Applied DAMOS_SPLIT with target_order=0.
>   - ShmemPmdMapped dropped from 4194304 KiB to 0 in every round.
>   - Repeated for five rounds without functional failures.
> 
> The functional selftest (damos_split.py) is included in this series.
> Additional experiment scripts and raw results are available on
> request.  Performance characterization using masim [1] and KMB [2]
> is in progress.
> 
> [1] https://github.com/sjp38/masim
> [2] https://gitee.com/OpenCloudOS/kernel-multi-bench

Hi,

you give no real motivation and evaluation why this is required or why this
gives the user any benefit.

HUGEPAGE + COLLAPSE is clear: give me THPs in a size not controlled by user
space, because the expectation is that this memory will be performance sensitive.

A SPLIT with an explicit order is not really want we want and it does not fit
the existing primitives.

-- 
Cheers,

David

^ permalink raw reply

* Re: [RFC PATCH v3 0/3] mm/damon: introduce DAMOS_SPLIT action
From: Lian Wang @ 2026-07-20  9:43 UTC (permalink / raw)
  To: gutierrez.asier
  Cc: damon, linux-mm, sj, akpm, linux-kernel, david, ljs, liam, vbabka,
	rppt, surenb, mhocko, npache, ziy, baolin.wang, ryan.roberts,
	daichaobing, wangkefeng.wang, zengheng4, kasong, corbet, skhan,
	linux-doc, linux-kselftest, lianux.mm, lianux.wang, kunwu.chan
In-Reply-To: <a168a9f2-953b-4ecb-98ee-ec6b27f4d963@huawei-partners.com>

Hi Asier,

Thanks for the quick feedback.

On 7/20/2026 12:28 PM, Gutierrez Asier wrote:
> You should mention why page split is be needed. The fact that page
> collapsing exist doesn't necessarily mean that split should exist.

Fair point.  The underlying problem I'm trying to address is that
DAMON's vaddr monitoring loses accuracy under PMD-mapped THP:
multiple sampled addresses share a single Accessed bit, so the
observed hot set is coarser than the true working set.  Split is one
way to restore fine-grain monitoring -- by dismantling the PMD
mapping, each base page gets its own PTE Accessed bit and DAMON can
see the real access distribution again.

Split is not the only possible approach, and it is certainly not
intended to be "the opposite of collapse".  It is just one concrete
proposal to start the discussion.  What I really care about is
whether the community agrees that this monitoring granularity problem
is worth solving.  If there are better ways to address it, I'm very
open to that direction.

The RFC is as much about the problem as it is about the mechanism.
Feedback on real workloads that suffer from this coarsening, and on
alternative approaches, is exactly what I'm hoping for.

> Could you add v1 as well?

Good catch, will add in the next revision.

[1] https://lore.kernel.org/20260620203915.82947-1-sj@kernel.org/

Thanks,
Lian Wang

^ permalink raw reply

* Re: [RFC PATCH v3 0/3] mm/damon: introduce DAMOS_SPLIT action
From: Gutierrez Asier @ 2026-07-20  9:28 UTC (permalink / raw)
  To: Lian Wang, damon, linux-mm
  Cc: sj, akpm, linux-kernel, david, ljs, liam, vbabka, rppt, surenb,
	mhocko, npache, ziy, baolin.wang, ryan.roberts, daichaobing,
	wangkefeng.wang, zengheng4, kasong, corbet, skhan, linux-doc,
	linux-kselftest, lianux.wang, kunwu.chan
In-Reply-To: <20260720030327.80153-1-lianux.mm@gmail.com>

Hi Lian,

On 7/20/2026 6:03 AM, Lian Wang wrote:
> DAMOS_SPLIT splits large folios in a target region down to a
> configured target order, using the existing split_folio_to_order().
> No new core-mm code or exported symbols are introduced.
> 
> Based on mm-unstable at 61cccb8363fc ("mm/swap, PM: hibernate:
> atomically replace hibernation pin").
> 
> Different addresses within a PMD-mapped folio resolve to the same
> PMD Accessed bit.  Accesses to a small part of the folio can
> therefore coarsen DAMON's observed hot set relative to the actual
> working set.
> 
> DAMOS already provides promotion actions (HUGEPAGE, COLLAPSE) but
> has no corresponding demotion action.  DAMOS_SPLIT fills this gap.
> It is a mechanism, not a policy -- it does not decide which folios
> to split.  Selection is left to DAMON's existing access patterns,
> filters, and future probe/PMU signals.
You should mention why page split is be needed. The fact that page
collapsing exist doesn't necessarily mean that split should exist.

I agree that it is a nice feature, but it should be backed in the
cover letter.
> target_order selects the split target: 0 for order-0 base pages,
> or a supported smaller mTHP order.  Both anonymous and file-backed
> folios are supported.  The locking follows split_huge_pages_in_pid()
> in mm/huge_memory.c.
> 
> Tests
> =====
> 
> damos_split.py (VM + Kunpeng 920):
>   anon THP -> order-0 split: PASS
> 
> sangfor_exp.py (Kunpeng 920, tmpfs, 4096 MiB):
> 
>   - Created a 4 GiB PMD-mapped tmpfs workload.
>   - Applied DAMOS_SPLIT with target_order=0.
>   - ShmemPmdMapped dropped from 4194304 KiB to 0 in every round.
>   - Repeated for five rounds without functional failures.
> 
> The functional selftest (damos_split.py) is included in this series.
> Additional experiment scripts and raw results are available on
> request.  Performance characterization using masim [1] and KMB [2]
> is in progress.
> 
> [1] https://github.com/sjp38/masim
> [2] https://gitee.com/OpenCloudOS/kernel-multi-bench
> 
> Open questions
> ==============
> 
> - Selection policy: this series keeps folio selection outside the
>   action and relies on DAMOS access patterns, filters, and quotas.
>   Is this the appropriate layering for future probe-based signals?
> 
> - Hysteresis: khugepaged may re-collapse a just-split folio.
>   Should cooldown live in DAMON policy or khugepaged?
> 
> - File-backed folios: adjust target_order upward to filesystem
>   minimum, or keep current "fail and skip"?
> 
> Beyond the action API itself, feedback on real workloads that need
> proactive large-folio demotion is particularly welcome.  Follow-up
> work will evaluate candidate selection signals, including DAMON
> probes and hardware-assisted sampling, as well as target-order
> selection and split/collapse hysteresis.  Those policies are
> intentionally kept outside this series.
> Changes since v2 [3]
> ====================
> 
> - Split-only series (collapse deferred).
> - Dropped SPE feedback (mechanism/policy separation).
> - DAMOS_MTHP_SPLIT -> DAMOS_SPLIT.
> - order field in existing union (no struct size increase).
> - Added functional selftest (damos_split.py).
> - checkpatch: 0 errors, 0 warnings.
> 
> [3] https://lore.kernel.org/20260701123000.00000-1-lianux.mm@gmail.com/
Could you add v1 as well?
> 
> Lian Wang (Processmission) (3):
>   mm/damon: introduce DAMOS_SPLIT action
>   mm/damon/vaddr: implement DAMOS_SPLIT handler
>   selftests/damon: add functional test for DAMOS_SPLIT
> 
>  .../ABI/testing/sysfs-kernel-mm-damon         |  7 ++
>  Documentation/mm/damon/design.rst             |  5 +
>  include/linux/damon.h                         | 15 ++-
>  mm/damon/core.c                               |  2 +
>  mm/damon/sysfs-schemes.c                      | 48 +++++++
>  mm/damon/vaddr.c                              | 90 +++++++++++++
>  tools/testing/selftests/damon/Makefile        |  1 +
>  tools/testing/selftests/damon/_damon_sysfs.py |  9 +-
>  tools/testing/selftests/damon/damos_split.py  | 99 +++++++++++++++
>  tools/testing/selftests/damon/sysfs.py        | 11 +-
>  10 files changed, 279 insertions(+), 8 deletions(-)
> 

-- 
Asier Gutierrez
Huawei


^ permalink raw reply

* Re: [PATCH 6/6] blk-crypto: Update docs for blk-crypto-fallback motivation
From: Christoph Hellwig @ 2026-07-20  9:28 UTC (permalink / raw)
  To: Eric Biggers
  Cc: linux-fscrypt, linux-block, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, linux-doc
In-Reply-To: <20260718214655.63186-7-ebiggers@kernel.org>

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


^ permalink raw reply

* Re: [PATCH 5/6] blk-crypto: Remove unused function blk_crypto_config_supported()
From: Christoph Hellwig @ 2026-07-20  9:28 UTC (permalink / raw)
  To: Eric Biggers
  Cc: linux-fscrypt, linux-block, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, linux-doc
In-Reply-To: <20260718214655.63186-6-ebiggers@kernel.org>

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply

* Re: [PATCH 4/6] fscrypt: Update docs for data path
From: Christoph Hellwig @ 2026-07-20  9:28 UTC (permalink / raw)
  To: Eric Biggers
  Cc: linux-fscrypt, linux-block, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, linux-doc
In-Reply-To: <20260718214655.63186-5-ebiggers@kernel.org>

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


^ permalink raw reply

* Re: [PATCH 3/6] fscrypt: Remove unused function fscrypt_finalize_bounce_page()
From: Christoph Hellwig @ 2026-07-20  9:26 UTC (permalink / raw)
  To: Eric Biggers
  Cc: linux-fscrypt, linux-block, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, linux-doc
In-Reply-To: <20260718214655.63186-4-ebiggers@kernel.org>

On Sat, Jul 18, 2026 at 02:46:52PM -0700, Eric Biggers wrote:
> fscrypt_finalize_bounce_page() is no longer called, so remove it.

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


^ permalink raw reply

* Re: [PATCH 2/6] f2fs: Update outdated comment in f2fs_write_begin()
From: Christoph Hellwig @ 2026-07-20  9:25 UTC (permalink / raw)
  To: Eric Biggers
  Cc: linux-fscrypt, linux-block, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, linux-doc
In-Reply-To: <20260718214655.63186-3-ebiggers@kernel.org>

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


^ permalink raw reply

* Re: [PATCH 1/6] fs: Update outdated comment for SB_INLINECRYPT
From: Christoph Hellwig @ 2026-07-20  9:25 UTC (permalink / raw)
  To: Eric Biggers
  Cc: linux-fscrypt, linux-block, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, linux-doc
In-Reply-To: <20260718214655.63186-2-ebiggers@kernel.org>

On Sat, Jul 18, 2026 at 02:46:50PM -0700, Eric Biggers wrote:
> Update the comment for SB_INLINECRYPT to match the latest code, where
> SB_INLINECRYPT now controls whether blk-crypto uses inline encryption
> hardware rather than whether blk-crypto is used.

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


^ permalink raw reply

* Re: [PATCH 0/4] vmcore-tasks: export per-task metadata to vmcoreinfo
From: Simon Horman @ 2026-07-20  9:19 UTC (permalink / raw)
  To: Mike Rapoport
  Cc: Pnina Feder, Andrew Morton, Baoquan He, Pasha Tatashin,
	Pratyush Yadav, Thomas Bogendoerfer, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Dave Young, Jonathan Corbet,
	Alexandre Ghiti, kexec, linux-kernel, linux-mips, linux-riscv,
	linux-doc
In-Reply-To: <akybBoCAm-kJbfHL@kernel.org>

On Tue, Jul 07, 2026 at 09:21:58AM +0300, Mike Rapoport wrote:
> (adding new Baoquan's email)
> 
> Hi Pnina,
> On Tue, Jun 23, 2026 at 12:14:26AM +0300, Pnina Feder wrote:
> > This series extends vmcoreinfo with struct offsets and sizes needed by
> > the vmcore-tasks userspace tool to extract per-task state from a vmcore
> > dump without requiring kernel debug symbols (DWARF/BTF).
> > 
> > The vmcore-tasks tool reads /proc/vmcore (or a saved vmcore file) and
> > reconstructs, for each task:
> >   - task name, pid, state, flags
> >   - VMA list (start, end, flags, backing file)
> >   - user register state (saved on the kernel stack at kernel entry)
> >   - user-space backtrace with VMA/filename mapping
> >   - kernel dmesg buffer
> > 
> > This provides a lightweight post-mortem crash analysis capability for
> > production environments where full debug info (DWARF/BTF) is not
> > available.
> > 
> > The companion userspace tool is submitted to kexec-tools:
> >   https://lore.kernel.org/all/20260622205550.1087163-1-pnina.feder@mobileye.com/
> 
> Sorry for the delay, this fell between the cracks somehow.
> 
> The kernel side looks fine overall, but to merge it there should be an
> agreement from the userspace side maintainers that vmcore-tasks is
> something they are wishing to accept.

Hi Mike, all,

Sorry for the extended delay.

I will send some minor feedback to the user-space tool patchset
but overall, yes, this is something I would be happy to accept.

I don't want to create a chicken-and-egg type problem here.
But it's probably worth mentioning that usually features
hit the kernel before the corresponding code is accepted
into kexec-tools.

Let me know how you would like to proceed.

^ permalink raw reply

* Re: [PATCH v3 3/3] Documentation: deprecated.rst: kmalloc-family: mark argument as optional
From: Manuel Ebner @ 2026-07-20  8:38 UTC (permalink / raw)
  To: Jonathan Corbet, Shuah Khan, linux-doc, Kees Cook, linux-kernel
  Cc: workflows, linux-mm, Geert Uytterhoeven, Janitors
In-Reply-To: <871pg0ras8.fsf@trenco.lwn.net>

On Mon, 2026-04-27 at 03:51 -0600, Jonathan Corbet wrote:
> Manuel Ebner <manuelebner@mailbox.org> writes:
> 
> > put the optional argument (gfp) in square brackets
> > add whitespace for readability
> > 
> > eg. ptr = kmalloc_obj(*ptr, gfp);
> >  -> ptr = kmalloc_obj(*ptr [, gfp] );
> > 
> > Signed-off-by: Manuel Ebner <manuelebner@mailbox.org>
> > ---
> >  Documentation/process/deprecated.rst | 12 ++++++------
> >  1 file changed, 6 insertions(+), 6 deletions(-)
> > 
> > diff --git a/Documentation/process/deprecated.rst
> > b/Documentation/process/deprecated.rst
> > index fed56864d036..b431993fd08e 100644
> > --- a/Documentation/process/deprecated.rst
> > +++ b/Documentation/process/deprecated.rst
> > @@ -392,12 +392,12 @@ allocations. For example, these open coded assignments::
> >  
> >  become, respectively::
> >  
> > -	ptr = kmalloc_obj(*ptr, gfp);
> > -	ptr = kzalloc_obj(*ptr, gfp);
> > -	ptr = kmalloc_objs(*ptr, count, gfp);
> > -	ptr = kzalloc_objs(*ptr, count, gfp);
> > -	ptr = kmalloc_flex(*ptr, flex_member, count, gfp);
> > -	__auto_type ptr = kmalloc_obj(struct foo, gfp);
> > +	ptr = kmalloc_obj(*ptr [, gfp] );
> > +	ptr = kzalloc_obj(*ptr [, gfp] );
> > +	ptr = kmalloc_objs(*ptr, count [, gfp] );
> > +	ptr = kzalloc_objs(*ptr, count [, gfp] );
> > +	ptr = kmalloc_flex(*ptr, flex_member, count [, gfp] );
> > +	__auto_type ptr = kmalloc_obj(struct foo [, gfp] );
> >  
> 
> Marking the GFP argument as optional is fine, but the documentation
> should surely say what the default is.
> 
> There are, of course, other kmalloc()-related entries in that file that
> could use an update, but that is a job for another time, I guess.

KTODO: Update the sections suggesting to use th deprecated
kamlloc(_array)() functions.

Thanks
 Manuel

> Thanks,
> 
> jon

^ permalink raw reply

* Re: [RFC PATCH 0/7] mm: defer address-space teardown of large exiting processes to a kthread
From: David Hildenbrand (Arm) @ 2026-07-20  8:13 UTC (permalink / raw)
  To: Aditya Sharma, Andrew Morton, Lorenzo Stoakes, Liam R . Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko
  Cc: David Rientjes, Shakeel Butt, Jonathan Corbet, Shuah Khan,
	Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers, Kees Cook,
	Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot,
	Dietmar Eggemann, Ben Segall, Mel Gorman, Valentin Schneider,
	K Prateek Nayak, linux-mm, linux-doc, linux-trace-kernel,
	linux-kernel, imbrenda
In-Reply-To: <20260719185409.409685-1-adi.sharma@zohomail.in>

On 7/19/26 19:54, Aditya Sharma wrote:
> Address-space teardown on process exit runs synchronously in the dying
> task's context: exit_mm() -> mmput() -> __mmput() -> exit_mmap() walks
> page tables, updates rmap, frees the RSS and drops file references, all
> on the exiting CPU. For a multi-GB process that is hundreds of
> milliseconds of exit-path latency, paid by whoever is waiting on the
> death: a supervisor's kill-and-respawn cycle, a shell's waitpid(), an
> orchestrator reaping a fleet of workers. On the test box below, killing
> a 16GB process costs ~280ms before the parent's waitpid() returns.
> 
> This series adds CONFIG_ASYNC_MM_TEARDOWN: an opt-in, default-off path
> that defers __mmput() of large exiting processes to a dedicated kernel
> thread (mm_reaper), so the exiting CPU is released as soon as the task
> is reaped and the teardown runs off to the side.

QEMU has an rather short implementation for async teardown using
clone(CLONE_VM), which is IIRC essentially the result of Claudios previous
kernel work you note below.

So nothing got merged because the problem was solvable in userspace.

Without something like CONFIG_ASYNC_MM_TEARDOWN in the kernel.

[1] https://github.com/qemu/qemu/blob/master/system/async-teardown.c

-- 
Cheers,

David

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox