* Re: [PATCH v5 11/13] iio: frequency: ad9910: show channel priority in debugfs
From: Jonathan Cameron @ 2026-05-22 18:07 UTC (permalink / raw)
To: Rodrigo Alencar via B4 Relay
Cc: rodrigo.alencar, linux-iio, devicetree, linux-kernel, linux-doc,
linux-hardening, Lars-Peter Clausen, Michael Hennerich,
David Lechner, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Jonathan Corbet, Shuah Khan,
Kees Cook, Gustavo A. R. Silva
In-Reply-To: <20260517-ad9910-iio-driver-v5-11-31599c88314a@analog.com>
On Sun, 17 May 2026 19:37:55 +0100
Rodrigo Alencar via B4 Relay <devnull+rodrigo.alencar.analog.com@kernel.org> wrote:
> From: Rodrigo Alencar <rodrigo.alencar@analog.com>
>
> Expose frequency_source, phase_source and amplitude_source attributes in
> debugfs. Those indicate from which channel the specific DDS parameter is
> being sourced by returning its label. The implementation follows the
> priority table found in the datasheet.
>
Examples here would be good.
I guess maybe this suffers the same label problem as the parent stuff.
Same solution?
> Signed-off-by: Rodrigo Alencar <rodrigo.alencar@analog.com>
^ permalink raw reply
* Re: [PATCH v5 06/13] iio: frequency: ad9910: initial driver implementation
From: Jonathan Cameron @ 2026-05-22 18:03 UTC (permalink / raw)
To: Rodrigo Alencar via B4 Relay
Cc: rodrigo.alencar, linux-iio, devicetree, linux-kernel, linux-doc,
linux-hardening, Lars-Peter Clausen, Michael Hennerich,
David Lechner, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Jonathan Corbet, Shuah Khan,
Kees Cook, Gustavo A. R. Silva
In-Reply-To: <20260517-ad9910-iio-driver-v5-6-31599c88314a@analog.com>
On Sun, 17 May 2026 19:37:50 +0100
Rodrigo Alencar via B4 Relay <devnull+rodrigo.alencar.analog.com@kernel.org> wrote:
> From: Rodrigo Alencar <rodrigo.alencar@analog.com>
>
> Add the core AD9910 DDS driver infrastructure with single tone mode
> support. This includes SPI register access, profile management via GPIO
> pins, PLL/DAC configuration from firmware properties, and single tone
> frequency/phase/amplitude control through IIO attributes.
>
> Signed-off-by: Rodrigo Alencar <rodrigo.alencar@analog.com>
Hi Rodrigo
A couple of potential nice to haves.
Jonathan
> +
> +static int ad9910_parse_fw(struct ad9910_state *st)
> +{
> + static const char * const refclk_out_drv0[] = {
> + "disabled", "low", "medium", "high",
> + };
> + struct device *dev = &st->spi->dev;
> + u32 tmp[2];
> + int ret;
> +
> + st->data.pll_enabled = device_property_read_bool(dev, "adi,pll-enable");
> + if (st->data.pll_enabled) {
> + tmp[0] = AD9910_ICP_MIN_uA;
> + device_property_read_u32(dev, "adi,charge-pump-current-microamp", &tmp[0]);
Might be a good idea to move to the pattern that seems to be becoming
the preferred way to do this and do
if (device_property_present()) {
ret = device_property_read_u32()...
...
} else {
...
}
That is slightly nicer ad picks up malformed DT. I know I was the advocate for
the set a default and don't check ret but I'm learning!
> + if (tmp[0] < AD9910_ICP_MIN_uA || tmp[0] > AD9910_ICP_MAX_uA)
> + return dev_err_probe(dev, -ERANGE,
> + "invalid charge pump current %u\n", tmp[0]);
> + st->data.pll_charge_pump_current = tmp[0];
> +
> + ret = device_property_match_property_string(dev,
> + "adi,refclk-out-drive-strength",
> + refclk_out_drv0,
> + ARRAY_SIZE(refclk_out_drv0));
> + if (ret < 0)
Similarly good to know if failure to match actually means wasn't there or not.
> + st->data.refclk_out_drv = AD9910_REFCLK_OUT_DRV_DISABLED;
> + else
> + st->data.refclk_out_drv = ret;
> + }
> +
> + tmp[1] = AD9910_DAC_IOUT_DEFAULT_uA;
And similar again.
> + device_property_read_u32_array(dev, "output-range-microamp", tmp,
> + ARRAY_SIZE(tmp));
> + if (tmp[1] < AD9910_DAC_IOUT_MIN_uA || tmp[1] > AD9910_DAC_IOUT_MAX_uA)
> + return dev_err_probe(dev, -ERANGE,
> + "Invalid DAC output current %u uA\n", tmp[1]);
> + st->data.dac_output_current = tmp[1];
> +
> + return 0;
> +}
> +static const struct spi_device_id ad9910_id[] = {
> + { "ad9910" },
Request to simplify what Uwe is busy doing (assuming he'll get to spi
at somepoint). Please use a named initializer like we always do for
of_device_id.
> + { }
> +};
> +MODULE_DEVICE_TABLE(spi, ad9910_id);
^ permalink raw reply
* Re: [PATCH v5 10/11] PCI: liveupdate: Do not disable bus mastering on preserved devices during kexec
From: Bjorn Helgaas @ 2026-05-22 18:01 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-mm, linux-pci,
Adithya Jayachandran, Alexander Graf, Alex Williamson,
Bjorn Helgaas, Chris Li, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Leon Romanovsky,
Lukas Wunner, Mike Rapoport, Parav Pandit, Pasha Tatashin,
Pranjal Shrivastava, Pratyush Yadav, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Vipin Sharma, William Tu, Yi Liu
In-Reply-To: <20260512184846.119396-11-dmatlack@google.com>
On Tue, May 12, 2026 at 06:48:45PM +0000, David Matlack wrote:
> Do not disable bus mastering on outgoing preserved devices during
> pci_device_shutdown() for kexec.
>
> Preserved devices must be allowed to perform memory transactions during
> a Live Update to minimize downtime and ensure continuous operation.
> Clearing the bus mastering bit would prevent these devices from issuing
> any memory requests while the new kernel boots.
s/minimize downtime and//
Ensuring continuous operation is the critical piece here. Minimizing
downtime is always good but IMO it's not actually a reason for this
change.
I guess what this is probably saying is that the continuous operation
and Live Update are what minimizes downtime, and preserving bus
mastering is a piece of that.
> Because bridges upstream of preserved endpoint devices are also
> automatically preserved, this change also avoids clearing bus mastering
> on them. This is critical because clearing bus mastering on an upstream
> bridge prevents the bridge from forwarding memory requests upstream (i.e.
> it would prevent the endpoint device from accessing system RAM and doing
> peer-to-peer transactions with devices not downstream of the bridge).
^ permalink raw reply
* [PATCH 3/3] arm64: Sort registers in cpu-feature-registers.rst
From: Mark Brown @ 2026-05-22 17:58 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Jonathan Corbet, Shuah Khan
Cc: Peter Maydell, Joey Gouly, linux-arm-kernel, linux-doc,
linux-kernel, Mark Brown
In-Reply-To: <20260522-arm64-cpu-ftr-regs-v1-0-19775b40faf0@kernel.org>
In order to make it a bit easier to work with sort the list of registers in
cpu-feature-registers.rst lexically. There should be no content changes
resulting from this patch.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
Documentation/arch/arm64/cpu-feature-registers.rst | 223 +++++++++++----------
1 file changed, 112 insertions(+), 111 deletions(-)
diff --git a/Documentation/arch/arm64/cpu-feature-registers.rst b/Documentation/arch/arm64/cpu-feature-registers.rst
index 02815db0c780..0ea294c56984 100644
--- a/Documentation/arch/arm64/cpu-feature-registers.rst
+++ b/Documentation/arch/arm64/cpu-feature-registers.rst
@@ -170,137 +170,161 @@ infrastructure:
+------------------------------+---------+---------+
- ID_AA64PFR0_EL1 - Processor Feature Register 0
+ ID_AA64ISAR1_EL1 - Instruction set attribute register 1
+------------------------------+---------+---------+
| Name | bits | visible |
+------------------------------+---------+---------+
- | DIT | [51-48] | y |
+ | LS64 | [63-60] | y |
+------------------------------+---------+---------+
- | MPAM | [43-40] | n |
+ | I8MM | [55-52] | y |
+------------------------------+---------+---------+
- | SVE | [35-32] | y |
+ | DGH | [51-48] | y |
+------------------------------+---------+---------+
- | GIC | [27-24] | n |
+ | BF16 | [47-44] | y |
+------------------------------+---------+---------+
- | AdvSIMD | [23-20] | y |
+ | SB | [39-36] | y |
+------------------------------+---------+---------+
- | FP | [19-16] | y |
+ | FRINTTS | [35-32] | y |
+------------------------------+---------+---------+
- | EL3 | [15-12] | n |
+ | GPI | [31-28] | y |
+------------------------------+---------+---------+
- | EL2 | [11-8] | n |
+ | GPA | [27-24] | y |
+------------------------------+---------+---------+
- | EL1 | [7-4] | n |
+ | LRCPC | [23-20] | y |
+------------------------------+---------+---------+
- | EL0 | [3-0] | n |
+ | FCMA | [19-16] | y |
+ +------------------------------+---------+---------+
+ | JSCVT | [15-12] | y |
+ +------------------------------+---------+---------+
+ | API | [11-8] | y |
+ +------------------------------+---------+---------+
+ | APA | [7-4] | y |
+ +------------------------------+---------+---------+
+ | DPB | [3-0] | y |
+------------------------------+---------+---------+
-
- ID_AA64PFR1_EL1 - Processor Feature Register 1
+ ID_AA64ISAR2_EL1 - Instruction set attribute register 2
+------------------------------+---------+---------+
| Name | bits | visible |
+------------------------------+---------+---------+
- | GCS | [47-44] | y |
+ | LUT | [59-56] | y |
+------------------------------+---------+---------+
- | SME | [27-24] | y |
+ | CSSC | [55-52] | y |
+------------------------------+---------+---------+
- | MTE | [11-8] | y |
+ | RPRFM | [51-48] | y |
+------------------------------+---------+---------+
- | SSBS | [7-4] | y |
+ | BC | [23-20] | y |
+------------------------------+---------+---------+
- | BT | [3-0] | y |
+ | MOPS | [19-16] | y |
+ +------------------------------+---------+---------+
+ | APA3 | [15-12] | y |
+ +------------------------------+---------+---------+
+ | GPA3 | [11-8] | y |
+ +------------------------------+---------+---------+
+ | RPRES | [7-4] | y |
+ +------------------------------+---------+---------+
+ | WFXT | [3-0] | y |
+------------------------------+---------+---------+
- ID_AA64PFR2_EL1 - Processor Feature Register 2
+ ID_AA64ISAR3_EL1 - Instruction set attribute register 3
+------------------------------+---------+---------+
| Name | bits | visible |
+------------------------------+---------+---------+
- | FPMR | [35-32] | y |
+ | FPRCVT | [31-28] | y |
+------------------------------+---------+---------+
- | MTEFAR | [11-8] | y |
+ | LSFE | [19-16] | y |
+------------------------------+---------+---------+
- | MTESTOREONLY | [7-4] | y |
+ | FAMINMAX | [7-4] | y |
+------------------------------+---------+---------+
- MIDR_EL1 - Main ID Register
+ ID_AA64MMFR0_EL1 - Memory model feature register 0
+------------------------------+---------+---------+
| Name | bits | visible |
+------------------------------+---------+---------+
- | Implementer | [31-24] | y |
- +------------------------------+---------+---------+
- | Variant | [23-20] | y |
+ | ECV | [63-60] | y |
+------------------------------+---------+---------+
- | Architecture | [19-16] | y |
+
+ ID_AA64MMFR1_EL1 - Memory model feature register 1
+
+------------------------------+---------+---------+
- | PartNum | [15-4] | y |
+ | Name | bits | visible |
+------------------------------+---------+---------+
- | Revision | [3-0] | y |
+ | AFP | [47-44] | y |
+------------------------------+---------+---------+
- NOTE: The 'visible' fields of MIDR_EL1 will contain the value
- as available on the CPU where it is fetched and is not a system
- wide safe value.
-
- ID_AA64ISAR1_EL1 - Instruction set attribute register 1
+ ID_AA64MMFR2_EL1 - Memory model feature register 2
+------------------------------+---------+---------+
| Name | bits | visible |
+------------------------------+---------+---------+
- | LS64 | [63-60] | y |
+ | AT | [35-32] | y |
+------------------------------+---------+---------+
- | I8MM | [55-52] | y |
+
+ ID_AA64MMFR3_EL1 - Memory model feature register 3
+
+------------------------------+---------+---------+
- | DGH | [51-48] | y |
+ | Name | bits | visible |
+------------------------------+---------+---------+
- | BF16 | [47-44] | y |
+ | S1POE | [19-16] | y |
+------------------------------+---------+---------+
- | SB | [39-36] | y |
+
+ ID_AA64PFR0_EL1 - Processor Feature Register 0
+
+------------------------------+---------+---------+
- | FRINTTS | [35-32] | y |
+ | Name | bits | visible |
+------------------------------+---------+---------+
- | GPI | [31-28] | y |
+ | DIT | [51-48] | y |
+------------------------------+---------+---------+
- | GPA | [27-24] | y |
+ | MPAM | [43-40] | n |
+------------------------------+---------+---------+
- | LRCPC | [23-20] | y |
+ | SVE | [35-32] | y |
+------------------------------+---------+---------+
- | FCMA | [19-16] | y |
+ | GIC | [27-24] | n |
+------------------------------+---------+---------+
- | JSCVT | [15-12] | y |
+ | AdvSIMD | [23-20] | y |
+------------------------------+---------+---------+
- | API | [11-8] | y |
+ | FP | [19-16] | y |
+------------------------------+---------+---------+
- | APA | [7-4] | y |
+ | EL3 | [15-12] | n |
+------------------------------+---------+---------+
- | DPB | [3-0] | y |
+ | EL2 | [11-8] | n |
+ +------------------------------+---------+---------+
+ | EL1 | [7-4] | n |
+ +------------------------------+---------+---------+
+ | EL0 | [3-0] | n |
+------------------------------+---------+---------+
- ID_AA64MMFR0_EL1 - Memory model feature register 0
+
+ ID_AA64PFR1_EL1 - Processor Feature Register 1
+------------------------------+---------+---------+
| Name | bits | visible |
+------------------------------+---------+---------+
- | ECV | [63-60] | y |
+ | GCS | [47-44] | y |
+------------------------------+---------+---------+
-
- ID_AA64MMFR2_EL1 - Memory model feature register 2
-
+ | SME | [27-24] | y |
+------------------------------+---------+---------+
- | Name | bits | visible |
+ | MTE | [11-8] | y |
+------------------------------+---------+---------+
- | AT | [35-32] | y |
+ | SSBS | [7-4] | y |
+ +------------------------------+---------+---------+
+ | BT | [3-0] | y |
+------------------------------+---------+---------+
- ID_AA64MMFR3_EL1 - Memory model feature register 3
+ ID_AA64PFR2_EL1 - Processor Feature Register 2
+------------------------------+---------+---------+
| Name | bits | visible |
+------------------------------+---------+---------+
- | S1POE | [19-16] | y |
+ | FPMR | [35-32] | y |
+ +------------------------------+---------+---------+
+ | MTEFAR | [11-8] | y |
+ +------------------------------+---------+---------+
+ | MTESTOREONLY | [7-4] | y |
+------------------------------+---------+---------+
ID_AA6SMFR0_EL1 - SME feature ID register 0
@@ -387,50 +411,64 @@ infrastructure:
| SVEVer | [3-0] | y |
+------------------------------+---------+---------+
- ID_AA64MMFR1_EL1 - Memory model feature register 1
+ ID_ISAR5_EL1 - AArch32 Instruction Set Attribute Register 5
+------------------------------+---------+---------+
| Name | bits | visible |
+------------------------------+---------+---------+
- | AFP | [47-44] | y |
+ | CRC32 | [19-16] | y |
+ +------------------------------+---------+---------+
+ | SHA2 | [15-12] | y |
+ +------------------------------+---------+---------+
+ | SHA1 | [11-8] | y |
+ +------------------------------+---------+---------+
+ | AES | [7-4] | y |
+------------------------------+---------+---------+
- ID_AA64ISAR2_EL1 - Instruction set attribute register 2
+ ID_ISAR6_EL1 - AArch32 Instruction Set Attribute Register 6
+------------------------------+---------+---------+
| Name | bits | visible |
+------------------------------+---------+---------+
- | LUT | [59-56] | y |
- +------------------------------+---------+---------+
- | CSSC | [55-52] | y |
+ | I8MM | [27-24] | y |
+------------------------------+---------+---------+
- | RPRFM | [51-48] | y |
+ | BF16 | [23-20] | y |
+------------------------------+---------+---------+
- | BC | [23-20] | y |
+ | SB | [15-12] | y |
+------------------------------+---------+---------+
- | MOPS | [19-16] | y |
+ | FHM | [11-8] | y |
+------------------------------+---------+---------+
- | APA3 | [15-12] | y |
+ | DP | [7-4] | y |
+------------------------------+---------+---------+
- | GPA3 | [11-8] | y |
+
+ ID_PFR2_EL1 - AArch32 Processor Feature Register 2
+
+------------------------------+---------+---------+
- | RPRES | [7-4] | y |
+ | Name | bits | visible |
+------------------------------+---------+---------+
- | WFXT | [3-0] | y |
+ | SSBS | [7-4] | y |
+------------------------------+---------+---------+
- ID_AA64ISAR3_EL1 - Instruction set attribute register 3
+ MIDR_EL1 - Main ID Register
+------------------------------+---------+---------+
| Name | bits | visible |
+------------------------------+---------+---------+
- | FPRCVT | [31-28] | y |
+ | Implementer | [31-24] | y |
+------------------------------+---------+---------+
- | LSFE | [19-16] | y |
+ | Variant | [23-20] | y |
+------------------------------+---------+---------+
- | FAMINMAX | [7-4] | y |
+ | Architecture | [19-16] | y |
+ +------------------------------+---------+---------+
+ | PartNum | [15-4] | y |
+ +------------------------------+---------+---------+
+ | Revision | [3-0] | y |
+------------------------------+---------+---------+
+ NOTE: The 'visible' fields of MIDR_EL1 will contain the value
+ as available on the CPU where it is fetched and is not a system
+ wide safe value.
+
MVFR0_EL1 - AArch32 Media and VFP Feature Register 0
+------------------------------+---------+---------+
@@ -457,43 +495,6 @@ infrastructure:
| SIMDLS | [11-8] | y |
+------------------------------+---------+---------+
- ID_ISAR5_EL1 - AArch32 Instruction Set Attribute Register 5
-
- +------------------------------+---------+---------+
- | Name | bits | visible |
- +------------------------------+---------+---------+
- | CRC32 | [19-16] | y |
- +------------------------------+---------+---------+
- | SHA2 | [15-12] | y |
- +------------------------------+---------+---------+
- | SHA1 | [11-8] | y |
- +------------------------------+---------+---------+
- | AES | [7-4] | y |
- +------------------------------+---------+---------+
-
- ID_ISAR6_EL1 - AArch32 Instruction Set Attribute Register 6
-
- +------------------------------+---------+---------+
- | Name | bits | visible |
- +------------------------------+---------+---------+
- | I8MM | [27-24] | y |
- +------------------------------+---------+---------+
- | BF16 | [23-20] | y |
- +------------------------------+---------+---------+
- | SB | [15-12] | y |
- +------------------------------+---------+---------+
- | FHM | [11-8] | y |
- +------------------------------+---------+---------+
- | DP | [7-4] | y |
- +------------------------------+---------+---------+
-
- ID_PFR2_EL1 - AArch32 Processor Feature Register 2
-
- +------------------------------+---------+---------+
- | Name | bits | visible |
- +------------------------------+---------+---------+
- | SSBS | [7-4] | y |
- +------------------------------+---------+---------+
Appendix I: Example
-------------------
--
2.47.3
^ permalink raw reply related
* [PATCH 2/3] arm64: Document missing bitfields in cpu-feature-registers.rst
From: Mark Brown @ 2026-05-22 17:58 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Jonathan Corbet, Shuah Khan
Cc: Peter Maydell, Joey Gouly, linux-arm-kernel, linux-doc,
linux-kernel, Mark Brown
In-Reply-To: <20260522-arm64-cpu-ftr-regs-v1-0-19775b40faf0@kernel.org>
We have been rather lax in updating the list of visible bitfields in the
ID registers in cpu-feature-registers.rst, it is currently missing several
of the registers and quite a few bitfields in existing registers. Bring it
into sync with current -next.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
Documentation/arch/arm64/cpu-feature-registers.rst | 146 +++++++++++++++++++++
1 file changed, 146 insertions(+)
diff --git a/Documentation/arch/arm64/cpu-feature-registers.rst b/Documentation/arch/arm64/cpu-feature-registers.rst
index c6e5bc053c09..02815db0c780 100644
--- a/Documentation/arch/arm64/cpu-feature-registers.rst
+++ b/Documentation/arch/arm64/cpu-feature-registers.rst
@@ -113,6 +113,30 @@ infrastructure:
4. List of registers with visible features
-------------------------------------------
+ ID_AA6FPFR0_EL1 - Floating Point feature ID register 0
+
+ +------------------------------+---------+---------+
+ | Name | bits | visible |
+ +------------------------------+---------+---------+
+ | F8CVT | [31] | y |
+ +------------------------------+---------+---------+
+ | F8FMA | [30] | y |
+ +------------------------------+---------+---------+
+ | F8DP4 | [29] | y |
+ +------------------------------+---------+---------+
+ | F8DP2 | [28] | y |
+ +------------------------------+---------+---------+
+ | F8MM8 | [27] | y |
+ +------------------------------+---------+---------+
+ | F8MM4 | [26] | y |
+ +------------------------------+---------+---------+
+ | F16MM2 | [15] | y |
+ +------------------------------+---------+---------+
+ | F8E4M3 | [1] | y |
+ +------------------------------+---------+---------+
+ | F8E5M2 | [0] | y |
+ +------------------------------+---------+---------+
+
ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0
+------------------------------+---------+---------+
@@ -178,6 +202,8 @@ infrastructure:
+------------------------------+---------+---------+
| Name | bits | visible |
+------------------------------+---------+---------+
+ | GCS | [47-44] | y |
+ +------------------------------+---------+---------+
| SME | [27-24] | y |
+------------------------------+---------+---------+
| MTE | [11-8] | y |
@@ -187,6 +213,17 @@ infrastructure:
| BT | [3-0] | y |
+------------------------------+---------+---------+
+ ID_AA64PFR2_EL1 - Processor Feature Register 2
+
+ +------------------------------+---------+---------+
+ | Name | bits | visible |
+ +------------------------------+---------+---------+
+ | FPMR | [35-32] | y |
+ +------------------------------+---------+---------+
+ | MTEFAR | [11-8] | y |
+ +------------------------------+---------+---------+
+ | MTESTOREONLY | [7-4] | y |
+ +------------------------------+---------+---------+
MIDR_EL1 - Main ID Register
@@ -213,6 +250,8 @@ infrastructure:
+------------------------------+---------+---------+
| Name | bits | visible |
+------------------------------+---------+---------+
+ | LS64 | [63-60] | y |
+ +------------------------------+---------+---------+
| I8MM | [55-52] | y |
+------------------------------+---------+---------+
| DGH | [51-48] | y |
@@ -256,6 +295,68 @@ infrastructure:
| AT | [35-32] | y |
+------------------------------+---------+---------+
+ ID_AA64MMFR3_EL1 - Memory model feature register 3
+
+ +------------------------------+---------+---------+
+ | Name | bits | visible |
+ +------------------------------+---------+---------+
+ | S1POE | [19-16] | y |
+ +------------------------------+---------+---------+
+
+ ID_AA6SMFR0_EL1 - SME feature ID register 0
+
+ +------------------------------+---------+---------+
+ | Name | bits | visible |
+ +------------------------------+---------+---------+
+ | FA64 | [63] | y |
+ +------------------------------+---------+---------+
+ | LUT6 | [61] | y |
+ +------------------------------+---------+---------+
+ | LUTv2 | [60] | y |
+ +------------------------------+---------+---------+
+ | SMEver | [59-56] | y |
+ +------------------------------+---------+---------+
+ | I16I64 | [55-52] | y |
+ +------------------------------+---------+---------+
+ | F64F64 | [48] | y |
+ +------------------------------+---------+---------+
+ | I16I32 | [47-44] | y |
+ +------------------------------+---------+---------+
+ | B16B16 | [43] | y |
+ +------------------------------+---------+---------+
+ | F16F16 | [42] | y |
+ +------------------------------+---------+---------+
+ | F8F16 | [41] | y |
+ +------------------------------+---------+---------+
+ | F8F32 | [40] | y |
+ +------------------------------+---------+---------+
+ | I8I32 | [39-36] | y |
+ +------------------------------+---------+---------+
+ | F16F32 | [35] | y |
+ +------------------------------+---------+---------+
+ | B16F32 | [34] | y |
+ +------------------------------+---------+---------+
+ | BI32I32 | [33] | y |
+ +------------------------------+---------+---------+
+ | F32F32 | [32] | y |
+ +------------------------------+---------+---------+
+ | SF8FMA | [30] | y |
+ +------------------------------+---------+---------+
+ | SF8DP4 | [29] | y |
+ +------------------------------+---------+---------+
+ | SF8DP2 | [28] | y |
+ +------------------------------+---------+---------+
+ | SBitPerm | [25] | y |
+ +------------------------------+---------+---------+
+ | AES | [24] | y |
+ +------------------------------+---------+---------+
+ | SFEXPA | [23] | y |
+ +------------------------------+---------+---------+
+ | STMOP | [16] | y |
+ +------------------------------+---------+---------+
+ | SMOP4 | [0] | y |
+ +------------------------------+---------+---------+
+
ID_AA64ZFR0_EL1 - SVE feature ID register 0
+------------------------------+---------+---------+
@@ -265,6 +366,8 @@ infrastructure:
+------------------------------+---------+---------+
| F32MM | [55-52] | y |
+------------------------------+---------+---------+
+ | F16MM | [51-48] | y |
+ +------------------------------+---------+---------+
| I8MM | [47-44] | y |
+------------------------------+---------+---------+
| SM4 | [43-40] | y |
@@ -277,6 +380,8 @@ infrastructure:
+------------------------------+---------+---------+
| BitPerm | [19-16] | y |
+------------------------------+---------+---------+
+ | EltPerm | [15-12] | y |
+ +------------------------------+---------+---------+
| AES | [7-4] | y |
+------------------------------+---------+---------+
| SVEVer | [3-0] | y |
@@ -295,6 +400,8 @@ infrastructure:
+------------------------------+---------+---------+
| Name | bits | visible |
+------------------------------+---------+---------+
+ | LUT | [59-56] | y |
+ +------------------------------+---------+---------+
| CSSC | [55-52] | y |
+------------------------------+---------+---------+
| RPRFM | [51-48] | y |
@@ -312,6 +419,18 @@ infrastructure:
| WFXT | [3-0] | y |
+------------------------------+---------+---------+
+ ID_AA64ISAR3_EL1 - Instruction set attribute register 3
+
+ +------------------------------+---------+---------+
+ | Name | bits | visible |
+ +------------------------------+---------+---------+
+ | FPRCVT | [31-28] | y |
+ +------------------------------+---------+---------+
+ | LSFE | [19-16] | y |
+ +------------------------------+---------+---------+
+ | FAMINMAX | [7-4] | y |
+ +------------------------------+---------+---------+
+
MVFR0_EL1 - AArch32 Media and VFP Feature Register 0
+------------------------------+---------+---------+
@@ -327,6 +446,10 @@ infrastructure:
+------------------------------+---------+---------+
| SIMDFMAC | [31-28] | y |
+------------------------------+---------+---------+
+ | FPHP | [27-24] | y |
+ +------------------------------+---------+---------+
+ | SIMDHP | [23-20] | y |
+ +------------------------------+---------+---------+
| SIMDSP | [19-16] | y |
+------------------------------+---------+---------+
| SIMDInt | [15-12] | y |
@@ -348,6 +471,29 @@ infrastructure:
| AES | [7-4] | y |
+------------------------------+---------+---------+
+ ID_ISAR6_EL1 - AArch32 Instruction Set Attribute Register 6
+
+ +------------------------------+---------+---------+
+ | Name | bits | visible |
+ +------------------------------+---------+---------+
+ | I8MM | [27-24] | y |
+ +------------------------------+---------+---------+
+ | BF16 | [23-20] | y |
+ +------------------------------+---------+---------+
+ | SB | [15-12] | y |
+ +------------------------------+---------+---------+
+ | FHM | [11-8] | y |
+ +------------------------------+---------+---------+
+ | DP | [7-4] | y |
+ +------------------------------+---------+---------+
+
+ ID_PFR2_EL1 - AArch32 Processor Feature Register 2
+
+ +------------------------------+---------+---------+
+ | Name | bits | visible |
+ +------------------------------+---------+---------+
+ | SSBS | [7-4] | y |
+ +------------------------------+---------+---------+
Appendix I: Example
-------------------
--
2.47.3
^ permalink raw reply related
* Re: [PATCH v5 05/11] PCI: liveupdate: Keep bus numbers constant during Live Update
From: Bjorn Helgaas @ 2026-05-22 17:59 UTC (permalink / raw)
To: David Matlack
Cc: kexec, linux-doc, linux-kernel, linux-mm, linux-pci,
Adithya Jayachandran, Alexander Graf, Alex Williamson,
Bjorn Helgaas, Chris Li, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Leon Romanovsky,
Lukas Wunner, Mike Rapoport, Parav Pandit, Pasha Tatashin,
Pranjal Shrivastava, Pratyush Yadav, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Vipin Sharma, William Tu, Yi Liu
In-Reply-To: <20260512184846.119396-6-dmatlack@google.com>
On Tue, May 12, 2026 at 06:48:40PM +0000, David Matlack wrote:
> ...
> + * The PCI core guarantees that preserved devices can be identified by the same
> + * bus, device, and function numbers for as long as they are preserved
> + * (including across kexec). To accomplish this, the PCI core always inherits
> + * the secondary and subordinate bus numbers assigned to bridges during scanning
> + * if any device is preserved. This is true even on architectures that always
> + * assign new bus numbers during scanning. The kernel assumes the previous
> + * kernel established a sane bus topology across kexec.
> + *
> + * If a misconfigured or unconfigured bridge is encountered during enumeration
> + * while there are preserved devices, itss secondary and subordinate bus numbers
> + * will be cleared and devices below it will not be enumerated.
s/itss/its/
> + * To keep things simple, inherit the secondary and subordinate bus numbers on
> + * _all_ bridges if _any_ PCI devices are preserved (i.e. even bridges without
> + * any downstream endpoints that were preserved). This avoids accidentally
> + * assigning a bridge a new window that overlaps with a preserved device that is
> + * downstream of a different bridge.
s/i.e. even/i.e. even/ (remove extra space)
^ permalink raw reply
* [PATCH 1/3] arm64: Don't number registers in cpu-feature-registers.rst
From: Mark Brown @ 2026-05-22 17:58 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Jonathan Corbet, Shuah Khan
Cc: Peter Maydell, Joey Gouly, linux-arm-kernel, linux-doc,
linux-kernel, Mark Brown
In-Reply-To: <20260522-arm64-cpu-ftr-regs-v1-0-19775b40faf0@kernel.org>
cpu-feature-regsters.rst documents the set of userspace visible ID
registers. At present the section for each register is numbered, this has
lead to the registers being documented in a haphazard order as new ones
have been added to the end of the list to avoid renumbering. Remove the
numbers so we can avoid this problem in future.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
Documentation/arch/arm64/cpu-feature-registers.rst | 26 +++++++++++-----------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/Documentation/arch/arm64/cpu-feature-registers.rst b/Documentation/arch/arm64/cpu-feature-registers.rst
index add66afc7b03..c6e5bc053c09 100644
--- a/Documentation/arch/arm64/cpu-feature-registers.rst
+++ b/Documentation/arch/arm64/cpu-feature-registers.rst
@@ -113,7 +113,7 @@ infrastructure:
4. List of registers with visible features
-------------------------------------------
- 1) ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0
+ ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0
+------------------------------+---------+---------+
| Name | bits | visible |
@@ -146,7 +146,7 @@ infrastructure:
+------------------------------+---------+---------+
- 2) ID_AA64PFR0_EL1 - Processor Feature Register 0
+ ID_AA64PFR0_EL1 - Processor Feature Register 0
+------------------------------+---------+---------+
| Name | bits | visible |
@@ -173,7 +173,7 @@ infrastructure:
+------------------------------+---------+---------+
- 3) ID_AA64PFR1_EL1 - Processor Feature Register 1
+ ID_AA64PFR1_EL1 - Processor Feature Register 1
+------------------------------+---------+---------+
| Name | bits | visible |
@@ -188,7 +188,7 @@ infrastructure:
+------------------------------+---------+---------+
- 4) MIDR_EL1 - Main ID Register
+ MIDR_EL1 - Main ID Register
+------------------------------+---------+---------+
| Name | bits | visible |
@@ -208,7 +208,7 @@ infrastructure:
as available on the CPU where it is fetched and is not a system
wide safe value.
- 5) ID_AA64ISAR1_EL1 - Instruction set attribute register 1
+ ID_AA64ISAR1_EL1 - Instruction set attribute register 1
+------------------------------+---------+---------+
| Name | bits | visible |
@@ -240,7 +240,7 @@ infrastructure:
| DPB | [3-0] | y |
+------------------------------+---------+---------+
- 6) ID_AA64MMFR0_EL1 - Memory model feature register 0
+ ID_AA64MMFR0_EL1 - Memory model feature register 0
+------------------------------+---------+---------+
| Name | bits | visible |
@@ -248,7 +248,7 @@ infrastructure:
| ECV | [63-60] | y |
+------------------------------+---------+---------+
- 7) ID_AA64MMFR2_EL1 - Memory model feature register 2
+ ID_AA64MMFR2_EL1 - Memory model feature register 2
+------------------------------+---------+---------+
| Name | bits | visible |
@@ -256,7 +256,7 @@ infrastructure:
| AT | [35-32] | y |
+------------------------------+---------+---------+
- 8) ID_AA64ZFR0_EL1 - SVE feature ID register 0
+ ID_AA64ZFR0_EL1 - SVE feature ID register 0
+------------------------------+---------+---------+
| Name | bits | visible |
@@ -282,7 +282,7 @@ infrastructure:
| SVEVer | [3-0] | y |
+------------------------------+---------+---------+
- 8) ID_AA64MMFR1_EL1 - Memory model feature register 1
+ ID_AA64MMFR1_EL1 - Memory model feature register 1
+------------------------------+---------+---------+
| Name | bits | visible |
@@ -290,7 +290,7 @@ infrastructure:
| AFP | [47-44] | y |
+------------------------------+---------+---------+
- 9) ID_AA64ISAR2_EL1 - Instruction set attribute register 2
+ ID_AA64ISAR2_EL1 - Instruction set attribute register 2
+------------------------------+---------+---------+
| Name | bits | visible |
@@ -312,7 +312,7 @@ infrastructure:
| WFXT | [3-0] | y |
+------------------------------+---------+---------+
- 10) MVFR0_EL1 - AArch32 Media and VFP Feature Register 0
+ MVFR0_EL1 - AArch32 Media and VFP Feature Register 0
+------------------------------+---------+---------+
| Name | bits | visible |
@@ -320,7 +320,7 @@ infrastructure:
| FPDP | [11-8] | y |
+------------------------------+---------+---------+
- 11) MVFR1_EL1 - AArch32 Media and VFP Feature Register 1
+ MVFR1_EL1 - AArch32 Media and VFP Feature Register 1
+------------------------------+---------+---------+
| Name | bits | visible |
@@ -334,7 +334,7 @@ infrastructure:
| SIMDLS | [11-8] | y |
+------------------------------+---------+---------+
- 12) ID_ISAR5_EL1 - AArch32 Instruction Set Attribute Register 5
+ ID_ISAR5_EL1 - AArch32 Instruction Set Attribute Register 5
+------------------------------+---------+---------+
| Name | bits | visible |
--
2.47.3
^ permalink raw reply related
* [PATCH 0/3] arm64: Fixes and cleanups for cpu-feature-registers.rst
From: Mark Brown @ 2026-05-22 17:58 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Jonathan Corbet, Shuah Khan
Cc: Peter Maydell, Joey Gouly, linux-arm-kernel, linux-doc,
linux-kernel, Mark Brown
Peter Maydell noticed some missing updates to cpu-feature-registers.rst,
while looking at these a number of other other omissions and some
maintainability problems were observed. Several registers and many
bitfields have not been added.
Following discussion with Catalin we remove the numbering of the
registers in the first patch so that when we add the registers we can
add them in a roughly sorted order, then fix up the missing
documentation before sorting the existing entries in the file.
This whole area should have much better tooling, rather than having to
update multiple places and manually cross check several different places
including rarely used documentation we should be marking up the sysreg
descriptions and then either generating the data or validating against
manually updated copies. Manually updated copies seem like a good idea
for the ABI documentation since while it's more work that would force
review. I did start on some sketches, it seemed like it might make
sense to tackle along with using the MRS but the libraries for that
seem not to be progressing at any great rate, I'll dig the sketches out.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
Mark Brown (3):
arm64: Don't number registers in cpu-feature-registers.rst
arm64: Document missing bitfields in cpu-feature-registers.rst
arm64: Sort registers in cpu-feature-registers.rst
Documentation/arch/arm64/cpu-feature-registers.rst | 281 ++++++++++++++++-----
1 file changed, 214 insertions(+), 67 deletions(-)
---
base-commit: 5200f5f493f79f14bbdc349e402a40dfb32f23c8
change-id: 20260521-arm64-cpu-ftr-regs-bceb2d34376f
Best regards,
--
Mark Brown <broonie@kernel.org>
^ permalink raw reply
* [PATCH net-next] Documentation: networking: Add a test plan for ethtool pause validation
From: Maxime Chevallier (Netdev Foundation) @ 2026-05-22 17:51 UTC (permalink / raw)
To: Andrew Lunn, Jakub Kicinski, davem, Eric Dumazet, Paolo Abeni,
Simon Horman, Russell King, Heiner Kallweit, Jonathan Corbet,
Shuah Khan
Cc: Maxime Chevallier (Netdev Foundation), Oleksij Rempel,
Vladimir Oltean, Florian Fainelli, thomas.petazzoni, netdev,
linux-kernel, linux-doc
Flow control configuration through Ethernet Pause frames is not
straightforward to get right when implementing a MAC or a PHY driver.
This is often a feature that's poorly tested during development, and
getting it right requires correct configuration both in MAC drivers,
that implement the flow-control, and the PHY drivers, which deal with
the negotiation of the pause parameters.
As part of the Netdev Foundation effort to improve driver testing, and to ease
the development and review effort, The netdev mailing list has been surveyed
to identify the common pitfalls. This testing plan has been written to try and
catch most of the common problems.
This document is aimed as being a human readable basis we can adjust and
discuss before diving into the actual tests implementation, it may not
necessarily have to live in the kernel doc forever, especially once
tests are implemented.
Note that Oleksij Rempel made some attempts at documenting Ethernet Flow-control
before [1], this current work isn't meant to superseed it but rather
complement it with a testing protocol.
[1] : https://lore.kernel.org/netdev/20260304094811.2779953-1-o.rempel@pengutronix.de/
Signed-off-by: Maxime Chevallier (Netdev Foundation) <maxime.chevallier@bootlin.com>
---
Temptative approach to send that as part of the kdoc, this may not be
the best path, as this could simply be some email thread.
Documentation/networking/index.rst | 1 +
Documentation/networking/pause_test_plan.rst | 556 +++++++++++++++++++
2 files changed, 557 insertions(+)
create mode 100644 Documentation/networking/pause_test_plan.rst
diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst
index 44a422ad3b05..fef54999267d 100644
--- a/Documentation/networking/index.rst
+++ b/Documentation/networking/index.rst
@@ -91,6 +91,7 @@ Contents:
openvswitch
operstates
packet_mmap
+ pause_test_plan
phonet
phy-link-topology
phy-port
diff --git a/Documentation/networking/pause_test_plan.rst b/Documentation/networking/pause_test_plan.rst
new file mode 100644
index 000000000000..5ff9860efbe5
--- /dev/null
+++ b/Documentation/networking/pause_test_plan.rst
@@ -0,0 +1,556 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Ethtool Pause testing
+=====================
+
+This document describes the test plan to be used for the ethtool selftest, aimed
+at providing a validation framework for Ethernet drivers that implement flow-control.
+
+To ease readability, the document uses the "ethtool" command to describe test cases,
+actual tests may use the netlink API directly.
+
+This document was written after surveying the common error patterns for pause-related
+patches on the netdev mailing list. The common mistakes are usually found in either
+MAC drivers that don't make use of phylink, or PHY drivers that interfere with
+pause settings.
+
+The main classes of problems are :
+
+ - MAC drivers incorrectly configuring the Pause/Asym capabilities in the attached
+ PHY device through calling phy_support_asym_pause() and phy_support_sym_pause().
+
+ These are used to allow the PHY do know what Pause settings the MAC supports, in
+ order to advertise it to the LP.
+
+ They aren't to be used to configure the Pause advertisement, and the MAC driver
+ needs to actually configure Pause on its side after negotiation finishes.
+
+ Using phylink is the easiest fix for this kind of problem.
+
+ - PHY drivers overriding the Pause/AsymPause bits in the supported/advertising
+ fields. Pause is a MAC feature, but the PHY negotiates the settings with the
+ partner. The PHY driver shouldn't have to tweak Pause settings, only advertise
+ them and report the negotiation results.
+
+ - MAC drivers confusing phydev->autoneg and pause autoneg. Pause autoneg is about
+ whether or not we want to negotiate the Pause settings with the partner, or use
+ locally enforced settings. phydev->autoneg, also referred to as link-wide autoneg
+ is about whether or not we want to negotiate anything with the link partner,
+ including speed, duplex, pause, etc. Both phydev->autoneg and pause autoneg can
+ be configured independently.
+
+ - MAC drivers mishandling the pause parameters in the ethtool get/set_pauseparam
+ callbacks, usually by ignoring the pause autoneg settings.
+
+The hardware capabilities regarding Pause support are reported through the
+linkmodes bits 'ETHTOOL_LINK_MODE_Pause' and 'ETHTOOL_LINK_MODE_Asym_Pause', the
+four different combinations are accepted and together describe the ability for
+the hardware to send TX pause frames, and process the received ones :
+
+ - **Pause** bit : the interface has the ability to Receive and process Pause frames
+ - **Asym** bit (Or AsymDir) : The TX and RX pause setting can be different.
+
+This translates to :
+
+ - **Pause** & **Asym** : We can support **ALL** combinations of rx/tx
+
+ - **Pause only** : only **rx == tx** configurations are valid
+
+ - **Asym** only : **rx** must be **off**, **tx** can be **on or off**
+
+Similarly, the link partner can advertise its capabilities through the same
+bits. These parameters are exchanged through the negotiation process, but can
+also be enforced locally by disabling **pause autoneg**, thus ignoring the
+link partner's capabilities.
+
+The local resolution of the pause configuration after receiving the link-partner
+abilities is done according to the following table, from 802.3 Annex 28B.3 :
+
++-------------+--------------+--------------------------+
+|Local device | Link partner | Pause settings resolution|
++------+------+-------+------+-----------+--------------+
+|Pause | Asym | Pause | Asym | RX | TX |
++======+======+=======+======+===========+==============+
+| 0 | 0 | Any | Any | No | No |
++------+------+-------+------+-----------+--------------+
+| 0 | 1 | 0 | Any | No | No |
++------+------+-------+------+-----------+--------------+
+| 0 | 1 | 1 | 0 | No | No |
++------+------+-------+------+-----------+--------------+
+| 0 | 1 | 1 | 1 | No | Yes |
++------+------+-------+------+-----------+--------------+
+| 1 | 0 | 0 | Any | No | No |
++------+------+-------+------+-----------+--------------+
+| 1 | Any | 1 | Any | Yes | Yes |
++------+------+-------+------+-----------+--------------+
+| 1 | 1 | 0 | 0 | No | No |
++------+------+-------+------+-----------+--------------+
+| 1 | 1 | 0 | 1 | Yes | No |
++------+------+-------+------+-----------+--------------+
+
+The currently configured and advertised settings can be queried with ::
+
+ ethtool <iface>
+
+ Settings for eth0:
+ ...
+ Supported pause frame use: Symmetric Receive-only
+ ...
+ Advertised pause frame use: Symmetric Receive-only
+ ...
+ Link partner advertised pause frame use: Symmetric Receive-only
+
+While testing can be done directly with the Netlink API, as a reminder here's
+what the ethtool output translates to :
+
++------------------------+-------+---------+
+| Ethtool output | Pause | AsymDir |
++========================+=======+=========+
+| No | 0 | 0 |
++------------------------+-------+---------+
+| Transmit-only | 0 | 1 |
++------------------------+-------+---------+
+| Symmetric | 1 | 0 |
++------------------------+-------+---------+
+| Symmetric Receive-only | 1 | 1 |
++------------------------+-------+---------+
+
+Mac drivers's current pause behaviour is reported through the
+ethtool -a/--show-pause command, e.g.::
+
+ ethtool -a <iface>
+
+ Autonegotiate: on
+ RX: off
+ TX: off
+ RX negotiated: on
+ TX negotiated: on
+
+When **pause autoneg** is on, the currently used pause parameters are the
+*negotiated* ones, that may differ from the user-specified rx and tx values.
+
+When **pause autoneg** is off, the rx and tx values are the ones used by the
+hardware.
+
+A : Standalone driver testing
+=============================
+
+Requirements : The interface under test must be connected to a link-partner whose
+interface is admin-up. We don't require the link-partner to be configured in any
+other specific manner for these tests.
+
+A.1 : Sanity Checks
+~~~~~~~~~~~~~~~~~~~
+
+Pause autoneg is set to off::
+
+ ethtool -A <iface> autoneg off
+
+The 'supported' fields retrieved using the ETHTOOL_MSG_LINKMODES_GET includes
+a "Pause" bit and an "Asym" bit.
+
+The ETHTOOL_MSG_PAUSE_GET command returns the currently configured pause modes
+in the "tx" and "rx" attributes.
+
+These parameters must validate against the following truth table :
+
+ +--------------+-----------------+
+ | linkmodes | pauseparam |
+ +-------+------+--------+--------+
+ | Pause | Asym | rx | tx |
+ +=======+======+========+========+
+ | 0 | 0 | 0 | 0 |
+ +-------+------+--------+--------+
+ | 0 | 1 | 0 | 0 or 1 |
+ +-------+------+--------+--------+
+ | 1 | 0 | rx == tx |
+ +-------+------+--------+--------+
+ | 1 | 1 | 0 or 1 | 0 or 1 |
+ +-------+------+--------+--------+
+
+Test scenario
+-------------
+
+Following the reported value from::
+
+ ethtool <iface>
+ Settings for <iface>:
+ ...
+ Supported pause frame use: <value>
+
+Iterate over all the 4 combinations of rx and tx pause parameters::
+
+ ethtool -A <iface> autoneg off rx <rx_val> tx <tx_val>
+
+The settings must be accepted or rejected, according to the above truth table.
+
+Failing this test likely means the MAC driver is incorrectly setting the PHY's
+Pause and AsymDir bits, or that the PHY driver overwrites the Pause and AsymDir
+supported bits.
+
+A.2 : Half-duplex operation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Pause settings as exposed with the ethtool API only concern full-duplex modes.
+
+Test scenario:
+--------------
+
+Set the interface under test in half-duplex mode with::
+
+ ethtool -s <iface> duplex half
+
+Expected behaviour::
+
+ - ethtool <iface>
+
+shows no Pause settings advertised.
+
+Should this test fail, it likely means that either the MAC driver incorrectly
+calls phydev_set_asym_pause(), or that the PHY driver overrides the settings.
+
+B : Combined devices testing
+============================
+
+Requirements : The interface under test must be connected to a link-partner that
+can be actively configured during the tests. It must at least support full-duplex
+modes, and optionally (but ideally) symmetric and asymmetric flow-control, as
+well as autonegotiation of the Pause parameters.
+
+B.1 : Autoneg advertising
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Goal: Validate that the *advertised* Pause and AsymDir bits match the configured
+pausemarams.
+
+The link-level autonegotiation must be enabled::
+
+ ethtool <iface> autoneg on
+
+Pause parameters are set with::
+
+ ethtool -A <iface> rx <val> tx <val> autoneg on
+
+Pause advertising is retrieved with::
+
+ ethtool <iface>
+
+Case 1
+------
+
+Pause parameters : rx **off** tx **off**
+
+Expected advertisement : **None** (Pause = 0, AsymDir = 0)
+
+Case 2
+------
+
+Pause parameters : rx **off** tx **on**
+
+Expected advertisement : **Transmit-only** (Pause = 0, AsymDir = 1)
+
+Case 3
+------
+
+Pause parameters : rx **on** tx **off**
+
+Expected advertisement : **Symmetric receive-only** (Pause = 1, Asymdir = 1)
+
+Case 4
+------
+
+Pause parameters : rx **on** tx **on**
+
+Expected advertisement : **Symmetric** (Pause = 1, Asymdir = 0)
+
+B.2 : Autoneg resolution
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Goal: Validate that the Pause and AsymDir negotiation translates to the right
+TX and RX pause parameters.
+
+The following table, from the 802.3 standard, exposes the autoneg resolution
+result for the advertised pause parameters by each link partner.
+
++-------------+--------------+--------------------------+
+|Local device | Link partner | Pause settings resolution|
++------+------+-------+------+-----------+--------------+
+|Pause | Asym | Pause | Asym | RX | TX |
++======+======+=======+======+===========+==============+
+| 0 | 0 | Any | Any | No | No |
++------+------+-------+------+-----------+--------------+
+| 0 | 1 | 0 | Any | No | No |
++------+------+-------+------+-----------+--------------+
+| 0 | 1 | 1 | 0 | No | No |
++------+------+-------+------+-----------+--------------+
+| 0 | 1 | 1 | 1 | No | Yes |
++------+------+-------+------+-----------+--------------+
+| 1 | 0 | 0 | Any | No | No |
++------+------+-------+------+-----------+--------------+
+| 1 | Any | 1 | Any | Yes | Yes |
++------+------+-------+------+-----------+--------------+
+| 1 | 1 | 0 | 0 | No | No |
++------+------+-------+------+-----------+--------------+
+| 1 | 1 | 0 | 1 | Yes | No |
++------+------+-------+------+-----------+--------------+
+
+The mapping between the configured pause parameters and advertised modes follow
+the following truth table :
+
++----+----+-------+---------+
+| tx | rx | Pause | AsymDir |
++====+====+=======+=========+
+| 0 | 0 | 0 | 0 |
++----+----+-------+---------+
+| 0 | 1 | 1 | 1 |
++----+----+-------+---------+
+| 1 | 0 | 0 | 1 |
++----+----+-------+---------+
+| 1 | 1 | 1 | 0 |
++----+----+-------+---------+
+
+We can boil that down to the following cases to test, keeping the number small
+to avoid dealing with the whole combinatory::
+
+ ethtool -A <iface> autoneg on rx <rx_param> tx <tx_param>
+
+Failing tests here would likely indicate that the MAC driver doesn't correctly
+accounts for the negotiated Pause parameters in its .adjust_link() callback. A
+MAC driver that uses phylink should pass these tests.
+
+Case 1
+------
+
+Local device : rx **off**, tx **off**
+Remote device : rx **on** tx **on**
+
+Expected result on local device after autonegotiation completes :
+ rx negotiated **off**
+ tx negotiated **off**
+
+Case 2
+------
+
+Local device : rx **off** tx **on**
+Remote device : rx **off** tx **on**
+
+Expected result on local device after autonegotiation completes :
+ rx negotiated **off**
+ tx negotiated **off**
+
+Case 3
+------
+
+Local device : rx **off** tx **on**
+Remote device : rx **on** tx **off**
+
+Expected result on local device after autonegotiation completes :
+ rx negotiated **off**
+ tx negotiated **on**
+
+Case 4
+------
+
+Local device : rx **off** tx **on**
+Remote device : rx **on** tx **on**
+
+Expected result on local device after autonegotiation completes :
+ rx negotiated **off**
+ tx negotiated **off**
+
+This case looks surprising but boils down to the fact that we advertise Asym only,
+whereas the LP is advertising Pause (and not Pause + Asym).
+
+As per 802.3 this resolves to all "Off".
+
+Case 5
+------
+
+Local device : rx **on** tx **off**
+Remote device : rx **off** tx **on**
+
+Expected result on local device after autonegotiation completes :
+ rx negotiated **on**
+ tx negotiated **off**
+
+Case 6
+------
+
+Local device : rx **on** tx **on**
+Remote device : rx **on** tx **off**
+
+Expected result on local device after autonegotiation completes :
+ rx negotiated **on**
+ tx negotiated **on**
+
+This is also not an obvious result. We advertise Pause, the Link partner advertises
+Pause + Asym, so it resolves to all "On".
+
+Case 7
+------
+
+Local device : rx **on** tx **on**
+Remote device : rx **off** tx **off**
+
+Expected result on local device after autonegotiation completes :
+ rx negotiated **off**
+ tx negotiated **off**
+
+Case 8
+------
+
+Local device : rx **on** tx **on**
+Remote device : rx **off** tx **on**
+
+Expected result on local device after autonegotiation completes :
+ rx negotiated **on**
+ tx negotiated **off**
+
+B.3 : Pause Autoneg
+~~~~~~~~~~~~~~~~~~~
+
+Goal: Validate that the Pause autonegotiation flag correctly toggles the
+advertised Pause and AsymDir link parameters.
+
+Test scenario:
+--------------
+
+ - Enable pause autoneg and at least rx or tx pause::
+
+ ethtool -A <iface> rx on tx on autoneg on
+
+ - Check the Advertised pause frame use::
+
+ ethtool <iface>
+
+ ...
+ Advertised pause frame use: Symmetric Receive-only
+
+ - Disable pause autoneg::
+
+ ethtool -A <iface> autoneg off
+
+ - Check the Advertised pause frame use, which must be 'No'::
+
+ ethtool <iface>
+
+ ...
+ Advertised pause frame use: No
+
+B.4 : Pause autoneg transition
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Goal: Validate the advertising and pause parameters upon toggling pause
+ autonegotiation. When pause autoneg is disabled, the local pause settings
+ are dictated by the user configuration, without relying on negotiated
+ parameters.
+
+This validation focuses on cases where the pause autoneg result differs from the
+user-specified rx and tx pauseparams, e.g. :
+
+Local device : rx **on** tx **off**
+Remote device : rx **on** tx **on**
+
+This will negotiate into rx and tx being **on**, contrary to the user intent.
+
+Test scenario:
+--------------
+
+ - Enable link-wide autonegotiation::
+
+ ethtool -s <iface> autoneg on
+
+ - Enable Pause autonegotiation, setting RX on and TX off::
+
+ ethtool -A <iface> rx on tx off autoneg on
+
+ - Expected result::
+
+ ethtool -a <iface>
+
+ Pause parameters for <iface>:
+ Autonegotiate: on
+ RX: on
+ TX: off
+ RX negotiated: on
+ TX negotiated: on
+
+Note that the currently applied configuration here is expressed by the "negotiated"
+parameters, so the link is currently using RX and TX Pauses.
+
+ - Disable pause autonegotiation::
+
+ ethtool -A <iface> autoneg off
+
+ - Expected result::
+
+ ethtool -a <iface>
+
+ Pause parameters for <iface>:
+ Autonegotiate: off
+ RX: on
+ TX: off
+
+Note that now, the currently applied configuration really is RX on TX off. It is
+expected that upon running the above command, the link flips down and up again
+as flow-control parameters are updated.
+
+ - Re-enable pause autonegotiation::
+
+ ethtool -A <iface> autoneg on
+
+ - Expected result::
+
+ ethtool -a <iface>
+
+ Pause parameters for <iface>:
+ Autonegotiate: on
+ RX: on
+ TX: off
+ RX negotiated: on
+ TX negotiated: on
+
+The user-defined pause parameters needs to be again converted to advertised Pause
+and Asym parameters, negotiated and the final outcome must be the same as the original
+conditions.
+
+B.5 : Pause autoneg only to Pause and Link autoneg transition
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Goal: Validate that drivers store the user intent in the pause rx/tx attributes
+when disabling link autoneg, but *keeping the pause autoneg enabled*.
+
+When pause autoneg is enabled, the rx and tx pause parameters are the user intent,
+but can be different to the actual pause parameters actively in use.
+
+Test scenario:
+--------------
+
+ - Configure rx and tx pause parameters to **on** and pause autoneg to **on**::
+
+ ethtool -A <iface> autoneg on rx on tx on
+
+ - Disable link autonegotiation::
+
+ ethtool -s <iface> autoneg off
+
+ - Configure rx and tx pause to **rx off**, **tx on** and autoneg to **on**::
+
+ ethtool -A <iface> autoneg on rx off tx on
+
+ - No change in the pause parameters should occur
+ - Re-enable link negotiation::
+
+ ethtool -s <iface> autoneg on
+
+ - Link must now re-negotiate pause to **rx off** and **tx on**::
+
+ ethtool -a <iface>
+
+ Pause parameters for <iface>:
+ Autonegotiate: on
+ RX: off
+ TX: on
+ RX negotiated: off
+ TX negotiated: on
+
--
2.54.0
^ permalink raw reply related
* [PATCH] arm64: Document SVE constraints on new hwcaps
From: Mark Brown @ 2026-05-22 17:50 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Jonathan Corbet, Shuah Khan
Cc: linux-arm-kernel, linux-doc, linux-kernel, Mark Brown
Two of the SVE hwcaps added for the SVE features in the 2025 dpISA did
not explicitly call out their dependency on SVE in the ABI documentation.
Do so.
While we're here reorder the SVE and fature specific ID registers for
HWCAP3_SVE_LUT6 which did have the SVE dependency but listed it second
unlike the other SVE specific ID registers.
Fixes: abca5e69ab626 ("arm64/cpufeature: Define hwcaps for 2025 dpISA features")
Reported-by: Will Deacon <will@kernel.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
Documentation/arch/arm64/elf_hwcaps.rst | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/Documentation/arch/arm64/elf_hwcaps.rst b/Documentation/arch/arm64/elf_hwcaps.rst
index 07ff9ea1d605..f60ca5612daa 100644
--- a/Documentation/arch/arm64/elf_hwcaps.rst
+++ b/Documentation/arch/arm64/elf_hwcaps.rst
@@ -452,10 +452,12 @@ HWCAP3_LS64
memory location, otherwise fallback to the non-atomic alternatives.
HWCAP3_SVE_B16MM
- Functionality implied by ID_AA64ZFR0_EL1.B16B16 == 0b0011
+ Functionality implied by ID_AA64PFR0_EL1.SVE == 0b0001 and
+ ID_AA64ZFR0_EL1.B16B16 == 0b0011
HWCAP3_SVE2P3
- Functionality implied by ID_AA64ZFR0_EL1.SVEver == 0b0100
+ Functionality implied by ID_AA64PFR0_EL1.SVE == 0b0001 and
+ ID_AA64ZFR0_EL1.SVEver == 0b0100
HWCAP3_SME_LUT6
Functionality implied by ID_AA64SMFR0_EL1.LUT6 == 0b1
@@ -473,8 +475,9 @@ HWCAP3_F16F32MM
Functionality implied by ID_AA64ISAR0_EL1.FHM == 0b0011
HWCAP3_SVE_LUT6
- Functionality implied by ID_AA64ISAR2_EL1.LUT == 0b0010 and
- ID_AA64PFR0_EL1.SVE == 0b0001.
+ Functionality implied by ID_AA64PFR0_EL1.SVE == 0b0001 and
+ ID_AA64ISAR2_EL1.LUT == 0b0010.
+
4. Unused AT_HWCAP bits
-----------------------
---
base-commit: abca5e69ab6268cbe1913b19da5a98c3383f8bb3
change-id: 20260522-arm64-elf-hwcaps-sve-cleanup-1af7874ad5b7
Best regards,
--
Mark Brown <broonie@kernel.org>
^ permalink raw reply related
* Re: [PATCH v4 27/30] KVM: x86: Add KVM_VCPU_TSC_EFFECTIVE_FREQ attribute
From: David Woodhouse @ 2026-05-22 17:48 UTC (permalink / raw)
To: Sean Christopherson
Cc: Paolo Bonzini, Jonathan Corbet, Shuah Khan, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Vitaly Kuznetsov, Juergen Gross, Boris Ostrovsky, Paul Durrant,
Jonathan Cameron, Sascha Bischoff, Marc Zyngier, Joey Gouly,
Jack Allister, Dongli Zhang, joe.jin, kvm, linux-doc,
linux-kernel, xen-devel, linux-kselftest
In-Reply-To: <ahCQluJj59uWlDAF@google.com>
[-- Attachment #1: Type: text/plain, Size: 287 bytes --]
On Fri, 2026-05-22 at 10:21 -0700, Sean Christopherson wrote:
>
> I'll send a standalone patch, along with a selftest tweak to verify the fix.
> It's technically a fix and won't generate any conflicts, no reason to delay it.
Are you suggesting the other 30 should be delayed? :P
[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 5069 bytes --]
^ permalink raw reply
* Re: [PATCH v5 04/13] Documentation: ABI: testing: add parent entry for iio channels
From: Jonathan Cameron @ 2026-05-22 17:47 UTC (permalink / raw)
To: Rodrigo Alencar via B4 Relay
Cc: rodrigo.alencar, linux-iio, devicetree, linux-kernel, linux-doc,
linux-hardening, Lars-Peter Clausen, Michael Hennerich,
David Lechner, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Jonathan Corbet, Shuah Khan,
Kees Cook, Gustavo A. R. Silva
In-Reply-To: <20260517-ad9910-iio-driver-v5-4-31599c88314a@analog.com>
On Sun, 17 May 2026 19:37:48 +0100
Rodrigo Alencar via B4 Relay <devnull+rodrigo.alencar.analog.com@kernel.org> wrote:
> From: Rodrigo Alencar <rodrigo.alencar@analog.com>
>
> Add documentation for a read-only sysfs attribute that allows to expose
> parent-child relationships between IIO channels.
>
> Signed-off-by: Rodrigo Alencar <rodrigo.alencar@analog.com>
> ---
> Documentation/ABI/testing/sysfs-bus-iio | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index 925a33fd309a..399944974e34 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> @@ -2118,6 +2118,19 @@ Description:
> specific attributes. This is useful for userspace to be able to
> better identify an individual channel.
>
> +What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_parent
> +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_parent
> +What: /sys/bus/iio/devices/iio:deviceX/in_altvoltageY_parent
> +What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_parent
> +KernelVersion: 7.1
> +Contact: linux-iio@vger.kernel.org
> +Description:
> + Read-only attribute containing the label of the parent channel
> + for hierarchical channel relationships. Only present on channels
> + that have a parent channel with a valid label. This is useful for
> + userspace to organize channels in tree-like structures that reflects
> + the physical or logical relationships between them.
Perhaps an example would be useful?
Otherwise it seems reasonable. One vague concern I have is maybe we end
up with a channel that actually has no other existence than as a parent.
Image two signals mixed into one. If that mixed signal has nothing to control
it wouldn't normally show up in the ABI.
I guess we can give it a label though to ensure there is something there
(even when not using labels for this!).
J
> +
> What: /sys/bus/iio/devices/iio:deviceX/in_phaseY_raw
> KernelVersion: 4.18
> Contact: linux-iio@vger.kernel.org
>
^ permalink raw reply
* [PATCH v2 6/6] kselftest: alloc_tag: extend the allocinfo ioctl kselftest
From: Abhishek Bapat @ 2026-05-22 17:45 UTC (permalink / raw)
To: Suren Baghdasaryan, Andrew Morton, Kent Overstreet, Hao Ge
Cc: Shuah Khan, Jonathan Corbet, linux-doc, linux-kernel, linux-mm,
Sourav Panda, Abhishek Bapat
In-Reply-To: <cover.1779471082.git.abhishekbapat@google.com>
Add the following 2 scenarios to the allocinfo ioctl kselftest:
1. Validate size based filtering
2. Validate lineno based filtering
The first test uses "do_init_module" as the candidate function for the
test. This is because the associated site will only allocate memory when
a kernel module is loaded. The return value of get_content_id() changes
every time modules are loaded or unloaded. Hence, as long as
get_content_id() values at the start and the end of the test are the
same, the memory allocated by the do_init_module call site should also
remain the same. Consequently, the test can assume consistency between
the value returned by the ioctl and the procfs resulting in less
flakiness.
Signed-off-by: Abhishek Bapat <abhishekbapat@google.com>
---
.../alloc_tag/allocinfo_ioctl_test.c | 194 +++++++++++++++++-
1 file changed, 193 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c b/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c
index 5c3c16e86c23..ce3576e3cd9b 100644
--- a/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c
+++ b/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c
@@ -291,11 +291,191 @@ static int test_function_filter(void)
return run_filter_test(&filter);
}
+static int test_size_filter(void)
+{
+ int fd;
+ struct allocinfo_tag_data_vec *tags = malloc(sizeof(*tags));
+ struct allocinfo_tag_data_vec *procfs_entries = malloc(sizeof(*procfs_entries));
+ struct allocinfo_filter filter;
+ int ret = KSFT_PASS;
+ __u64 target_size, i;
+ bool found = false;
+ const char *target_function = "do_init_module";
+
+ if (!tags || !procfs_entries) {
+ ksft_print_msg("Memory allocation failed.\n");
+ ret = KSFT_FAIL;
+ goto freemem;
+ }
+
+ fd = open(ALLOCINFO_PROC, O_RDONLY);
+ if (fd < 0) {
+ ksft_exit_skip("Failed to open " ALLOCINFO_PROC ": %s\n", strerror(errno));
+ ret = KSFT_FAIL;
+ goto freemem;
+ }
+
+ memset(&filter, 0, sizeof(filter));
+ filter.mask |= ALLOCINFO_FILTER_MASK_FUNCTION;
+ strncpy(filter.fields.function, target_function, ALLOCINFO_STR_SIZE);
+
+ if (get_filtered_procfs_entries(procfs_entries, &filter, fd)) {
+ ksft_print_msg("Error retrieving entries from " ALLOCINFO_PROC "\n");
+ ret = KSFT_FAIL;
+ goto exit;
+ }
+
+ if (procfs_entries->count == 0) {
+ ksft_print_msg("Function %s not found in procfs\n", target_function);
+ ret = KSFT_SKIP;
+ goto exit;
+ }
+
+ /*
+ * We depend on the result of procfs entries to create the ioctl_filter. Hence we
+ * cannot recycle the run_filter_test function here.
+ */
+ target_size = procfs_entries->tag[0].counter.bytes;
+
+ memset(&filter, 0, sizeof(filter));
+ filter.mask |= ALLOCINFO_FILTER_MASK_MIN_SIZE | ALLOCINFO_FILTER_MASK_MAX_SIZE;
+ filter.min_size = target_size;
+ filter.max_size = target_size;
+
+ __u64 pos = 0;
+ enum ioctl_ret ioctl_status;
+
+ /*
+ * This loop is required because the first 32 entries fetched by the IOCTL based on
+ * the size parameter might not contain the exact entry that was used from procfs.
+ * If that happens, we must update pos and fetch again until we find the exact entry.
+ */
+ while (1) {
+ ioctl_status = get_filtered_ioctl_entries(tags, &filter, fd, pos);
+ if (ioctl_status == IOCTL_INVALID_DATA) {
+ ksft_print_msg("Trouble retrieving valid IOCTL entries, skipping.\n");
+ ret = KSFT_SKIP;
+ goto exit;
+ }
+ if (ioctl_status == IOCTL_FAILURE) {
+ ksft_print_msg("Error retrieving IOCTL entries.\n");
+ ret = KSFT_FAIL;
+ goto exit;
+ }
+
+ for (i = 0; i < tags->count; i++) {
+ if (strcmp(tags->tag[i].tag.function, target_function) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ break;
+
+ if (tags->count < VEC_MAX_ENTRIES)
+ break;
+
+ pos += tags->count;
+ }
+
+ if (!found) {
+ ksft_print_msg("Entry with function %s not found in IOCTL results\n",
+ target_function);
+ ret = KSFT_FAIL;
+ }
+
+exit:
+ close(fd);
+freemem:
+ free(tags);
+ free(procfs_entries);
+ return ret;
+}
+
+static int test_lineno_filter(void)
+{
+ int fd;
+ struct allocinfo_tag_data_vec *tags = malloc(sizeof(*tags));
+ struct allocinfo_tag_data_vec *procfs_entries = malloc(sizeof(*procfs_entries));
+ struct allocinfo_filter filter;
+ enum ioctl_ret ioctl_status;
+ int ret = KSFT_PASS;
+ __u64 target_lineno, i;
+
+ if (!tags || !procfs_entries) {
+ ksft_print_msg("Memory allocation failed.\n");
+ ret = KSFT_FAIL;
+ goto freemem;
+ }
+
+ fd = open(ALLOCINFO_PROC, O_RDONLY);
+ if (fd < 0) {
+ ksft_exit_skip("Failed to open " ALLOCINFO_PROC ": %s\n", strerror(errno));
+ ret = KSFT_FAIL;
+ goto freemem;
+ }
+
+ memset(&filter, 0, sizeof(filter));
+
+ if (get_filtered_procfs_entries(procfs_entries, &filter, fd)) {
+ ksft_print_msg("Error retrieving entries from " ALLOCINFO_PROC "\n");
+ ret = KSFT_FAIL;
+ goto exit;
+ }
+ if (procfs_entries->count == 0) {
+ ksft_print_msg("Could not retrieve procfs entries\n");
+ ret = KSFT_SKIP;
+ goto exit;
+ }
+ /*
+ * We depend on the result of procfs entries to create the ioctl_filter. Hence we
+ * cannot recycle the run_filter_test function here.
+ */
+ target_lineno = procfs_entries->tag[0].tag.lineno;
+
+ filter.mask |= ALLOCINFO_FILTER_MASK_LINENO;
+ filter.fields.lineno = target_lineno;
+
+ ioctl_status = get_filtered_ioctl_entries(tags, &filter, fd, 0);
+ if (ioctl_status == IOCTL_INVALID_DATA) {
+ ksft_print_msg("Trouble retrieving valid IOCTL entries, skipping.\n");
+ ret = KSFT_SKIP;
+ goto exit;
+ }
+ if (ioctl_status == IOCTL_FAILURE) {
+ ksft_print_msg("Error retrieving IOCTL entries.\n");
+ ret = KSFT_FAIL;
+ goto exit;
+ }
+
+ if (tags->count == 0) {
+ ksft_print_msg("IOCTL returned 0 matches for target lineno %llu.\n", target_lineno);
+ ret = KSFT_FAIL;
+ goto exit;
+ }
+ for (i = 0; i < tags->count; i++) {
+ if (tags->tag[i].tag.lineno != target_lineno) {
+ ksft_print_msg("IOCTL entry %llu has incorrect lineno %llu.\n",
+ i, tags->tag[i].tag.lineno);
+ ret = KSFT_FAIL;
+ goto exit;
+ }
+ }
+
+exit:
+ close(fd);
+freemem:
+ free(tags);
+ free(procfs_entries);
+ return ret;
+}
+
int main(int argc, char *argv[])
{
int ret;
- ksft_set_plan(2);
+ ksft_set_plan(4);
ret = test_filename_filter();
if (ret == KSFT_SKIP)
@@ -309,5 +489,17 @@ int main(int argc, char *argv[])
else
ksft_test_result(ret == KSFT_PASS, "test_function_filter\n");
+ ret = test_size_filter();
+ if (ret == KSFT_SKIP)
+ ksft_test_result_skip("Skipping test_size_filter\n");
+ else
+ ksft_test_result(ret == KSFT_PASS, "test_size_filter\n");
+
+ ret = test_lineno_filter();
+ if (ret == KSFT_SKIP)
+ ksft_test_result_skip("Skipping test_lineno_filter\n");
+ else
+ ksft_test_result(ret == KSFT_PASS, "test_lineno_filter\n");
+
ksft_finished();
}
--
2.54.0.746.g67dd491aae-goog
^ permalink raw reply related
* [PATCH v2 5/6] kselftest: alloc_tag: add kselftest for ioctl interface
From: Abhishek Bapat @ 2026-05-22 17:45 UTC (permalink / raw)
To: Suren Baghdasaryan, Andrew Morton, Kent Overstreet, Hao Ge
Cc: Shuah Khan, Jonathan Corbet, linux-doc, linux-kernel, linux-mm,
Sourav Panda, Abhishek Bapat
In-Reply-To: <cover.1779471082.git.abhishekbapat@google.com>
Introduce a kselftest to verify the new IOCTL-based interface for
/proc/allocinfo. The test covers:
1. Validation of the filename filter.
2. Validation of the function filter.
The first test validates the functionality of the filename filter. Using
"mm/memory.c" as the candidate filename filter, it retrieves filtered
entries from both procfs and ioctl and matches the first VEC_MAX_ENTRIES
entries.
The second test validates the functionality of the function filter.
It uses "dup_mm" as the candidate function as we do not expect this
function name to change frequently and hence won't be needing to modify
this test often.
Note that both the tests match line no, function name and file name
fields. Bytes allocated and calls are not matched as those values may
change in the time when the data is being read from procfs and ioctl and
hence can lead to false negatives.
Signed-off-by: Abhishek Bapat <abhishekbapat@google.com>
---
MAINTAINERS | 1 +
tools/testing/selftests/alloc_tag/Makefile | 9 +
.../alloc_tag/allocinfo_ioctl_test.c | 313 ++++++++++++++++++
3 files changed, 323 insertions(+)
create mode 100644 tools/testing/selftests/alloc_tag/Makefile
create mode 100644 tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c
diff --git a/MAINTAINERS b/MAINTAINERS
index d176bde8fbfc..6d57ab4dfb8f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16711,6 +16711,7 @@ F: include/linux/alloc_tag.h
F: include/linux/pgalloc_tag.h
F: include/uapi/linux/alloc_tag.h
F: lib/alloc_tag.c
+F: tools/testing/selftests/alloc_tag/
MEMORY CONTROLLER DRIVERS
M: Krzysztof Kozlowski <krzk@kernel.org>
diff --git a/tools/testing/selftests/alloc_tag/Makefile b/tools/testing/selftests/alloc_tag/Makefile
new file mode 100644
index 000000000000..f2b8fc022c3b
--- /dev/null
+++ b/tools/testing/selftests/alloc_tag/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+TEST_GEN_PROGS := allocinfo_ioctl_test
+
+CFLAGS += -Wall
+CFLAGS += -I../../../../usr/include
+
+include ../lib.mk
+
diff --git a/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c b/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c
new file mode 100644
index 000000000000..5c3c16e86c23
--- /dev/null
+++ b/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/* kselftest for allocinfo ioctl
+ * allocinfo ioctl retrives allocinfo data through ioctl
+ * Copyright (C) 2026 Google, Inc.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/alloc_tag.h>
+#include "../kselftest.h"
+
+#define MAX_LINE_LEN 512
+#define ALLOCINFO_PROC "/proc/allocinfo"
+
+enum ioctl_ret {
+ IOCTL_SUCCESS = 0,
+ IOCTL_FAILURE = 1,
+ IOCTL_INVALID_DATA = 2,
+};
+
+#define VEC_MAX_ENTRIES 32
+
+struct allocinfo_tag_data_vec {
+ struct allocinfo_tag_data tag[VEC_MAX_ENTRIES];
+ __u64 count;
+};
+
+static inline int __allocinfo_get_content_id(int dev_fd, struct allocinfo_content_id *params)
+{
+ return ioctl(dev_fd, ALLOCINFO_IOC_CONTENT_ID, params);
+}
+
+static inline int __allocinfo_get_at(int dev_fd, struct allocinfo_get_at *params)
+{
+ return ioctl(dev_fd, ALLOCINFO_IOC_GET_AT, params);
+}
+
+static inline int __allocinfo_get_next(int dev_fd, struct allocinfo_tag_data *params)
+{
+ return ioctl(dev_fd, ALLOCINFO_IOC_GET_NEXT, params);
+}
+
+static bool match_entry(const struct allocinfo_tag_data *procfs_entry,
+ const struct allocinfo_tag_data *tag_data,
+ bool match_bytes, bool match_calls, bool match_lineno,
+ bool match_function, bool match_filename)
+{
+ if (match_bytes && tag_data->counter.bytes != procfs_entry->counter.bytes) {
+ ksft_print_msg("size retrieved through ioctl does not match procfs\n");
+ return false;
+ }
+
+ if (match_calls && tag_data->counter.calls != procfs_entry->counter.calls) {
+ ksft_print_msg("call count retrieved through ioctl does not match procfs\n");
+ return false;
+ }
+
+ if (match_lineno && tag_data->tag.lineno != procfs_entry->tag.lineno) {
+ ksft_print_msg("lineno retrieved through ioctl does not match procfs\n");
+ return false;
+ }
+
+ if (match_function &&
+ strncmp(tag_data->tag.function, procfs_entry->tag.function, ALLOCINFO_STR_SIZE)) {
+ ksft_print_msg("function retrieved through ioctl does not match procfs\n");
+ return false;
+ }
+
+ if (match_filename &&
+ strncmp(tag_data->tag.filename, procfs_entry->tag.filename, ALLOCINFO_STR_SIZE)) {
+ ksft_print_msg("filename retrieved through ioctl does not match procfs\n");
+ return false;
+ }
+ return true;
+}
+
+static bool match_entries(const struct allocinfo_tag_data_vec *procfs_entries,
+ const struct allocinfo_tag_data_vec *tags,
+ bool match_bytes, bool match_calls, bool match_lineno,
+ bool match_function, bool match_filename)
+{
+ __u64 i;
+
+ if (procfs_entries->count != tags->count) {
+ ksft_print_msg("Entry count mismatch. ioctl entries: %llu, proc entries: %llu\n",
+ tags->count, procfs_entries->count);
+ return false;
+ }
+ for (i = 0; i < procfs_entries->count; i++) {
+ if (!match_entry(&procfs_entries->tag[i], &tags->tag[i],
+ match_bytes, match_calls, match_lineno,
+ match_function, match_filename)) {
+ ksft_print_msg("%lluth entry does not match.\n", i);
+ return false;
+ }
+ }
+ return true;
+}
+
+static int get_filtered_procfs_entries(struct allocinfo_tag_data_vec *procfs_entries,
+ const struct allocinfo_filter *filter, int fd)
+{
+ FILE *fp = fdopen(fd, "r");
+ char line[MAX_LINE_LEN];
+ int matches;
+ struct allocinfo_tag_data procfs_entry;
+
+ if (!fp) {
+ ksft_print_msg("Failed to open " ALLOCINFO_PROC " for reading\n");
+ return 1;
+ }
+ memset(procfs_entries, 0, sizeof(*procfs_entries));
+ while (fgets(line, sizeof(line), fp) && procfs_entries->count < VEC_MAX_ENTRIES) {
+
+ memset(&procfs_entry, 0, sizeof(procfs_entry));
+ matches = sscanf(line, "%llu %llu %[^:]:%llu func:%s",
+ &procfs_entry.counter.bytes,
+ &procfs_entry.counter.calls,
+ procfs_entry.tag.filename,
+ &procfs_entry.tag.lineno,
+ procfs_entry.tag.function);
+
+ if (matches != 5)
+ continue;
+
+ if (filter->mask & ALLOCINFO_FILTER_MASK_FILENAME) {
+ if (strncmp(procfs_entry.tag.filename,
+ filter->fields.filename, ALLOCINFO_STR_SIZE))
+ continue;
+ }
+ if (filter->mask & ALLOCINFO_FILTER_MASK_FUNCTION) {
+ if (strncmp(procfs_entry.tag.function,
+ filter->fields.function, ALLOCINFO_STR_SIZE))
+ continue;
+ }
+ if (filter->mask & ALLOCINFO_FILTER_MASK_LINENO) {
+ if (procfs_entry.tag.lineno != filter->fields.lineno)
+ continue;
+ }
+ if (filter->mask & ALLOCINFO_FILTER_MASK_MIN_SIZE) {
+ if (procfs_entry.counter.bytes < filter->min_size)
+ continue;
+ }
+ if (filter->mask & ALLOCINFO_FILTER_MASK_MAX_SIZE) {
+ if (procfs_entry.counter.bytes > filter->max_size)
+ continue;
+ }
+
+ memcpy(&procfs_entries->tag[procfs_entries->count++], &procfs_entry,
+ sizeof(procfs_entry));
+ }
+ return 0;
+}
+
+static enum ioctl_ret get_filtered_ioctl_entries(struct allocinfo_tag_data_vec *tags,
+ const struct allocinfo_filter *filter, int fd,
+ __u64 start_pos)
+{
+ struct allocinfo_content_id start_cont_id, end_cont_id;
+ struct allocinfo_get_at get_at_params;
+ const int max_retries = 10;
+ int retry_count = 0;
+ int status;
+
+ /*
+ * __allocinfo_get_content_id may return different values if a kernel module was loaded
+ * between the two calls. If that happens, the data gathered cannot be considered consistent
+ * and hence needs to be fetched again to avoid flakiness.
+ */
+ do {
+ if (__allocinfo_get_content_id(fd, &start_cont_id)) {
+ ksft_print_msg("allocinfo_get_content_id failed\n");
+ return IOCTL_FAILURE;
+ }
+
+ memset(tags, 0, sizeof(*tags));
+ memset(&get_at_params, 0, sizeof(get_at_params));
+ memcpy(&get_at_params.filter, filter, sizeof(*filter));
+ get_at_params.pos = start_pos;
+ if (__allocinfo_get_at(fd, &get_at_params)) {
+ ksft_print_msg("allocinfo_get_at failed\n");
+ return IOCTL_FAILURE;
+ }
+ memcpy(&tags->tag[tags->count++], &get_at_params.data, sizeof(get_at_params.data));
+
+ while (tags->count < VEC_MAX_ENTRIES &&
+ __allocinfo_get_next(fd, &tags->tag[tags->count]) == 0)
+ tags->count++;
+
+ if (__allocinfo_get_content_id(fd, &end_cont_id)) {
+ ksft_print_msg("allocinfo_get_content_id failed\n");
+ return IOCTL_FAILURE;
+ }
+
+ if (start_cont_id.id == end_cont_id.id) {
+ status = IOCTL_SUCCESS;
+ } else {
+ ksft_print_msg("allocinfo_get_content_id mismatch, retrying...\n");
+ status = IOCTL_INVALID_DATA;
+ }
+ } while (status == IOCTL_INVALID_DATA && retry_count++ < max_retries);
+
+ return status;
+}
+
+static int run_filter_test(const struct allocinfo_filter *filter)
+{
+ int fd;
+ struct allocinfo_tag_data_vec *tags = malloc(sizeof(*tags));
+ struct allocinfo_tag_data_vec *procfs_entries = malloc(sizeof(*procfs_entries));
+ int ioctl_status;
+ int ret = KSFT_PASS;
+
+ if (!tags || !procfs_entries) {
+ ksft_print_msg("Memory allocation failed.\n");
+ ret = KSFT_FAIL;
+ goto freemem;
+ }
+
+ fd = open(ALLOCINFO_PROC, O_RDONLY);
+ if (fd < 0) {
+ ksft_exit_skip("Failed to open " ALLOCINFO_PROC ": %s\n", strerror(errno));
+ ret = KSFT_FAIL;
+ goto freemem;
+ }
+
+ if (get_filtered_procfs_entries(procfs_entries, filter, fd)) {
+ ksft_print_msg("Error retrieving entries from " ALLOCINFO_PROC "\n");
+ ret = KSFT_FAIL;
+ goto exit;
+ }
+
+ if (procfs_entries->count == 0) {
+ ksft_print_msg("No entries found in " ALLOCINFO_PROC ", skipping test\n");
+ ret = KSFT_SKIP;
+ goto exit;
+ }
+
+ ioctl_status = get_filtered_ioctl_entries(tags, filter, fd, 0);
+ if (ioctl_status == IOCTL_INVALID_DATA) {
+ ksft_print_msg("Trouble retrieving valid IOCTL entries, skipping.\n");
+ ret = KSFT_SKIP;
+ goto exit;
+ }
+ if (ioctl_status == IOCTL_FAILURE) {
+ ksft_print_msg("Error retrieving IOCTL entries.\n");
+ ret = KSFT_FAIL;
+ goto exit;
+ }
+
+ if (!match_entries(procfs_entries, tags, false, false, true, true, true))
+ ret = KSFT_FAIL;
+
+exit:
+ close(fd);
+freemem:
+ free(tags);
+ free(procfs_entries);
+ return ret;
+}
+
+static int test_filename_filter(void)
+{
+ struct allocinfo_filter filter;
+ const char *target_filename = "mm/memory.c";
+
+ memset(&filter, 0, sizeof(filter));
+ filter.mask |= ALLOCINFO_FILTER_MASK_FILENAME;
+ strncpy(filter.fields.filename, target_filename, ALLOCINFO_STR_SIZE);
+
+ return run_filter_test(&filter);
+}
+
+static int test_function_filter(void)
+{
+ struct allocinfo_filter filter;
+ const char *target_function = "dup_mm";
+
+ memset(&filter, 0, sizeof(filter));
+ filter.mask |= ALLOCINFO_FILTER_MASK_FUNCTION;
+ strncpy(filter.fields.function, target_function, ALLOCINFO_STR_SIZE);
+
+ return run_filter_test(&filter);
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ ksft_set_plan(2);
+
+ ret = test_filename_filter();
+ if (ret == KSFT_SKIP)
+ ksft_test_result_skip("Skipping test_filename_filter\n");
+ else
+ ksft_test_result(ret == KSFT_PASS, "test_filename_filter\n");
+
+ ret = test_function_filter();
+ if (ret == KSFT_SKIP)
+ ksft_test_result_skip("Skipping test_function_filter\n");
+ else
+ ksft_test_result(ret == KSFT_PASS, "test_function_filter\n");
+
+ ksft_finished();
+}
--
2.54.0.746.g67dd491aae-goog
^ permalink raw reply related
* [PATCH v2 4/6] alloc_tag: add accuracy based filtering to ioctl
From: Abhishek Bapat @ 2026-05-22 17:45 UTC (permalink / raw)
To: Suren Baghdasaryan, Andrew Morton, Kent Overstreet, Hao Ge
Cc: Shuah Khan, Jonathan Corbet, linux-doc, linux-kernel, linux-mm,
Sourav Panda, Abhishek Bapat
In-Reply-To: <cover.1779471082.git.abhishekbapat@google.com>
Extend the allocinfo filtering mechanism to allow users to filter tags
based on their accuracy.
Signed-off-by: Abhishek Bapat <abhishekbapat@google.com>
---
include/uapi/linux/alloc_tag.h | 3 +++
lib/alloc_tag.c | 8 ++++++++
2 files changed, 11 insertions(+)
diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h
index 45f158bee0a6..6c4c0e609cd9 100644
--- a/include/uapi/linux/alloc_tag.h
+++ b/include/uapi/linux/alloc_tag.h
@@ -20,6 +20,7 @@ struct allocinfo_tag {
char function[ALLOCINFO_STR_SIZE];
char filename[ALLOCINFO_STR_SIZE];
__u64 lineno;
+ __u64 inaccurate;
};
struct allocinfo_counter {
@@ -39,6 +40,7 @@ enum {
ALLOCINFO_FILTER_FUNCTION,
ALLOCINFO_FILTER_FILENAME,
ALLOCINFO_FILTER_LINENO,
+ ALLOCINFO_FILTER_INACCURATE,
ALLOCINFO_FILTER_MIN_SIZE,
ALLOCINFO_FILTER_MAX_SIZE,
__ALLOCINFO_FILTER_LAST = ALLOCINFO_FILTER_MAX_SIZE
@@ -48,6 +50,7 @@ enum {
#define ALLOCINFO_FILTER_MASK_FUNCTION (1 << ALLOCINFO_FILTER_FUNCTION)
#define ALLOCINFO_FILTER_MASK_FILENAME (1 << ALLOCINFO_FILTER_FILENAME)
#define ALLOCINFO_FILTER_MASK_LINENO (1 << ALLOCINFO_FILTER_LINENO)
+#define ALLOCINFO_FILTER_MASK_INACCURATE (1 << ALLOCINFO_FILTER_INACCURATE)
#define ALLOCINFO_FILTER_MASK_MIN_SIZE (1 << ALLOCINFO_FILTER_MIN_SIZE)
#define ALLOCINFO_FILTER_MASK_MAX_SIZE (1 << ALLOCINFO_FILTER_MAX_SIZE)
diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c
index 6c8743eead2d..b1fc14eed7f2 100644
--- a/lib/alloc_tag.c
+++ b/lib/alloc_tag.c
@@ -217,6 +217,8 @@ static int allocinfo_ioctl_get_content_id(struct seq_file *m, void __user *arg)
static bool matches_filter(struct codetag *ct, struct allocinfo_filter *filter,
struct alloc_tag_counters *counters)
{
+ bool inaccurate;
+
if (!filter || !filter->mask)
return true;
@@ -239,6 +241,12 @@ static bool matches_filter(struct codetag *ct, struct allocinfo_filter *filter,
ct->lineno != filter->fields.lineno)
return false;
+ if (filter->mask & ALLOCINFO_FILTER_MASK_INACCURATE) {
+ inaccurate = !!(ct->flags & CODETAG_FLAG_INACCURATE);
+ if (inaccurate != filter->fields.inaccurate)
+ return false;
+ }
+
if ((filter->mask & ALLOCINFO_FILTER_MASK_MIN_SIZE) ||
(filter->mask & ALLOCINFO_FILTER_MASK_MAX_SIZE)) {
/* We assume counters is not NULL here as per caller logic */
--
2.54.0.746.g67dd491aae-goog
^ permalink raw reply related
* [PATCH v2 3/6] alloc_tag: add size-based filtering to ioctl
From: Abhishek Bapat @ 2026-05-22 17:45 UTC (permalink / raw)
To: Suren Baghdasaryan, Andrew Morton, Kent Overstreet, Hao Ge
Cc: Shuah Khan, Jonathan Corbet, linux-doc, linux-kernel, linux-mm,
Sourav Panda, Abhishek Bapat
In-Reply-To: <cover.1779471082.git.abhishekbapat@google.com>
Extend the allocinfo filtering mechanism to allow users to filter tags
based on the total number of bytes allocated [min_size, max_size]. The
size range is inclusive.
Filtering by size involves retrieving allocinfo per-CPU counters, which
is an expensive operation. Hence, the performance of size-based
filtering will be worse than other filters.
Signed-off-by: Abhishek Bapat <abhishekbapat@google.com>
---
include/uapi/linux/alloc_tag.h | 8 +++-
lib/alloc_tag.c | 72 ++++++++++++++++++++++++++++------
2 files changed, 68 insertions(+), 12 deletions(-)
diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h
index 0cc9db5298c6..45f158bee0a6 100644
--- a/include/uapi/linux/alloc_tag.h
+++ b/include/uapi/linux/alloc_tag.h
@@ -39,13 +39,17 @@ enum {
ALLOCINFO_FILTER_FUNCTION,
ALLOCINFO_FILTER_FILENAME,
ALLOCINFO_FILTER_LINENO,
- __ALLOCINFO_FILTER_LAST = ALLOCINFO_FILTER_LINENO
+ ALLOCINFO_FILTER_MIN_SIZE,
+ ALLOCINFO_FILTER_MAX_SIZE,
+ __ALLOCINFO_FILTER_LAST = ALLOCINFO_FILTER_MAX_SIZE
};
#define ALLOCINFO_FILTER_MASK_MODNAME (1 << ALLOCINFO_FILTER_MODNAME)
#define ALLOCINFO_FILTER_MASK_FUNCTION (1 << ALLOCINFO_FILTER_FUNCTION)
#define ALLOCINFO_FILTER_MASK_FILENAME (1 << ALLOCINFO_FILTER_FILENAME)
#define ALLOCINFO_FILTER_MASK_LINENO (1 << ALLOCINFO_FILTER_LINENO)
+#define ALLOCINFO_FILTER_MASK_MIN_SIZE (1 << ALLOCINFO_FILTER_MIN_SIZE)
+#define ALLOCINFO_FILTER_MASK_MAX_SIZE (1 << ALLOCINFO_FILTER_MAX_SIZE)
#define ALLOCINFO_FILTER_MASKS \
((1 << (__ALLOCINFO_FILTER_LAST + 1)) - 1)
@@ -53,6 +57,8 @@ enum {
struct allocinfo_filter {
__u64 mask; /* bitmask of the filter fields used */
struct allocinfo_tag fields;
+ __u64 min_size;
+ __u64 max_size;
};
struct allocinfo_get_at {
diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c
index 56c394ef721f..6c8743eead2d 100644
--- a/lib/alloc_tag.c
+++ b/lib/alloc_tag.c
@@ -173,11 +173,21 @@ static int allocinfo_cmp_str(const char *str, const char *template)
return strncmp(allocinfo_str(str), template, ALLOCINFO_STR_SIZE);
}
+static inline struct alloc_tag_counters allocinfo_prefetch_counters(struct codetag *ct)
+{
+ return alloc_tag_read(ct_to_alloc_tag(ct));
+}
+
static void allocinfo_to_params(struct codetag *ct,
- struct allocinfo_tag_data *data)
+ struct allocinfo_tag_data *data,
+ struct alloc_tag_counters *counters)
{
- struct alloc_tag *tag = ct_to_alloc_tag(ct);
- struct alloc_tag_counters counter = alloc_tag_read(tag);
+ struct alloc_tag_counters local_counters;
+
+ if (!counters) {
+ local_counters = allocinfo_prefetch_counters(ct);
+ counters = &local_counters;
+ }
if (ct->modname)
allocinfo_copy_str(data->tag.modname, ct->modname);
@@ -186,9 +196,9 @@ static void allocinfo_to_params(struct codetag *ct,
allocinfo_copy_str(data->tag.function, ct->function);
allocinfo_copy_str(data->tag.filename, ct->filename);
data->tag.lineno = ct->lineno;
- data->counter.bytes = counter.bytes;
- data->counter.calls = counter.calls;
- data->counter.accurate = !alloc_tag_is_inaccurate(tag);
+ data->counter.bytes = counters->bytes;
+ data->counter.calls = counters->calls;
+ data->counter.accurate = !alloc_tag_is_inaccurate(ct_to_alloc_tag(ct));
}
static int allocinfo_ioctl_get_content_id(struct seq_file *m, void __user *arg)
@@ -204,7 +214,8 @@ static int allocinfo_ioctl_get_content_id(struct seq_file *m, void __user *arg)
return 0;
}
-static bool matches_filter(struct codetag *ct, struct allocinfo_filter *filter)
+static bool matches_filter(struct codetag *ct, struct allocinfo_filter *filter,
+ struct alloc_tag_counters *counters)
{
if (!filter || !filter->mask)
return true;
@@ -228,6 +239,17 @@ static bool matches_filter(struct codetag *ct, struct allocinfo_filter *filter)
ct->lineno != filter->fields.lineno)
return false;
+ if ((filter->mask & ALLOCINFO_FILTER_MASK_MIN_SIZE) ||
+ (filter->mask & ALLOCINFO_FILTER_MASK_MAX_SIZE)) {
+ /* We assume counters is not NULL here as per caller logic */
+ if ((filter->mask & ALLOCINFO_FILTER_MASK_MIN_SIZE) &&
+ counters->bytes < filter->min_size)
+ return false;
+ if ((filter->mask & ALLOCINFO_FILTER_MASK_MAX_SIZE) &&
+ counters->bytes > filter->max_size)
+ return false;
+ }
+
return true;
}
@@ -237,6 +259,9 @@ static int allocinfo_ioctl_get_at(struct seq_file *m, void __user *arg)
struct codetag *ct;
struct allocinfo_get_at params = {0};
__u64 skip_count;
+ bool sizes_set;
+ struct alloc_tag_counters counters;
+ struct alloc_tag_counters *counters_ptr = NULL;
if (copy_from_user(¶ms, arg, sizeof(params)))
return -EFAULT;
@@ -244,9 +269,16 @@ static int allocinfo_ioctl_get_at(struct seq_file *m, void __user *arg)
if (params.filter.mask & ~ALLOCINFO_FILTER_MASKS)
return -EINVAL;
+ if ((params.filter.mask & ALLOCINFO_FILTER_MASK_MIN_SIZE) &&
+ (params.filter.mask & ALLOCINFO_FILTER_MASK_MAX_SIZE) &&
+ params.filter.min_size > params.filter.max_size)
+ return -EINVAL;
+
priv = (struct allocinfo_private *)m->private;
skip_count = params.pos;
+ sizes_set = (params.filter.mask &
+ (ALLOCINFO_FILTER_MASK_MIN_SIZE | ALLOCINFO_FILTER_MASK_MAX_SIZE));
mutex_lock(&priv->ioctl_lock);
codetag_lock_module_list(alloc_tag_cttype, true);
@@ -261,7 +293,11 @@ static int allocinfo_ioctl_get_at(struct seq_file *m, void __user *arg)
ct = codetag_next_ct(&priv->ioctl_iter);
while (ct) {
- if (matches_filter(ct, &priv->filter)) {
+ if (sizes_set) {
+ counters = allocinfo_prefetch_counters(ct);
+ counters_ptr = &counters;
+ }
+ if (matches_filter(ct, &priv->filter, counters_ptr)) {
if (skip_count == 0)
break;
skip_count--;
@@ -270,7 +306,7 @@ static int allocinfo_ioctl_get_at(struct seq_file *m, void __user *arg)
}
if (ct) {
- allocinfo_to_params(ct, ¶ms.data);
+ allocinfo_to_params(ct, ¶ms.data, counters_ptr);
priv->positioned = true;
}
@@ -292,9 +328,15 @@ static int allocinfo_ioctl_get_next(struct seq_file *m, void __user *arg)
struct codetag *ct;
struct allocinfo_tag_data params = {0};
int ret = 0;
+ bool sizes_set;
+ struct alloc_tag_counters counters;
+ struct alloc_tag_counters *counters_ptr = NULL;
priv = (struct allocinfo_private *)m->private;
+ sizes_set = (priv->filter.mask &
+ (ALLOCINFO_FILTER_MASK_MIN_SIZE | ALLOCINFO_FILTER_MASK_MAX_SIZE));
+
mutex_lock(&priv->ioctl_lock);
codetag_lock_module_list(alloc_tag_cttype, true);
@@ -304,10 +346,18 @@ static int allocinfo_ioctl_get_next(struct seq_file *m, void __user *arg)
}
ct = codetag_next_ct(&priv->ioctl_iter);
- while (ct && !matches_filter(ct, &priv->filter))
+ while (ct) {
+ if (sizes_set) {
+ counters = allocinfo_prefetch_counters(ct);
+ counters_ptr = &counters;
+ }
+ if (matches_filter(ct, &priv->filter, counters_ptr))
+ break;
ct = codetag_next_ct(&priv->ioctl_iter);
+ }
+
if (ct)
- allocinfo_to_params(ct, ¶ms);
+ allocinfo_to_params(ct, ¶ms, counters_ptr);
if (!ct) {
priv->positioned = false;
--
2.54.0.746.g67dd491aae-goog
^ permalink raw reply related
* [PATCH v2 2/6] alloc_tag: add ioctl filters to /proc/allocinfo
From: Abhishek Bapat @ 2026-05-22 17:45 UTC (permalink / raw)
To: Suren Baghdasaryan, Andrew Morton, Kent Overstreet, Hao Ge
Cc: Shuah Khan, Jonathan Corbet, linux-doc, linux-kernel, linux-mm,
Sourav Panda, Abhishek Bapat
In-Reply-To: <cover.1779471082.git.abhishekbapat@google.com>
Extend the capability of the IOCTL mechanism to filter allocations based
on tag's module name, function name, file name and line number.
Signed-off-by: Abhishek Bapat <abhishekbapat@google.com>
---
include/uapi/linux/alloc_tag.h | 26 ++++++++++++++-
lib/alloc_tag.c | 58 ++++++++++++++++++++++++++++++++--
2 files changed, 80 insertions(+), 4 deletions(-)
diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h
index e9a5b55fcc7a..0cc9db5298c6 100644
--- a/include/uapi/linux/alloc_tag.h
+++ b/include/uapi/linux/alloc_tag.h
@@ -34,8 +34,32 @@ struct allocinfo_tag_data {
struct allocinfo_counter counter;
};
+enum {
+ ALLOCINFO_FILTER_MODNAME,
+ ALLOCINFO_FILTER_FUNCTION,
+ ALLOCINFO_FILTER_FILENAME,
+ ALLOCINFO_FILTER_LINENO,
+ __ALLOCINFO_FILTER_LAST = ALLOCINFO_FILTER_LINENO
+};
+
+#define ALLOCINFO_FILTER_MASK_MODNAME (1 << ALLOCINFO_FILTER_MODNAME)
+#define ALLOCINFO_FILTER_MASK_FUNCTION (1 << ALLOCINFO_FILTER_FUNCTION)
+#define ALLOCINFO_FILTER_MASK_FILENAME (1 << ALLOCINFO_FILTER_FILENAME)
+#define ALLOCINFO_FILTER_MASK_LINENO (1 << ALLOCINFO_FILTER_LINENO)
+
+#define ALLOCINFO_FILTER_MASKS \
+ ((1 << (__ALLOCINFO_FILTER_LAST + 1)) - 1)
+
+struct allocinfo_filter {
+ __u64 mask; /* bitmask of the filter fields used */
+ struct allocinfo_tag fields;
+};
+
struct allocinfo_get_at {
- __u64 pos; /* input */
+ /* inputs */
+ __u64 pos;
+ struct allocinfo_filter filter;
+ /* output */
struct allocinfo_tag_data data;
};
diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c
index 3598735b6c93..56c394ef721f 100644
--- a/lib/alloc_tag.c
+++ b/lib/alloc_tag.c
@@ -48,6 +48,7 @@ int alloc_tag_ref_offs;
struct allocinfo_private {
struct codetag_iterator iter;
bool print_header;
+ struct allocinfo_filter filter;
/* ioctl uses a separate iterator not to interfere with reads */
struct codetag_iterator ioctl_iter;
bool positioned; /* seq_open_private() sets to 0 */
@@ -167,6 +168,11 @@ static void allocinfo_copy_str(char *dest, const char *src)
strscpy(dest, allocinfo_str(src), ALLOCINFO_STR_SIZE);
}
+static int allocinfo_cmp_str(const char *str, const char *template)
+{
+ return strncmp(allocinfo_str(str), template, ALLOCINFO_STR_SIZE);
+}
+
static void allocinfo_to_params(struct codetag *ct,
struct allocinfo_tag_data *data)
{
@@ -198,27 +204,71 @@ static int allocinfo_ioctl_get_content_id(struct seq_file *m, void __user *arg)
return 0;
}
+static bool matches_filter(struct codetag *ct, struct allocinfo_filter *filter)
+{
+ if (!filter || !filter->mask)
+ return true;
+
+ if (filter->mask & ALLOCINFO_FILTER_MASK_MODNAME) {
+ if (!ct->modname)
+ return false;
+ if (allocinfo_cmp_str(ct->modname, filter->fields.modname))
+ return false;
+ }
+
+ if ((filter->mask & ALLOCINFO_FILTER_MASK_FUNCTION) &&
+ ct->function && (allocinfo_cmp_str(ct->function, filter->fields.function)))
+ return false;
+
+ if ((filter->mask & ALLOCINFO_FILTER_MASK_FILENAME) &&
+ ct->filename && (allocinfo_cmp_str(ct->filename, filter->fields.filename)))
+ return false;
+
+ if ((filter->mask & ALLOCINFO_FILTER_MASK_LINENO) &&
+ ct->lineno != filter->fields.lineno)
+ return false;
+
+ return true;
+}
+
static int allocinfo_ioctl_get_at(struct seq_file *m, void __user *arg)
{
struct allocinfo_private *priv;
struct codetag *ct;
- __u64 pos;
struct allocinfo_get_at params = {0};
+ __u64 skip_count;
if (copy_from_user(¶ms, arg, sizeof(params)))
return -EFAULT;
+ if (params.filter.mask & ~ALLOCINFO_FILTER_MASKS)
+ return -EINVAL;
+
priv = (struct allocinfo_private *)m->private;
- pos = params.pos;
+
+ skip_count = params.pos;
mutex_lock(&priv->ioctl_lock);
codetag_lock_module_list(alloc_tag_cttype, true);
+ if (params.filter.mask)
+ priv->filter = params.filter;
+ else
+ priv->filter.mask = 0;
+
/* Find the codetag */
priv->ioctl_iter = codetag_get_ct_iter(alloc_tag_cttype);
ct = codetag_next_ct(&priv->ioctl_iter);
- while (ct && pos--)
+
+ while (ct) {
+ if (matches_filter(ct, &priv->filter)) {
+ if (skip_count == 0)
+ break;
+ skip_count--;
+ }
ct = codetag_next_ct(&priv->ioctl_iter);
+ }
+
if (ct) {
allocinfo_to_params(ct, ¶ms.data);
priv->positioned = true;
@@ -254,6 +304,8 @@ static int allocinfo_ioctl_get_next(struct seq_file *m, void __user *arg)
}
ct = codetag_next_ct(&priv->ioctl_iter);
+ while (ct && !matches_filter(ct, &priv->filter))
+ ct = codetag_next_ct(&priv->ioctl_iter);
if (ct)
allocinfo_to_params(ct, ¶ms);
--
2.54.0.746.g67dd491aae-goog
^ permalink raw reply related
* [PATCH v2 1/6] alloc_tag: add ioctl to /proc/allocinfo
From: Abhishek Bapat @ 2026-05-22 17:45 UTC (permalink / raw)
To: Suren Baghdasaryan, Andrew Morton, Kent Overstreet, Hao Ge
Cc: Shuah Khan, Jonathan Corbet, linux-doc, linux-kernel, linux-mm,
Sourav Panda, Abhishek Bapat
In-Reply-To: <cover.1779471082.git.abhishekbapat@google.com>
From: Suren Baghdasaryan <surenb@google.com>
Add the following ioctl commands for /proc/allocinfo file:
ALLOCINFO_IOC_CONTENT_ID - gets content identifier which can be used
to check whether the file content has changed specifically due to module
load/unload. Every time a module is loaded / unloaded, the returned
value will be different. By comparing the identifier value at the
beginning and at the end of the content retrieval operation, users can
validate retrieved information for consistency.
ALLOCINFO_IOC_GET_AT - gets the record at the specified position. This
is the position of a record in /proc/allocinfo.
ALLOCINFO_IOC_GET_NEXT - gets the record next to the last retrieved
one. If no records were previously retrieved, returns the first
record.
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Abhishek Bapat <abhishekbapat@google.com>
---
.../userspace-api/ioctl/ioctl-number.rst | 2 +
MAINTAINERS | 1 +
include/linux/codetag.h | 1 +
include/uapi/linux/alloc_tag.h | 54 +++++
lib/alloc_tag.c | 193 +++++++++++++++++-
lib/codetag.c | 11 +
6 files changed, 260 insertions(+), 2 deletions(-)
create mode 100644 include/uapi/linux/alloc_tag.h
diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
index 331223761fff..84f6808a8578 100644
--- a/Documentation/userspace-api/ioctl/ioctl-number.rst
+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
@@ -349,6 +349,8 @@ Code Seq# Include File Comments
<mailto:luzmaximilian@gmail.com>
0xA5 20-2F linux/surface_aggregator/dtx.h Microsoft Surface DTX driver
<mailto:luzmaximilian@gmail.com>
+0xA6 00-0F uapi/linux/alloc_tag.h Memory allocation profiling
+ <mailto:surenb@google.com>
0xAA 00-3F linux/uapi/linux/userfaultfd.h
0xAB 00-1F linux/nbd.h
0xAC 00-1F linux/raw.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 46ed0f0e76d8..d176bde8fbfc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16709,6 +16709,7 @@ S: Maintained
F: Documentation/mm/allocation-profiling.rst
F: include/linux/alloc_tag.h
F: include/linux/pgalloc_tag.h
+F: include/uapi/linux/alloc_tag.h
F: lib/alloc_tag.c
MEMORY CONTROLLER DRIVERS
diff --git a/include/linux/codetag.h b/include/linux/codetag.h
index 8ea2a5f7c98a..2bcd4e7c809e 100644
--- a/include/linux/codetag.h
+++ b/include/linux/codetag.h
@@ -76,6 +76,7 @@ struct codetag_iterator {
void codetag_lock_module_list(struct codetag_type *cttype, bool lock);
bool codetag_trylock_module_list(struct codetag_type *cttype);
+unsigned long codetag_get_content_id(struct codetag_type *cttype);
struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype);
struct codetag *codetag_next_ct(struct codetag_iterator *iter);
diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h
new file mode 100644
index 000000000000..e9a5b55fcc7a
--- /dev/null
+++ b/include/uapi/linux/alloc_tag.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * include/linux/alloc_tag.h
+ */
+
+#ifndef _UAPI_ALLOC_TAG_H
+#define _UAPI_ALLOC_TAG_H
+
+#include <linux/types.h>
+
+#define ALLOCINFO_STR_SIZE 64
+
+struct allocinfo_content_id {
+ __u64 id;
+};
+
+struct allocinfo_tag {
+ /* Longer names are trimmed */
+ char modname[ALLOCINFO_STR_SIZE];
+ char function[ALLOCINFO_STR_SIZE];
+ char filename[ALLOCINFO_STR_SIZE];
+ __u64 lineno;
+};
+
+struct allocinfo_counter {
+ __u64 bytes;
+ __u64 calls;
+ __u8 accurate;
+ __u8 pad[7]; /* Add alignment to not break the 32-bit compatible interface */
+};
+
+struct allocinfo_tag_data {
+ struct allocinfo_tag tag;
+ struct allocinfo_counter counter;
+};
+
+struct allocinfo_get_at {
+ __u64 pos; /* input */
+ struct allocinfo_tag_data data;
+};
+
+#define _ALLOCINFO_IOC_CONTENT_ID 0
+#define _ALLOCINFO_IOC_GET_AT 1
+#define _ALLOCINFO_IOC_GET_NEXT 2
+
+#define ALLOCINFO_IOC_BASE 0xA6
+#define ALLOCINFO_IOC_CONTENT_ID _IOR(ALLOCINFO_IOC_BASE, _ALLOCINFO_IOC_CONTENT_ID, \
+ struct allocinfo_content_id)
+#define ALLOCINFO_IOC_GET_AT _IOWR(ALLOCINFO_IOC_BASE, _ALLOCINFO_IOC_GET_AT, \
+ struct allocinfo_get_at)
+#define ALLOCINFO_IOC_GET_NEXT _IOR(ALLOCINFO_IOC_BASE, _ALLOCINFO_IOC_GET_NEXT, \
+ struct allocinfo_tag_data)
+
+#endif /* _UAPI_ALLOC_TAG_H */
diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c
index b9ca95d1f506..3598735b6c93 100644
--- a/lib/alloc_tag.c
+++ b/lib/alloc_tag.c
@@ -5,6 +5,7 @@
#include <linux/gfp.h>
#include <linux/kallsyms.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/page_ext.h>
#include <linux/pgalloc_tag.h>
#include <linux/proc_fs.h>
@@ -14,6 +15,7 @@
#include <linux/string_choices.h>
#include <linux/vmalloc.h>
#include <linux/kmemleak.h>
+#include <uapi/linux/alloc_tag.h>
#define ALLOCINFO_FILE_NAME "allocinfo"
#define MODULE_ALLOC_TAG_VMAP_SIZE (100000UL * sizeof(struct alloc_tag))
@@ -46,6 +48,10 @@ int alloc_tag_ref_offs;
struct allocinfo_private {
struct codetag_iterator iter;
bool print_header;
+ /* ioctl uses a separate iterator not to interfere with reads */
+ struct codetag_iterator ioctl_iter;
+ bool positioned; /* seq_open_private() sets to 0 */
+ struct mutex ioctl_lock;
};
static void *allocinfo_start(struct seq_file *m, loff_t *pos)
@@ -125,6 +131,190 @@ static const struct seq_operations allocinfo_seq_op = {
.show = allocinfo_show,
};
+static int allocinfo_open(struct inode *inode, struct file *file)
+{
+ int ret;
+
+ ret = seq_open_private(file, &allocinfo_seq_op,
+ sizeof(struct allocinfo_private));
+ if (!ret) {
+ struct seq_file *m = file->private_data;
+ struct allocinfo_private *priv = m->private;
+
+ mutex_init(&priv->ioctl_lock);
+ }
+ return ret;
+}
+
+static int allocinfo_release(struct inode *inode, struct file *file)
+{
+ return seq_release_private(inode, file);
+}
+
+static const char *allocinfo_str(const char *str)
+{
+ size_t len = strlen(str);
+
+ /* Keep an extra space for the trailing NULL. */
+ if (len >= ALLOCINFO_STR_SIZE)
+ str += (len - ALLOCINFO_STR_SIZE) + 1;
+ return str;
+}
+
+/* Copy a string and trim from the beginning if it's too long */
+static void allocinfo_copy_str(char *dest, const char *src)
+{
+ strscpy(dest, allocinfo_str(src), ALLOCINFO_STR_SIZE);
+}
+
+static void allocinfo_to_params(struct codetag *ct,
+ struct allocinfo_tag_data *data)
+{
+ struct alloc_tag *tag = ct_to_alloc_tag(ct);
+ struct alloc_tag_counters counter = alloc_tag_read(tag);
+
+ if (ct->modname)
+ allocinfo_copy_str(data->tag.modname, ct->modname);
+ else
+ data->tag.modname[0] = '\0';
+ allocinfo_copy_str(data->tag.function, ct->function);
+ allocinfo_copy_str(data->tag.filename, ct->filename);
+ data->tag.lineno = ct->lineno;
+ data->counter.bytes = counter.bytes;
+ data->counter.calls = counter.calls;
+ data->counter.accurate = !alloc_tag_is_inaccurate(tag);
+}
+
+static int allocinfo_ioctl_get_content_id(struct seq_file *m, void __user *arg)
+{
+ struct allocinfo_content_id params;
+
+ codetag_lock_module_list(alloc_tag_cttype, true);
+ params.id = codetag_get_content_id(alloc_tag_cttype);
+ codetag_lock_module_list(alloc_tag_cttype, false);
+ if (copy_to_user(arg, ¶ms, sizeof(params)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int allocinfo_ioctl_get_at(struct seq_file *m, void __user *arg)
+{
+ struct allocinfo_private *priv;
+ struct codetag *ct;
+ __u64 pos;
+ struct allocinfo_get_at params = {0};
+
+ if (copy_from_user(¶ms, arg, sizeof(params)))
+ return -EFAULT;
+
+ priv = (struct allocinfo_private *)m->private;
+ pos = params.pos;
+
+ mutex_lock(&priv->ioctl_lock);
+ codetag_lock_module_list(alloc_tag_cttype, true);
+
+ /* Find the codetag */
+ priv->ioctl_iter = codetag_get_ct_iter(alloc_tag_cttype);
+ ct = codetag_next_ct(&priv->ioctl_iter);
+ while (ct && pos--)
+ ct = codetag_next_ct(&priv->ioctl_iter);
+ if (ct) {
+ allocinfo_to_params(ct, ¶ms.data);
+ priv->positioned = true;
+ }
+
+ codetag_lock_module_list(alloc_tag_cttype, false);
+ mutex_unlock(&priv->ioctl_lock);
+
+ if (!ct)
+ return -ENOENT;
+
+ if (copy_to_user(arg, ¶ms, sizeof(params)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int allocinfo_ioctl_get_next(struct seq_file *m, void __user *arg)
+{
+ struct allocinfo_private *priv;
+ struct codetag *ct;
+ struct allocinfo_tag_data params = {0};
+ int ret = 0;
+
+ priv = (struct allocinfo_private *)m->private;
+
+ mutex_lock(&priv->ioctl_lock);
+ codetag_lock_module_list(alloc_tag_cttype, true);
+
+ if (!priv->positioned) {
+ priv->ioctl_iter = codetag_get_ct_iter(alloc_tag_cttype);
+ priv->positioned = true;
+ }
+
+ ct = codetag_next_ct(&priv->ioctl_iter);
+ if (ct)
+ allocinfo_to_params(ct, ¶ms);
+
+ if (!ct) {
+ priv->positioned = false;
+ ret = -ENOENT;
+ }
+ codetag_lock_module_list(alloc_tag_cttype, false);
+ mutex_unlock(&priv->ioctl_lock);
+
+ if (ret == 0) {
+ if (copy_to_user(arg, ¶ms, sizeof(params)))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+static long allocinfo_ioctl(struct file *file, unsigned int cmd,
+ unsigned long __arg)
+{
+ void __user *arg = (void __user *)__arg;
+ int ret;
+
+ switch (cmd) {
+ case ALLOCINFO_IOC_CONTENT_ID:
+ ret = allocinfo_ioctl_get_content_id(file->private_data, arg);
+ break;
+ case ALLOCINFO_IOC_GET_AT:
+ ret = allocinfo_ioctl_get_at(file->private_data, arg);
+ break;
+ case ALLOCINFO_IOC_GET_NEXT:
+ ret = allocinfo_ioctl_get_next(file->private_data, arg);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long allocinfo_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return allocinfo_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static const struct proc_ops allocinfo_proc_ops = {
+ .proc_open = allocinfo_open,
+ .proc_read_iter = seq_read_iter,
+ .proc_lseek = seq_lseek,
+ .proc_release = allocinfo_release,
+ .proc_ioctl = allocinfo_ioctl,
+#ifdef CONFIG_COMPAT
+ .proc_compat_ioctl = allocinfo_compat_ioctl,
+#endif
+
+};
+
size_t alloc_tag_top_users(struct codetag_bytes *tags, size_t count, bool can_sleep)
{
struct codetag_iterator iter;
@@ -989,8 +1179,7 @@ static int __init alloc_tag_init(void)
return 0;
}
- if (!proc_create_seq_private(ALLOCINFO_FILE_NAME, 0400, NULL, &allocinfo_seq_op,
- sizeof(struct allocinfo_private), NULL)) {
+ if (!proc_create(ALLOCINFO_FILE_NAME, 0400, NULL, &allocinfo_proc_ops)) {
pr_err("Failed to create %s file\n", ALLOCINFO_FILE_NAME);
shutdown_mem_profiling(false);
return -ENOMEM;
diff --git a/lib/codetag.c b/lib/codetag.c
index 304667897ad4..93aa30991563 100644
--- a/lib/codetag.c
+++ b/lib/codetag.c
@@ -48,6 +48,17 @@ bool codetag_trylock_module_list(struct codetag_type *cttype)
return down_read_trylock(&cttype->mod_lock) != 0;
}
+unsigned long codetag_get_content_id(struct codetag_type *cttype)
+{
+ lockdep_assert_held(&cttype->mod_lock);
+
+ /*
+ * next_mod_seq is updated on every load, so can be used to identify
+ * content changes.
+ */
+ return cttype->next_mod_seq;
+}
+
struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype)
{
struct codetag_iterator iter = {
--
2.54.0.746.g67dd491aae-goog
^ permalink raw reply related
* [PATCH v2 0/6] alloc_tag: introduce IOCTL-based filtering for MAP
From: Abhishek Bapat @ 2026-05-22 17:45 UTC (permalink / raw)
To: Suren Baghdasaryan, Andrew Morton, Kent Overstreet, Hao Ge
Cc: Shuah Khan, Jonathan Corbet, linux-doc, linux-kernel, linux-mm,
Sourav Panda, Abhishek Bapat
Currently, memory allocation profiling data is primarily exposed through
/proc/allocinfo. While useful for manual inspection, this text-based
interface poses challenges for production monitoring and large-scale
analysis:
1. Userspace must parse large amounts of text to extract specific
fields.
2. To find specific tags, userspace must read the entire dataset,
requiring many context switches and high data copying.
3. The kernel currently aggregates per-CPU counters for every allocation
size, even those the user intends to filter out immediately.
This series introduces a new IOCTL-based binary interface for allocinfo
that supports kernel-side filtering. By allowing the user to specify a
filter mask, we significantly reduce the work performed in-kernel and
the amount of data transferred to userspace.
Performance measurements were conducted on an Intel Xeon Platinum 8481C
(224 CPUs) with caches dropped before each run.
The IOCTL mechanism shows a ~20x performance improvement for
filtered queries. The kernel avoids the expensive per-CPU counter
aggregation (alloc_tag_read) for any tags that fail the initial string
or location filters.
Scenario 1: Specific File Filtering (arch/x86/events/rapl.c)
1. Traditional (cat /proc/allocinfo | grep): 22ms (sys)
2. IOCTL Interface: 1ms (sys)
Scenario 2: Compound Filtering (Filename + Size)
1. Traditional: (cat ... | grep | awk): 21ms (sys)
2. IOCTL Interface: 1ms (sys)
Scenario 3: Size-Based Filtering (min_size = 1MB)
1. Traditional: (cat ... | awk): 21ms (sys)
2. IOCTL Interface: 14ms (sys)
v2 changes:
- Patch 1/6: Introduced locking for m->private. Also included the new uapi
header file in MAINTAINERS list.
- Patch 2/6: Handled the case where ALLOCINFO_FILTER_MASK_MODNAME is
passed but ct->modname is NULL.
- Patch 3/6: Moved min_size and max_size outside of struct allocinfo_tag
into struct allocinfo_filter. Added validation that min_size <=
max_size. Prefetched alloc_tag_counters if size based filter masks are
provided to avoid assimilating per-cpu counters twice.
- Patch 5/6: Removed the hardcoded logic to skip the header, instead the
test will skip lines that don't match the format. Also included the
newly added alloc_tag selftests directory in MAINTAINERS list.
Abhishek Bapat (5):
alloc_tag: add ioctl filters to /proc/allocinfo
alloc_tag: add size-based filtering to ioctl
alloc_tag: add accuracy based filtering to ioctl
kselftest: alloc_tag: add kselftest for ioctl interface
kselftest: alloc_tag: extend the allocinfo ioctl kselftest
Suren Baghdasaryan (1):
alloc_tag: add ioctl to /proc/allocinfo
.../userspace-api/ioctl/ioctl-number.rst | 2 +
MAINTAINERS | 2 +
include/linux/codetag.h | 1 +
include/uapi/linux/alloc_tag.h | 87 +++
lib/alloc_tag.c | 303 ++++++++++-
lib/codetag.c | 11 +
tools/testing/selftests/alloc_tag/Makefile | 9 +
.../alloc_tag/allocinfo_ioctl_test.c | 505 ++++++++++++++++++
8 files changed, 918 insertions(+), 2 deletions(-)
create mode 100644 include/uapi/linux/alloc_tag.h
create mode 100644 tools/testing/selftests/alloc_tag/Makefile
create mode 100644 tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c
--
2.54.0.746.g67dd491aae-goog
^ permalink raw reply
* Re: [PATCH v5 03/13] iio: core: add hierarchical channel relationships
From: Jonathan Cameron @ 2026-05-22 17:45 UTC (permalink / raw)
To: Rodrigo Alencar
Cc: rodrigo.alencar, linux-iio, devicetree, linux-kernel, linux-doc,
linux-hardening, Lars-Peter Clausen, Michael Hennerich,
David Lechner, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Jonathan Corbet, Shuah Khan,
Kees Cook, Gustavo A. R. Silva
In-Reply-To: <hjv4uuudhkueaotpyuzj3u3jg2rkr73jmrx2vxi37w3po5xk5x@3fhfebj6a3wt>
On Thu, 21 May 2026 14:48:30 +0100
Rodrigo Alencar <455.rodrigo.alencar@gmail.com> wrote:
> On 26/05/18 03:26PM, Rodrigo Alencar wrote:
> > On 26/05/17 06:56PM, sashiko-bot@kernel.org wrote:
> > > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> > > - [Medium] Exposing the hierarchical relationship via channel labels creates an ambiguous UAPI for userspace.
> > > --
> > >
> > > commit 64c6f961f1d7645c58f732e4bd4c11200b999e93
> > > Author: Rodrigo Alencar <rodrigo.alencar@analog.com>
> > >
> > > iio: core: add hierarchical channel relationships
> > >
> > > This commit introduces a parent-child relationship between IIO channels.
> > > It adds a parent pointer to the iio_chan_spec struct and exposes this
> > > relationship to userspace through a new "parent" sysfs attribute that
> > > returns the parent channel's label.
> > >
> > > > diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> > > > index 5c8404efd0a56..348ac7a597385 100644
> > > > --- a/drivers/iio/industrialio-core.c
> > > > +++ b/drivers/iio/industrialio-core.c
> > >
> > > [ ... ]
> > >
> > > > @@ -1263,6 +1271,31 @@ static int iio_device_add_channel_label(struct iio_dev *indio_dev,
> > > > return 1;
> > > > }
> > > >
> > > > +static int iio_device_add_channel_parent(struct iio_dev *indio_dev,
> > > > + struct iio_chan_spec const *chan)
> > > > +{
> > > > + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
> > > > + int ret;
> > > > +
> > > > + if (!chan->parent || (!indio_dev->info->read_label &&
> > > > + !chan->parent->extend_name))
> > > > + return 0;
> > >
> > > Is relying on channel labels robust enough for programmatic parent resolution?
> > >
> > > IIO channel labels are optional, human-readable descriptors and are not
> > > guaranteed by the core to be unique. If multiple channels within a device
> > > share the same label, how can userspace definitively resolve which specific
> > > channel is the parent?
> > >
> > > Also, if a driver establishes a hierarchy where chan->parent is set, but the
> > > parent channel lacks a label, this attribute is silently omitted, hiding the
> > > relationship entirely.
> > >
> > > Would it be more reliable to expose a definitive, unique identifier (such as
> > > the parent channel's sysfs prefix or index) rather than relying on an optional
> > > descriptive string?
> >
> > A bit impressive that sashiko can comment on that architecture level.
> >
> > Those are all good points. I suppose I went for this because otherwise it would
> > require refactoring core code to get the needed parts from __iio_device_attr_init()
> > that gets you the channel name without the attribute part.
> >
> > Maybe we should have a function that outputs a channel name into a buffer based on
> > __iio_device_attr_init() behavior, and that could be reused.
>
> This is the function with behavior extracted from __iio_device_attr_init():
>
> static int __iio_chan_prefix_emit(const struct iio_chan_spec *chan,
> enum iio_shared_by shared_by,
> char *buf, size_t len)
> {
> const char *dir = iio_direction[chan->output];
> const char *type = iio_chan_type_name_spec[chan->type];
> int n = 0;
>
> switch (shared_by) {
> case IIO_SHARED_BY_ALL:
> break;
> case IIO_SHARED_BY_DIR:
> n = scnprintf(buf, len, "%s", dir);
> break;
> case IIO_SHARED_BY_TYPE:
> n = scnprintf(buf, len, "%s_%s", dir, type);
> if (chan->differential)
> n += scnprintf(buf + n, len - n, "-%s", type);
> break;
> case IIO_SEPARATE:
> if (chan->indexed) {
> n = scnprintf(buf, len, "%s_%s%d", dir, type,
> chan->channel);
> if (chan->differential)
> n += scnprintf(buf + n, len - n, "-%s%d", type,
> chan->channel2);
> } else {
> if (chan->differential) {
> WARN(1, "Differential channels must be indexed\n");
> return -EINVAL;
> }
> n = scnprintf(buf, len, "%s_%s", dir, type);
> }
>
> if (chan->modified) {
> if (chan->differential) {
> WARN(1, "Differential channels can not have modifier\n");
> return -EINVAL;
> }
> n += scnprintf(buf + n, len - n, "_%s",
> iio_modifier_names[chan->channel2]);
> }
>
> if (chan->extend_name)
> n += scnprintf(buf + n, len - n, "_%s", chan->extend_name);
> break;
> }
>
> return n;
> }
>
> I think it is clear and reusable.
You only what the SEPARATE case but given the rest is much simpler anyway probably fine
to just use this function.
Jonathan
>
> > > > +
> > > > + ret = __iio_add_chan_devattr("parent",
> > > > + chan,
> > > > + &iio_read_channel_parent,
> > > > + NULL,
> > > > + 0,
> > > > + IIO_SEPARATE,
> > > > + &indio_dev->dev,
> > > > + NULL,
> > > > + &iio_dev_opaque->channel_attr_list);
> > > > + if (ret < 0)
> > > > + return ret;
> > > > +
> > > > + return 1;
> > > > +}
> > >
> > > --
> > > Sashiko AI review · https://sashiko.dev/#/patchset/20260517-ad9910-iio-driver-v5-0-31599c88314a@analog.com?part=3
>
^ permalink raw reply
* Re: [PATCH] ARM: zte: clean up zx297520v3 doc. warnings
From: Randy Dunlap @ 2026-05-22 17:44 UTC (permalink / raw)
To: Stefan Dösinger, linux-kernel
Cc: Linus Walleij, Krzysztof Kozlowski, linux-arm-kernel,
Jonathan Corbet, Shuah Khan, linux-doc
In-Reply-To: <13240501.O9o76ZdvQC@strix>
On 5/22/26 12:09 AM, Stefan Dösinger wrote:
> Hi,
>
> Am Donnerstag, 21. Mai 2026, 22:14:57 Ostafrikanische Zeit schrieben Sie:
>> Fix multiple documentation build warnings.
>> Improve punctuation and formatting of the rendered output.
>>
>> Documentation/arch/arm/zte/zx297520v3.rst:66: WARNING: Title underline too
>> short. 3. Building for built-in U-Boot
>
> I am sorry for the mess. I'll look into doc building before I send clock
> documentation...
>
> Reviewed-by: Stefan Dösinger <stefandoesinger@gmail.com>
Hi Stefan,
Does this mean that you will be merging this patch since you merged the
original patch?
thanks.
--
~Randy
^ permalink raw reply
* Re: [PATCH v3 2/2] iio: dac: Add AD5529R DAC driver support
From: Jonathan Cameron @ 2026-05-22 17:24 UTC (permalink / raw)
To: Janani Sunil
Cc: Lars-Peter Clausen, Michael Hennerich, David Lechner,
Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Jonathan Corbet, Shuah Khan,
linux-iio, devicetree, linux-kernel, linux-doc, Janani Sunil
In-Reply-To: <20260519-ad5529r-driver-v3-2-267c0731aa68@analog.com>
On Tue, 19 May 2026 17:42:59 +0200
Janani Sunil <janani.sunil@analog.com> wrote:
> Add support for AD5529R 16-channel, 12/16 bit Digital to Analog Converter
>
> Signed-off-by: Janani Sunil <janani.sunil@analog.com>
Hi Janani,
A few more things inline from a fresh read.
Have a good weekend
Jonathan
> diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
> index 003431798498..f35e060b3643 100644
> --- a/drivers/iio/dac/Makefile
> +++ b/drivers/iio/dac/Makefile
> @@ -18,6 +18,7 @@ obj-$(CONFIG_AD5446) += ad5446.o
> obj-$(CONFIG_AD5446_SPI) += ad5446-spi.o
> obj-$(CONFIG_AD5446_I2C) += ad5446-i2c.o
> obj-$(CONFIG_AD5449) += ad5449.o
> +obj-$(CONFIG_AD5529R) += ad5529r.o
> obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o
> obj-$(CONFIG_AD5592R) += ad5592r.o
> obj-$(CONFIG_AD5593R) += ad5593r.o
> diff --git a/drivers/iio/dac/ad5529r.c b/drivers/iio/dac/ad5529r.c
> new file mode 100644
> index 000000000000..9bb63030db95
> --- /dev/null
> +++ b/drivers/iio/dac/ad5529r.c
> @@ -0,0 +1,527 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * AD5529R Digital-to-Analog Converter Driver
> + * 16-Channel, 12/16-Bit, 40V High Voltage Precision DAC
> + *
> + * Copyright 2026 Analog Devices Inc.
> + * Author: Janani Sunil <janani.sunil@analog.com>
> + */
> +
> +#include <linux/array_size.h>
> +#include <linux/bits.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
Generally don't include this in drivers unless you actually use
stuff in that header. dev_printk.h etc are preferred.
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/iio/iio.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/reset.h>
> +#include <linux/spi/spi.h>
> +
> +#define AD5529R_REG_INTERFACE_CONFIG_A 0x00
> +#define AD5529R_REG_DEVICE_CONFIG 0x02
> +#define AD5529R_REG_CHIP_GRADE 0x06
> +#define AD5529R_REG_SCRATCH_PAD 0x0A
> +#define AD5529R_REG_SPI_REVISION 0x0B
> +#define AD5529R_REG_VENDOR_H 0x0D
> +#define AD5529R_REG_STREAM_MODE 0x0E
> +#define AD5529R_REG_INTERFACE_STATUS_A 0x11
> +#define AD5529R_REG_MULTI_DAC_CH_SEL 0x14
> +#define AD5529R_REG_OUT_RANGE_BASE 0x3C
> +#define AD5529R_REG_OUT_RANGE(ch) (AD5529R_REG_OUT_RANGE_BASE + (ch) * 2)
> +#define AD5529R_REG_DAC_INPUT_A_BASE 0x148
> +#define AD5529R_REG_DAC_INPUT_A(ch) (AD5529R_REG_DAC_INPUT_A_BASE + (ch) * 2)
> +#define AD5529R_REG_DAC_DATA_READBACK_BASE 0x16A
> +#define AD5529R_REG_TSENS_ALERT_FLAG 0x18C
> +#define AD5529R_REG_TSENS_SHTD_FLAG 0x18E
> +#define AD5529R_REG_FUNC_BUSY 0x1A0
> +#define AD5529R_REG_REF_SEL 0x1A2
> +#define AD5529R_REG_INIT_CRC_ERR_STAT 0x1A4
> +#define AD5529R_REG_MULTI_DAC_HOTPATH_SW_LDAC 0x1A8
> +
> +#define AD5529R_INTERFACE_CONFIG_A_SW_RESET (BIT(7) | BIT(0))
> +#define AD5529R_INTERFACE_CONFIG_A_ADDR_ASCENSION BIT(5)
> +#define AD5529R_INTERFACE_CONFIG_A_SDO_ENABLE BIT(4)
> +#define AD5529R_REF_SEL_MASK BIT(0)
Often when it's a single bit we don't call it MASK, but instead express
what the value with the bit set means.
> +#define AD5529R_MAX_REGISTER 0x232
> +#define AD5529R_8BIT_REG_MAX 0x13
> +#define AD5529R_SPI_READ_FLAG 0x80
> +static int ad5529r_reset(struct ad5529r_state *st)
> +{
> + struct reset_control *rst;
> + int ret;
> +
> + rst = devm_reset_control_get_optional_exclusive(&st->spi->dev, NULL);
> + if (IS_ERR(rst))
> + return PTR_ERR(rst);
> +
> + if (rst) {
> + ret = reset_control_deassert(rst);
> + if (ret)
> + return ret;
> + } else {
> + ret = regmap_write(st->regmap_8bit, AD5529R_REG_INTERFACE_CONFIG_A,
> + AD5529R_INTERFACE_CONFIG_A_SW_RESET);
> + if (ret)
> + return ret;
> + }
> +
> + fsleep(10000);
Comment on why this value - typically a datasheet reference.
> +
> + return regmap_write(st->regmap_8bit, AD5529R_REG_INTERFACE_CONFIG_A,
> + AD5529R_INTERFACE_CONFIG_A_SDO_ENABLE |
> + AD5529R_INTERFACE_CONFIG_A_ADDR_ASCENSION);
> +}
> +
> +static int ad5529r_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int *val, int *val2, long mask)
> +{
> + struct ad5529r_state *st = iio_priv(indio_dev);
> + unsigned int reg_addr, reg_val_h;
> + int ret, range_idx, span_mv;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + reg_addr = AD5529R_REG_DAC_INPUT_A(chan->channel);
Sashiko made an interesting point here about whether the readback register
makes more sense here. I think not but maybe we should add a comment on
why. My understanding is we are only dealing with the A value of the
toggle for now and this therefore always reflects the value set.
> + ret = regmap_read(st->regmap_16bit, reg_addr, ®_val_h);
> + if (ret)
> + return ret;
> +
> + *val = reg_val_h;
> +
> + return IIO_VAL_INT;
> +
> +static int ad5529r_find_output_range(const s32 *vals)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(ad5529r_output_ranges_mv); i++) {
for (unsigned int i = 0; ...
> + if (vals[0] == ad5529r_output_ranges_mv[i][0] * 1000 &&
> + vals[1] == ad5529r_output_ranges_mv[i][1] * 1000)
> + return i;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int ad5529r_parse_channel_ranges(struct device *dev,
> + struct ad5529r_state *st)
> +{
> + int ret, ch, range_idx;
> + s32 vals[2];
> +
> + device_for_each_child_node_scoped(dev, child) {
> + range_idx = AD5529R_RANGE_0V_5V;
> +
> + ret = fwnode_property_read_u32(child, "reg", &ch);
Another sashiko one. Type is wrong. Need to pass in a u32 point. In practice
unlikely to be a problem but lets match what is expected.
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "Missing reg property in channel node\n");
> +
> + if (ch >= 16)
> + return dev_err_probe(dev, -EINVAL,
> + "Invalid channel number: %d\n", ch);
> +
> + if (!fwnode_property_read_u32_array(child,
> + "adi,output-range-microvolt",
> + vals, 2)) {
Here I think it is deliberately reading into signed storage. Add a comment on that.
Might get the bot to leave it alone ;) ARRAY_SIZE(vals) instead of 2.
> + range_idx = ad5529r_find_output_range(vals);
> + if (range_idx < 0)
> + return dev_err_probe(dev, range_idx,
> + "Invalid range [%d %d] for ch %d\n",
> + vals[0], vals[1], ch);
> + }
> +
> + st->output_range_idx[ch] = range_idx;
> + ret = regmap_write(st->regmap_16bit,
> + AD5529R_REG_OUT_RANGE(ch), range_idx);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "Failed to configure range for ch %d\n",
> + ch);
> + }
> +
> + return 0;
> +}
> +
> +static int ad5529r_debugfs_reg_read(struct ad5529r_state *st, unsigned int reg,
> + unsigned int *val)
> +{
> + return regmap_read(ad5529r_get_regmap(st, reg), reg, val);
> +}
> +
> +static int ad5529r_debugfs_reg_write(struct ad5529r_state *st, unsigned int reg,
> + unsigned int val)
> +{
> + return regmap_write(ad5529r_get_regmap(st, reg), reg, val);
> +}
These two helpers don't seem worth having over putting the calls inline.
Particularly as both are getting the regmap.
> +
> +static int ad5529r_reg_access(struct iio_dev *indio_dev,
> + unsigned int reg,
> + unsigned int writeval,
> + unsigned int *readval)
> +{
> + struct ad5529r_state *st = iio_priv(indio_dev);
> +
> + if (readval)
> + return ad5529r_debugfs_reg_read(st, reg, readval);
> +
> + return ad5529r_debugfs_reg_write(st, reg, writeval);
> +}
> +static int ad5529r_probe(struct spi_device *spi)
> +{
> + struct device *dev = &spi->dev;
> + struct iio_dev *indio_dev;
> + struct ad5529r_state *st;
> + int ret;
> +
> + indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + st = iio_priv(indio_dev);
> +
> + st->spi = spi;
> +
> + st->model_data = spi_get_device_match_data(spi);
> + if (!st->model_data)
> + return dev_err_probe(dev, -EINVAL, "Failed to identify device variant\n");
> +
> + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad5529r_supply_names),
> + ad5529r_supply_names);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "Failed to get and enable regulators\n");
> +
> + ret = devm_regulator_get_enable_optional(dev, "hvss");
Sashiko spotted this. Try dropping hvss from your dt and see what return value you get.
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "Failed to get and enable hvss regulator\n");
> +
> + st->vref_regulator = devm_regulator_get_optional(dev, "vref");
> + if (IS_ERR(st->vref_regulator)) {
> + if (PTR_ERR(st->vref_regulator) != -ENODEV)
> + return dev_err_probe(dev, PTR_ERR(st->vref_regulator),
> + "Failed to get vref regulator\n");
> + st->vref_regulator = NULL;
> + }
> +
> + if (st->vref_regulator) {
> + ret = regulator_enable(st->vref_regulator);
If you aren't going to use it except to enable, use
devm_regulator_get_optional_enabled() and a bool flag.
Sashiko had a comment about the oddity of not reading the voltage, but I think
that's fine as the datasheet seems pretty insistent it must be 4.096V to work
correctly. Bit odd as it also provides a range of values. Ah well.
Perhaps add a comment somewhere to remind us of this assumption.
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "Failed to enable vref regulator\n");
> +
> + ret = devm_add_action_or_reset(dev, ad5529r_disable_regulator,
> + st->vref_regulator);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "Failed to add vref regulator cleanup\n");
> + }
> +
> + ret = regmap_update_bits(st->regmap_16bit, AD5529R_REG_REF_SEL,
> + AD5529R_REF_SEL_MASK,
> + st->vref_regulator ? 0 : AD5529R_REF_SEL_MASK);
regmap_assign_bits() using a flag for vref presence as mentioned above
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to configure reference\n");
> +static const struct spi_device_id ad5529r_id[] = {
> + { "ad5529r-16", .driver_data = (kernel_ulong_t)&ad5529r_16bit_model_data },
> + { "ad5529r-12", .driver_data = (kernel_ulong_t)&ad5529r_12bit_model_data },
.name =
Might be long enough you need to do.
{
.name = ....
.driver_data = (kernel_ulong_t)&...
> + { }
> +};
^ permalink raw reply
* Re: [PATCH v4 27/30] KVM: x86: Add KVM_VCPU_TSC_EFFECTIVE_FREQ attribute
From: Sean Christopherson @ 2026-05-22 17:21 UTC (permalink / raw)
To: David Woodhouse
Cc: Paolo Bonzini, Jonathan Corbet, Shuah Khan, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Vitaly Kuznetsov, Juergen Gross, Boris Ostrovsky, Paul Durrant,
Jonathan Cameron, Sascha Bischoff, Marc Zyngier, Joey Gouly,
Jack Allister, Dongli Zhang, joe.jin, kvm, linux-doc,
linux-kernel, xen-devel, linux-kselftest
In-Reply-To: <c4b498c401287477402ddd60a0120b0c5a9bf8d3.camel@infradead.org>
On Fri, May 22, 2026, David Woodhouse wrote:
> On Fri, 2026-05-22 at 05:49 -0700, Sean Christopherson wrote:
> >
> > Oh, that's just an oversight, definitely not intentional. Easy enough to fix:
>
> Want me to roll that into the series? As you eloquently put it the
> other day, what's one more patch...?
I'll send a standalone patch, along with a selftest tweak to verify the fix.
It's technically a fix and won't generate any conflicts, no reason to delay it.
^ permalink raw reply
* Re: [PATCH v15 net-next 10/11] net/nebula-matrix: add common/ctrl dev init/reinit operation
From: Jakub Kicinski @ 2026-05-22 17:16 UTC (permalink / raw)
To: illusion.wang
Cc: dimon.zhao, alvin.wang, sam.chen, netdev, andrew+netdev, corbet,
horms, linux-doc, pabeni, vadim.fedorenko, lukas.bulwahn,
edumazet, enelsonmoore, skhan, hkallweit1, open list
In-Reply-To: <20260520032950.4874-11-illusion.wang@nebula-matrix.com>
On Wed, 20 May 2026 11:29:42 +0800 illusion.wang wrote:
> Common Device Setup: nbl_dev_setup_common_dev configures mailbox queues,
> registers cleanup tasks, and MSI-X interrupt counter initialization.
> Control Device Setup (optional): nbl_dev_setup_ctrl_dev initializes
> the chip and configures all channel queues.
drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c:97:21: warning: result of comparison of constant 4294967295 with expression of type 'u16' (aka 'unsigned short') is always false [-Wtautological-constant-out-of-range-compare]
97 | if (common->vsi_id == U32_MAX) {
| ~~~~~~~~~~~~~~ ^ ~~~~~~~
^ permalink raw reply
* Re: [PATCH v15 net-next 05/11] net/nebula-matrix: add channel layer
From: Jakub Kicinski @ 2026-05-22 17:16 UTC (permalink / raw)
To: illusion.wang
Cc: dimon.zhao, alvin.wang, sam.chen, netdev, andrew+netdev, corbet,
horms, linux-doc, pabeni, vadim.fedorenko, lukas.bulwahn,
edumazet, enelsonmoore, skhan, hkallweit1, open list
In-Reply-To: <20260520032950.4874-6-illusion.wang@nebula-matrix.com>
On Wed, 20 May 2026 11:29:37 +0800 illusion.wang wrote:
> A channel management layer provides a structured approach to handle
> communication between different components and drivers. Here's a summary
> of its key functionalities:
In file included from ../include/linux/device.h:15,
from ../drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.c:6:
../drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.c: In function ‘nbl_chan_recv_msg’:
../drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.c:502:38: warning: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 4 has type ‘unsigned int’ [-Wformat=]
502 | dev_err(dev, "buf_len=%u exceeds external buffer size=%lu\n",
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../include/linux/dev_printk.h:110:30: note: in definition of macro ‘dev_printk_index_wrap’
110 | _p_func(dev, fmt, ##__VA_ARGS__); \
| ^~~
../include/linux/dev_printk.h:154:56: note: in expansion of macro ‘dev_fmt’
154 | dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
| ^~~~~~~
../drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.c:502:25: note: in expansion of macro ‘dev_err’
502 | dev_err(dev, "buf_len=%u exceeds external buffer size=%lu\n",
| ^~~~~~~
../drivers/net/ethernet/nebula-matrix/nbl/nbl_channel/nbl_channel.c:502:81: note: format string is defined here
502 | dev_err(dev, "buf_len=%u exceeds external buffer size=%lu\n",
| ~~^
| |
| long unsigned int
| %u
--
pw-bot: cr
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox