Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v15 12/28] drm/i915/dp: Add YCBCR444 handling for sink formats
From: Ville Syrjälä @ 2026-05-22 19:19 UTC (permalink / raw)
  To: Nicolas Frattaroli
  Cc: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
	Christian König, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
	Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
	Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
	Jonathan Corbet, Shuah Khan, Daniel Stone, kernel, amd-gfx,
	dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip,
	intel-gfx, intel-xe, linux-doc, wayland-devel
In-Reply-To: <20260522-color-format-v15-12-21fb136c9df2@collabora.com>

On Fri, May 22, 2026 at 02:32:03PM +0200, Nicolas Frattaroli wrote:
> In anticipation of userspace being able to explicitly select supported
> sink formats, add handling of the YCBCR444 sink format. The AUTO path
> does not choose this format, but with explicit format selection added to
> the driver, it becomes a possibility.
> 
> Check for both source and sink support of YCBCR444 in
> intel_dp_sink_format_valid.
> 
> Acked-by: Daniel Stone <daniel@fooishbar.org>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> ---
>  drivers/gpu/drm/i915/display/intel_dp.c | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index 1920d2f02666..143ed85224be 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -1344,6 +1344,20 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector,
>  					 8, sink_format, true);
>  }
>  
> +static bool
> +intel_dp_can_ycbcr444(struct intel_dp *intel_dp)
> +{
> +	if (source_can_output(intel_dp, INTEL_OUTPUT_FORMAT_YCBCR444) &&
> +	    !drm_dp_is_branch(intel_dp->dpcd))
> +		return true;
> +
> +	if (source_can_output(intel_dp, INTEL_OUTPUT_FORMAT_RGB) &&
> +	    dfp_can_convert_from_rgb(intel_dp, INTEL_OUTPUT_FORMAT_YCBCR444))

IIRC my previous conclusion was that we don't want the dfp convert
stuff here, at least initially. So this should just are about
source_can_output().

> +		return true;
> +
> +	return false;
> +}
> +
>  static enum drm_mode_status
>  intel_dp_sink_format_valid(struct intel_connector *connector,
>  			   const struct drm_display_mode *mode,
> @@ -1364,6 +1378,13 @@ intel_dp_sink_format_valid(struct intel_connector *connector,
>  
>  		return MODE_OK;

Again, would prefer a cleanr 420->444->rgb order.

>  	case INTEL_OUTPUT_FORMAT_RGB:
> +		return MODE_OK;
> +	case INTEL_OUTPUT_FORMAT_YCBCR444:
> +		if (!(info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)))
> +			return MODE_BAD;
> +		if (!intel_dp_can_ycbcr444(intel_dp))
> +			return MODE_BAD;

These two ifs are swapped when compared to the HDMI version for no
good reason that I can see.

And missing the has_hdmi_sink check here as well.

> +
>  		return MODE_OK;
>  	default:
>  		MISSING_CASE(sink_format);
> 
> -- 
> 2.54.0

-- 
Ville Syrjälä
Intel


^ permalink raw reply

* Re: [PATCH v15 11/28] drm/i915/hdmi: Add YCBCR444 handling for sink formats
From: Ville Syrjälä @ 2026-05-22 19:12 UTC (permalink / raw)
  To: Nicolas Frattaroli
  Cc: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
	Christian König, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
	Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
	Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
	Jonathan Corbet, Shuah Khan, Daniel Stone, kernel, amd-gfx,
	dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip,
	intel-gfx, intel-xe, linux-doc, wayland-devel
In-Reply-To: <20260522-color-format-v15-11-21fb136c9df2@collabora.com>

On Fri, May 22, 2026 at 02:32:02PM +0200, Nicolas Frattaroli wrote:
> In anticipation of userspace being able to explicitly select supported
> sink formats, add handling of the YCBCR444 sink format. The AUTO path
> does not choose this format, but with explicit format selection added to
> the driver, it becomes a possibility.
> 
> Check for YCBCR444 support on the sink in sink_bpc_possible, and on the
> source and sink in sink_format_valid.
> 
> Acked-by: Daniel Stone <daniel@fooishbar.org>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> ---
>  drivers/gpu/drm/i915/display/intel_hdmi.c | 32 +++++++++++++++++++++++++++++++
>  1 file changed, 32 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
> index 9076c2b176ec..97cb321e6568 100644
> --- a/drivers/gpu/drm/i915/display/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
> @@ -1966,6 +1966,8 @@ static bool intel_hdmi_sink_bpc_possible(struct drm_connector *_connector,
>  
>  		if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR420)
>  			return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_36;
> +		else if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR444)
> +			return info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_36;
>  		else
>  			return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36;
>  	case 10:
> @@ -1974,6 +1976,8 @@ static bool intel_hdmi_sink_bpc_possible(struct drm_connector *_connector,
>  
>  		if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR420)
>  			return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_30;
> +		else if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR444)
> +			return info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_30;
>  		else
>  			return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30;
>  	case 8:
> @@ -2021,6 +2025,27 @@ intel_hdmi_mode_clock_valid(struct drm_connector *_connector, int clock,
>  	return status;
>  }
>  
> +/**
> + * intel_hdmi_can_ycbcr444 - Check whether connector can output YCbCr444
> + * @connector: pointer to &struct intel_connector to check
> + *
> + * Checks whether the hardware that backs @connector is capable of outputting
> + * YCbCr444 video over HDMI. Does not check whether currently connected sink is
> + * capable of receiving it.
> + *
> + * Returns: %true if source supports outputting YCbCr444, %false otherwise.
> + */

We don't need kernel docs for internal stuff.

> +static bool
> +intel_hdmi_can_ycbcr444(struct intel_connector *connector)
> +{
> +	const struct intel_display *display = to_intel_display(connector);
> +
> +	if (HAS_GMCH(display))
> +		return true;

Exactly the wrong way around.

> +
> +	return false;
> +}
> +
>  static enum drm_mode_status
>  intel_hdmi_sink_format_valid(struct intel_connector *connector,
>  			     const struct drm_display_mode *mode,
> @@ -2038,6 +2063,13 @@ intel_hdmi_sink_format_valid(struct intel_connector *connector,
>  
>  		return MODE_OK;

I would put the 444 stuff here between 420 and RGB. Then we logically go
from YCbCr420 -> YCbCr444 -> RGB when reading the code.

>  	case INTEL_OUTPUT_FORMAT_RGB:
> +		return MODE_OK;
> +	case INTEL_OUTPUT_FORMAT_YCBCR444:
> +		if (!intel_hdmi_can_ycbcr444(connector))
> +			return MODE_BAD;

We're missing the has_hdmi_sink check as well.

> +		if (!(info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)))
> +			return MODE_BAD;
> +
>  		return MODE_OK;
>  	default:
>  		MISSING_CASE(sink_format);
> 
> -- 
> 2.54.0

-- 
Ville Syrjälä
Intel


^ permalink raw reply

* [PATCH v2] pwm: imx27: Fix variable truncation in .apply()
From: Ronaldo Nunez @ 2026-05-22 19:13 UTC (permalink / raw)
  To: linux-pwm
  Cc: Uwe Kleine-König, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, imx, linux-arm-kernel,
	linux-kernel, Ronaldo Nunez

Fix a variable truncation when calculating period in microseconds as
part of the solution for the ERR051198 in .apply() callback.

Example scenario:
 - Period of 3us (PWMPR = 196 and prescaler = 1)
 - Expected value in tmp: 198000000000 (NSEC_PER_SEC * (196 + 2) * 1)
 - Actual value is 431504384 (truncation to u32)

Signed-off-by: Ronaldo Nunez <rnunez@baylibre.com>
---
Changes in v2:
- Added example with actual PWMPR/prescaler values per Frank Li's feedback
- Dropped testing section
---
 drivers/pwm/pwm-imx27.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c
index 3d34cdc4a3a5..c8b801fcb525 100644
--- a/drivers/pwm/pwm-imx27.c
+++ b/drivers/pwm/pwm-imx27.c
@@ -200,7 +200,7 @@ static void pwm_imx27_wait_fifo_slot(struct pwm_chip *chip,
 static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 			   const struct pwm_state *state)
 {
-	unsigned long period_cycles, duty_cycles, prescale, period_us, tmp;
+	unsigned long period_cycles, duty_cycles, prescale, period_us;
 	struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
 	unsigned long long c;
 	unsigned long long clkrate;
@@ -208,6 +208,7 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	int val;
 	int ret;
 	u32 cr;
+	u64 tmp;
 
 	clkrate = clk_get_rate(imx->clks[PWM_IMX27_PER].clk);
 	c = clkrate * state->period;
@@ -249,6 +250,11 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	val = readl(imx->mmio_base + MX3_PWMPR);
 	val = val >= MX3_PWMPR_MAX ? MX3_PWMPR_MAX : val;
 	cr = readl(imx->mmio_base + MX3_PWMCR);
+
+	/*
+	 * tmp stores period in nanoseconds. Result fits in u64 since
+	 * val <= 0xfffe and prescaler in [1, 0x1000].
+	 */
 	tmp = NSEC_PER_SEC * (u64)(val + 2) * MX3_PWMCR_PRESCALER_GET(cr);
 	tmp = DIV_ROUND_UP_ULL(tmp, clkrate);
 	period_us = DIV_ROUND_UP_ULL(tmp, 1000);
-- 
2.53.0



^ permalink raw reply related

* Re: [PATCH 1/2] gpio: mxc: fix irq_high handling
From: Frank Li @ 2026-05-22 18:21 UTC (permalink / raw)
  To: Alexander Stein
  Cc: Linus Walleij, Bartosz Golaszewski, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, linux-gpio, imx,
	linux-arm-kernel, linux-kernel
In-Reply-To: <20260522070118.800671-1-alexander.stein@ew.tq-group.com>

On Fri, May 22, 2026 at 09:01:15AM +0200, Alexander Stein wrote:
> If port->irq_high is -1 (fsl,imx21-gpio compatible) and gpio_idx is >= 16
> enable_irq_wake() is called with -1 which is wrong.
>
> Fixes: 5f6d1998adeb ("gpio: mxc: release the parent IRQ in runtime suspend")
> Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
> ---
> I don't have hardware to test. I just noticed this by code review.

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>
>  drivers/gpio/gpio-mxc.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
> index 647b6f4861b74..12f11a6c96653 100644
> --- a/drivers/gpio/gpio-mxc.c
> +++ b/drivers/gpio/gpio-mxc.c
> @@ -469,7 +469,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
>  		 * the handler is needed only once, but doing it for every port
>  		 * is more robust and easier.
>  		 */
> -		port->irq_high = -1;
> +		port->irq_high = 0;
>  		port->mx_irq_handler = mx2_gpio_irq_handler;
>  	} else
>  		port->mx_irq_handler = mx3_gpio_irq_handler;
> --
> 2.43.0
>


^ permalink raw reply

* [PATCH] mmc: dw_mmc-rockchip: Add missing private data for very old controllers
From: Heiko Stuebner @ 2026-05-22 18:43 UTC (permalink / raw)
  To: ulfh, shawn.lin, jh80.chung
  Cc: heiko, linux-mmc, linux-arm-kernel, linux-rockchip, linux-kernel,
	stable

The really old controllers (rk2928, rk3066, rk3188) do not support UHS
speeds at all, and thus never handled phase data.

For that reason it never had a parse_dt callback and no driver private
data at all.

Commit ff6f0286c896 ("mmc: dw_mmc-rockchip: Add memory clock auto-gating
support") makes the private data sort of mandatory, because the init
function checks whether phases are configured internally or through the
clock controller.

This results in the old SoCs then experiencing NULL-pointer dereferences
when they try to access that private-data struct.

While we could have if (priv) conditionals in all places, it's way less
cluttery to just give the old types their private-data struct.

Fixes: ff6f0286c896 ("mmc: dw_mmc-rockchip: Add memory clock auto-gating support")
Cc: stable@vger.kernel.org
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/mmc/host/dw_mmc-rockchip.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index c6eece4ec3fd..75c82ff20f17 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -441,6 +441,22 @@ static int dw_mci_common_parse_dt(struct dw_mci *host)
 	return 0;
 }
 
+static int dw_mci_rk2928_parse_dt(struct dw_mci *host)
+{
+	struct dw_mci_rockchip_priv_data *priv;
+	int err;
+
+	err = dw_mci_common_parse_dt(host);
+	if (err)
+		return err;
+
+	priv = host->priv;
+
+	priv->internal_phase = false;
+
+	return 0;
+}
+
 static int dw_mci_rk3288_parse_dt(struct dw_mci *host)
 {
 	struct dw_mci_rockchip_priv_data *priv;
@@ -514,6 +530,7 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
 
 static const struct dw_mci_drv_data rk2928_drv_data = {
 	.init			= dw_mci_rockchip_init,
+	.parse_dt		= dw_mci_rk2928_parse_dt,
 };
 
 static const struct dw_mci_drv_data rk3288_drv_data = {
-- 
2.47.3



^ permalink raw reply related

* Re: [PATCH v1 3/4] arm64/vdso: Enable SFrame generation in vDSO
From: Dylan Hatch @ 2026-05-22 18:24 UTC (permalink / raw)
  To: Jens Remus
  Cc: Catalin Marinas, Will Deacon, Steven Rostedt, Josh Poimboeuf,
	Indu Bhagat, Peter Zijlstra, Weinan Liu, linux-arm-kernel,
	linux-kernel, Heiko Carstens, Ilya Leoshkevich
In-Reply-To: <48871045-9ec8-4e62-a2c5-809e3070d671@linux.ibm.com>

On Fri, May 22, 2026 at 1:51 AM Jens Remus <jremus@linux.ibm.com> wrote:
>
> Hello Dylan,
>
> thank you for the feedback!
>
> On 5/22/2026 3:31 AM, Dylan Hatch wrote:
> > On Fri, Apr 17, 2026 at 8:08 AM Jens Remus <jremus@linux.ibm.com> wrote:
> >>
> >> This replicates Josh's x86 patch "x86/vdso: Enable sframe generation
> >> in VDSO" [1] for arm64.
> >>
> >> Enable .sframe generation in the vDSO library so kernel and user space
> >> can unwind through it.  Keep all function symbols in the vDSO .symtab
> >> for stack trace purposes.  This enables perf to lookup these function
> >> symbols in addition to those already exported in vDSO .dynsym.
> >>
> >> Starting with binutils 2.46 both GNU assembler and GNU linker
> >> exclusively support generating and merging .sframe in SFrame V3 format.
> >> For vDSO, only if supported by the assembler, generate .sframe, collect
> >> it, mark it as KEEP, and generate a GNU_SFRAME program table entry.
> >> Otherwise explicitly discard any .sframe.
> >>
> >> [1]: x86/vdso: Enable sframe generation in VDSO,
> >>      https://lore.kernel.org/all/20260211141357.271402-7-jremus@linux.ibm.com/
> >>
> >> Signed-off-by: Jens Remus <jremus@linux.ibm.com>
> >> ---
> >>
> >> Notes (jremus):
> >>     @Dylan:  Adding -Wa,--gsframe-3 to the VDSO CC_FLAGS_ADD_VDSO (and
> >>     AS_FLAGS_ADD_VDSO) may clash with your patch [1] that adds likewise
> >>     to the CC_FLAGS_REMOVE_VDSO.  Any idea how to resolve?
> >>
> >>     [1]: [PATCH v3 2/8] arm64, unwind: build kernel with sframe V3 info,
> >>          https://lore.kernel.org/all/20260406185000.1378082-3-dylanbhatch@google.com/
> >
> > In a kernel tree with both your patch and my [1] patch merged, I
> > believe we'd want to hold two invariants true:
> >
> > 1. If HAVE_UNWIND_KERNEL_SFRAME=n, we must not build the kernel with .sframe.
> > 2. If AS_SFRAME3=y, we must build vDSO with .sframe.
> >
> > Since HAVE_UNWIND_KERNEL_SFRAME=y implies AS_SFRAME3=y, I wonder if we
> > should be able to drop CC_FLAGS_SFRAME from CC_FLAGS_REMOVE_VDSO and
> > move some definitions:
> >
> > diff --git a/Makefile b/Makefile
> > index 227fda16deb1..ef059bccb8c1 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -1147,12 +1147,15 @@ endif
> >  # Ensure compilers do not transform certain loops into calls to wcslen()
> >  KBUILD_CFLAGS += -fno-builtin-wcslen
> >
> > +ifeq ($(CONFIG_AS_SFRAME3),y)
> > +CC_FLAGS_SFRAME := -Wa,--gsframe-3
> > +export CC_FLAGS_SFRAME
> > +endif
> > +
> >  # build with sframe table
> >  ifdef CONFIG_HAVE_UNWIND_KERNEL_SFRAME
> > -CC_FLAGS_SFRAME := -Wa,--gsframe-3
> >  KBUILD_CFLAGS  += $(CC_FLAGS_SFRAME)
> >  KBUILD_AFLAGS  += $(CC_FLAGS_SFRAME)
> > -export CC_FLAGS_SFRAME
> >  endif
> >
> >  # change __FILE__ to the relative path to the source directory
> > diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
> > index e90427a8d0f6..f03cac27857c 100644
> > --- a/arch/arm64/kernel/vdso/Makefile
> > +++ b/arch/arm64/kernel/vdso/Makefile
> > @@ -15,10 +15,6 @@ obj-vdso := vgettimeofday.o note.o sigreturn.o
> > vgetrandom.o vgetrandom-chacha.o
> >  targets := $(obj-vdso) vdso.so vdso.so.dbg
> >  obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
> >
> > -ifeq ($(CONFIG_AS_SFRAME3),y)
> > -  SFRAME_CFLAGS := -Wa,--gsframe-3
> > -endif
> > -
> >  btildflags-$(CONFIG_ARM64_BTI_KERNEL) += -z force-bti
> >
> >  # -Bsymbolic has been added for consistency with arm, the compat vDSO and
> > @@ -42,12 +38,12 @@ ccflags-y += -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO
> >  CC_FLAGS_REMOVE_VDSO := $(CC_FLAGS_FTRACE) -Os $(CC_FLAGS_SCS) \
> >                         $(RANDSTRUCT_CFLAGS) $(KSTACK_ERASE_CFLAGS) \
> >                         $(GCC_PLUGINS_CFLAGS) \
> > -                       $(CC_FLAGS_LTO) $(CC_FLAGS_CFI) $(CC_FLAGS_SFRAME) \
> > +                       $(CC_FLAGS_LTO) $(CC_FLAGS_CFI) \
> >                         -Wmissing-prototypes -Wmissing-declarations
> >
> > -CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
> > $(SFRAME_CFLAGS)
> > +CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
> > $(CC_FLAGS_SFRAME)
> >
> > -AS_FLAGS_ADD_VDSO := $(SFRAME_CFLAGS)
> > +AS_FLAGS_ADD_VDSO := $(CC_FLAGS_SFRAME)
> >
> >  CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_REMOVE_VDSO)
> >  CFLAGS_REMOVE_vgetrandom.o = $(CC_FLAGS_REMOVE_VDSO)
> >
> >
> > If done this way I think we will add the -Wa,--gsframe-3 twice when
> > HAVE_UNWIND_KERNEL_SFRAME=y, but maybe that's not a problem? This
> > could probably be folded into either this patch or mine [1], depending
> > which is applied first. I'm happy to rebase my unwind-for-kernel
> > patches onto this series, or we can do the other way around if that
> > works better.
> >
> > What do you think?
>
> I like that approach.  Go ahead.

Do you have an updated version you can send? I noticed some of these
patches don't apply cleanly on Steven's current sframe branch. If you
can't get to it before you leave then no worries, have a good vacation
:)


^ permalink raw reply

* Re: [PATCH] clocksource/drivers/owl: fix refcount leak
From: Alexander A. Klimov @ 2026-05-22 18:20 UTC (permalink / raw)
  To: Markus Elfring, linux-actions, linux-arm-kernel,
	Andreas Färber, Daniel Lezcano, Manivannan Sadhasivam,
	Thomas Gleixner
  Cc: LKML
In-Reply-To: <c1aba09f-0a74-485c-b787-59b215a3bd88@web.de>



On 5/21/26 14:10, Markus Elfring wrote:
>> Every value returned from of_clk_get() is supposed to be cleaned up
>> via clk_put() once not needed anymore.
> 
> How do you think about to add a wording like “Thus add a missing function call.”?
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v7.1-rc4#n94
> 
> Would the application of another guard become helpful?

TIL (from you) there's DEFINE_FREE.
This seems pretty cool on its own.
I think I can apply it here, but I'd have to recompile.
This takes long.

Or we just fix this leak with the oneliner
I already compiled, booted and submitted.

I'll wait what maintainers decide...

> 
> How will chances evolve to adjust variable scopes accordingly?

Is this even a thing in Linux?
I mean specifying C variables anywhere ex. at function begin.


^ permalink raw reply

* Re: [PATCH 2/2] gpio: mxc: use BIT() macro
From: Frank Li @ 2026-05-22 18:09 UTC (permalink / raw)
  To: Alexander Stein
  Cc: Linus Walleij, Bartosz Golaszewski, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, linux-gpio, imx,
	linux-arm-kernel, linux-kernel
In-Reply-To: <20260522070118.800671-2-alexander.stein@ew.tq-group.com>

On Fri, May 22, 2026 at 09:01:16AM +0200, Alexander Stein wrote:
> Do not open-code the BIT() macro.

Nit: Replace the open-code with the BIT() macro.

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>
> Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
> ---
>  drivers/gpio/gpio-mxc.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
> index 12f11a6c96653..7e2690d92df6f 100644
> --- a/drivers/gpio/gpio-mxc.c
> +++ b/drivers/gpio/gpio-mxc.c
> @@ -330,13 +330,13 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable)
>  			ret = enable_irq_wake(port->irq_high);
>  		else
>  			ret = enable_irq_wake(port->irq);
> -		port->wakeup_pads |= (1 << gpio_idx);
> +		port->wakeup_pads |= BIT(gpio_idx);
>  	} else {
>  		if (port->irq_high && (gpio_idx >= 16))
>  			ret = disable_irq_wake(port->irq_high);
>  		else
>  			ret = disable_irq_wake(port->irq);
> -		port->wakeup_pads &= ~(1 << gpio_idx);
> +		port->wakeup_pads &= ~BIT(gpio_idx);
>  	}
>
>  	return ret;
> --
> 2.43.0
>


^ permalink raw reply

* Re: [PATCH v3 0/6] mm/vmalloc: Speed up ioremap, vmalloc and vmap with contiguous memory
From: Andrew Morton @ 2026-05-22 18:07 UTC (permalink / raw)
  To: Wen Jiang
  Cc: linux-mm, linux-arm-kernel, catalin.marinas, will, urezki, baohua,
	Xueyuan.chen21, dev.jain, rppt, david, ryan.roberts,
	anshuman.khandual, ajd, linux-kernel, jiangwen6
In-Reply-To: <20260522053146.83209-1-jiangwenxiaomi@gmail.com>

On Fri, 22 May 2026 13:31:40 +0800 Wen Jiang <jiangwenxiaomi@gmail.com> wrote:

> This patchset accelerates ioremap, vmalloc, and vmap when the memory
> is physically fully or partially contiguous.

Thanks.  AI review asked a few things and might have found an existing
32-bit bug in vmap():

	https://sashiko.dev/#/patchset/20260522053146.83209-1-jiangwenxiaomi@gmail.com


^ permalink raw reply

* [PATCH] KVM: arm64: Preserve all guest ZCR_EL2.LEN values
From: Mark Brown @ 2026-05-22 18:00 UTC (permalink / raw)
  To: Marc Zyngier, Oliver Upton, Joey Gouly, Steffen Eiden,
	Suzuki K Poulose, Catalin Marinas, Will Deacon
  Cc: Mark Rutland, linux-arm-kernel, kvmarm, linux-kernel, Mark Brown

Since b3d29a823099 ("KVM: arm64: nv: Handle ZCR_EL2 traps") when guests
write to ZCR_EL2 we have clamped the value of ZCR_EL2.LEN to be at most
that configuring the maximum guest VL. This is not the behaviour the
architecture documents for ZCR_EL2.LEN, the expectation is that all bits
will be read as written. Further, writing values larger than the largest
available vector length is part of the documented procedure for enumerating
the supported vector lengths so we expect to see this happen in practice.

The reasoning for the current behaviour is not specifically articulated, my
best guess is that it is intended to ensure that the guest can not see an
effective VL greater than the maximum that has been configured. This can
instead be achieved by configuring ZCR_EL2 when loading guest state:

 - When running at EL0 or EL1 configure ZCR_EL2.LEN to the minimum of the
   guest ZCR_EL2.LEN and vcpu_sve_max_vq(vcpu)-1.
 - When running at EL2 configure the maximum VL for the guest in
   ZCR_EL2.LEN like we do for non-nested guests and load the guest
   ZCR_EL2 into ZCR_EL1.

This will ensure that the guest sees both the ZCR_EL2.LEN value which it
wrote and the effective VL that resulting from the values it has configured
in ZCR_ELx.LEN.

Currently all other bits in ZCR_EL2 are either RES0 or RAZ/WI, values
written are sanitised based on this.

Fixes: b3d29a823099 ("KVM: arm64: nv: Handle ZCR_EL2 traps")
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/kvm/hyp/include/hyp/switch.h | 8 ++++----
 arch/arm64/kvm/sys_regs.c               | 6 +-----
 2 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index bf0eb5e43427..fd277cb70967 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -501,11 +501,11 @@ static inline void fpsimd_lazy_switch_to_guest(struct kvm_vcpu *vcpu)
 		return;
 
 	if (vcpu_has_sve(vcpu)) {
+		zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
+
 		/* A guest hypervisor may restrict the effective max VL. */
-		if (is_nested_ctxt(vcpu))
-			zcr_el2 = __vcpu_sys_reg(vcpu, ZCR_EL2);
-		else
-			zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
+		if (is_nested_ctxt(vcpu) && !is_hyp_ctxt(vcpu))
+			zcr_el2 = min(zcr_el2, __vcpu_sys_reg(vcpu, ZCR_EL2));
 
 		write_sysreg_el2(zcr_el2, SYS_ZCR);
 
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 148fc3400ea8..c4d3bbae2d14 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -2862,8 +2862,6 @@ static bool access_zcr_el2(struct kvm_vcpu *vcpu,
 			   struct sys_reg_params *p,
 			   const struct sys_reg_desc *r)
 {
-	unsigned int vq;
-
 	if (guest_hyp_sve_traps_enabled(vcpu)) {
 		kvm_inject_nested_sve_trap(vcpu);
 		return false;
@@ -2874,9 +2872,7 @@ static bool access_zcr_el2(struct kvm_vcpu *vcpu,
 		return true;
 	}
 
-	vq = SYS_FIELD_GET(ZCR_ELx, LEN, p->regval) + 1;
-	vq = min(vq, vcpu_sve_max_vq(vcpu));
-	__vcpu_assign_sys_reg(vcpu, ZCR_EL2, vq - 1);
+	__vcpu_assign_sys_reg(vcpu, ZCR_EL2, p->regval & ZCR_ELx_LEN);
 	return true;
 }
 

---
base-commit: 5200f5f493f79f14bbdc349e402a40dfb32f23c8
change-id: 20260519-kvm-arm64-fix-zcr-len-nv-9e9e7bae012a

Best regards,
--  
Mark Brown <broonie@kernel.org>



^ permalink raw reply related

* Re: [PATCH 1/5] dt-bindings: remoteproc: imx_rproc: document optional "memory-region-names"
From: Frank Li @ 2026-05-22 18:00 UTC (permalink / raw)
  To: Laurentiu Mihalcea
  Cc: Bjorn Andersson, Mathieu Poirier, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sascha Hauer, Peng Fan,
	Fabio Estevam, Pengutronix Kernel Team, linux-remoteproc,
	devicetree, imx, linux-arm-kernel, linux-kernel
In-Reply-To: <20260522111849.783-2-laurentiumihalcea111@gmail.com>

On Fri, May 22, 2026 at 04:18:45AM -0700, Laurentiu Mihalcea wrote:
> From: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
>
> Document the optional "memory-region-names" property.

Need add reason why need memory-region-names.

Try to fix previous use undocument ABI method, which depend memory node
name. But now prefer use morden memory-region-names to fetch related
resource.

you can rephrase it.

Frank

>
> Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
> ---
>  .../devicetree/bindings/remoteproc/fsl,imx-rproc.yaml     | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
> index c18f71b64889..6679b10f9da5 100644
> --- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
> +++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
> @@ -62,6 +62,14 @@ properties:
>      minItems: 1
>      maxItems: 32
>
> +  memory-region-names:
> +    minItems: 1
> +    maxItems: 32
> +    items:
> +      oneOf:
> +        - const: rsc-table
> +        - pattern: '^vdev[0-9](buffer|vring[0-9])$'
> +
>    power-domains:
>      minItems: 2
>      maxItems: 8
> --
> 2.43.0
>


^ 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

* [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] 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 1/2] drivers/acpi: Move RISC-V interrupt controllers autodep to ACPI IRQ code
From: Rafael J. Wysocki @ 2026-05-22 17:45 UTC (permalink / raw)
  To: Lorenzo Pieralisi
  Cc: Rafael J. Wysocki, Len Brown, Sunil V L, Marc Zyngier,
	Thomas Gleixner, Huacai Chen, Anup Patel, Hanjun Guo,
	Sudeep Holla, Catalin Marinas, Will Deacon, linux-riscv,
	linux-kernel, linux-acpi, linux-arm-kernel, loongarch
In-Reply-To: <20260505-gic-v5-acpi-iwb-probe-deferral-v1-1-b37b85998362@kernel.org>

On Tue, May 5, 2026 at 10:48 AM Lorenzo Pieralisi <lpieralisi@kernel.org> wrote:
>
> RISC-V implements arch code to detect probe dependencies for devices and
> the interrupt controller the devices GSIs are routed to.
>
> The code itself is arch agnostic apart from an arch specific helper
> function required to retrieve the acpi_handle of the interrupt controller
> that manages the device GSI interrupt.
>
> In order to enable IRQ probe dependencies detection on other
> architectures, move RISC-V IRQ probe dependency detection code to
> generic ACPI IRQ code.
>
> RISC-V IRQ code detecting IRQ probe dependency has some limitations/latent
> bugs:
>
> - riscv_acpi_irq_get_dep() would force the loop in
>   riscv_acpi_add_irq_dep() to stop at the first IRQ index that does not
>   map to an interrupt controller handle (missing some possible
>   dependencies)
> - riscv_acpi_add_prt_dep() does not validate acpi_get_handle() output
> - riscv_acpi_add_prt_dep() logic to handle memory allocation failure is
>   forcing the loop to continue on the same PRT entry
>
> Fix the above limitations along with the code move.

I'd rather do the cleanup first, possibly in multiple steps, and then
move the code separately.

As it stands, it's quite hard to figure out what's going on and why.

> Allow interrupt controller drivers to register an arch specific
> function to determine the acpi_handle for a specific GSI number to use
> the mechanism if needed by the respective interrupt controller drivers.
>
> Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
> Cc: Huacai Chen <chenhuacai@kernel.org>
> Cc: Thomas Gleixner <tglx@kernel.org>
> Cc: Anup Patel <anup@brainfault.org>
> Cc: "Rafael J. Wysocki" <rafael@kernel.org>
> Cc: Sunil V L <sunilvl@ventanamicro.com>
> Cc: Marc Zyngier <maz@kernel.org>
> ---
>  arch/riscv/include/asm/acpi.h       |   1 +
>  drivers/acpi/irq.c                  | 172 +++++++++++++++++++++++++++++++++++-
>  drivers/acpi/riscv/irq.c            | 141 +----------------------------
>  drivers/irqchip/irq-gic-v3.c        |   2 +-
>  drivers/irqchip/irq-gic-v5.c        |   2 +-
>  drivers/irqchip/irq-gic.c           |   2 +-
>  drivers/irqchip/irq-loongarch-cpu.c |   2 +-
>  drivers/irqchip/irq-riscv-intc.c    |   3 +-
>  include/linux/acpi.h                |   5 +-
>  9 files changed, 181 insertions(+), 149 deletions(-)
>
> diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h
> index 26ab37c171bc..f598520ac903 100644
> --- a/arch/riscv/include/asm/acpi.h
> +++ b/arch/riscv/include/asm/acpi.h
> @@ -67,6 +67,7 @@ int acpi_get_riscv_isa(struct acpi_table_header *table,
>
>  void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size,
>                              u32 *cboz_size, u32 *cbop_size);
> +acpi_handle acpi_get_riscv_gsi_handle(u32 gsi);
>  #else
>  static inline void acpi_init_rintc_map(void) { }
>  static inline struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu)
> diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
> index d1595156c86a..e4293458bf61 100644
> --- a/drivers/acpi/irq.c
> +++ b/drivers/acpi/irq.c
> @@ -13,6 +13,7 @@
>  enum acpi_irq_model_id acpi_irq_model;
>
>  static acpi_gsi_domain_disp_fn acpi_get_gsi_domain_id;
> +static acpi_gsi_handle_disp_fn acpi_get_gsi_handle;
>  static u32 (*acpi_gsi_to_irq_fallback)(u32 gsi);
>
>  /**
> @@ -321,15 +322,19 @@ const struct cpumask *acpi_irq_get_affinity(acpi_handle handle,
>
>  /**
>   * acpi_set_irq_model - Setup the GSI irqdomain information
> - * @model: the value assigned to acpi_irq_model
> - * @fn: a dispatcher function that will return the domain fwnode
> - *     for a given GSI
> + * @model:     the value assigned to acpi_irq_model
> + * @fn:                a dispatcher function that will return the domain fwnode
> + *             for a given GSI
> + * @gsi_dep_fn: a function to retrieve the acpi_handle a GSI interrupt is
> + *             dependent on
> + *
>   */
>  void __init acpi_set_irq_model(enum acpi_irq_model_id model,
> -                              acpi_gsi_domain_disp_fn fn)
> +                              acpi_gsi_domain_disp_fn fn, acpi_gsi_handle_disp_fn gsi_dep_fn)
>  {
>         acpi_irq_model = model;
>         acpi_get_gsi_domain_id = fn;
> +       acpi_get_gsi_handle = gsi_dep_fn;
>  }
>
>  /*
> @@ -385,3 +390,162 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
>                                            host_data);
>  }
>  EXPORT_SYMBOL_GPL(acpi_irq_create_hierarchy);
> +
> +struct acpi_irq_dep_ctx {
> +       int             rc;
> +       unsigned int    index;
> +       acpi_handle     handle;
> +};
> +
> +static acpi_status acpi_irq_get_parent(struct acpi_resource *ares, void *context)
> +{
> +       struct acpi_irq_dep_ctx *ctx = context;
> +       struct acpi_resource_irq *irq;
> +       struct acpi_resource_extended_irq *eirq;
> +
> +       switch (ares->type) {
> +       case ACPI_RESOURCE_TYPE_IRQ:
> +               irq = &ares->data.irq;
> +               if (ctx->index >= irq->interrupt_count) {
> +                       ctx->index -= irq->interrupt_count;
> +                       return AE_OK;
> +               }
> +               ctx->handle = acpi_get_gsi_handle(irq->interrupts[ctx->index]);
> +               ctx->rc = 0;
> +               return AE_CTRL_TERMINATE;
> +       case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
> +               eirq = &ares->data.extended_irq;
> +               if (eirq->producer_consumer == ACPI_PRODUCER)
> +                       return AE_OK;
> +
> +               if (ctx->index >= eirq->interrupt_count) {
> +                       ctx->index -= eirq->interrupt_count;
> +                       return AE_OK;
> +               }
> +
> +               /* Support GSIs only */
> +               if (eirq->resource_source.string_length)
> +                       return AE_OK;
> +
> +               ctx->handle = acpi_get_gsi_handle(eirq->interrupts[ctx->index]);
> +               ctx->rc = 0;
> +               return AE_CTRL_TERMINATE;
> +       }
> +
> +       return AE_OK;
> +}
> +
> +static int acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_handle *gsi_handle)
> +{
> +       struct acpi_irq_dep_ctx ctx = {-EINVAL, index, NULL};
> +
> +       if (!gsi_handle)
> +               return -EINVAL;
> +
> +       acpi_walk_resources(handle, METHOD_NAME__CRS, acpi_irq_get_parent, &ctx);
> +       *gsi_handle = ctx.handle;
> +
> +       return ctx.rc;
> +}
> +
> +static bool acpi_prt_entry_valid(void *prt_entry)
> +{
> +       struct acpi_pci_routing_table *entry = prt_entry;
> +
> +       return entry && entry->length > 0;
> +}
> +
> +static void *acpi_prt_next_entry(void *prt_entry)
> +{
> +       struct acpi_pci_routing_table *entry = prt_entry;
> +
> +       return prt_entry + entry->length;
> +}
> +
> +static u32 acpi_add_prt_dep(acpi_handle handle)
> +{
> +       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
> +       struct acpi_pci_routing_table *entry;
> +       struct acpi_handle_list dep_devices;
> +       acpi_handle gsi_handle;
> +       acpi_handle link_handle;
> +       acpi_status status;
> +       u32 count = 0;
> +
> +       status = acpi_get_irq_routing_table(handle, &buffer);
> +       if (ACPI_FAILURE(status)) {
> +               acpi_handle_err(handle, "failed to get IRQ routing table\n");
> +               kfree(buffer.pointer);
> +               return 0;
> +       }
> +
> +       entry = buffer.pointer;
> +       for (; acpi_prt_entry_valid(entry); entry = acpi_prt_next_entry(entry)) {
> +               if (entry->source[0]) {
> +                       status = acpi_get_handle(handle, entry->source, &link_handle);
> +                       if (ACPI_FAILURE(status))
> +                               continue;
> +                       dep_devices.count = 1;
> +                       dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
> +                       if (!dep_devices.handles) {
> +                               acpi_handle_err(handle, "failed to allocate memory\n");
> +                               continue;
> +                       }
> +
> +                       dep_devices.handles[0] = link_handle;
> +                       count += acpi_scan_add_dep(handle, &dep_devices);
> +               } else {
> +                       gsi_handle = acpi_get_gsi_handle(entry->source_index);
> +                       if (!gsi_handle)
> +                               continue;
> +                       dep_devices.count = 1;
> +                       dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
> +                       if (!dep_devices.handles) {
> +                               acpi_handle_err(handle, "failed to allocate memory\n");
> +                               continue;
> +                       }
> +
> +                       dep_devices.handles[0] = gsi_handle;
> +                       count += acpi_scan_add_dep(handle, &dep_devices);
> +               }
> +       }
> +
> +       kfree(buffer.pointer);
> +       return count;
> +}
> +
> +static u32 acpi_add_irq_dep(acpi_handle handle)
> +{
> +       struct acpi_handle_list dep_devices;
> +       acpi_handle gsi_handle;
> +       u32 count = 0;
> +       int i;
> +
> +       for (i = 0; !acpi_irq_get_dep(handle, i, &gsi_handle); i++) {
> +               if (!gsi_handle)
> +                       continue;
> +
> +               dep_devices.count = 1;
> +               dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
> +               if (!dep_devices.handles) {
> +                       acpi_handle_err(handle, "failed to allocate memory\n");
> +                       continue;
> +               }
> +
> +               dep_devices.handles[0] = gsi_handle;
> +               count += acpi_scan_add_dep(handle, &dep_devices);
> +       }
> +
> +       return count;
> +}
> +
> +u32 acpi_irq_add_auto_dep(acpi_handle handle)
> +{
> +       if (!acpi_get_gsi_handle)
> +               return 0;
> +
> +       if (acpi_has_method(handle, "_PRT"))
> +               return acpi_add_prt_dep(handle);
> +
> +       return acpi_add_irq_dep(handle);
> +}
> diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
> index 9b88d0993e88..da2c42e0ebfd 100644
> --- a/drivers/acpi/riscv/irq.c
> +++ b/drivers/acpi/riscv/irq.c
> @@ -23,12 +23,6 @@ struct riscv_ext_intc_list {
>         struct list_head        list;
>  };
>
> -struct acpi_irq_dep_ctx {
> -       int             rc;
> -       unsigned int    index;
> -       acpi_handle     handle;
> -};
> -
>  LIST_HEAD(ext_intc_list);
>
>  static int irqchip_cmp_func(const void *in0, const void *in1)
> @@ -254,7 +248,7 @@ void __init riscv_acpi_init_gsi_mapping(void)
>         acpi_get_devices("RSCV0006", riscv_acpi_create_gsi_map_smsi, NULL, NULL);
>  }
>
> -static acpi_handle riscv_acpi_get_gsi_handle(u32 gsi)
> +acpi_handle acpi_get_riscv_gsi_handle(u32 gsi)
>  {
>         struct riscv_ext_intc_list *ext_intc_element;
>         struct list_head *i;
> @@ -269,138 +263,7 @@ static acpi_handle riscv_acpi_get_gsi_handle(u32 gsi)
>         return NULL;
>  }
>
> -static acpi_status riscv_acpi_irq_get_parent(struct acpi_resource *ares, void *context)
> -{
> -       struct acpi_irq_dep_ctx *ctx = context;
> -       struct acpi_resource_irq *irq;
> -       struct acpi_resource_extended_irq *eirq;
> -
> -       switch (ares->type) {
> -       case ACPI_RESOURCE_TYPE_IRQ:
> -               irq = &ares->data.irq;
> -               if (ctx->index >= irq->interrupt_count) {
> -                       ctx->index -= irq->interrupt_count;
> -                       return AE_OK;
> -               }
> -               ctx->handle = riscv_acpi_get_gsi_handle(irq->interrupts[ctx->index]);
> -               return AE_CTRL_TERMINATE;
> -       case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
> -               eirq = &ares->data.extended_irq;
> -               if (eirq->producer_consumer == ACPI_PRODUCER)
> -                       return AE_OK;
> -
> -               if (ctx->index >= eirq->interrupt_count) {
> -                       ctx->index -= eirq->interrupt_count;
> -                       return AE_OK;
> -               }
> -
> -               /* Support GSIs only */
> -               if (eirq->resource_source.string_length)
> -                       return AE_OK;
> -
> -               ctx->handle = riscv_acpi_get_gsi_handle(eirq->interrupts[ctx->index]);
> -               return AE_CTRL_TERMINATE;
> -       }
> -
> -       return AE_OK;
> -}
> -
> -static int riscv_acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_handle *gsi_handle)
> -{
> -       struct acpi_irq_dep_ctx ctx = {-EINVAL, index, NULL};
> -
> -       if (!gsi_handle)
> -               return 0;
> -
> -       acpi_walk_resources(handle, METHOD_NAME__CRS, riscv_acpi_irq_get_parent, &ctx);
> -       *gsi_handle = ctx.handle;
> -       if (*gsi_handle)
> -               return 1;
> -
> -       return 0;
> -}
> -
> -static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
> -{
> -       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
> -       struct acpi_pci_routing_table *entry;
> -       struct acpi_handle_list dep_devices;
> -       acpi_handle gsi_handle;
> -       acpi_handle link_handle;
> -       acpi_status status;
> -       u32 count = 0;
> -
> -       status = acpi_get_irq_routing_table(handle, &buffer);
> -       if (ACPI_FAILURE(status)) {
> -               acpi_handle_err(handle, "failed to get IRQ routing table\n");
> -               kfree(buffer.pointer);
> -               return 0;
> -       }
> -
> -       entry = buffer.pointer;
> -       while (entry && (entry->length > 0)) {
> -               if (entry->source[0]) {
> -                       acpi_get_handle(handle, entry->source, &link_handle);
> -                       dep_devices.count = 1;
> -                       dep_devices.handles = kzalloc_objs(*dep_devices.handles,
> -                                                          1);
> -                       if (!dep_devices.handles) {
> -                               acpi_handle_err(handle, "failed to allocate memory\n");
> -                               continue;
> -                       }
> -
> -                       dep_devices.handles[0] = link_handle;
> -                       count += acpi_scan_add_dep(handle, &dep_devices);
> -               } else {
> -                       gsi_handle = riscv_acpi_get_gsi_handle(entry->source_index);
> -                       dep_devices.count = 1;
> -                       dep_devices.handles = kzalloc_objs(*dep_devices.handles,
> -                                                          1);
> -                       if (!dep_devices.handles) {
> -                               acpi_handle_err(handle, "failed to allocate memory\n");
> -                               continue;
> -                       }
> -
> -                       dep_devices.handles[0] = gsi_handle;
> -                       count += acpi_scan_add_dep(handle, &dep_devices);
> -               }
> -
> -               entry = (struct acpi_pci_routing_table *)
> -                       ((unsigned long)entry + entry->length);
> -       }
> -
> -       kfree(buffer.pointer);
> -       return count;
> -}
> -
> -static u32 riscv_acpi_add_irq_dep(acpi_handle handle)
> -{
> -       struct acpi_handle_list dep_devices;
> -       acpi_handle gsi_handle;
> -       u32 count = 0;
> -       int i;
> -
> -       for (i = 0;
> -            riscv_acpi_irq_get_dep(handle, i, &gsi_handle);
> -            i++) {
> -               dep_devices.count = 1;
> -               dep_devices.handles = kzalloc_objs(*dep_devices.handles, 1);
> -               if (!dep_devices.handles) {
> -                       acpi_handle_err(handle, "failed to allocate memory\n");
> -                       continue;
> -               }
> -
> -               dep_devices.handles[0] = gsi_handle;
> -               count += acpi_scan_add_dep(handle, &dep_devices);
> -       }
> -
> -       return count;
> -}
> -
>  u32 arch_acpi_add_auto_dep(acpi_handle handle)
>  {
> -       if (acpi_has_method(handle, "_PRT"))
> -               return riscv_acpi_add_prt_dep(handle);
> -
> -       return riscv_acpi_add_irq_dep(handle);
> +       return acpi_irq_add_auto_dep(handle);
>  }
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index 99444a1b2ffa..2673954d4577 100644
> --- a/drivers/irqchip/irq-gic-v3.c
> +++ b/drivers/irqchip/irq-gic-v3.c
> @@ -2588,7 +2588,7 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
>         if (err)
>                 goto out_fwhandle_free;
>
> -       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id);
> +       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id, NULL);
>
>         if (static_branch_likely(&supports_deactivate_key))
>                 gic_acpi_setup_kvm_info();
> diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
> index 6b0903be8ebf..03cc2830b260 100644
> --- a/drivers/irqchip/irq-gic-v5.c
> +++ b/drivers/irqchip/irq-gic-v5.c
> @@ -1242,7 +1242,7 @@ static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsig
>         if (ret)
>                 goto out_irs;
>
> -       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id);
> +       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id, NULL);
>
>         return 0;
>
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index ec70c84e9f91..f6bc29f515fb 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -1690,7 +1690,7 @@ static int __init gic_v2_acpi_init(union acpi_subtable_headers *header,
>                 return ret;
>         }
>
> -       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v2_get_gsi_domain_id);
> +       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v2_get_gsi_domain_id, NULL);
>
>         if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
>                 gicv2m_init(NULL, gic_data[0].domain);
> diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c
> index 950bc087e388..84ce24889488 100644
> --- a/drivers/irqchip/irq-loongarch-cpu.c
> +++ b/drivers/irqchip/irq-loongarch-cpu.c
> @@ -168,7 +168,7 @@ static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,
>                 panic("Failed to add irqdomain for LoongArch CPU");
>
>         set_handle_irq(&handle_cpu_irq);
> -       acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id);
> +       acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id, NULL);
>         acpi_set_gsi_to_irq_fallback(lpic_gsi_to_irq);
>         ret = acpi_cascade_irqdomain_init();
>
> diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
> index 84418dbd5a27..0595144116e2 100644
> --- a/drivers/irqchip/irq-riscv-intc.c
> +++ b/drivers/irqchip/irq-riscv-intc.c
> @@ -384,7 +384,8 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
>         if (rc)
>                 irq_domain_free_fwnode(fn);
>         else
> -               acpi_set_irq_model(ACPI_IRQ_MODEL_RINTC, riscv_acpi_get_gsi_domain_id);
> +               acpi_set_irq_model(ACPI_IRQ_MODEL_RINTC, riscv_acpi_get_gsi_domain_id,
> +                                  acpi_get_riscv_gsi_handle);
>
>         return rc;
>  }
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 67effb91fa98..468fc6a54651 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -360,9 +360,10 @@ int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
>  int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi);
>
>  typedef struct fwnode_handle *(*acpi_gsi_domain_disp_fn)(u32);
> +typedef acpi_handle (*acpi_gsi_handle_disp_fn)(u32);
>
>  void acpi_set_irq_model(enum acpi_irq_model_id model,
> -                       acpi_gsi_domain_disp_fn fn);
> +                       acpi_gsi_domain_disp_fn fn, acpi_gsi_handle_disp_fn gsi_dep_fn);
>  acpi_gsi_domain_disp_fn acpi_get_gsi_dispatcher(void);
>  void acpi_set_gsi_to_irq_fallback(u32 (*)(u32));
>
> @@ -372,6 +373,8 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
>                                              const struct irq_domain_ops *ops,
>                                              void *host_data);
>
> +u32 acpi_irq_add_auto_dep(acpi_handle handle);
> +
>  #ifdef CONFIG_X86_IO_APIC
>  extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity);
>  #else
>
> --
> 2.54.0
>


^ 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 v2 0/2] spi: aspeed: Fix __iomem annotation and VLA parameter
From: Mark Brown @ 2026-05-22 11:01 UTC (permalink / raw)
  To: clg, joel, andrew, linux-aspeed, openbmc, linux-spi,
	linux-arm-kernel, linux-kernel, david.laight.linux, BMC-SW,
	Chin-Ting Kuo
In-Reply-To: <20260522071621.102507-1-chin-ting_kuo@aspeedtech.com>

On Fri, 22 May 2026 15:16:19 +0800, Chin-Ting Kuo wrote:
> spi: aspeed: Fix __iomem annotation and VLA parameter
> 
> This series fixes two sparse warnings reported by the kernel test robot.
> The first patch fixes missing __iomem annotation on an MMIO pointer
> parameter, which also caused a redundant cast at the call site.
> A VLA function parameter warning is also fixed in this patch series.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-7.2

Thanks!

[1/2] spi: aspeed: Fix missing __iomem annotation in output transfer path
      https://git.kernel.org/broonie/spi/c/5c3091e23f8f
[2/2] spi: aspeed: Replace VLA parameter with flat pointer in calibration helper
      https://git.kernel.org/broonie/spi/c/94f5efbaa751

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



^ permalink raw reply

* Re: [PATCH v2 0/4] ASoC: stm: Use guard() for mutex & spin locks
From: Mark Brown @ 2026-05-22 12:36 UTC (permalink / raw)
  To: olivier.moysan, arnaud.pouliquen, phucduc.bui
  Cc: lgirdwood, perex, tiwai, mcoquelin.stm32, alexandre.torgue,
	linux-sound, linux-stm32, linux-arm-kernel, linux-kernel
In-Reply-To: <20260515112458.34378-1-phucduc.bui@gmail.com>

On Fri, 15 May 2026 18:24:54 +0700, phucduc.bui@gmail.com wrote:
> ASoC: stm: Use guard() for mutex & spin locks
> 
> From: bui duc phuc <phucduc.bui@gmail.com>
> 
> Hi all,
> 
> This series converts mutex and spinlock handling in the STM drivers
> to use guard() helpers.
> The changes are code cleanup only and should have no functional impact.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-7.2

Thanks!

[1/4] ASoC: stm: stm32_adfsdm: Use guard() for mutex locks
      https://git.kernel.org/broonie/sound/c/dabf5b45b18c
[2/4] ASoC: stm: stm32_i2s: Use guard() for spin locks
      https://git.kernel.org/broonie/sound/c/b212cb00168c
[3/4] ASoC: stm: stm32_sai_sub: Use guard() for mutex & spin locks
      https://git.kernel.org/broonie/sound/c/5e54b4c280af
[4/4] ASoC: stm: stm32_spdifrx: Use guard() for spin locks
      https://git.kernel.org/broonie/sound/c/3f0d573c3259

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



^ permalink raw reply

* Re: [PATCH] ASoC: mediatek: mt8189: Fix probe resource cleanup
From: Mark Brown @ 2026-05-22 12:30 UTC (permalink / raw)
  To: Liam Girdwood, Jaroslav Kysela, Takashi Iwai, Matthias Brugger,
	AngeloGioacchino Del Regno, Cyril Chao, Cássio Gabriel
  Cc: linux-sound, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <20260514-asoc-mt8189-probe-cleanup-v1-1-ded733363281@gmail.com>

On Thu, 14 May 2026 10:52:35 -0300, Cássio Gabriel wrote:
> ASoC: mediatek: mt8189: Fix probe resource cleanup

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-7.2

Thanks!

[1/1] ASoC: mediatek: mt8189: Fix probe resource cleanup
      https://git.kernel.org/broonie/sound/c/5404599c3292

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



^ permalink raw reply

* [PATCH 2/8] bpf: Recover arena kernel faults with scratch page
From: Tejun Heo @ 2026-05-22 17:22 UTC (permalink / raw)
  To: David Vernet, Andrea Righi, Changwoo Min, Alexei Starovoitov,
	Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau,
	Kumar Kartikeya Dwivedi
  Cc: Peter Zijlstra, Catalin Marinas, Will Deacon, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, Andrew Morton,
	David Hildenbrand, Mike Rapoport, Emil Tsalapatis, sched-ext, bpf,
	x86, linux-arm-kernel, linux-mm, linux-kernel, Tejun Heo
In-Reply-To: <20260522172219.1423324-1-tj@kernel.org>

From: Kumar Kartikeya Dwivedi <memxor@gmail.com>

BPF arena usage is becoming more prevalent, but kernel <-> BPF communication
over arena memory is awkward today. Data has to be staged through a trusted
kernel pointer with extra code and copying on the BPF side. While reads
through arena pointers can use a fault-safe helper, writes don't have a good
solution. The in-line alternative would need instruction emulation or asm
fixup labels.

Enable direct kernel-side reads and writes within GUARD_SZ / 2 of any
handed-in arena pointer, without bounds checking. A per-arena scratch page
is installed by the arch fault path into empty arena kernel PTEs - x86 from
page_fault_oops() for not-present faults, arm64 from __do_kernel_fault() for
translation faults, both after the existing exception-table and KFENCE
handling. The faulting instruction retries and the access is also reported
through the program's BPF stream, preserving error reporting.

bpf_prog_find_from_stack() resolves the current BPF program (and its arena)
from the kernel stack - no new bpf_run_ctx state is added. Recovery covers
the 4 GiB arena plus the upper half-guard (GUARD_SZ / 2). The lower
half-guard is excluded because well-behaved kfuncs only access forward from
arena pointers. The kfunc-author contract - access at most GUARD_SZ / 2 past
a handed-in pointer - is documented in Documentation/bpf/kfuncs.rst.

The install is lock-free via ptep_try_set(). On race-loss the winning
installer's PTE is already valid, so the access retry succeeds. The arena
clear path uses ptep_get_and_clear() so installer and clearer race through
atomic accessors. No flush_tlb_kernel_range() afterwards. Stale "not mapped"
entries just cause one extra re-fault, cheaper than a global IPI on every
install.

Scratch exists only to keep the kernel from oopsing on an in-line arena
access. Its presence at a PTE means the BPF program has already
malfunctioned, and the violation is reported through the program's BPF
stream. The only requirement for behavior on a scratched PTE is that the
kernel doesn't crash. In particular, any user-side access through such a PTE
may segfault. The shared scratch page is freed once during map destruction.

BPF instruction faults continue to use the existing JIT exception-table
path. This patch changes only the kernel-text fault path. No UAPI flag is
added. The new behavior is the default.

v2: Use ptep_get_and_clear() in apply_range_clear_cb(). (David)
v3: Stub bpf_arena_handle_page_fault() for !CONFIG_BPF_SYSCALL. (lkp)

Suggested-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Cc: David Hildenbrand <david@kernel.org>
---
 Documentation/bpf/kfuncs.rst |  14 +++
 arch/arm64/mm/fault.c        |  10 +-
 arch/x86/mm/fault.c          |  12 ++-
 include/linux/bpf.h          |   1 +
 include/linux/bpf_defs.h     |  19 ++++
 kernel/bpf/arena.c           | 177 +++++++++++++++++++++++++++--------
 kernel/bpf/core.c            |   5 +
 7 files changed, 191 insertions(+), 47 deletions(-)
 create mode 100644 include/linux/bpf_defs.h

diff --git a/Documentation/bpf/kfuncs.rst b/Documentation/bpf/kfuncs.rst
index 75e6c078e0e7..6d497e720998 100644
--- a/Documentation/bpf/kfuncs.rst
+++ b/Documentation/bpf/kfuncs.rst
@@ -462,6 +462,20 @@ In order to accommodate such requirements, the verifier will enforce strict
 PTR_TO_BTF_ID type matching if two types have the exact same name, with one
 being suffixed with ``___init``.
 
+2.8 Accessing arena memory through kfunc arguments
+--------------------------------------------------
+
+A read or write at any address inside an arena does not oops the kernel.
+Unallocated arena pages are lazily backed by a scratch page and the
+access is reported through the program's BPF stream as an error. Only
+the BPF program's correctness is affected; the kernel itself remains
+intact.
+
+The arena is followed by a ``GUARD_SZ / 2`` (32 KiB) guard region that
+is also covered by this recovery. A kfunc handed an arena pointer may
+therefore access up to ``GUARD_SZ / 2`` past it without bounds-checking
+against the arena. Larger accesses must verify the range explicitly.
+
 .. _BPF_kfunc_lifecycle_expectations:
 
 3. kfunc lifecycle expectations
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 920a8b244d59..0d58d667fcd8 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -9,6 +9,7 @@
 
 #include <linux/acpi.h>
 #include <linux/bitfield.h>
+#include <linux/bpf_defs.h>
 #include <linux/extable.h>
 #include <linux/kfence.h>
 #include <linux/signal.h>
@@ -416,9 +417,12 @@ static void __do_kernel_fault(unsigned long addr, unsigned long esr,
 	} else if (addr < PAGE_SIZE) {
 		msg = "NULL pointer dereference";
 	} else {
-		if (esr_fsc_is_translation_fault(esr) &&
-		    kfence_handle_page_fault(addr, esr & ESR_ELx_WNR, regs))
-			return;
+		if (esr_fsc_is_translation_fault(esr)) {
+			if (kfence_handle_page_fault(addr, esr & ESR_ELx_WNR, regs))
+				return;
+			if (bpf_arena_handle_page_fault(addr, esr & ESR_ELx_WNR, regs->pc))
+				return;
+		}
 
 		msg = "paging request";
 	}
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index f0e77e084482..b0f103ddbd23 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -8,6 +8,7 @@
 #include <linux/sched/task_stack.h>	/* task_stack_*(), ...		*/
 #include <linux/kdebug.h>		/* oops_begin/end, ...		*/
 #include <linux/memblock.h>		/* max_low_pfn			*/
+#include <linux/bpf_defs.h>		/* bpf_arena_handle_page_fault	*/
 #include <linux/kfence.h>		/* kfence_handle_page_fault	*/
 #include <linux/kprobes.h>		/* NOKPROBE_SYMBOL, ...		*/
 #include <linux/mmiotrace.h>		/* kmmio_handler, ...		*/
@@ -688,10 +689,13 @@ page_fault_oops(struct pt_regs *regs, unsigned long error_code,
 	if (IS_ENABLED(CONFIG_EFI))
 		efi_crash_gracefully_on_page_fault(address);
 
-	/* Only not-present faults should be handled by KFENCE. */
-	if (!(error_code & X86_PF_PROT) &&
-	    kfence_handle_page_fault(address, error_code & X86_PF_WRITE, regs))
-		return;
+	/* Only not-present faults should be handled by KFENCE or BPF arena. */
+	if (!(error_code & X86_PF_PROT)) {
+		if (kfence_handle_page_fault(address, error_code & X86_PF_WRITE, regs))
+			return;
+		if (bpf_arena_handle_page_fault(address, error_code & X86_PF_WRITE, regs->ip))
+			return;
+	}
 
 oops:
 	/*
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 0136a108d083..831996c411cf 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -6,6 +6,7 @@
 
 #include <uapi/linux/bpf.h>
 #include <uapi/linux/filter.h>
+#include <linux/bpf_defs.h>
 
 #include <crypto/sha2.h>
 #include <linux/workqueue.h>
diff --git a/include/linux/bpf_defs.h b/include/linux/bpf_defs.h
new file mode 100644
index 000000000000..2185cd3966d4
--- /dev/null
+++ b/include/linux/bpf_defs.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Subset of bpf.h declarations, split out so files that need only these
+ * declarations can avoid bpf.h's full include cost.
+ */
+#ifndef _LINUX_BPF_DEFS_H
+#define _LINUX_BPF_DEFS_H
+
+#ifdef CONFIG_BPF_SYSCALL
+bool bpf_arena_handle_page_fault(unsigned long addr, bool is_write, unsigned long fault_ip);
+#else
+static inline bool bpf_arena_handle_page_fault(unsigned long addr, bool is_write,
+					       unsigned long fault_ip)
+{
+	return false;
+}
+#endif
+
+#endif /* _LINUX_BPF_DEFS_H */
diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
index 08d008cc471e..1c0b87ecc817 100644
--- a/kernel/bpf/arena.c
+++ b/kernel/bpf/arena.c
@@ -53,6 +53,7 @@ struct bpf_arena {
 	u64 user_vm_start;
 	u64 user_vm_end;
 	struct vm_struct *kern_vm;
+	struct page *scratch_page;
 	struct range_tree rt;
 	/* protects rt */
 	rqspinlock_t spinlock;
@@ -118,6 +119,11 @@ struct apply_range_data {
 	int i;
 };
 
+struct clear_range_data {
+	struct llist_head *free_pages;
+	struct page *scratch_page;
+};
+
 static int apply_range_set_cb(pte_t *pte, unsigned long addr, void *data)
 {
 	struct apply_range_data *d = data;
@@ -144,33 +150,59 @@ static void flush_vmap_cache(unsigned long start, unsigned long size)
 	flush_cache_vmap(start, start + size);
 }
 
-static int apply_range_clear_cb(pte_t *pte, unsigned long addr, void *free_pages)
+static int apply_range_clear_cb(pte_t *pte, unsigned long addr, void *data)
 {
+	struct clear_range_data *d = data;
 	pte_t old_pte;
 	struct page *page;
 
-	/* sanity check */
-	old_pte = ptep_get(pte);
+	/*
+	 * Pairs with ptep_try_set() in the kernel-fault scratch installer.
+	 * Both sides must be atomic.
+	 */
+	old_pte = ptep_get_and_clear(&init_mm, addr, pte);
 	if (pte_none(old_pte) || !pte_present(old_pte))
-		return 0; /* nothing to do */
+		return 0;
 
 	page = pte_page(old_pte);
 	if (WARN_ON_ONCE(!page))
 		return -EINVAL;
 
-	pte_clear(&init_mm, addr, pte);
+	/*
+	 * Skip the per-arena scratch page. A kernel fault on an unallocated uaddr
+	 * scratches its PTE. A later bpf_arena_free_pages() over that range walks
+	 * here. Without the skip, scratch_page would be freed.
+	 */
+	if (page == d->scratch_page)
+		return 0;
+
+	__llist_add(&page->pcp_llist, d->free_pages);
+	return 0;
+}
 
-	/* Add page to the list so it is freed later */
-	if (free_pages)
-		__llist_add(&page->pcp_llist, free_pages);
+static int apply_range_set_scratch_cb(pte_t *pte, unsigned long addr, void *data)
+{
+	struct page *scratch_page = data;
 
+	if (!pte_none(ptep_get(pte)))
+		return 0;
+	/*
+	 * Best-effort install. ptep_try_set() returns false only if another
+	 * installer (real allocation or concurrent fault) won the cmpxchg.
+	 * Their PTE is already valid, so the access retry succeeds.
+	 *
+	 * No flush_tlb_kernel_range() needed. Stale "not mapped" entries just
+	 * cause one extra re-fault through this same path.
+	 */
+	ptep_try_set(pte, mk_pte(scratch_page, PAGE_KERNEL));
 	return 0;
 }
 
 static int populate_pgtable_except_pte(struct bpf_arena *arena)
 {
+	/* Populate intermediates for the recovery range (4 GiB + upper half-guard). */
 	return apply_to_page_range(&init_mm, bpf_arena_get_kern_vm_start(arena),
-				   KERN_VM_SZ - GUARD_SZ, apply_range_set_cb, NULL);
+				   SZ_4G + GUARD_SZ / 2, apply_range_set_cb, NULL);
 }
 
 static struct bpf_map *arena_map_alloc(union bpf_attr *attr)
@@ -221,22 +253,29 @@ static struct bpf_map *arena_map_alloc(union bpf_attr *attr)
 	init_irq_work(&arena->free_irq, arena_free_irq);
 	INIT_WORK(&arena->free_work, arena_free_worker);
 	bpf_map_init_from_attr(&arena->map, attr);
+
+	err = bpf_map_alloc_pages(&arena->map, NUMA_NO_NODE, 1, &arena->scratch_page);
+	if (err)
+		goto err_free_arena;
+
 	range_tree_init(&arena->rt);
 	err = range_tree_set(&arena->rt, 0, attr->max_entries);
-	if (err) {
-		bpf_map_area_free(arena);
-		goto err;
-	}
+	if (err)
+		goto err_free_scratch;
 	mutex_init(&arena->lock);
 	raw_res_spin_lock_init(&arena->spinlock);
 	err = populate_pgtable_except_pte(arena);
-	if (err) {
-		range_tree_destroy(&arena->rt);
-		bpf_map_area_free(arena);
-		goto err;
-	}
+	if (err)
+		goto err_destroy_rt;
 
 	return &arena->map;
+
+err_destroy_rt:
+	range_tree_destroy(&arena->rt);
+err_free_scratch:
+	__free_page(arena->scratch_page);
+err_free_arena:
+	bpf_map_area_free(arena);
 err:
 	free_vm_area(kern_vm);
 	return ERR_PTR(err);
@@ -244,6 +283,7 @@ static struct bpf_map *arena_map_alloc(union bpf_attr *attr)
 
 static int existing_page_cb(pte_t *ptep, unsigned long addr, void *data)
 {
+	struct bpf_arena *arena = data;
 	struct page *page;
 	pte_t pte;
 
@@ -251,6 +291,12 @@ static int existing_page_cb(pte_t *ptep, unsigned long addr, void *data)
 	if (!pte_present(pte)) /* sanity check */
 		return 0;
 	page = pte_page(pte);
+	/*
+	 * Skip the scratch page. The walk is page-table-driven, not range-tree-driven,
+	 * so it can visit scratch PTEs at uaddrs the BPF program never allocated.
+	 */
+	if (page == arena->scratch_page)
+		return 0;
 	/*
 	 * We do not update pte here:
 	 * 1. Nobody should be accessing bpf_arena's range outside of a kernel bug
@@ -286,9 +332,10 @@ static void arena_map_free(struct bpf_map *map)
 	 * free those pages.
 	 */
 	apply_to_existing_page_range(&init_mm, bpf_arena_get_kern_vm_start(arena),
-				     KERN_VM_SZ - GUARD_SZ, existing_page_cb, NULL);
+				     SZ_4G + GUARD_SZ / 2, existing_page_cb, arena);
 	free_vm_area(arena->kern_vm);
 	range_tree_destroy(&arena->rt);
+	__free_page(arena->scratch_page);
 	bpf_map_area_free(arena);
 }
 
@@ -374,33 +421,37 @@ static vm_fault_t arena_vm_fault(struct vm_fault *vmf)
 		return VM_FAULT_RETRY;
 
 	page = vmalloc_to_page((void *)kaddr);
-	if (page)
+	if (page) {
+		if (page == arena->scratch_page)
+			/* BPF triggered scratch here; don't lazy-alloc over it */
+			goto out_sigsegv;
 		/* already have a page vmap-ed */
 		goto out;
+	}
 
 	bpf_map_memcg_enter(&arena->map, &old_memcg, &new_memcg);
 
 	if (arena->map.map_flags & BPF_F_SEGV_ON_FAULT)
 		/* User space requested to segfault when page is not allocated by bpf prog */
-		goto out_unlock_sigsegv;
+		goto out_sigsegv_memcg;
 
 	ret = range_tree_clear(&arena->rt, vmf->pgoff, 1);
 	if (ret)
-		goto out_unlock_sigsegv;
+		goto out_sigsegv_memcg;
 
 	struct apply_range_data data = { .pages = &page, .i = 0 };
 	/* Account into memcg of the process that created bpf_arena */
 	ret = bpf_map_alloc_pages(map, NUMA_NO_NODE, 1, &page);
 	if (ret) {
 		range_tree_set(&arena->rt, vmf->pgoff, 1);
-		goto out_unlock_sigsegv;
+		goto out_sigsegv_memcg;
 	}
 
 	ret = apply_to_page_range(&init_mm, kaddr, PAGE_SIZE, apply_range_set_cb, &data);
 	if (ret) {
 		range_tree_set(&arena->rt, vmf->pgoff, 1);
 		free_pages_nolock(page, 0);
-		goto out_unlock_sigsegv;
+		goto out_sigsegv_memcg;
 	}
 	flush_vmap_cache(kaddr, PAGE_SIZE);
 	bpf_map_memcg_exit(old_memcg, new_memcg);
@@ -409,8 +460,9 @@ static vm_fault_t arena_vm_fault(struct vm_fault *vmf)
 	raw_res_spin_unlock_irqrestore(&arena->spinlock, flags);
 	vmf->page = page;
 	return 0;
-out_unlock_sigsegv:
+out_sigsegv_memcg:
 	bpf_map_memcg_exit(old_memcg, new_memcg);
+out_sigsegv:
 	raw_res_spin_unlock_irqrestore(&arena->spinlock, flags);
 	return VM_FAULT_SIGSEGV;
 }
@@ -668,6 +720,7 @@ static void arena_free_pages(struct bpf_arena *arena, long uaddr, long page_cnt,
 	struct llist_head free_pages;
 	struct llist_node *pos, *t;
 	struct arena_free_span *s;
+	struct clear_range_data cdata;
 	unsigned long flags;
 	int ret = 0;
 
@@ -696,9 +749,11 @@ static void arena_free_pages(struct bpf_arena *arena, long uaddr, long page_cnt,
 	range_tree_set(&arena->rt, pgoff, page_cnt);
 
 	init_llist_head(&free_pages);
+	cdata.free_pages = &free_pages;
+	cdata.scratch_page = arena->scratch_page;
 	/* clear ptes and collect struct pages */
 	apply_to_existing_page_range(&init_mm, kaddr, page_cnt << PAGE_SHIFT,
-				     apply_range_clear_cb, &free_pages);
+				     apply_range_clear_cb, &cdata);
 
 	/* drop the lock to do the tlb flush and zap pages */
 	raw_res_spin_unlock_irqrestore(&arena->spinlock, flags);
@@ -788,6 +843,7 @@ static void arena_free_worker(struct work_struct *work)
 	struct arena_free_span *s;
 	u64 arena_vm_start, user_vm_start;
 	struct llist_head free_pages;
+	struct clear_range_data cdata;
 	struct page *page;
 	unsigned long full_uaddr;
 	long kaddr, page_cnt, pgoff;
@@ -801,6 +857,8 @@ static void arena_free_worker(struct work_struct *work)
 	bpf_map_memcg_enter(&arena->map, &old_memcg, &new_memcg);
 
 	init_llist_head(&free_pages);
+	cdata.free_pages = &free_pages;
+	cdata.scratch_page = arena->scratch_page;
 	arena_vm_start = bpf_arena_get_kern_vm_start(arena);
 	user_vm_start = bpf_arena_get_user_vm_start(arena);
 
@@ -813,7 +871,7 @@ static void arena_free_worker(struct work_struct *work)
 
 		/* clear ptes and collect pages in free_pages llist */
 		apply_to_existing_page_range(&init_mm, kaddr, page_cnt << PAGE_SHIFT,
-					     apply_range_clear_cb, &free_pages);
+					     apply_range_clear_cb, &cdata);
 
 		range_tree_set(&arena->rt, pgoff, page_cnt);
 	}
@@ -928,23 +986,12 @@ static int __init kfunc_init(void)
 }
 late_initcall(kfunc_init);
 
-void bpf_prog_report_arena_violation(bool write, unsigned long addr, unsigned long fault_ip)
+static void __bpf_prog_report_arena_violation(struct bpf_prog *prog, bool write,
+					      unsigned long addr, unsigned long fault_ip)
 {
 	struct bpf_stream_stage ss;
-	struct bpf_prog *prog;
 	u64 user_vm_start;
 
-	/*
-	 * The RCU read lock is held to safely traverse the latch tree, but we
-	 * don't need its protection when accessing the prog, since it will not
-	 * disappear while we are handling the fault.
-	 */
-	rcu_read_lock();
-	prog = bpf_prog_ksym_find(fault_ip);
-	rcu_read_unlock();
-	if (!prog)
-		return;
-
 	/* Use main prog for stream access */
 	prog = prog->aux->main_prog_aux->prog;
 
@@ -957,3 +1004,53 @@ void bpf_prog_report_arena_violation(bool write, unsigned long addr, unsigned lo
 		bpf_stream_dump_stack(ss);
 	}));
 }
+
+bool bpf_arena_handle_page_fault(unsigned long addr, bool is_write, unsigned long fault_ip)
+{
+	struct bpf_arena *arena;
+	struct bpf_prog *prog;
+	unsigned long kbase;
+	unsigned long page_addr = addr & PAGE_MASK;
+
+	prog = bpf_prog_find_from_stack();
+	if (!prog)
+		return false;
+
+	arena = prog->aux->arena;
+	/* a prog not using arena may be on stack, so arena can be NULL */
+	if (!arena)
+		return false;
+
+	kbase = bpf_arena_get_kern_vm_start(arena);
+
+	/*
+	 * Recovery covers the 4 GiB mappable band plus the upper half-guard.
+	 * Lower guard is unreachable from kfuncs; an address there indicates
+	 * a different bug class - leave it to the regular kernel oops path.
+	 */
+	if (page_addr < kbase || page_addr >= kbase + SZ_4G + GUARD_SZ / 2)
+		return false;
+
+	apply_to_page_range(&init_mm, page_addr, PAGE_SIZE,
+			    apply_range_set_scratch_cb, arena->scratch_page);
+	flush_vmap_cache(page_addr, PAGE_SIZE);
+	__bpf_prog_report_arena_violation(prog, is_write, page_addr - kbase, fault_ip);
+	return true;
+}
+
+void bpf_prog_report_arena_violation(bool write, unsigned long addr, unsigned long fault_ip)
+{
+	struct bpf_prog *prog;
+
+	/*
+	 * The RCU read lock is held to safely traverse the latch tree, but we
+	 * don't need its protection when accessing the prog, since it will not
+	 * disappear while we are handling the fault.
+	 */
+	rcu_read_lock();
+	prog = bpf_prog_ksym_find(fault_ip);
+	rcu_read_unlock();
+	if (!prog)
+		return;
+	__bpf_prog_report_arena_violation(prog, write, addr, fault_ip);
+}
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 066b86e7233c..fa368d8920d9 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -3290,6 +3290,11 @@ __weak u64 bpf_arena_get_kern_vm_start(struct bpf_arena *arena)
 {
 	return 0;
 }
+__weak bool bpf_arena_handle_page_fault(unsigned long addr, bool is_write,
+					unsigned long fault_ip)
+{
+	return false;
+}
 
 #ifdef CONFIG_BPF_SYSCALL
 static int __init bpf_global_ma_init(void)
-- 
2.54.0



^ permalink raw reply related

* [PATCH 7/8] sched_ext: Sub-allocator over kernel-claimed BPF arena pages
From: Tejun Heo @ 2026-05-22 17:22 UTC (permalink / raw)
  To: David Vernet, Andrea Righi, Changwoo Min, Alexei Starovoitov,
	Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau,
	Kumar Kartikeya Dwivedi
  Cc: Peter Zijlstra, Catalin Marinas, Will Deacon, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, Andrew Morton,
	David Hildenbrand, Mike Rapoport, Emil Tsalapatis, sched-ext, bpf,
	x86, linux-arm-kernel, linux-mm, linux-kernel, Tejun Heo
In-Reply-To: <20260522172219.1423324-1-tj@kernel.org>

Build a per-scheduler sub-allocator on top of pages claimed from the BPF
arena registered in the previous patch. Subsequent kernel-managed
arena-resident structures (e.g. per-CPU set_cmask cmask) carve their storage
from this pool.

scx_arena_pool_init() creates a gen_pool. scx_arena_alloc() returns the
kernel VA. On exhaustion, the pool grows by claiming more pages via
bpf_arena_alloc_pages_sleepable(). Chunks are added at the kernel-side
mapping address. Callers translate to the BPF-arena form themselves if
needed.

Allocations sleep (GFP_KERNEL) - they may grow the pool through vzalloc and
arena page allocation. All current consumers run from the enable path (after
ops.init() and the kernel-side arena auto-discovery, before validate_ops()),
where sleeping is fine.

scx_arena_pool_destroy() walks each chunk, returns outstanding ranges to the
gen_pool with gen_pool_free() and then calls gen_pool_destroy(). The
underlying arena pages are released when the arena map itself is torn down,
so the pool destroy doesn't free them explicitly.

v2: Switch scx_arena_alloc() to a loop. (Andrea)

Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Andrea Righi <arighi@nvidia.com>
---
 kernel/sched/build_policy.c |   4 ++
 kernel/sched/ext.c          |  11 ++++
 kernel/sched/ext_arena.c    | 126 ++++++++++++++++++++++++++++++++++++
 kernel/sched/ext_arena.h    |  18 ++++++
 kernel/sched/ext_internal.h |   5 ++
 5 files changed, 164 insertions(+)
 create mode 100644 kernel/sched/ext_arena.c
 create mode 100644 kernel/sched/ext_arena.h

diff --git a/kernel/sched/build_policy.c b/kernel/sched/build_policy.c
index 5e76c9177d54..067979a7b69e 100644
--- a/kernel/sched/build_policy.c
+++ b/kernel/sched/build_policy.c
@@ -59,12 +59,16 @@
 
 #ifdef CONFIG_SCHED_CLASS_EXT
 # include <linux/btf_ids.h>
+# include <linux/find.h>
+# include <linux/genalloc.h>
 # include "ext_types.h"
 # include "ext_internal.h"
 # include "ext_cid.h"
+# include "ext_arena.h"
 # include "ext_idle.h"
 # include "ext.c"
 # include "ext_cid.c"
+# include "ext_arena.c"
 # include "ext_idle.c"
 #endif
 
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 56f94ac32ba0..fb91079c1244 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -5003,6 +5003,7 @@ static void scx_sched_free_rcu_work(struct work_struct *work)
 
 	rhashtable_free_and_destroy(&sch->dsq_hash, NULL, NULL);
 	free_exit_info(sch->exit_info);
+	scx_arena_pool_destroy(sch);
 	if (sch->arena_map)
 		bpf_map_put(sch->arena_map);
 	kfree(sch);
@@ -7155,6 +7156,12 @@ static void scx_root_enable_workfn(struct kthread_work *work)
 		sch->exit_info->flags |= SCX_EFLAG_INITIALIZED;
 	}
 
+	ret = scx_arena_pool_init(sch);
+	if (ret) {
+		cpus_read_unlock();
+		goto err_disable;
+	}
+
 	for (i = SCX_OPI_CPU_HOTPLUG_BEGIN; i < SCX_OPI_CPU_HOTPLUG_END; i++)
 		if (((void (**)(void))ops)[i])
 			set_bit(i, sch->has_op);
@@ -7473,6 +7480,10 @@ static void scx_sub_enable_workfn(struct kthread_work *work)
 		sch->exit_info->flags |= SCX_EFLAG_INITIALIZED;
 	}
 
+	ret = scx_arena_pool_init(sch);
+	if (ret)
+		goto err_disable;
+
 	if (validate_ops(sch, ops))
 		goto err_disable;
 
diff --git a/kernel/sched/ext_arena.c b/kernel/sched/ext_arena.c
new file mode 100644
index 000000000000..b413e155ba6b
--- /dev/null
+++ b/kernel/sched/ext_arena.c
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * BPF extensible scheduler class: Documentation/scheduler/sched-ext.rst
+ *
+ * scx_arena_pool: kernel-side sub-allocator over BPF-arena pages.
+ *
+ * Each chunk added to @sch->arena_pool comes from one
+ * bpf_arena_alloc_pages_sleepable() call and is registered at the
+ * kernel-side mapping address. Callers translate to the BPF-arena form
+ * themselves if needed.
+ *
+ * Allocations grow the pool on demand. Underlying arena pages are released
+ * when the arena map itself is torn down.
+ *
+ * Copyright (c) 2026 Meta Platforms, Inc. and affiliates.
+ * Copyright (c) 2026 Tejun Heo <tj@kernel.org>
+ */
+
+enum scx_arena_consts {
+	SCX_ARENA_MIN_ORDER		= 3,	/* 8-byte minimum sub-allocation */
+	SCX_ARENA_GROW_PAGES		= 4,	/* per growth */
+};
+
+s32 scx_arena_pool_init(struct scx_sched *sch)
+{
+	if (!sch->arena_map)
+		return 0;
+
+	sch->arena_pool = gen_pool_create(SCX_ARENA_MIN_ORDER, NUMA_NO_NODE);
+	if (!sch->arena_pool)
+		return -ENOMEM;
+	return 0;
+}
+
+static void scx_arena_clear_chunk(struct gen_pool *pool, struct gen_pool_chunk *chunk,
+				  void *data)
+{
+	int order = pool->min_alloc_order;
+	size_t chunk_sz = chunk->end_addr - chunk->start_addr + 1;
+	unsigned long end_bit = chunk_sz >> order;
+	unsigned long b, e;
+
+	for_each_set_bitrange(b, e, chunk->bits, end_bit)
+		gen_pool_free(pool, chunk->start_addr + (b << order),
+			      (e - b) << order);
+}
+
+/*
+ * Tear down the pool. Outstanding gen_pool allocations are freed via
+ * scx_arena_clear_chunk() so gen_pool_destroy() doesn't BUG. The underlying
+ * arena pages are released when the arena map itself is torn down.
+ */
+void scx_arena_pool_destroy(struct scx_sched *sch)
+{
+	if (!sch->arena_pool)
+		return;
+	gen_pool_for_each_chunk(sch->arena_pool, scx_arena_clear_chunk, NULL);
+	gen_pool_destroy(sch->arena_pool);
+	sch->arena_pool = NULL;
+}
+
+/*
+ * Grow the pool by @page_cnt pages. bpf_arena_alloc_pages_sleepable() and
+ * gen_pool_add() (which calls vzalloc(GFP_KERNEL)) require a sleepable
+ * context.
+ */
+static int scx_arena_grow(struct scx_sched *sch, u32 page_cnt)
+{
+	u64 kern_vm_start;
+	u32 uaddr32;
+	void *p;
+	int ret;
+
+	if (!sch->arena_map || !sch->arena_pool)
+		return -EINVAL;
+
+	p = bpf_arena_alloc_pages_sleepable(sch->arena_map, NULL,
+					    page_cnt, NUMA_NO_NODE, 0);
+	if (!p)
+		return -ENOMEM;
+
+	uaddr32 = (u32)(unsigned long)p;
+	kern_vm_start = bpf_arena_map_kern_vm_start(sch->arena_map);
+
+	ret = gen_pool_add(sch->arena_pool, kern_vm_start + uaddr32,
+			   page_cnt * PAGE_SIZE, NUMA_NO_NODE);
+	if (ret) {
+		bpf_arena_free_pages_non_sleepable(sch->arena_map, p, page_cnt);
+		return ret;
+	}
+	return 0;
+}
+
+/*
+ * Allocate @size bytes from the arena pool. Returns kernel VA on success, NULL
+ * on failure. May grow the pool via scx_arena_grow() which sleeps. Caller must
+ * be in a GFP_KERNEL context.
+ */
+void *scx_arena_alloc(struct scx_sched *sch, size_t size)
+{
+	unsigned long kern_va;
+	u32 page_cnt;
+
+	might_sleep();
+
+	if (!sch->arena_pool)
+		return NULL;
+
+	while (true) {
+		kern_va = gen_pool_alloc(sch->arena_pool, size);
+		if (kern_va)
+			break;
+		page_cnt = max_t(u32, SCX_ARENA_GROW_PAGES,
+				 (size + PAGE_SIZE - 1) >> PAGE_SHIFT);
+		if (scx_arena_grow(sch, page_cnt))
+			return NULL;
+	}
+
+	return (void *)kern_va;
+}
+
+void scx_arena_free(struct scx_sched *sch, void *kern_va, size_t size)
+{
+	if (sch->arena_pool && kern_va)
+		gen_pool_free(sch->arena_pool, (unsigned long)kern_va, size);
+}
diff --git a/kernel/sched/ext_arena.h b/kernel/sched/ext_arena.h
new file mode 100644
index 000000000000..4f3610160102
--- /dev/null
+++ b/kernel/sched/ext_arena.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * BPF extensible scheduler class: Documentation/scheduler/sched-ext.rst
+ *
+ * Copyright (c) 2025 Meta Platforms, Inc. and affiliates.
+ * Copyright (c) 2025 Tejun Heo <tj@kernel.org>
+ */
+#ifndef _KERNEL_SCHED_EXT_ARENA_H
+#define _KERNEL_SCHED_EXT_ARENA_H
+
+struct scx_sched;
+
+s32 scx_arena_pool_init(struct scx_sched *sch);
+void scx_arena_pool_destroy(struct scx_sched *sch);
+void *scx_arena_alloc(struct scx_sched *sch, size_t size);
+void scx_arena_free(struct scx_sched *sch, void *kern_va, size_t size);
+
+#endif /* _KERNEL_SCHED_EXT_ARENA_H */
diff --git a/kernel/sched/ext_internal.h b/kernel/sched/ext_internal.h
index d40cfd29ddaa..ff7e882bd67a 100644
--- a/kernel/sched/ext_internal.h
+++ b/kernel/sched/ext_internal.h
@@ -1116,8 +1116,13 @@ struct scx_sched {
 	 * Arena map auto-discovered from member progs at struct_ops attach.
 	 * cid-form schedulers must use exactly one arena across all member
 	 * progs. NULL on cpu-form.
+	 *
+	 * @arena_pool sub-allocates @arena_map. Each gen_pool chunk is added
+	 * at the kernel-side mapping address. Grows on demand and pages are
+	 * not released until sched destroy.
 	 */
 	struct bpf_map		*arena_map;
+	struct gen_pool		*arena_pool;
 
 	DECLARE_BITMAP(has_op, SCX_OPI_END);
 
-- 
2.54.0



^ permalink raw reply related

* [PATCH 8/8] sched_ext: Convert ops.set_cmask() to arena-resident cmask
From: Tejun Heo @ 2026-05-22 17:22 UTC (permalink / raw)
  To: David Vernet, Andrea Righi, Changwoo Min, Alexei Starovoitov,
	Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau,
	Kumar Kartikeya Dwivedi
  Cc: Peter Zijlstra, Catalin Marinas, Will Deacon, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, Andrew Morton,
	David Hildenbrand, Mike Rapoport, Emil Tsalapatis, sched-ext, bpf,
	x86, linux-arm-kernel, linux-mm, linux-kernel, Tejun Heo
In-Reply-To: <20260522172219.1423324-1-tj@kernel.org>

ops_cid.set_cmask() expects a cmask. The kernel couldn't write into the
arena, so it translated cpumask -> cmask in kernel memory and passed the
result as a trusted pointer. The BPF cmask helpers all operate on arena
cmasks though, so the BPF side had to word-by-word probe-read the kernel
cmask into an arena cmask via cmask_copy_from_kernel() before any helper
could touch it. It works, but is clumsy.

With direct kernel-side arena access now in place, build the cmask in the
arena. The kernel writes to it through the kern_va side of the dual mapping.
BPF directly dereferences it via an __arena pointer like any other arena
struct.

Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
---
 kernel/sched/ext.c                    | 68 +++++++++++++++++++++++++--
 kernel/sched/ext_cid.c                | 20 +-------
 kernel/sched/ext_internal.h           | 10 +++-
 tools/sched_ext/include/scx/cid.bpf.h | 52 --------------------
 tools/sched_ext/scx_qmap.bpf.c        |  5 +-
 5 files changed, 75 insertions(+), 80 deletions(-)

diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index fb91079c1244..94562e3350c6 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -621,11 +621,16 @@ static inline void scx_call_op_set_cpumask(struct scx_sched *sch, struct rq *rq,
 		update_locked_rq(rq);
 
 	if (scx_is_cid_type()) {
-		struct scx_cmask *cmask = this_cpu_ptr(scx_set_cmask_scratch);
-
-		lockdep_assert_irqs_disabled();
-		scx_cpumask_to_cmask(cpumask, cmask);
-		sch->ops_cid.set_cmask(task, cmask);
+		struct scx_cmask *kern_va = *this_cpu_ptr(sch->set_cmask_scratch);
+		unsigned long uaddr = (unsigned long)kern_va -
+			bpf_arena_map_kern_vm_start(sch->arena_map);
+		/*
+		 * Build the per-CPU arena cmask and hand BPF the uaddr. Caller
+		 * holds the rq lock with IRQs disabled, which makes us the sole
+		 * user of the scratch area.
+		 */
+		scx_cpumask_to_cmask(cpumask, kern_va);
+		sch->ops_cid.set_cmask(task, (struct scx_cmask *)uaddr);
 	} else {
 		sch->ops.set_cpumask(task, cpumask);
 	}
@@ -4949,6 +4954,48 @@ static const struct attribute_group scx_global_attr_group = {
 static void free_pnode(struct scx_sched_pnode *pnode);
 static void free_exit_info(struct scx_exit_info *ei);
 
+static s32 scx_set_cmask_scratch_alloc(struct scx_sched *sch)
+{
+	size_t size = struct_size_t(struct scx_cmask, bits,
+				    SCX_CMASK_NR_WORDS(num_possible_cpus()));
+	int cpu;
+
+	if (!sch->is_cid_type || !sch->arena_pool)
+		return 0;
+
+	sch->set_cmask_scratch = alloc_percpu(struct scx_cmask *);
+	if (!sch->set_cmask_scratch)
+		return -ENOMEM;
+
+	for_each_possible_cpu(cpu) {
+		struct scx_cmask **slot = per_cpu_ptr(sch->set_cmask_scratch, cpu);
+
+		*slot = scx_arena_alloc(sch, size);
+		if (!*slot)
+			return -ENOMEM;
+		scx_cmask_init(*slot, 0, num_possible_cpus());
+	}
+	return 0;
+}
+
+static void scx_set_cmask_scratch_free(struct scx_sched *sch)
+{
+	size_t size = struct_size_t(struct scx_cmask, bits,
+				    SCX_CMASK_NR_WORDS(num_possible_cpus()));
+	int cpu;
+
+	if (!sch->set_cmask_scratch)
+		return;
+
+	for_each_possible_cpu(cpu) {
+		struct scx_cmask **slot = per_cpu_ptr(sch->set_cmask_scratch, cpu);
+
+		scx_arena_free(sch, *slot, size);
+	}
+	free_percpu(sch->set_cmask_scratch);
+	sch->set_cmask_scratch = NULL;
+}
+
 static void scx_sched_free_rcu_work(struct work_struct *work)
 {
 	struct rcu_work *rcu_work = to_rcu_work(work);
@@ -5003,6 +5050,7 @@ static void scx_sched_free_rcu_work(struct work_struct *work)
 
 	rhashtable_free_and_destroy(&sch->dsq_hash, NULL, NULL);
 	free_exit_info(sch->exit_info);
+	scx_set_cmask_scratch_free(sch);
 	scx_arena_pool_destroy(sch);
 	if (sch->arena_map)
 		bpf_map_put(sch->arena_map);
@@ -7162,6 +7210,12 @@ static void scx_root_enable_workfn(struct kthread_work *work)
 		goto err_disable;
 	}
 
+	ret = scx_set_cmask_scratch_alloc(sch);
+	if (ret) {
+		cpus_read_unlock();
+		goto err_disable;
+	}
+
 	for (i = SCX_OPI_CPU_HOTPLUG_BEGIN; i < SCX_OPI_CPU_HOTPLUG_END; i++)
 		if (((void (**)(void))ops)[i])
 			set_bit(i, sch->has_op);
@@ -7484,6 +7538,10 @@ static void scx_sub_enable_workfn(struct kthread_work *work)
 	if (ret)
 		goto err_disable;
 
+	ret = scx_set_cmask_scratch_alloc(sch);
+	if (ret)
+		goto err_disable;
+
 	if (validate_ops(sch, ops))
 		goto err_disable;
 
diff --git a/kernel/sched/ext_cid.c b/kernel/sched/ext_cid.c
index 0c91b951fd33..808c6390da5a 100644
--- a/kernel/sched/ext_cid.c
+++ b/kernel/sched/ext_cid.c
@@ -7,14 +7,6 @@
  */
 #include <linux/cacheinfo.h>
 
-/*
- * Per-cpu scratch cmask used by scx_call_op_set_cpumask() to synthesize a
- * cmask from a cpumask. Allocated alongside the cid arrays on first enable
- * and never freed. Sized to the full cid space. Caller holds rq lock so
- * this_cpu_ptr is safe.
- */
-struct scx_cmask __percpu *scx_set_cmask_scratch;
-
 /*
  * cid tables.
  *
@@ -54,8 +46,6 @@ static s32 scx_cid_arrays_alloc(void)
 	u32 npossible = num_possible_cpus();
 	s16 *cid_to_cpu, *cpu_to_cid;
 	struct scx_cid_topo *cid_topo;
-	struct scx_cmask __percpu *set_cmask_scratch;
-	s32 cpu;
 
 	if (scx_cid_to_cpu_tbl)
 		return 0;
@@ -63,25 +53,17 @@ static s32 scx_cid_arrays_alloc(void)
 	cid_to_cpu = kzalloc_objs(*scx_cid_to_cpu_tbl, npossible, GFP_KERNEL);
 	cpu_to_cid = kzalloc_objs(*scx_cpu_to_cid_tbl, nr_cpu_ids, GFP_KERNEL);
 	cid_topo = kmalloc_objs(*scx_cid_topo, npossible, GFP_KERNEL);
-	set_cmask_scratch = __alloc_percpu(struct_size(set_cmask_scratch, bits,
-						       SCX_CMASK_NR_WORDS(npossible)),
-					   sizeof(u64));
 
-	if (!cid_to_cpu || !cpu_to_cid || !cid_topo || !set_cmask_scratch) {
+	if (!cid_to_cpu || !cpu_to_cid || !cid_topo) {
 		kfree(cid_to_cpu);
 		kfree(cpu_to_cid);
 		kfree(cid_topo);
-		free_percpu(set_cmask_scratch);
 		return -ENOMEM;
 	}
 
 	WRITE_ONCE(scx_cid_to_cpu_tbl, cid_to_cpu);
 	WRITE_ONCE(scx_cpu_to_cid_tbl, cpu_to_cid);
 	WRITE_ONCE(scx_cid_topo, cid_topo);
-	for_each_possible_cpu(cpu)
-		scx_cmask_init(per_cpu_ptr(set_cmask_scratch, cpu),
-			       0, npossible);
-	WRITE_ONCE(scx_set_cmask_scratch, set_cmask_scratch);
 	return 0;
 }
 
diff --git a/kernel/sched/ext_internal.h b/kernel/sched/ext_internal.h
index ff7e882bd67a..9bb65367f510 100644
--- a/kernel/sched/ext_internal.h
+++ b/kernel/sched/ext_internal.h
@@ -1124,6 +1124,14 @@ struct scx_sched {
 	struct bpf_map		*arena_map;
 	struct gen_pool		*arena_pool;
 
+	/*
+	 * Per-CPU arena cmask used by scx_call_op_set_cpumask() to hand a cmask
+	 * to ops_cid.set_cmask(). The kernel writes through the stored kern_va;
+	 * the BPF-arena uaddr handed to BPF is recovered by subtracting the
+	 * arena's kern_vm_start.
+	 */
+	struct scx_cmask * __percpu *set_cmask_scratch;
+
 	DECLARE_BITMAP(has_op, SCX_OPI_END);
 
 	/*
@@ -1480,8 +1488,6 @@ enum scx_ops_state {
 extern struct scx_sched __rcu *scx_root;
 DECLARE_PER_CPU(struct rq *, scx_locked_rq_state);
 
-extern struct scx_cmask __percpu *scx_set_cmask_scratch;
-
 /*
  * True when the currently loaded scheduler hierarchy is cid-form. All scheds
  * in a hierarchy share one form, so this single key tells callsites which
diff --git a/tools/sched_ext/include/scx/cid.bpf.h b/tools/sched_ext/include/scx/cid.bpf.h
index e281c88fa824..70f2a3829af4 100644
--- a/tools/sched_ext/include/scx/cid.bpf.h
+++ b/tools/sched_ext/include/scx/cid.bpf.h
@@ -675,56 +675,4 @@ static __always_inline void cmask_from_cpumask(struct scx_cmask __arena *m,
 	}
 }
 
-/**
- * cmask_copy_from_kernel - probe-read a kernel cmask into an arena cmask
- * @dst: arena cmask to fill; must have @dst->base == 0 and be sized for @src.
- * @src: kernel-memory cmask (e.g. ops.set_cmask() arg); @src->base must be 0.
- *
- * Word-for-word copy; @src and @dst must share base 0 alignment. Triggers
- * scx_bpf_error() on probe failure or precondition violation.
- */
-static __always_inline void cmask_copy_from_kernel(struct scx_cmask __arena *dst,
-						   const struct scx_cmask *src)
-{
-	u32 base = 0, nr_cids = 0, nr_words, wi;
-
-	if (dst->base != 0) {
-		scx_bpf_error("cmask_copy_from_kernel requires dst->base == 0");
-		return;
-	}
-
-	if (bpf_probe_read_kernel(&base, sizeof(base), &src->base)) {
-		scx_bpf_error("probe-read cmask->base failed");
-		return;
-	}
-	if (base != 0) {
-		scx_bpf_error("cmask_copy_from_kernel requires src->base == 0");
-		return;
-	}
-
-	if (bpf_probe_read_kernel(&nr_cids, sizeof(nr_cids), &src->nr_cids)) {
-		scx_bpf_error("probe-read cmask->nr_cids failed");
-		return;
-	}
-
-	if (nr_cids > dst->nr_cids) {
-		scx_bpf_error("src cmask nr_cids=%u exceeds dst nr_cids=%u",
-			      nr_cids, dst->nr_cids);
-		return;
-	}
-
-	nr_words = CMASK_NR_WORDS(nr_cids);
-	cmask_zero(dst);
-	bpf_for(wi, 0, CMASK_MAX_WORDS) {
-		u64 word = 0;
-		if (wi >= nr_words)
-			break;
-		if (bpf_probe_read_kernel(&word, sizeof(u64), &src->bits[wi])) {
-			scx_bpf_error("probe-read cmask->bits[%u] failed", wi);
-			return;
-		}
-		dst->bits[wi] = word;
-	}
-}
-
 #endif /* __SCX_CID_BPF_H */
diff --git a/tools/sched_ext/scx_qmap.bpf.c b/tools/sched_ext/scx_qmap.bpf.c
index 7e77f22674ea..8a2d6a8ebd8e 100644
--- a/tools/sched_ext/scx_qmap.bpf.c
+++ b/tools/sched_ext/scx_qmap.bpf.c
@@ -919,14 +919,15 @@ void BPF_STRUCT_OPS(qmap_update_idle, s32 cid, bool idle)
 }
 
 void BPF_STRUCT_OPS(qmap_set_cmask, struct task_struct *p,
-		    const struct scx_cmask *cmask)
+		    const struct scx_cmask *cmask_in)
 {
+	struct scx_cmask __arena *cmask = (struct scx_cmask __arena *)(long)cmask_in;
 	task_ctx_t *taskc;
 
 	taskc = lookup_task_ctx(p);
 	if (!taskc)
 		return;
-	cmask_copy_from_kernel(&taskc->cpus_allowed, cmask);
+	cmask_copy(&taskc->cpus_allowed, cmask);
 }
 
 struct monitor_timer {
-- 
2.54.0



^ permalink raw reply related

* [PATCH 6/8] sched_ext: Require an arena for cid-form schedulers
From: Tejun Heo @ 2026-05-22 17:22 UTC (permalink / raw)
  To: David Vernet, Andrea Righi, Changwoo Min, Alexei Starovoitov,
	Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau,
	Kumar Kartikeya Dwivedi
  Cc: Peter Zijlstra, Catalin Marinas, Will Deacon, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, Andrew Morton,
	David Hildenbrand, Mike Rapoport, Emil Tsalapatis, sched-ext, bpf,
	x86, linux-arm-kernel, linux-mm, linux-kernel, Tejun Heo
In-Reply-To: <20260522172219.1423324-1-tj@kernel.org>

Upcoming patches will let the kernel place arena-resident scratch shared
with the BPF program (e.g. per-CPU set_cmask cmask) so the BPF side can
dereference it directly via __arena pointers, replacing the current
cmask_copy_from_kernel() probe-read loop. That requires each cid-form
scheduler to expose its arena to the kernel. Kernel- side accesses are
recovered by the per-arena scratch-page mechanism.

bpf_scx_reg_cid() walks the struct_ops member progs via
bpf_struct_ops_for_each_prog() and reads each prog's arena via
bpf_prog_arena(). The verifier enforces one arena per program, so each
member prog contributes at most one arena. All non-NULL contributions must
match and at least one member prog must use an arena. The map ref is held on
scx_sched and dropped on sched destroy. cpu-form schedulers (bpf_scx_reg)
are unchanged - no arena requirement.

Signed-off-by: Tejun Heo <tj@kernel.org>
---
 kernel/sched/ext.c          | 56 ++++++++++++++++++++++++++++++++++++-
 kernel/sched/ext_internal.h |  8 ++++++
 2 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 9c458552d14f..56f94ac32ba0 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -5003,6 +5003,8 @@ static void scx_sched_free_rcu_work(struct work_struct *work)
 
 	rhashtable_free_and_destroy(&sch->dsq_hash, NULL, NULL);
 	free_exit_info(sch->exit_info);
+	if (sch->arena_map)
+		bpf_map_put(sch->arena_map);
 	kfree(sch);
 }
 
@@ -6746,6 +6748,7 @@ struct scx_enable_cmd {
 		struct sched_ext_ops_cid	*ops_cid;
 	};
 	bool			is_cid_type;
+	struct bpf_map		*arena_map;	/* arena ref to transfer to sch */
 	int			ret;
 };
 
@@ -6913,6 +6916,15 @@ static struct scx_sched *scx_alloc_and_add_sched(struct scx_enable_cmd *cmd,
 		return ERR_PTR(ret);
 	}
 #endif	/* CONFIG_EXT_SUB_SCHED */
+
+	/*
+	 * Consume the arena_map ref bpf_scx_reg_cid() took. Defer to here so
+	 * earlier failure paths leave cmd->arena_map set and bpf_scx_reg_cid
+	 * drops the ref. After this point, sch owns the ref and any cleanup
+	 * runs through scx_sched_free_rcu_work() which puts it.
+	 */
+	sch->arena_map = cmd->arena_map;
+	cmd->arena_map = NULL;
 	return sch;
 
 #ifdef CONFIG_EXT_SUB_SCHED
@@ -7898,11 +7910,53 @@ static int bpf_scx_reg(void *kdata, struct bpf_link *link)
 	return scx_enable(&cmd, link);
 }
 
+struct scx_arena_scan {
+	struct bpf_map	*arena;
+	int		err;
+};
+
+/*
+ * The verifier enforces one arena per BPF program, so each struct_ops
+ * member prog contributes at most one arena via bpf_prog_arena().
+ * Require all non-NULL contributions to match.
+ */
+static int scx_arena_scan_prog(struct bpf_prog *prog, void *data)
+{
+	struct scx_arena_scan *s = data;
+	struct bpf_map *arena = bpf_prog_arena(prog);
+
+	if (!arena)
+		return 0;
+	if (s->arena && s->arena != arena) {
+		s->err = -EINVAL;
+		return 1;
+	}
+	s->arena = arena;
+	return 0;
+}
+
 static int bpf_scx_reg_cid(void *kdata, struct bpf_link *link)
 {
 	struct scx_enable_cmd cmd = { .ops_cid = kdata, .is_cid_type = true };
+	struct scx_arena_scan scan = {};
+	int ret;
 
-	return scx_enable(&cmd, link);
+	bpf_struct_ops_for_each_prog(kdata, scx_arena_scan_prog, &scan);
+	if (scan.err) {
+		pr_err("sched_ext: cid-form scheduler uses multiple arena maps\n");
+		return scan.err;
+	}
+	if (!scan.arena) {
+		pr_err("sched_ext: cid-form scheduler must use a BPF arena map\n");
+		return -EINVAL;
+	}
+
+	bpf_map_inc(scan.arena);
+	cmd.arena_map = scan.arena;
+	ret = scx_enable(&cmd, link);
+	if (cmd.arena_map)		/* not consumed by scx_alloc_and_add_sched() */
+		bpf_map_put(cmd.arena_map);
+	return ret;
 }
 
 static void bpf_scx_unreg(void *kdata, struct bpf_link *link)
diff --git a/kernel/sched/ext_internal.h b/kernel/sched/ext_internal.h
index 7258aea94b9f..d40cfd29ddaa 100644
--- a/kernel/sched/ext_internal.h
+++ b/kernel/sched/ext_internal.h
@@ -1111,6 +1111,14 @@ struct scx_sched {
 		struct sched_ext_ops_cid	ops_cid;
 	};
 	bool			is_cid_type;	/* true if registered via bpf_sched_ext_ops_cid */
+
+	/*
+	 * Arena map auto-discovered from member progs at struct_ops attach.
+	 * cid-form schedulers must use exactly one arena across all member
+	 * progs. NULL on cpu-form.
+	 */
+	struct bpf_map		*arena_map;
+
 	DECLARE_BITMAP(has_op, SCX_OPI_END);
 
 	/*
-- 
2.54.0



^ permalink raw reply related


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