Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [v1,PATCH 1/1] i2c: mediatek: add bus regulator control for power saving
From: Andi Shyti @ 2026-04-14 23:03 UTC (permalink / raw)
  To: adlavinitha reddy
  Cc: Qii Wang, Matthias Brugger, AngeloGioacchino Del Regno, linux-i2c,
	linux-kernel, linux-arm-kernel, linux-mediatek,
	Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260318084621.4127757-2-adlavinitha.reddy@mediatek.com>

Hi Adlavinitha,

On Wed, Mar 18, 2026 at 04:46:16PM +0800, adlavinitha reddy wrote:
> Add conditional bus regulator enable/disable in mtk_i2c_transfer()
> to support I2C bus power gating for platforms that require it.
> 
> This implementation:
> - Enables bus_regulator before clk_bulk_enable() if vbus-supply is defined
> - Disables bus_regulator after clk_bulk_disable()
> - Only activates when vbus-supply is provided in device tree
> - Has no impact on platforms without vbus-supply defined
> 
> This approach provides power savinggs for platforms with an extra I2C bus

I changed /savinggs/savings/.

> regulator, while avoiding runtime PM complexity.
> 
> TEST= Build and boot on MT8188

'"TEST=..." is a tag. There is no need to save characters in the
commit log. I changed it to "Tested on MT8188.".'

> Signed-off-by: adlavinitha reddy <adlavinitha.reddy@mediatek.com>

Please use capital letters for your name and for the committer's
name as well. I fixed it.

Now you have to explain me why you sent three times this same
patch.

Next time, please use the format '[PATCH v1 1/1]' instead of
'[v1,PATCH 1/1]'. Normally for the first version you can omit v1.

For single patches you don't need the 0/1 cover letter. Just send
as [PATCH].

Please read Documentation/SubmittingPatches.

For now I merged this patch in i2c/i2c-host-2.

Thanks,
Andi


^ permalink raw reply

* Re: [PATCH v1 1/2] arm_mpam: resctrl: Fix the check for no monitor components found
From: Gavin Shan @ 2026-04-14 23:08 UTC (permalink / raw)
  To: Ben Horgan
  Cc: Dan Carpenter, Dan Carpenter, James Morse, Reinette Chatre,
	Fenghua Yu, lkml, linux-arm-kernel
In-Reply-To: <20260414132758.196874-3-ben.horgan@arm.com>

On 4/14/26 11:27 PM, Ben Horgan wrote:
> Dan Carpenter reports that, in mpam_resctrl_alloc_domain(), any_mon_comp is
> used in an 'if' condition when it may be uninitialized. Initialize it to
> NULL so that the check behaves correctly when no monitor components are
> found.
> 
> Reported-by: Dan Carpenter <error27@gmail.com>
> Fixes: 264c285999fc ("arm_mpam: resctrl: Add monitor initialisation and domain boilerplate")
> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
> ---
>   drivers/resctrl/mpam_resctrl.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
Reviewed-by: Gavin Shan <gshan@redhat.com>



^ permalink raw reply

* Re: [PATCH v1 2/2] arm_mpam: resctrl: Make resctrl_mon_ctx_waiters static
From: Gavin Shan @ 2026-04-14 23:09 UTC (permalink / raw)
  To: Ben Horgan
  Cc: Dan Carpenter, Dan Carpenter, James Morse, Reinette Chatre,
	Fenghua Yu, lkml, linux-arm-kernel, kernel test robot
In-Reply-To: <20260414132758.196874-4-ben.horgan@arm.com>

On 4/14/26 11:27 PM, Ben Horgan wrote:
> resctrl_mon_ctx_waiters is not used outside of this file, so make it
> static. This fixes the sparse warning:
> 
> drivers/resctrl/mpam_resctrl.c:25:1: warning: symbol 'resctrl_mon_ctx_waiters' was not declared. Should it be static?
> 
> Reported-by: kernel test robot <lkp@intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202603281842.c2K96tJA-lkp@intel.com/
> Fixes: 2a3c79c61539 ("arm_mpam: resctrl: Allow resctrl to allocate monitors")
> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
> ---
>   drivers/resctrl/mpam_resctrl.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
Reviewed-by: Gavin Shan <gshan@redhat.com>



^ permalink raw reply

* ✅ PASS (MISSED 51 of 56): Test report for for-kernelci (7.0.0-0, upstream-arm-next, 986cb454)
From: cki-project @ 2026-04-15  0:02 UTC (permalink / raw)
  To: linux-arm-kernel, catalin.marinas, will

Hi, we tested your kernel and here are the results:

    Overall result: PASSED
             Merge: OK
           Compile: OK
              Test: OK

Tested-by: CKI Project <cki-project@redhat.com>

Kernel information:
    Commit message: Merge branch 'for-next/core' into for-kernelci

You can find all the details about the test run at
    https://datawarehouse.cki-project.org/kcidb/checkouts/redhat:2453129617

Tests that were not ran because of internal issues:
    /distribution/check-install [aarch64]
    /distribution/command [aarch64]
    /test/misc/machineinfo [aarch64]
    Boot test [aarch64]
    CKI/restraint [aarch64]
    Hardware - Firmware test suite [aarch64]
    Reboot test [aarch64]
    SELinux Custom Module Setup [aarch64]
    selinux-policy: serge-testsuite [aarch64]
    Storage - blktests - throtl [aarch64]
    Storage - blktests - ublk [aarch64]
    stress: stress-ng - cpu-cache [aarch64]
    stress: stress-ng - memory [aarch64]
    xfstests - btrfs [aarch64]
    xfstests - ext4 [aarch64]
    xfstests - xfs [aarch64]


If you find a failure unrelated to your changes, please ask the test maintainer to review it.
This will prevent the failures from being incorrectly reported in the future.

Please reply to this email if you have any questions about the tests that we
ran or if you have any suggestions on how to make future tests more effective.

        ,-.   ,-.
       ( C ) ( K )  Continuous
        `-',-.`-'   Kernel
          ( I )     Integration
           `-'
______________________________________________________________________________



^ permalink raw reply

* Re: [GIT PULL] arm64 updates for 7.1
From: Linus Torvalds @ 2026-04-15  0:02 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: Will Deacon, Thomas Gleixner, James Morse, Ben Horgan,
	linux-arm-kernel, linux-kernel, Peter Zijlstra
In-Reply-To: <ad5Fh5JUqptcYkrp@arm.com>

On Tue, 14 Apr 2026 at 06:47, Catalin Marinas <catalin.marinas@arm.com> wrote:
>
> The generic entry patches touch include/linux/*entry* and kernel/entry/*
> as they are based on a tag from tip. Not sure when Thomas will send them
> your way, so sending the arm64 pull request in the meantime.

Ok, so the conflict with the irq changes is something that I want
Thomas and PeterZ to take a look at, because it involved two calls to
hrtimer_rearm_deferred() that got added in the meantime - while in
this pull the call site then got split up and moved from
kernel/entry/common.c to include/linux/irq-entry-common.h.

In my initial resolution I placed the two hrtimer_rearm_deferred()
calls very similarly to how they were placed before (just in the moved
location).

So my initial resolution was the fairly direct "that's what the code
movement would do".

But then I double-checked what linux-next did, and it did something
quite different. The linux-next resolution isn't the naive direct code
movement, and seems to be a smarter semantic resolution with just one
call-site.

So after having stared at it for a long time, and convinced myself it
was the better resolution I went back and fixed up mine too.

It all makes me go "PeterZ and Thomas should double-check me that I
didn't miss something else".

I did the builds on both x86-64 and arm64, but I feel it should still
be checked by people involved with that hrtimer code.

               Linus


^ permalink raw reply

* Re: [GIT PULL] arm64 updates for 7.1
From: pr-tracker-bot @ 2026-04-15  0:03 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: Linus Torvalds, Will Deacon, Thomas Gleixner, James Morse,
	Ben Horgan, linux-arm-kernel, linux-kernel
In-Reply-To: <ad5Fh5JUqptcYkrp@arm.com>

The pull request you sent on Tue, 14 Apr 2026 14:47:51 +0100:

> git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux tags/arm64-upstream

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/c43267e6794a36013fd495a4d81bf7f748fe4615

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


^ permalink raw reply

* Re: [RFC PATCH 00/12] Add Linux RISC-V trace support via CoreSight
From: Bo Gan @ 2026-04-15  0:10 UTC (permalink / raw)
  To: Zane Leung, Anup Patel
  Cc: robh, krzk+dt, conor+dt, palmer, pjw, gregkh, alexander.shishkin,
	irogers, coresight, peterz, mingo, namhyung, mark.rutland, jolsa,
	adrian.hunter, mchitale, atish.patra, andrew.jones, sunilvl,
	linux-riscv, linux-kernel, anup.patel, mayuresh.chitale,
	zhuangqiubin, suzuki.poulose, mike.leach, james.clark,
	linux-arm-kernel
In-Reply-To: <7EFD9F2504326BD1+26395797-fbe8-491b-b651-701286fb5751@linux.spacemit.com>

Hi Zane, Anup,

On 4/14/26 02:04, Zane Leung wrote:
> 
> On 4/14/2026 3:23 PM, Anup Patel wrote:
>> On Tue, Apr 14, 2026 at 9:12 AM Zane Leung <liangzhen@linux.spacemit.com> wrote:
>>> From: liangzhen <zhen.liang@spacemit.com>
>>>
>>> This series adds Linux RISC-V trace support via CoreSight, implementing RISC-V
>>> trace drivers within the CoreSight framework and integrating them with perf tools.
>>> The K3 SoC contains RISC-V Encoder, Funnel, ATB, CoreSight Funnel, and CoreSight TMC
>>> components, which can be directly leveraged through the existing CoreSight infrastructure.
>>>
>>> Linux RISC-V trace support form Anup Patel:
>>> (https://patchwork.kernel.org/project/linux-riscv/cover/20260225062448.4027948-1-anup.patel@oss.qualcomm.com/)
>>> which currently lacks ATB component support and guidance on reusing CoreSight components.
>> What stops you from adding RISC-V trace funnel and ATB bridge drivers
>> on top of this series ?
>>
> Firstly, my works started much earlier than this series. Secondly, it is difficult to add the coresight funnel and coresight tmc components to this series. Based on the coresight framework, I can directly reuse them.
> 
>>
>>> The series includes:
>>> - RISC-V trace driver implementation within the CoreSight framework
>> The RISC-V trace very different from the CoreSight framework in many ways:
>> 1) Types of components supported
>> 2) Trace packet formats
>> 3) The way MMIO based components are discoverd
>> 4) ... and more ...
> 1) I believe that RISC-V tracing is coresight-alike, where have encoders/funnel/sink/bridge that are described through DT and controlled by MMIO.
> 2) I think the difference in package format is nothing more than the coresight frame generated by the ATB component to distinguish the trace source. After removing it, it becomes riscv trace data.
> 3) The current CoreSight framework code does not introduce this mechanism, it is described through DT.
>>> - RISC-V Trace Encoder, Funnel, and ATB Bridge drivers as CoreSight devices
>>> - RISC-V trace PMU record capabilities and parsing events in perf.
>>> - RISC-V Nexus Trace decoder for perf tools
>>>
>>> Any comments or suggestions are welcome.
>>>
>>> Verification on K3 SoC:
>>> To verify this patch series on K3 hardware, the following device tree are required:
>>> 1. RISC-V Trace Encoder node (8)
>>> 2. RISC-V ATB Bridge node (8)
>>> 3. RISC-V Trace Funnel node (2)
>>> 3. CoreSight Funnel configuration for RISC-V (1)
>>> 4. CoreSight TMC configuration for trace buffer (1)
>>>
>>> /{
>>>          dummy_clk: apb-pclk {
>>>                  compatible = "fixed-clock";
>>>                  #clock-cells = <0x0>;
>>>                  clock-output-names = "clk14mhz";
>>>                  clock-frequency = <14000000>;
>>>          };
>>>
>>>
>>>          soc: soc {
>>>                  #address-cells = <2>;
>>>                  #size-cells = <2>;
>>>
>>>                  encoder0: encoder@d9002000 {
>>>                          compatible = "riscv,trace-encoder";
>>>                          reg = <0x0 0xd9002000 0x0 0x1000>;
>>>                          cpus = <&cpu_0>;
>>>                          out-ports {
>>>                                  port {
>>>                                          cluster0_encoder0_out_port: endpoint {
>>>                                                  remote-endpoint = <&cluster0_bridge0_in_port>;
>>>                                          };
>>>                                  };
>>>                          };
>>>                  };
>>>
>>>                  bridge0: bridge@d9003000 {
>>>                          compatible = "riscv,trace-atbbridge";
>>>                          reg = <0x0 0xd9003000 0x0 0x1000>;
>>>                          cpus = <&cpu_0>;
>>>                          out-ports {
>>>                                  port {
>>>                                          cluster0_bridge0_out_port: endpoint {
>>>                                                  remote-endpoint = <&cluster0_funnel_in_port0>;
>>>                                          };
>>>                                  };
>>>                          };
>>>                          in-ports {
>>>                                  port {
>>>                                          cluster0_bridge0_in_port: endpoint {
>>>                                                  remote-endpoint = <&cluster0_encoder0_out_port>;
>>>                                          };
>>>                                  };
>>>                          };
>>>                  };
>>>
>>> ...
>>>
>>>                  cluster0_funnel: funnel@d9000000 {
>>>                          compatible = "riscv,trace-funnel";
>>>                          reg = <0x0 0xd9000000 0x0 0x1000>;
>>>                          cpus = <&cpu_0>, <&cpu_1>, <&cpu_2>, <&cpu_3>;
>>>                          riscv,timestamp-present;
>>>                          out-ports {
>>>                                  port {
>>>                                          cluster0_funnel_out_port: endpoint {
>>>                                                  remote-endpoint = <&main_funnel_in_port0>;
>>>                                          };
>>>                                  };
>>>                          };
>>>                          in-ports {
>>>                                  #address-cells = <1>;
>>>                                  #size-cells = <0>;
>>>
>>>                                  port@0 {
>>>                                          reg = <0>;
>>>                                          cluster0_funnel_in_port0: endpoint {
>>>                                                  remote-endpoint = <&cluster0_bridge0_out_port>;
>>>                                          };
>>>                                  };
>>>
>>>                                  port@1 {
>>>                                          reg = <1>;
>>>                                          cluster0_funnel_in_port1: endpoint {
>>>                                                  remote-endpoint = <&cluster0_bridge1_out_port>;
>>>                                          };
>>>                                  };
>>>
>>>                                  port@2 {
>>>                                          reg = <2>;
>>>                                          cluster0_funnel_in_port2: endpoint {
>>>                                                  remote-endpoint = <&cluster0_bridge2_out_port>;
>>>                                          };
>>>                                  };
>>>
>>>                                  port@3 {
>>>                                          reg = <3>;
>>>                                          cluster0_funnel_in_port3: endpoint {
>>>                                                  remote-endpoint = <&cluster0_bridge3_out_port>;
>>>                                          };
>>>                                  };
>>>                          };
>>>                  };
>>>
>>>                  cluster1_funnel: funnel@d9010000 {
>>>                          compatible = "riscv,trace-funnel";
>>>                          reg = <0x0 0xd9010000 0x0 0x1000>;
>>>                          cpus = <&cpu_4>, <&cpu_5>, <&cpu_6>, <&cpu_7>;
>>>                          riscv,timestamp-present;
>>>                          out-ports {
>>>                                  port {
>>>                                          cluster1_funnel_out_port: endpoint {
>>>                                                  remote-endpoint = <&main_funnel_in_port1>;
>>>                                          };
>>>                                  };
>>>                          };
>>>                          in-ports {
>>>                                  #address-cells = <1>;
>>>                                  #size-cells = <0>;
>>>
>>>                                  port@0 {
>>>                                          reg = <0>;
>>>                                          cluster1_funnel_in_port0: endpoint {
>>>                                                  remote-endpoint = <&cluster1_bridge0_out_port>;
>>>                                          };
>>>                                  };
>>>
>>>                                  port@1 {
>>>                                          reg = <1>;
>>>                                          cluster1_funnel_in_port1: endpoint {
>>>                                                  remote-endpoint = <&cluster1_bridge1_out_port>;
>>>                                          };
>>>                                  };
>>>
>>>                                  port@2 {
>>>                                          reg = <2>;
>>>                                          cluster1_funnel_in_port2: endpoint {
>>>                                                  remote-endpoint = <&cluster1_bridge2_out_port>;
>>>                                          };
>>>                                  };
>>>
>>>                                  port@3 {
>>>                                          reg = <3>;
>>>                                          cluster1_funnel_in_port3: endpoint {
>>>                                                  remote-endpoint = <&cluster1_bridge3_out_port>;
>>>                                          };
>>>                                  };
>>>                          };
>>>                  };
>>>
>>>                  main_funnel: funnel@d9042000 {
>>>                          compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
>> Is it legally allowed to mix and match ARM coresight IPs with
>> RISC-V trace components at hardware level ?
> The ATB Bridge allows sending RISC-V trace to Arm CoreSight infrastructure (instead of RISC-V compliant sink defined in this document) as an ATB initiator.  see:
> https://github.com/riscv-non-isa/riscv-nexus-trace/blob/105dc1c349556622e4d202d22b584a887ded462f/docs/RISC-V-Trace-Control-Interface.adoc#L184
> For ATB Bridge, read trace using Coresight components (ETB/TMC/TPIU). see:
> https://github.com/riscv-non-isa/riscv-nexus-trace/blob/105dc1c349556622e4d202d22b584a887ded462f/docs/RISC-V-Trace-Control-Interface.adoc#L1684
>>
>>>                          reg = <0x0 0xd9042000 0x0 0x1000>;
>>>                          clocks = <&dummy_clk>;
>>>                          clock-names = "apb_pclk";
>>>                          out-ports {
>>>                                  port {
>>>                                          main_funnel_out_port: endpoint {
>>>                                                  remote-endpoint = <&etf_in_port>;
>>>                                          };
>>>                                  };
>>>                          };
>>>                          in-ports {
>>>                                  #address-cells = <1>;
>>>                                  #size-cells = <0>;
>>>
>>>                                  port@0 {
>>>                                          reg = <0>;
>>>                                          main_funnel_in_port0: endpoint {
>>>                                                  remote-endpoint = <&cluster0_funnel_out_port>;
>>>                                          };
>>>                                  };
>>>
>>>                                  port@1 {
>>>                                          reg = <1>;
>>>                                          main_funnel_in_port1: endpoint {
>>>                                                  remote-endpoint = <&cluster1_funnel_out_port>;
>>>                                          };
>>>                                  };
>>>                          };
>>>                  };
>>>
>>>                  etf: etf@d9043000 {
>>>                          compatible = "arm,coresight-tmc", "arm,primecell";
>>>                          reg = <0x0 0xd9043000 0x0 0x1000>;
>>>                          clocks = <&dummy_clk>;
>>>                          clock-names = "apb_pclk";
>>>                          out-ports {
>>>                                  port {
>>>                                          etf_out_port: endpoint {
>>>                                                  remote-endpoint = <&etr_in_port>;
>>>                                          };
>>>                                  };
>>>                          };
>>>                          in-ports {
>>>                                  port {
>>>                                          etf_in_port: endpoint {
>>>                                                  remote-endpoint = <&main_funnel_out_port>;
>>>                                          };
>>>                                  };
>>>                          };
>>>                  };
>>>
>>>                  etr: etr@d9044000 {
>>>                          compatible = "arm,coresight-tmc", "arm,primecell";
>>>                          reg = <0x0 0xd9044000 0x0 0x1000>;
>>>                          clocks = <&dummy_clk>;
>>>                          clock-names = "apb_pclk";
>>>                          arm,scatter-gather;
>>>                          in-ports {
>>>                                  port {
>>>                                          etr_in_port: endpoint {
>>>                                                  remote-endpoint = <&etf_out_port>;
>>>                                          };
>>>                                  };
>>>                          };
>>>                  };
>>>          };
>>> };
>>>
>>> Verification case:
>>>
>>> ~ # perf list pmu
>>>    rvtrace//                                          [Kernel PMU event]
>>>
>>> ~ # perf record -e rvtrace/@tmc_etr0/ --per-thread uname
>>> Linux
>>> [ perf record: Woken up 1 times to write data ]
>>> [ perf record: Captured and wrote 0.191 MB perf.data ]
>>> ~ # perf script
>>>             uname     137 [003]          1           branches:  ffffffff80931470 rvtrace_poll_bit+0x38 ([kernel.kallsyms]) => ffffffff80931492 rvtrace_poll_bit+0x5a ([kernel.kallsyms])
>>>             uname     137 [003]          1           branches:  ffffffff809328a6 encoder_enable_hw+0x252 ([kernel.kallsyms]) => ffffffff809328ba encoder_enable_hw+0x266 ([kernel.kallsyms])
>>>             uname     137 [003]          1           branches:  ffffffff80932c4a encoder_enable+0x82 ([kernel.kallsyms]) => ffffffff80932c36 encoder_enable+0x6e ([kernel.kallsyms])
>>>             uname     137 [003]          1           branches:  ffffffff80928198 etm_event_start+0xf0 ([kernel.kallsyms]) => ffffffff809281aa etm_event_start+0x102 ([kernel.kallsyms])
>>>             uname     137 [003]          1           branches:  ffffffff809281e6 etm_event_start+0x13e ([kernel.kallsyms]) => ffffffff8092755e coresight_get_sink_id+0x16 ([kernel.kallsyms])
>>>             uname     137 [003]          1           branches:  ffffffff8092820e etm_event_start+0x166 ([kernel.kallsyms]) => ffffffff80928226 etm_event_start+0x17e ([kernel.kallsyms])
>>>             uname     137 [003]          1           branches:  ffffffff801c3bb4 perf_report_aux_output_id+0x0 ([kernel.kallsyms]) => ffffffff801c3bd6 perf_report_aux_output_id+0x22 ([kernel.kallsyms])
>>>             uname     137 [003]          1           branches:  ffffffff801c3c5a perf_report_aux_output_id+0xa6 ([kernel.kallsyms]) => ffffffff801c3bf0 perf_report_aux_output_id+0x3c ([kernel.kallsyms])
>>>             uname     137 [003]          1           branches:  ffffffff801c3c40 perf_report_aux_output_id+0x8c ([kernel.kallsyms]) => ffffffff801c3aea __perf_event_header__init_id+0x2a ([kernel.kallsyms])
>>>             uname     137 [003]          1           branches:  ffffffff801c3b42 __perf_event_header__init_id+0x82 ([kernel.kallsyms]) => ffffffff801c3b4a __perf_event_header__init_id+0x8a ([kernel.kallsyms])
>>>             uname     137 [003]          1           branches:  ffffffff801c3bb0 __perf_event_header__init_id+0xf0 ([kernel.kallsyms]) => ffffffff801c3b58 __perf_event_header__init_id+0x98 ([kernel.kallsyms])
>>>             uname     137 [003]          1           branches:  ffffffff8004c658 __task_pid_nr_ns+0x0 ([kernel.kallsyms]) => ffffffff8004c696 __task_pid_nr_ns+0x3e ([kernel.kallsyms])
>>>             uname     137 [003]          1           branches:  ffffffff8004c71e __task_pid_nr_ns+0xc6 ([kernel.kallsyms]) => ffffffff8004c6a4 __task_pid_nr_ns+0x4c ([kernel.kallsyms])
>>>             uname     137 [003]          1           branches:  ffffffff8004c6e4 __task_pid_nr_ns+0x8c ([kernel.kallsyms]) => ffffffff8004c6e4 __task_pid_nr_ns+0x8c ([kernel.kallsyms])
>>> ...
>>>
>>> liangzhen (12):
>>>    coresight: Add RISC-V support to CoreSight tracing
>>>    coresight: Initial implementation of RISC-V trace driver
>>>    coresight: Add RISC-V Trace Encoder driver
>>>    coresight: Add RISC-V Trace Funnel driver
>>>    coresight: Add RISC-V Trace ATB Bridge driver
>>>    coresight rvtrace: Add timestamp component support for encoder and
>>>      funnel
>>>    coresight: Add RISC-V PMU name support
>>>    perf tools: riscv: making rvtrace PMU listable
>>>    perf tools: Add RISC-V trace PMU record capabilities
>>>    perf tools: Add Nexus RISC-V Trace decoder
>>>    perf symbols: Add RISC-V PLT entry sizes
>>>    perf tools: Integrate RISC-V trace decoder into auxtrace
>>>
>>>   drivers/hwtracing/Kconfig                     |    2 +
>>>   drivers/hwtracing/coresight/Kconfig           |   46 +-
>>>   drivers/hwtracing/coresight/Makefile          |    6 +
>>>   drivers/hwtracing/coresight/coresight-core.c  |    8 +
>>>   .../hwtracing/coresight/coresight-etm-perf.c  |    1 -
>>>   .../hwtracing/coresight/coresight-etm-perf.h  |   21 +
>>>   .../hwtracing/coresight/coresight-platform.c  |    1 -
>>>   .../hwtracing/coresight/coresight-tmc-etf.c   |    4 +
>>>   .../hwtracing/coresight/coresight-tmc-etr.c   |    4 +
>>>   .../hwtracing/coresight/rvtrace-atbbridge.c   |  239 +++
>>>   drivers/hwtracing/coresight/rvtrace-core.c    |  135 ++
>>>   .../coresight/rvtrace-encoder-core.c          |  562 +++++++
>>>   .../coresight/rvtrace-encoder-sysfs.c         |  363 +++++
>>>   drivers/hwtracing/coresight/rvtrace-encoder.h |  151 ++
>>>   drivers/hwtracing/coresight/rvtrace-funnel.c  |  337 ++++
>>>   drivers/hwtracing/coresight/rvtrace-funnel.h  |   39 +
>>>   .../hwtracing/coresight/rvtrace-timestamp.c   |  278 ++++
>>>   .../hwtracing/coresight/rvtrace-timestamp.h   |   64 +
>>>   include/linux/coresight-pmu.h                 |    4 +
>>>   include/linux/rvtrace.h                       |  116 ++
>>>   tools/arch/riscv/include/asm/insn.h           |  645 ++++++++
>>>   tools/perf/arch/riscv/util/Build              |    2 +
>>>   tools/perf/arch/riscv/util/auxtrace.c         |  490 ++++++
>>>   tools/perf/arch/riscv/util/pmu.c              |   20 +
>>>   tools/perf/util/Build                         |    3 +
>>>   tools/perf/util/auxtrace.c                    |    4 +
>>>   tools/perf/util/auxtrace.h                    |    1 +
>>>   tools/perf/util/nexus-rv-decoder/Build        |    1 +
>>>   .../util/nexus-rv-decoder/nexus-rv-decoder.c  | 1364 +++++++++++++++++
>>>   .../util/nexus-rv-decoder/nexus-rv-decoder.h  |  139 ++
>>>   .../perf/util/nexus-rv-decoder/nexus-rv-msg.h |  190 +++
>>>   tools/perf/util/rvtrace-decoder.c             | 1039 +++++++++++++
>>>   tools/perf/util/rvtrace.h                     |   40 +
>>>   tools/perf/util/symbol-elf.c                  |    4 +
>>>   34 files changed, 6320 insertions(+), 3 deletions(-)
>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-atbbridge.c
>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-core.c
>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-encoder-core.c
>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-encoder-sysfs.c
>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-encoder.h
>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-funnel.c
>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-funnel.h
>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-timestamp.c
>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-timestamp.h
>>>   create mode 100644 include/linux/rvtrace.h
>>>   create mode 100644 tools/arch/riscv/include/asm/insn.h
>>>   create mode 100644 tools/perf/arch/riscv/util/auxtrace.c
>>>   create mode 100644 tools/perf/arch/riscv/util/pmu.c
>>>   create mode 100644 tools/perf/util/nexus-rv-decoder/Build
>>>   create mode 100644 tools/perf/util/nexus-rv-decoder/nexus-rv-decoder.c
>>>   create mode 100644 tools/perf/util/nexus-rv-decoder/nexus-rv-decoder.h
>>>   create mode 100644 tools/perf/util/nexus-rv-decoder/nexus-rv-msg.h
>>>   create mode 100644 tools/perf/util/rvtrace-decoder.c
>>>   create mode 100644 tools/perf/util/rvtrace.h
>>>
>>> --
>>> 2.34.1
>>>
>> NACK to this approach of retrofitting RISC-V trace into ARM coresight.
> I agree that integrating RISC-V trace directly into CoreSight is not a good approach, so I think we should abstract some of the logic of coresight and reuse it in RISC-V Trace.

I think we should indeed abstract out some coresight logic so it can be
reused by both coresight/rvtrace, especially the way of handling trace
component topology. The generic logic of building a path from source ->
sink should be common among coresight/rvtrace and for future architecture.
To support ATB use case like the K3, I think the best way to approach this
is to model the atb driver as a separate rvtrace-atb drive and let it
drive the ARM coresight components. Don't treat risc-v trace as another
type of coresight.

@Zane, can you also clarify that only the 2 X100 clusters have trace
encoders, and the A100 clusters do not? I don't see the 2 A100 clusters
listed in your sample devicetree. If that's the case, then we'll be faced
with heterogeneous trace setup, making it even more complicated.

>>
>> Regards,
>> Anup
> 
> Thanks,
> Zane

Bo


^ permalink raw reply

* Re: [PATCH v3 2/4] phy: axiado: add Axiado eMMC PHY driver
From: Tzu-Hao Wei @ 2026-04-15  0:55 UTC (permalink / raw)
  To: SriNavmani A, Prasad Bolisetty, Vinod Koul, Neil Armstrong,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-phy, devicetree, linux-arm-kernel, linux-kernel, openbmc
In-Reply-To: <20260317-axiado-ax3000-add-emmc-phy-driver-support-v3-2-fbf790f3f711@axiado.com>

On 3/18/2026 3:52 AM, Tzu-Hao Wei wrote:
> From: SriNavmani A <srinavmani@axiado.com>
> 
> It provides the required configurations for Axiado eMMC PHY driver for
> HS200 mode.
> 
> Signed-off-by: SriNavmani A <srinavmani@axiado.com>
> Co-developed-by: Prasad Bolisetty <pbolisetty@axiado.com>
> Signed-off-by: Prasad Bolisetty <pbolisetty@axiado.com>
> Signed-off-by: Tzu-Hao Wei <twei@axiado.com>
> ---
>  drivers/phy/Kconfig                  |   1 +
>  drivers/phy/Makefile                 |   1 +
>  drivers/phy/axiado/Kconfig           |  11 ++
>  drivers/phy/axiado/Makefile          |   1 +
>  drivers/phy/axiado/phy-axiado-emmc.c | 217 +++++++++++++++++++++++++++++++++++
>  5 files changed, 231 insertions(+)
> 

Hi Vinod,

Just a gentle ping on this patch series.

Since you reviewed the previous version, I wanted to check if you might have
a chance to take a look at this one when time permits.

Any feedback would be appreciated.

Best regards,
TH



^ permalink raw reply

* Re: [PATCH net-next] net: stmmac: enable RPS and RBU interrupts
From: Russell King (Oracle) @ 2026-04-15  1:19 UTC (permalink / raw)
  To: Sam Edwards
  Cc: Jakub Kicinski, Andrew Lunn, Alexandre Torgue, Andrew Lunn,
	David S. Miller, Eric Dumazet,
	moderated list:BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE,
	linux-stm32, Linux Network Development Mailing List, Paolo Abeni
In-Reply-To: <ad5LlXzeQ8j14Mjg@shell.armlinux.org.uk>

Okay, just a quick note to say that nvidia's 5.10.216-tegra kernel
survives iperf3 -c -R to the imx6.

Dumping the registers and comparing, and then forcing the RQS and TQS
values to 0x23 (+1 = 36, *256 = 9216 bytes) and 0x8f (+1 = 144,
*256 = 36864 ytes) respectively seems to solve the problem. Under
net-next, these both end up being 0xff (+1 = 256, *256 = 65536 bytes.)
Suspiciously, 36 * 4 = 144, and I also see that this kernel programs
all four of the MTL receive operation mode registers, but only the
first MTL transmit operation mode register. However, DMA channels 1-3
aren't initialised.

net-next derives them from:

        unsigned int tqs = fifosz / 256 - 1;

where fifosz is passed in to dwmac4_dma_tx_chan_op_mode() and

        unsigned int rqs = fifosz / 256 - 1;

where fifosz is passed in to dwmac4_dma_rx_chan_op_mode().

Now, according to the DMA capabilities:

        Number of Additional RX channel: 4
        Number of Additional TX channel: 4
        Number of Additional RX queues: 4
        Number of Additional TX queues: 4
        TX Fifo Size: 65536
        RX Fifo Size: 65536

However:

# ethtool -l eth0
Channel parameters for eth0:
Pre-set maximums:
RX:             4
TX:             4
Other:          0
Combined:       0
Current hardware settings:
RX:             1
TX:             1
Other:          0
Combined:       0

So, we end up allocating the entire 64K of the tx and rx FIFO to one
queue in net-next.

Looking back at 5.10, I don't see any code that would account for these
values being programmed for TQS and RQS, it looks like the calculations
are basically the same as we have today.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


^ permalink raw reply

* Re: [PATCH v4 3/9] coresight: etm4x: fix leaked trace id
From: Jie Gan @ 2026-04-15  1:21 UTC (permalink / raw)
  To: Yeoreum Yun, Leo Yan
  Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
	mike.leach, james.clark, alexander.shishkin
In-Reply-To: <ad5wVVnUw1jnkCdn@e129823.arm.com>



On 4/15/2026 12:50 AM, Yeoreum Yun wrote:
> Hi,
> 
>> On Mon, Apr 13, 2026 at 03:19:56PM +0100, Yeoreum Yun wrote:
>>> If etm4_enable_sysfs() fails in cscfg_csdev_enable_active_config(),
>>> the trace ID may be leaked because it is not released.
>>>
>>> To address this, call etm4_release_trace_id() when etm4_enable_sysfs()
>>> fails in cscfg_csdev_enable_active_config().
>>>
>>> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
>>> ---
>>>   drivers/hwtracing/coresight/coresight-etm4x-core.c | 4 +++-
>>>   1 file changed, 3 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>> index 8ebfd3924143..1bc9f13e33f7 100644
>>> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>> @@ -918,8 +918,10 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
>>>   	cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
>>>   	if (cfg_hash) {
>>>   		ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
>>> -		if (ret)
>>> +		if (ret) {
>>> +			etm4_release_trace_id(drvdata);
>>
>> I am not familiar with the trace ID, seems to me, it just allocate a ID
>> for each tracer from the ID map and then always use this cached ID for
>> the tracers.
>>
>> If so, even an ID is reserved for failures, and the ID map is big enough
>> for each CPU, we don't need to worry memory leak or ID used out issue ?
>>
> 
> Agree. Practically, this is not a big issue and I don't think
> because of this new id couldn't be allocated in 128
> although the one id is occupied by cpu while source is disabled.
> 
> However, in theory, this could lead to an ID leak,
> so it would be better to release it in error cases.

Actually, the 128 Trace ID is not enough for allocating. That's why the 
TPDM devices share the trace ID of the connected TPDA devices.

For the QCOM platform, we may got plenty of ETM devices (SoC with more 
than 20 Cores), lots of TPDM devices for each subsystem(CDSP, ADSP, GPU, 
GCC, MODEM, etc ...), and lots of dummy sources...

What I am thinking is as SoCs continue to grow more complex with an 
increasing number of subsystems, trace IDs may be exhausted in the near 
future. (that's why we have dynamic trace ID allocation/release).

Thanks,
Jie

> 
> [...]
> 
> --
> Sincerely,
> Yeoreum Yun



^ permalink raw reply

* Re: [RFC PATCH 00/12] Add Linux RISC-V trace support via CoreSight
From: Zane Leung @ 2026-04-15  1:23 UTC (permalink / raw)
  To: Bo Gan, Anup Patel
  Cc: robh, krzk+dt, conor+dt, palmer, pjw, gregkh, alexander.shishkin,
	irogers, coresight, peterz, mingo, namhyung, mark.rutland, jolsa,
	adrian.hunter, mchitale, atish.patra, andrew.jones, sunilvl,
	linux-riscv, linux-kernel, anup.patel, mayuresh.chitale,
	zhuangqiubin, suzuki.poulose, mike.leach, james.clark,
	linux-arm-kernel
In-Reply-To: <1ced8f98-6ac5-4ffc-ac29-cef25937a920@gmail.com>

Hi Bo,

On 4/15/2026 8:10 AM, Bo Gan wrote:
> Hi Zane, Anup,
>
> On 4/14/26 02:04, Zane Leung wrote:
>>
>> On 4/14/2026 3:23 PM, Anup Patel wrote:
>>> On Tue, Apr 14, 2026 at 9:12 AM Zane Leung <liangzhen@linux.spacemit.com> wrote:
>>>> From: liangzhen <zhen.liang@spacemit.com>
>>>>
>>>> This series adds Linux RISC-V trace support via CoreSight, implementing RISC-V
>>>> trace drivers within the CoreSight framework and integrating them with perf tools.
>>>> The K3 SoC contains RISC-V Encoder, Funnel, ATB, CoreSight Funnel, and CoreSight TMC
>>>> components, which can be directly leveraged through the existing CoreSight infrastructure.
>>>>
>>>> Linux RISC-V trace support form Anup Patel:
>>>> (https://patchwork.kernel.org/project/linux-riscv/cover/20260225062448.4027948-1-anup.patel@oss.qualcomm.com/)
>>>> which currently lacks ATB component support and guidance on reusing CoreSight components.
>>> What stops you from adding RISC-V trace funnel and ATB bridge drivers
>>> on top of this series ?
>>>
>> Firstly, my works started much earlier than this series. Secondly, it is difficult to add the coresight funnel and coresight tmc components to this series. Based on the coresight framework, I can directly reuse them.
>>
>>>
>>>> The series includes:
>>>> - RISC-V trace driver implementation within the CoreSight framework
>>> The RISC-V trace very different from the CoreSight framework in many ways:
>>> 1) Types of components supported
>>> 2) Trace packet formats
>>> 3) The way MMIO based components are discoverd
>>> 4) ... and more ...
>> 1) I believe that RISC-V tracing is coresight-alike, where have encoders/funnel/sink/bridge that are described through DT and controlled by MMIO.
>> 2) I think the difference in package format is nothing more than the coresight frame generated by the ATB component to distinguish the trace source. After removing it, it becomes riscv trace data.
>> 3) The current CoreSight framework code does not introduce this mechanism, it is described through DT.
>>>> - RISC-V Trace Encoder, Funnel, and ATB Bridge drivers as CoreSight devices
>>>> - RISC-V trace PMU record capabilities and parsing events in perf.
>>>> - RISC-V Nexus Trace decoder for perf tools
>>>>
>>>> Any comments or suggestions are welcome.
>>>>
>>>> Verification on K3 SoC:
>>>> To verify this patch series on K3 hardware, the following device tree are required:
>>>> 1. RISC-V Trace Encoder node (8)
>>>> 2. RISC-V ATB Bridge node (8)
>>>> 3. RISC-V Trace Funnel node (2)
>>>> 3. CoreSight Funnel configuration for RISC-V (1)
>>>> 4. CoreSight TMC configuration for trace buffer (1)
>>>>
>>>> /{
>>>>          dummy_clk: apb-pclk {
>>>>                  compatible = "fixed-clock";
>>>>                  #clock-cells = <0x0>;
>>>>                  clock-output-names = "clk14mhz";
>>>>                  clock-frequency = <14000000>;
>>>>          };
>>>>
>>>>
>>>>          soc: soc {
>>>>                  #address-cells = <2>;
>>>>                  #size-cells = <2>;
>>>>
>>>>                  encoder0: encoder@d9002000 {
>>>>                          compatible = "riscv,trace-encoder";
>>>>                          reg = <0x0 0xd9002000 0x0 0x1000>;
>>>>                          cpus = <&cpu_0>;
>>>>                          out-ports {
>>>>                                  port {
>>>>                                          cluster0_encoder0_out_port: endpoint {
>>>>                                                  remote-endpoint = <&cluster0_bridge0_in_port>;
>>>>                                          };
>>>>                                  };
>>>>                          };
>>>>                  };
>>>>
>>>>                  bridge0: bridge@d9003000 {
>>>>                          compatible = "riscv,trace-atbbridge";
>>>>                          reg = <0x0 0xd9003000 0x0 0x1000>;
>>>>                          cpus = <&cpu_0>;
>>>>                          out-ports {
>>>>                                  port {
>>>>                                          cluster0_bridge0_out_port: endpoint {
>>>>                                                  remote-endpoint = <&cluster0_funnel_in_port0>;
>>>>                                          };
>>>>                                  };
>>>>                          };
>>>>                          in-ports {
>>>>                                  port {
>>>>                                          cluster0_bridge0_in_port: endpoint {
>>>>                                                  remote-endpoint = <&cluster0_encoder0_out_port>;
>>>>                                          };
>>>>                                  };
>>>>                          };
>>>>                  };
>>>>
>>>> ...
>>>>
>>>>                  cluster0_funnel: funnel@d9000000 {
>>>>                          compatible = "riscv,trace-funnel";
>>>>                          reg = <0x0 0xd9000000 0x0 0x1000>;
>>>>                          cpus = <&cpu_0>, <&cpu_1>, <&cpu_2>, <&cpu_3>;
>>>>                          riscv,timestamp-present;
>>>>                          out-ports {
>>>>                                  port {
>>>>                                          cluster0_funnel_out_port: endpoint {
>>>>                                                  remote-endpoint = <&main_funnel_in_port0>;
>>>>                                          };
>>>>                                  };
>>>>                          };
>>>>                          in-ports {
>>>>                                  #address-cells = <1>;
>>>>                                  #size-cells = <0>;
>>>>
>>>>                                  port@0 {
>>>>                                          reg = <0>;
>>>>                                          cluster0_funnel_in_port0: endpoint {
>>>>                                                  remote-endpoint = <&cluster0_bridge0_out_port>;
>>>>                                          };
>>>>                                  };
>>>>
>>>>                                  port@1 {
>>>>                                          reg = <1>;
>>>>                                          cluster0_funnel_in_port1: endpoint {
>>>>                                                  remote-endpoint = <&cluster0_bridge1_out_port>;
>>>>                                          };
>>>>                                  };
>>>>
>>>>                                  port@2 {
>>>>                                          reg = <2>;
>>>>                                          cluster0_funnel_in_port2: endpoint {
>>>>                                                  remote-endpoint = <&cluster0_bridge2_out_port>;
>>>>                                          };
>>>>                                  };
>>>>
>>>>                                  port@3 {
>>>>                                          reg = <3>;
>>>>                                          cluster0_funnel_in_port3: endpoint {
>>>>                                                  remote-endpoint = <&cluster0_bridge3_out_port>;
>>>>                                          };
>>>>                                  };
>>>>                          };
>>>>                  };
>>>>
>>>>                  cluster1_funnel: funnel@d9010000 {
>>>>                          compatible = "riscv,trace-funnel";
>>>>                          reg = <0x0 0xd9010000 0x0 0x1000>;
>>>>                          cpus = <&cpu_4>, <&cpu_5>, <&cpu_6>, <&cpu_7>;
>>>>                          riscv,timestamp-present;
>>>>                          out-ports {
>>>>                                  port {
>>>>                                          cluster1_funnel_out_port: endpoint {
>>>>                                                  remote-endpoint = <&main_funnel_in_port1>;
>>>>                                          };
>>>>                                  };
>>>>                          };
>>>>                          in-ports {
>>>>                                  #address-cells = <1>;
>>>>                                  #size-cells = <0>;
>>>>
>>>>                                  port@0 {
>>>>                                          reg = <0>;
>>>>                                          cluster1_funnel_in_port0: endpoint {
>>>>                                                  remote-endpoint = <&cluster1_bridge0_out_port>;
>>>>                                          };
>>>>                                  };
>>>>
>>>>                                  port@1 {
>>>>                                          reg = <1>;
>>>>                                          cluster1_funnel_in_port1: endpoint {
>>>>                                                  remote-endpoint = <&cluster1_bridge1_out_port>;
>>>>                                          };
>>>>                                  };
>>>>
>>>>                                  port@2 {
>>>>                                          reg = <2>;
>>>>                                          cluster1_funnel_in_port2: endpoint {
>>>>                                                  remote-endpoint = <&cluster1_bridge2_out_port>;
>>>>                                          };
>>>>                                  };
>>>>
>>>>                                  port@3 {
>>>>                                          reg = <3>;
>>>>                                          cluster1_funnel_in_port3: endpoint {
>>>>                                                  remote-endpoint = <&cluster1_bridge3_out_port>;
>>>>                                          };
>>>>                                  };
>>>>                          };
>>>>                  };
>>>>
>>>>                  main_funnel: funnel@d9042000 {
>>>>                          compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
>>> Is it legally allowed to mix and match ARM coresight IPs with
>>> RISC-V trace components at hardware level ?
>> The ATB Bridge allows sending RISC-V trace to Arm CoreSight infrastructure (instead of RISC-V compliant sink defined in this document) as an ATB initiator.  see:
>> https://github.com/riscv-non-isa/riscv-nexus-trace/blob/105dc1c349556622e4d202d22b584a887ded462f/docs/RISC-V-Trace-Control-Interface.adoc#L184
>> For ATB Bridge, read trace using Coresight components (ETB/TMC/TPIU). see:
>> https://github.com/riscv-non-isa/riscv-nexus-trace/blob/105dc1c349556622e4d202d22b584a887ded462f/docs/RISC-V-Trace-Control-Interface.adoc#L1684
>>>
>>>>                          reg = <0x0 0xd9042000 0x0 0x1000>;
>>>>                          clocks = <&dummy_clk>;
>>>>                          clock-names = "apb_pclk";
>>>>                          out-ports {
>>>>                                  port {
>>>>                                          main_funnel_out_port: endpoint {
>>>>                                                  remote-endpoint = <&etf_in_port>;
>>>>                                          };
>>>>                                  };
>>>>                          };
>>>>                          in-ports {
>>>>                                  #address-cells = <1>;
>>>>                                  #size-cells = <0>;
>>>>
>>>>                                  port@0 {
>>>>                                          reg = <0>;
>>>>                                          main_funnel_in_port0: endpoint {
>>>>                                                  remote-endpoint = <&cluster0_funnel_out_port>;
>>>>                                          };
>>>>                                  };
>>>>
>>>>                                  port@1 {
>>>>                                          reg = <1>;
>>>>                                          main_funnel_in_port1: endpoint {
>>>>                                                  remote-endpoint = <&cluster1_funnel_out_port>;
>>>>                                          };
>>>>                                  };
>>>>                          };
>>>>                  };
>>>>
>>>>                  etf: etf@d9043000 {
>>>>                          compatible = "arm,coresight-tmc", "arm,primecell";
>>>>                          reg = <0x0 0xd9043000 0x0 0x1000>;
>>>>                          clocks = <&dummy_clk>;
>>>>                          clock-names = "apb_pclk";
>>>>                          out-ports {
>>>>                                  port {
>>>>                                          etf_out_port: endpoint {
>>>>                                                  remote-endpoint = <&etr_in_port>;
>>>>                                          };
>>>>                                  };
>>>>                          };
>>>>                          in-ports {
>>>>                                  port {
>>>>                                          etf_in_port: endpoint {
>>>>                                                  remote-endpoint = <&main_funnel_out_port>;
>>>>                                          };
>>>>                                  };
>>>>                          };
>>>>                  };
>>>>
>>>>                  etr: etr@d9044000 {
>>>>                          compatible = "arm,coresight-tmc", "arm,primecell";
>>>>                          reg = <0x0 0xd9044000 0x0 0x1000>;
>>>>                          clocks = <&dummy_clk>;
>>>>                          clock-names = "apb_pclk";
>>>>                          arm,scatter-gather;
>>>>                          in-ports {
>>>>                                  port {
>>>>                                          etr_in_port: endpoint {
>>>>                                                  remote-endpoint = <&etf_out_port>;
>>>>                                          };
>>>>                                  };
>>>>                          };
>>>>                  };
>>>>          };
>>>> };
>>>>
>>>> Verification case:
>>>>
>>>> ~ # perf list pmu
>>>>    rvtrace//                                          [Kernel PMU event]
>>>>
>>>> ~ # perf record -e rvtrace/@tmc_etr0/ --per-thread uname
>>>> Linux
>>>> [ perf record: Woken up 1 times to write data ]
>>>> [ perf record: Captured and wrote 0.191 MB perf.data ]
>>>> ~ # perf script
>>>>             uname     137 [003]          1           branches:  ffffffff80931470 rvtrace_poll_bit+0x38 ([kernel.kallsyms]) => ffffffff80931492 rvtrace_poll_bit+0x5a ([kernel.kallsyms])
>>>>             uname     137 [003]          1           branches:  ffffffff809328a6 encoder_enable_hw+0x252 ([kernel.kallsyms]) => ffffffff809328ba encoder_enable_hw+0x266 ([kernel.kallsyms])
>>>>             uname     137 [003]          1           branches:  ffffffff80932c4a encoder_enable+0x82 ([kernel.kallsyms]) => ffffffff80932c36 encoder_enable+0x6e ([kernel.kallsyms])
>>>>             uname     137 [003]          1           branches:  ffffffff80928198 etm_event_start+0xf0 ([kernel.kallsyms]) => ffffffff809281aa etm_event_start+0x102 ([kernel.kallsyms])
>>>>             uname     137 [003]          1           branches:  ffffffff809281e6 etm_event_start+0x13e ([kernel.kallsyms]) => ffffffff8092755e coresight_get_sink_id+0x16 ([kernel.kallsyms])
>>>>             uname     137 [003]          1           branches:  ffffffff8092820e etm_event_start+0x166 ([kernel.kallsyms]) => ffffffff80928226 etm_event_start+0x17e ([kernel.kallsyms])
>>>>             uname     137 [003]          1           branches:  ffffffff801c3bb4 perf_report_aux_output_id+0x0 ([kernel.kallsyms]) => ffffffff801c3bd6 perf_report_aux_output_id+0x22 ([kernel.kallsyms])
>>>>             uname     137 [003]          1           branches:  ffffffff801c3c5a perf_report_aux_output_id+0xa6 ([kernel.kallsyms]) => ffffffff801c3bf0 perf_report_aux_output_id+0x3c ([kernel.kallsyms])
>>>>             uname     137 [003]          1           branches:  ffffffff801c3c40 perf_report_aux_output_id+0x8c ([kernel.kallsyms]) => ffffffff801c3aea __perf_event_header__init_id+0x2a ([kernel.kallsyms])
>>>>             uname     137 [003]          1           branches:  ffffffff801c3b42 __perf_event_header__init_id+0x82 ([kernel.kallsyms]) => ffffffff801c3b4a __perf_event_header__init_id+0x8a ([kernel.kallsyms])
>>>>             uname     137 [003]          1           branches:  ffffffff801c3bb0 __perf_event_header__init_id+0xf0 ([kernel.kallsyms]) => ffffffff801c3b58 __perf_event_header__init_id+0x98 ([kernel.kallsyms])
>>>>             uname     137 [003]          1           branches:  ffffffff8004c658 __task_pid_nr_ns+0x0 ([kernel.kallsyms]) => ffffffff8004c696 __task_pid_nr_ns+0x3e ([kernel.kallsyms])
>>>>             uname     137 [003]          1           branches:  ffffffff8004c71e __task_pid_nr_ns+0xc6 ([kernel.kallsyms]) => ffffffff8004c6a4 __task_pid_nr_ns+0x4c ([kernel.kallsyms])
>>>>             uname     137 [003]          1           branches:  ffffffff8004c6e4 __task_pid_nr_ns+0x8c ([kernel.kallsyms]) => ffffffff8004c6e4 __task_pid_nr_ns+0x8c ([kernel.kallsyms])
>>>> ...
>>>>
>>>> liangzhen (12):
>>>>    coresight: Add RISC-V support to CoreSight tracing
>>>>    coresight: Initial implementation of RISC-V trace driver
>>>>    coresight: Add RISC-V Trace Encoder driver
>>>>    coresight: Add RISC-V Trace Funnel driver
>>>>    coresight: Add RISC-V Trace ATB Bridge driver
>>>>    coresight rvtrace: Add timestamp component support for encoder and
>>>>      funnel
>>>>    coresight: Add RISC-V PMU name support
>>>>    perf tools: riscv: making rvtrace PMU listable
>>>>    perf tools: Add RISC-V trace PMU record capabilities
>>>>    perf tools: Add Nexus RISC-V Trace decoder
>>>>    perf symbols: Add RISC-V PLT entry sizes
>>>>    perf tools: Integrate RISC-V trace decoder into auxtrace
>>>>
>>>>   drivers/hwtracing/Kconfig                     |    2 +
>>>>   drivers/hwtracing/coresight/Kconfig           |   46 +-
>>>>   drivers/hwtracing/coresight/Makefile          |    6 +
>>>>   drivers/hwtracing/coresight/coresight-core.c  |    8 +
>>>>   .../hwtracing/coresight/coresight-etm-perf.c  |    1 -
>>>>   .../hwtracing/coresight/coresight-etm-perf.h  |   21 +
>>>>   .../hwtracing/coresight/coresight-platform.c  |    1 -
>>>>   .../hwtracing/coresight/coresight-tmc-etf.c   |    4 +
>>>>   .../hwtracing/coresight/coresight-tmc-etr.c   |    4 +
>>>>   .../hwtracing/coresight/rvtrace-atbbridge.c   |  239 +++
>>>>   drivers/hwtracing/coresight/rvtrace-core.c    |  135 ++
>>>>   .../coresight/rvtrace-encoder-core.c          |  562 +++++++
>>>>   .../coresight/rvtrace-encoder-sysfs.c         |  363 +++++
>>>>   drivers/hwtracing/coresight/rvtrace-encoder.h |  151 ++
>>>>   drivers/hwtracing/coresight/rvtrace-funnel.c  |  337 ++++
>>>>   drivers/hwtracing/coresight/rvtrace-funnel.h  |   39 +
>>>>   .../hwtracing/coresight/rvtrace-timestamp.c   |  278 ++++
>>>>   .../hwtracing/coresight/rvtrace-timestamp.h   |   64 +
>>>>   include/linux/coresight-pmu.h                 |    4 +
>>>>   include/linux/rvtrace.h                       |  116 ++
>>>>   tools/arch/riscv/include/asm/insn.h           |  645 ++++++++
>>>>   tools/perf/arch/riscv/util/Build              |    2 +
>>>>   tools/perf/arch/riscv/util/auxtrace.c         |  490 ++++++
>>>>   tools/perf/arch/riscv/util/pmu.c              |   20 +
>>>>   tools/perf/util/Build                         |    3 +
>>>>   tools/perf/util/auxtrace.c                    |    4 +
>>>>   tools/perf/util/auxtrace.h                    |    1 +
>>>>   tools/perf/util/nexus-rv-decoder/Build        |    1 +
>>>>   .../util/nexus-rv-decoder/nexus-rv-decoder.c  | 1364 +++++++++++++++++
>>>>   .../util/nexus-rv-decoder/nexus-rv-decoder.h  |  139 ++
>>>>   .../perf/util/nexus-rv-decoder/nexus-rv-msg.h |  190 +++
>>>>   tools/perf/util/rvtrace-decoder.c             | 1039 +++++++++++++
>>>>   tools/perf/util/rvtrace.h                     |   40 +
>>>>   tools/perf/util/symbol-elf.c                  |    4 +
>>>>   34 files changed, 6320 insertions(+), 3 deletions(-)
>>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-atbbridge.c
>>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-core.c
>>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-encoder-core.c
>>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-encoder-sysfs.c
>>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-encoder.h
>>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-funnel.c
>>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-funnel.h
>>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-timestamp.c
>>>>   create mode 100644 drivers/hwtracing/coresight/rvtrace-timestamp.h
>>>>   create mode 100644 include/linux/rvtrace.h
>>>>   create mode 100644 tools/arch/riscv/include/asm/insn.h
>>>>   create mode 100644 tools/perf/arch/riscv/util/auxtrace.c
>>>>   create mode 100644 tools/perf/arch/riscv/util/pmu.c
>>>>   create mode 100644 tools/perf/util/nexus-rv-decoder/Build
>>>>   create mode 100644 tools/perf/util/nexus-rv-decoder/nexus-rv-decoder.c
>>>>   create mode 100644 tools/perf/util/nexus-rv-decoder/nexus-rv-decoder.h
>>>>   create mode 100644 tools/perf/util/nexus-rv-decoder/nexus-rv-msg.h
>>>>   create mode 100644 tools/perf/util/rvtrace-decoder.c
>>>>   create mode 100644 tools/perf/util/rvtrace.h
>>>>
>>>> -- 
>>>> 2.34.1
>>>>
>>> NACK to this approach of retrofitting RISC-V trace into ARM coresight.
>> I agree that integrating RISC-V trace directly into CoreSight is not a good approach, so I think we should abstract some of the logic of coresight and reuse it in RISC-V Trace.
>
> I think we should indeed abstract out some coresight logic so it can be
> reused by both coresight/rvtrace, especially the way of handling trace
> component topology. The generic logic of building a path from source ->
> sink should be common among coresight/rvtrace and for future architecture.
> To support ATB use case like the K3, I think the best way to approach this
> is to model the atb driver as a separate rvtrace-atb drive and let it
> drive the ARM coresight components. Don't treat risc-v trace as another
> type of coresight.
>
> @Zane, can you also clarify that only the 2 X100 clusters have trace
> encoders, and the A100 clusters do not? I don't see the 2 A100 clusters
> listed in your sample devicetree. If that's the case, then we'll be faced
> with heterogeneous trace setup, making it even more complicated.
>
The A100 clusters also have trace encoders, just like the X100 clusters. The reason I didn't include the two A100 clusters in the sample devicetree is to maintain consistency with the upstream k3.dtsi.


>>>
>>> Regards,
>>> Anup
>>
>> Thanks,
>> Zane
>
> Bo
>

Thanks,

Zane


^ permalink raw reply

* Re: [Question mpam mpam/snapshot+extras/v6.18-rc1] Question with Configuring iommu_group in 'task'
From: Zeng Heng @ 2026-04-15  1:27 UTC (permalink / raw)
  To: Ben Horgan, James Morse
  Cc: Qinxin Xia, amitsinght, baisheng.gao, baolin.wang, carl,
	dave.martin, david, dfustini, fenghuay, gshan, james.morse,
	jonathan.cameron, kobak, lcherian, linux-arm-kernel, linux-kernel,
	peternewman, punit.agrawal, quic_jiles, reinette.chatre,
	rohit.mathew, scott, sdonthineni, xhao, Linuxarm
In-Reply-To: <0d578c61-1341-4149-9e8c-936ea0ce0c50@arm.com>

Hi Ben,

On 2026/4/13 23:02, Ben Horgan wrote:
> Hi Qinxin,
> 
> On 4/3/26 03:44, Qinxin Xia wrote:
>>
>>
>> On 2026/3/27 18:47:49, Ben Horgan <ben.horgan@arm.com> wrote:
>>> Hi Qinxin,
>>>
>>> On 3/27/26 10:21, Qinxin Xia wrote:
>>>>
>>>> Hello everyone!
>>>>
>>>> In earlier versions, mpam supports the configuration of iommu_groups.
>>>>
>>>>    823 static ssize_t rdtgroup_tasks_write(struct kernfs_open_file *of,
>>>>    824                                     char *buf, size_t nbytes,
>>>> loff_t off)
>>>>    825 {
>>>>    826         struct rdtgroup *rdtgrp;
>>>>    827         int iommu_group_id;
>>>>    828         bool is_iommu;
>>>>    829         char *pid_str;
>>>>    830         int ret = 0;
>>>>    831         pid_t pid;
>>>>    832
>>>>    833         rdtgrp = rdtgroup_kn_lock_live(of->kn);
>>>>    834         if (!rdtgrp) {
>>>>    835                 rdtgroup_kn_unlock(of->kn);
>>>>    836                 return -ENOENT;
>>>>    837         }
>>>>    838         rdt_last_cmd_clear();
>>>>    839
>>>>    840         if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED ||
>>>>    841             rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
>>>>    842                 ret = -EINVAL;
>>>>    843                 rdt_last_cmd_puts("Pseudo-locking in progress\n");
>>>>    844                 goto unlock;
>>>>    845         }
>>>>    846
>>>>    847         while (buf && buf[0] != '\0' && buf[0] != '\n') {
>>>>    848                 pid_str = strim(strsep(&buf, ","));
>>>>    849
>>>>    850                 is_iommu = string_is_iommu_group(pid_str, &iommu_group_id);
>>>>
>>>> What puzzles me is why we would put it under 'task'—this seems a little
>>>>    strange to users.It seems they are not related.Why don't we add a new
>>>> interface like 'iommu'?
>>>
>>> I think it is likely that this interface would change if upstream support is added.
>>>
>>
>> I have done some work in this direction before, and I will release an
>> RFC later for further discussion.:-)
> 
> Looking forward to seeing it.
> 
> Ben
> 

Following the current SMMU approach, I've submitted several bugfix
patches for the MPAM driver, but haven't received any review feedback
yet.

To avoid these being overlooked, I'd like to kindly remind to take a
look:
v2: 
https://lore.kernel.org/all/20260414032610.1523958-1-zengheng4@huawei.com/
v1: 
https://lore.kernel.org/all/20251107063300.1580046-1-zengheng4@huawei.com/

Additionally, I'd like to check on the status of this branch — is it
still actively maintained? It would be helpful to understand the future
plans for MPAM development.


Thanks for your time,
Zeng Heng


^ permalink raw reply

* Re: [PATCH RFC] ACPI: processor: idle: Do not propagate acpi_processor_ffh_lpi_probe() -ENODEV
From: lihuisong (C) @ 2026-04-15  1:32 UTC (permalink / raw)
  To: Sudeep Holla, Rafael J. Wysocki
  Cc: Breno Leitao, Len Brown, lpieralisi, catalin.marinas, will,
	Rafael J. Wysocki, linux-acpi, linux-kernel, pjaroszynski,
	guohanjun, linux-arm-kernel, rmikey, kernel-team, lihuisong
In-Reply-To: <20260414-cute-shapeless-dolphin-c5b2fc@sudeepholla>


On 4/14/2026 8:25 PM, Sudeep Holla wrote:
> On Tue, Apr 14, 2026 at 07:31:29PM +0800, lihuisong (C) wrote:
>> On 4/14/2026 6:21 PM, Breno Leitao wrote:
>>> Hello Huisong,
>>>
>>> On Tue, Apr 14, 2026 at 05:43:51PM +0800, lihuisong (C) wrote:
>>>> But it is a real issue. Thanks for your report.
>>>> I think the best way to fix your issue is that remove this verification in
>>>> psci_acpi_cpu_init_idle().
>>>> Because it is legal for platform to report one LPI state.
>>>> This function just needs to verify the LPI states which are FFH.
>>> Thank you for the prompt feedback.
>>>
>>> Would this approach work?
>>>
>>> commit 6c9d52840a4f778cc989838ba76ee51416e85de3
>>> Author: Breno Leitao <leitao@debian.org>
>>> Date:   Tue Apr 14 03:16:08 2026 -0700
>>>
>>>       ACPI: processor: idle: Allow platforms with only one LPI state
>>>       psci_acpi_cpu_init_idle() rejects platforms where power.count - 1 <= 0
>>>       by returning -ENODEV. However, having a single LPI state (WFI) is a
>>>       valid configuration. The function's purpose is to verify FFH idle states,
>>>       and when count is zero, there are simply no FFH states to validate —
>>>       this is not an error.
>>>       On NVIDIA Grace (aarch64) systems with PSCIv1.1, power.count is 1 for
>>>       all 72 CPUs, so the probe fails with -ENODEV. After commit cac173bea57d
>>>       ("ACPI: processor: idle: Rework the handling of
>>>       acpi_processor_ffh_lpi_probe()"), this failure propagates up and prevents
>>>       cpuidle registration entirely.
>>>       Change the check from (count <= 0) to (count < 0) so that platforms
>>>       with only WFI are accepted. The for loop naturally handles count == 0
>>>       by not iterating.
>>>       Fixes: cac173bea57d ("ACPI: processor: idle: Rework the handling of acpi_processor_ffh_lpi_probe()")
>>>       Signed-off-by: Breno Leitao <leitao@debian.org>
>>>
>>> diff --git a/drivers/acpi/arm64/cpuidle.c b/drivers/acpi/arm64/cpuidle.c
>>> index 801f9c4501425..7791b751042ce 100644
>>> --- a/drivers/acpi/arm64/cpuidle.c
>>> +++ b/drivers/acpi/arm64/cpuidle.c
>>> @@ -31,7 +31,7 @@ static int psci_acpi_cpu_init_idle(unsigned int cpu)
>>>    		return -EOPNOTSUPP;
>>>    	count = pr->power.count - 1;
>>> -	if (count <= 0)
>>> +	if (count < 0)
>>>    		return -ENODEV;
>>>    	for (i = 0; i < count; i++) {
>> This count already verified in acpi_processor_get_lpi_info.
>>
>> I suggest modifing it as below:
>>
>> -->
>>
>> git diff
>> diff --git a/drivers/acpi/arm64/cpuidle.c b/drivers/acpi/arm64/cpuidle.c
>> index 801f9c450142..c68a5db8ebba 100644
>> --- a/drivers/acpi/arm64/cpuidle.c
>> +++ b/drivers/acpi/arm64/cpuidle.c
>> @@ -16,7 +16,7 @@
>>
>>   static int psci_acpi_cpu_init_idle(unsigned int cpu)
>>   {
>> -       int i, count;
>> +       int i;
>>          struct acpi_lpi_state *lpi;
>>          struct acpi_processor *pr = per_cpu(processors, cpu);
>>
>> @@ -30,14 +30,10 @@ static int psci_acpi_cpu_init_idle(unsigned int cpu)
>>          if (!psci_ops.cpu_suspend)
>>                  return -EOPNOTSUPP;
>>
>> -       count = pr->power.count - 1;
>> -       if (count <= 0)
>> -               return -ENODEV;
>> -
> It was intentionally designed this way, as there is little value in defining
> only WFI in the _LPI tables. In the absence of a cpuidle driver/LPI entry,
> arch_cpu_idle() is invoked, which is sufficient and avoids unnecessary
> complexity, only to ultimately execute wfi() anyway.
Yeah, it's correct. The code flow will be more simple and high-efficiency.
This looks good to me.


But cpuidle sysfs under per CPU is created when firmware just reports 
WFI state before
my commit cac173bea57d ("ACPI: processor: idle: Rework the handling of 
acpi_processor_ffh_lpi_probe()").
However, these platforms will no longer be created now and some 
statistics for state0 are also missing.
This change in behavor is visiable to user space.I'm not sure if it is 
acceptable.
What do you think, Rafael?
> So while I understand that the kernel did not report an error previously, that
> does not mean the _LPI table is merely moot on this platform when it contains
> only a WFI state.
>
>


^ permalink raw reply

* Re: [PATCH bpf-next v14 1/5] bpf: Move constants blinding out of arch-specific JITs
From: Hengqi Chen @ 2026-04-15  1:55 UTC (permalink / raw)
  To: Xu Kuohai
  Cc: bpf, linux-kernel, linux-arm-kernel, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Yonghong Song,
	Puranjay Mohan, Anton Protopopov, Alexis Lothoré,
	Shahab Vahedi, Russell King, Tiezhu Yang, Johan Almbladh,
	Paul Burton, Hari Bathini, Christophe Leroy, Naveen N Rao,
	Luke Nelson, Xi Wang, Björn Töpel, Pu Lehui,
	Ilya Leoshkevich, Heiko Carstens, Vasily Gorbik, David S . Miller,
	Wang YanQing
In-Reply-To: <7d88904b4028cbe124bbaba5739c525663bedc64.1776062885.git.xukuohai@hotmail.com>

On Mon, Apr 13, 2026 at 9:07 PM Xu Kuohai <xukuohai@huaweicloud.com> wrote:
>
> From: Xu Kuohai <xukuohai@huawei.com>
>
> During the JIT stage, constants blinding rewrites instructions but only
> rewrites the private instruction copy of the JITed subprog, leaving the
> global env->prog->insnsi and env->insn_aux_data untouched. This causes a
> mismatch between subprog instructions and the global state, making it
> difficult to use the global data in the JIT.
>
> To avoid this mismatch, and given that all arch-specific JITs already
> support constants blinding, move it to the generic verifier code, and
> switch to rewrite the global env->prog->insnsi with the global states
> adjusted, as other rewrites in the verifier do.
>
> This removes the constants blinding calls in each JIT, which are largely
> duplicated code across architectures.
>
> Since constants blinding is only required for JIT, and there are two
> JIT entry functions, jit_subprogs() for BPF programs with multiple
> subprogs and bpf_prog_select_runtime() for programs with no subprogs,
> move the constants blinding invocation into these two functions.
>
> In the verifier path, bpf_patch_insn_data() is used to keep global
> verifier auxiliary data in sync with patched instructions. A key
> question is whether this global auxiliary data should be restored
> on the failure path.
>
> Besides instructions, bpf_patch_insn_data() adjusts:
>   - prog->aux->poke_tab
>   - env->insn_array_maps
>   - env->subprog_info
>   - env->insn_aux_data
>
> For prog->aux->poke_tab, it is only used by JIT or only meaningful after
> JIT succeeds, so it does not need to be restored on the failure path.
>
> For env->insn_array_maps, when JIT fails, programs using insn arrays
> are rejected by bpf_insn_array_ready() due to missing JIT addresses.
> Hence, env->insn_array_maps is only meaningful for JIT and does not need
> to be restored.
>
> For subprog_info, if jit_subprogs fails and CONFIG_BPF_JIT_ALWAYS_ON
> is not enabled, kernel falls back to interpreter. In this case,
> env->subprog_info is used to determine subprogram stack depth. So it
> must be restored on failure.
>
> For env->insn_aux_data, it is freed by clear_insn_aux_data() at the
> end of bpf_check(). Before freeing, clear_insn_aux_data() loops over
> env->insn_aux_data to release jump targets recorded in it. The loop
> uses env->prog->len as the array length, but this length no longer
> matches the actual size of the adjusted env->insn_aux_data array after
> constants blinding.
>
> To address it, a simple approach is to keep insn_aux_data as adjusted
> after failure, since it will be freed shortly, and record its actual size
> for the loop in clear_insn_aux_data(). But since clear_insn_aux_data()
> uses the same index to loop over both env->prog->insnsi and env->insn_aux_data,
> this approach results in incorrect index for the insnsi array. So an
> alternative approach is adopted: clone the original env->insn_aux_data
> before blinding and restore it after failure, similar to env->prog.
>
> For classic BPF programs, constants blinding works as before since it
> is still invoked from bpf_prog_select_runtime().
>
> Reviewed-by: Anton Protopopov <a.s.protopopov@gmail.com> # v8
> Reviewed-by: Hari Bathini <hbathini@linux.ibm.com> # powerpc jit
> Reviewed-by: Pu Lehui <pulehui@huawei.com> # riscv jit
> Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
> ---

Acked-by: Hengqi Chen <hengqi.chen@gmail.com> # loongarch jit

>  arch/arc/net/bpf_jit_core.c      |  39 +++------
>  arch/arm/net/bpf_jit_32.c        |  41 ++-------
>  arch/arm64/net/bpf_jit_comp.c    |  72 +++++-----------
>  arch/loongarch/net/bpf_jit.c     |  59 ++++---------
>  arch/mips/net/bpf_jit_comp.c     |  20 +----
>  arch/parisc/net/bpf_jit_core.c   |  73 +++++++---------
>  arch/powerpc/net/bpf_jit_comp.c  |  68 ++++++---------
>  arch/riscv/net/bpf_jit_core.c    |  61 +++++--------
>  arch/s390/net/bpf_jit_comp.c     |  59 +++++--------
>  arch/sparc/net/bpf_jit_comp_64.c |  61 +++++--------
>  arch/x86/net/bpf_jit_comp.c      |  43 ++-------
>  arch/x86/net/bpf_jit_comp32.c    |  33 +------
>  include/linux/filter.h           |  33 ++++++-
>  kernel/bpf/core.c                |  69 +++++++++++++--
>  kernel/bpf/fixups.c              | 144 ++++++++++++++++++++++++++-----
>  15 files changed, 400 insertions(+), 475 deletions(-)
>
> diff --git a/arch/arc/net/bpf_jit_core.c b/arch/arc/net/bpf_jit_core.c
> index 1421eeced0f5..973ceae48675 100644
> --- a/arch/arc/net/bpf_jit_core.c
> +++ b/arch/arc/net/bpf_jit_core.c
> @@ -79,7 +79,6 @@ struct arc_jit_data {
>   * The JIT pertinent context that is used by different functions.
>   *
>   * prog:               The current eBPF program being handled.
> - * orig_prog:          The original eBPF program before any possible change.
>   * jit:                        The JIT buffer and its length.
>   * bpf_header:         The JITed program header. "jit.buf" points inside it.
>   * emit:               If set, opcodes are written to memory; else, a dry-run.
> @@ -94,12 +93,10 @@ struct arc_jit_data {
>   * need_extra_pass:    A forecast if an "extra_pass" will occur.
>   * is_extra_pass:      Indicates if the current pass is an extra pass.
>   * user_bpf_prog:      True, if VM opcodes come from a real program.
> - * blinded:            True if "constant blinding" step returned a new "prog".
>   * success:            Indicates if the whole JIT went OK.
>   */
>  struct jit_context {
>         struct bpf_prog                 *prog;
> -       struct bpf_prog                 *orig_prog;
>         struct jit_buffer               jit;
>         struct bpf_binary_header        *bpf_header;
>         bool                            emit;
> @@ -114,7 +111,6 @@ struct jit_context {
>         bool                            need_extra_pass;
>         bool                            is_extra_pass;
>         bool                            user_bpf_prog;
> -       bool                            blinded;
>         bool                            success;
>  };
>
> @@ -161,13 +157,7 @@ static int jit_ctx_init(struct jit_context *ctx, struct bpf_prog *prog)
>  {
>         memset(ctx, 0, sizeof(*ctx));
>
> -       ctx->orig_prog = prog;
> -
> -       /* If constant blinding was requested but failed, scram. */
> -       ctx->prog = bpf_jit_blind_constants(prog);
> -       if (IS_ERR(ctx->prog))
> -               return PTR_ERR(ctx->prog);
> -       ctx->blinded = (ctx->prog != ctx->orig_prog);
> +       ctx->prog = prog;
>
>         /* If the verifier doesn't zero-extend, then we have to do it. */
>         ctx->do_zext = !ctx->prog->aux->verifier_zext;
> @@ -214,14 +204,6 @@ static inline void maybe_free(struct jit_context *ctx, void **mem)
>   */
>  static void jit_ctx_cleanup(struct jit_context *ctx)
>  {
> -       if (ctx->blinded) {
> -               /* if all went well, release the orig_prog. */
> -               if (ctx->success)
> -                       bpf_jit_prog_release_other(ctx->prog, ctx->orig_prog);
> -               else
> -                       bpf_jit_prog_release_other(ctx->orig_prog, ctx->prog);
> -       }
> -
>         maybe_free(ctx, (void **)&ctx->bpf2insn);
>         maybe_free(ctx, (void **)&ctx->jit_data);
>
> @@ -229,12 +211,19 @@ static void jit_ctx_cleanup(struct jit_context *ctx)
>                 ctx->bpf2insn_valid = false;
>
>         /* Freeing "bpf_header" is enough. "jit.buf" is a sub-array of it. */
> -       if (!ctx->success && ctx->bpf_header) {
> -               bpf_jit_binary_free(ctx->bpf_header);
> -               ctx->bpf_header = NULL;
> -               ctx->jit.buf    = NULL;
> -               ctx->jit.index  = 0;
> -               ctx->jit.len    = 0;
> +       if (!ctx->success) {
> +               if (ctx->bpf_header) {
> +                       bpf_jit_binary_free(ctx->bpf_header);
> +                       ctx->bpf_header = NULL;
> +                       ctx->jit.buf    = NULL;
> +                       ctx->jit.index  = 0;
> +                       ctx->jit.len    = 0;
> +               }
> +               if (ctx->is_extra_pass) {
> +                       ctx->prog->bpf_func = NULL;
> +                       ctx->prog->jited = 0;
> +                       ctx->prog->jited_len = 0;
> +               }
>         }
>
>         ctx->emit = false;
> diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
> index deeb8f292454..e6b1bb2de627 100644
> --- a/arch/arm/net/bpf_jit_32.c
> +++ b/arch/arm/net/bpf_jit_32.c
> @@ -2144,9 +2144,7 @@ bool bpf_jit_needs_zext(void)
>
>  struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>  {
> -       struct bpf_prog *tmp, *orig_prog = prog;
>         struct bpf_binary_header *header;
> -       bool tmp_blinded = false;
>         struct jit_ctx ctx;
>         unsigned int tmp_idx;
>         unsigned int image_size;
> @@ -2156,20 +2154,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>          * the interpreter.
>          */
>         if (!prog->jit_requested)
> -               return orig_prog;
> -
> -       /* If constant blinding was enabled and we failed during blinding
> -        * then we must fall back to the interpreter. Otherwise, we save
> -        * the new JITed code.
> -        */
> -       tmp = bpf_jit_blind_constants(prog);
> -
> -       if (IS_ERR(tmp))
> -               return orig_prog;
> -       if (tmp != prog) {
> -               tmp_blinded = true;
> -               prog = tmp;
> -       }
> +               return prog;
>
>         memset(&ctx, 0, sizeof(ctx));
>         ctx.prog = prog;
> @@ -2179,10 +2164,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>          * we must fall back to the interpreter
>          */
>         ctx.offsets = kcalloc(prog->len, sizeof(int), GFP_KERNEL);
> -       if (ctx.offsets == NULL) {
> -               prog = orig_prog;
> -               goto out;
> -       }
> +       if (ctx.offsets == NULL)
> +               return prog;
>
>         /* 1) fake pass to find in the length of the JITed code,
>          * to compute ctx->offsets and other context variables
> @@ -2194,10 +2177,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>          * being successful in the second pass, so just fall back
>          * to the interpreter.
>          */
> -       if (build_body(&ctx)) {
> -               prog = orig_prog;
> +       if (build_body(&ctx))
>                 goto out_off;
> -       }
>
>         tmp_idx = ctx.idx;
>         build_prologue(&ctx);
> @@ -2213,10 +2194,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         ctx.idx += ctx.imm_count;
>         if (ctx.imm_count) {
>                 ctx.imms = kcalloc(ctx.imm_count, sizeof(u32), GFP_KERNEL);
> -               if (ctx.imms == NULL) {
> -                       prog = orig_prog;
> +               if (ctx.imms == NULL)
>                         goto out_off;
> -               }
>         }
>  #else
>         /* there's nothing about the epilogue on ARMv7 */
> @@ -2238,10 +2217,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         /* Not able to allocate memory for the structure then
>          * we must fall back to the interpretation
>          */
> -       if (header == NULL) {
> -               prog = orig_prog;
> +       if (header == NULL)
>                 goto out_imms;
> -       }
>
>         /* 2.) Actual pass to generate final JIT code */
>         ctx.target = (u32 *) image_ptr;
> @@ -2278,16 +2255,12 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>  #endif
>  out_off:
>         kfree(ctx.offsets);
> -out:
> -       if (tmp_blinded)
> -               bpf_jit_prog_release_other(prog, prog == orig_prog ?
> -                                          tmp : orig_prog);
> +
>         return prog;
>
>  out_free:
>         image_ptr = NULL;
>         bpf_jit_binary_free(header);
> -       prog = orig_prog;
>         goto out_imms;
>  }
>
> diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
> index adf84962d579..cd5a72fff500 100644
> --- a/arch/arm64/net/bpf_jit_comp.c
> +++ b/arch/arm64/net/bpf_jit_comp.c
> @@ -2009,14 +2009,12 @@ struct arm64_jit_data {
>  struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>  {
>         int image_size, prog_size, extable_size, extable_align, extable_offset;
> -       struct bpf_prog *tmp, *orig_prog = prog;
>         struct bpf_binary_header *header;
>         struct bpf_binary_header *ro_header = NULL;
>         struct arm64_jit_data *jit_data;
>         void __percpu *priv_stack_ptr = NULL;
>         bool was_classic = bpf_prog_was_classic(prog);
>         int priv_stack_alloc_sz;
> -       bool tmp_blinded = false;
>         bool extra_pass = false;
>         struct jit_ctx ctx;
>         u8 *image_ptr;
> @@ -2025,26 +2023,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         int exentry_idx;
>
>         if (!prog->jit_requested)
> -               return orig_prog;
> -
> -       tmp = bpf_jit_blind_constants(prog);
> -       /* If blinding was requested and we failed during blinding,
> -        * we must fall back to the interpreter.
> -        */
> -       if (IS_ERR(tmp))
> -               return orig_prog;
> -       if (tmp != prog) {
> -               tmp_blinded = true;
> -               prog = tmp;
> -       }
> +               return prog;
>
>         jit_data = prog->aux->jit_data;
>         if (!jit_data) {
>                 jit_data = kzalloc_obj(*jit_data);
> -               if (!jit_data) {
> -                       prog = orig_prog;
> -                       goto out;
> -               }
> +               if (!jit_data)
> +                       return prog;
>                 prog->aux->jit_data = jit_data;
>         }
>         priv_stack_ptr = prog->aux->priv_stack_ptr;
> @@ -2056,10 +2041,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 priv_stack_alloc_sz = round_up(prog->aux->stack_depth, 16) +
>                                       2 * PRIV_STACK_GUARD_SZ;
>                 priv_stack_ptr = __alloc_percpu_gfp(priv_stack_alloc_sz, 16, GFP_KERNEL);
> -               if (!priv_stack_ptr) {
> -                       prog = orig_prog;
> +               if (!priv_stack_ptr)
>                         goto out_priv_stack;
> -               }
>
>                 priv_stack_init_guard(priv_stack_ptr, priv_stack_alloc_sz);
>                 prog->aux->priv_stack_ptr = priv_stack_ptr;
> @@ -2079,10 +2062,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         ctx.prog = prog;
>
>         ctx.offset = kvzalloc_objs(int, prog->len + 1);
> -       if (ctx.offset == NULL) {
> -               prog = orig_prog;
> +       if (ctx.offset == NULL)
>                 goto out_off;
> -       }
>
>         ctx.user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
>         ctx.arena_vm_start = bpf_arena_get_kern_vm_start(prog->aux->arena);
> @@ -2095,15 +2076,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>          * BPF line info needs ctx->offset[i] to be the offset of
>          * instruction[i] in jited image, so build prologue first.
>          */
> -       if (build_prologue(&ctx, was_classic)) {
> -               prog = orig_prog;
> +       if (build_prologue(&ctx, was_classic))
>                 goto out_off;
> -       }
>
> -       if (build_body(&ctx, extra_pass)) {
> -               prog = orig_prog;
> +       if (build_body(&ctx, extra_pass))
>                 goto out_off;
> -       }
>
>         ctx.epilogue_offset = ctx.idx;
>         build_epilogue(&ctx, was_classic);
> @@ -2121,10 +2098,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr,
>                                               sizeof(u64), &header, &image_ptr,
>                                               jit_fill_hole);
> -       if (!ro_header) {
> -               prog = orig_prog;
> +       if (!ro_header)
>                 goto out_off;
> -       }
>
>         /* Pass 2: Determine jited position and result for each instruction */
>
> @@ -2152,10 +2127,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         /* Dont write body instructions to memory for now */
>         ctx.write = false;
>
> -       if (build_body(&ctx, extra_pass)) {
> -               prog = orig_prog;
> +       if (build_body(&ctx, extra_pass))
>                 goto out_free_hdr;
> -       }
>
>         ctx.epilogue_offset = ctx.idx;
>         ctx.exentry_idx = exentry_idx;
> @@ -2164,19 +2137,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>
>         /* Pass 3: Adjust jump offset and write final image */
>         if (build_body(&ctx, extra_pass) ||
> -               WARN_ON_ONCE(ctx.idx != ctx.epilogue_offset)) {
> -               prog = orig_prog;
> +               WARN_ON_ONCE(ctx.idx != ctx.epilogue_offset))
>                 goto out_free_hdr;
> -       }
>
>         build_epilogue(&ctx, was_classic);
>         build_plt(&ctx);
>
>         /* Extra pass to validate JITed code. */
> -       if (validate_ctx(&ctx)) {
> -               prog = orig_prog;
> +       if (validate_ctx(&ctx))
>                 goto out_free_hdr;
> -       }
>
>         /* update the real prog size */
>         prog_size = sizeof(u32) * ctx.idx;
> @@ -2193,16 +2162,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 if (extra_pass && ctx.idx > jit_data->ctx.idx) {
>                         pr_err_once("multi-func JIT bug %d > %d\n",
>                                     ctx.idx, jit_data->ctx.idx);
> -                       prog->bpf_func = NULL;
> -                       prog->jited = 0;
> -                       prog->jited_len = 0;
>                         goto out_free_hdr;
>                 }
>                 if (WARN_ON(bpf_jit_binary_pack_finalize(ro_header, header))) {
> -                       /* ro_header has been freed */
> +                       /* ro_header and header has been freed */
>                         ro_header = NULL;
> -                       prog = orig_prog;
> -                       goto out_off;
> +                       header = NULL;
> +                       goto out_free_hdr;
>                 }
>                 /*
>                  * The instructions have now been copied to the ROX region from
> @@ -2245,13 +2211,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 kfree(jit_data);
>                 prog->aux->jit_data = NULL;
>         }
> -out:
> -       if (tmp_blinded)
> -               bpf_jit_prog_release_other(prog, prog == orig_prog ?
> -                                          tmp : orig_prog);
> +
>         return prog;
>
>  out_free_hdr:
> +       if (extra_pass) {
> +               prog->bpf_func = NULL;
> +               prog->jited = 0;
> +               prog->jited_len = 0;
> +       }
>         if (header) {
>                 bpf_arch_text_copy(&ro_header->size, &header->size,
>                                    sizeof(header->size));
> diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
> index 9cb796e16379..fcc8c0c29fb0 100644
> --- a/arch/loongarch/net/bpf_jit.c
> +++ b/arch/loongarch/net/bpf_jit.c
> @@ -1922,43 +1922,26 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
>
>  struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>  {
> -       bool tmp_blinded = false, extra_pass = false;
> +       bool extra_pass = false;
>         u8 *image_ptr, *ro_image_ptr;
>         int image_size, prog_size, extable_size;
>         struct jit_ctx ctx;
>         struct jit_data *jit_data;
>         struct bpf_binary_header *header;
>         struct bpf_binary_header *ro_header;
> -       struct bpf_prog *tmp, *orig_prog = prog;
>
>         /*
>          * If BPF JIT was not enabled then we must fall back to
>          * the interpreter.
>          */
>         if (!prog->jit_requested)
> -               return orig_prog;
> -
> -       tmp = bpf_jit_blind_constants(prog);
> -       /*
> -        * If blinding was requested and we failed during blinding,
> -        * we must fall back to the interpreter. Otherwise, we save
> -        * the new JITed code.
> -        */
> -       if (IS_ERR(tmp))
> -               return orig_prog;
> -
> -       if (tmp != prog) {
> -               tmp_blinded = true;
> -               prog = tmp;
> -       }
> +               return prog;
>
>         jit_data = prog->aux->jit_data;
>         if (!jit_data) {
>                 jit_data = kzalloc_obj(*jit_data);
> -               if (!jit_data) {
> -                       prog = orig_prog;
> -                       goto out;
> -               }
> +               if (!jit_data)
> +                       return prog;
>                 prog->aux->jit_data = jit_data;
>         }
>         if (jit_data->ctx.offset) {
> @@ -1978,17 +1961,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         ctx.user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
>
>         ctx.offset = kvcalloc(prog->len + 1, sizeof(u32), GFP_KERNEL);
> -       if (ctx.offset == NULL) {
> -               prog = orig_prog;
> +       if (ctx.offset == NULL)
>                 goto out_offset;
> -       }
>
>         /* 1. Initial fake pass to compute ctx->idx and set ctx->flags */
>         build_prologue(&ctx);
> -       if (build_body(&ctx, extra_pass)) {
> -               prog = orig_prog;
> +       if (build_body(&ctx, extra_pass))
>                 goto out_offset;
> -       }
>         ctx.epilogue_offset = ctx.idx;
>         build_epilogue(&ctx);
>
> @@ -2004,10 +1983,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         /* Now we know the size of the structure to make */
>         ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr, sizeof(u32),
>                                               &header, &image_ptr, jit_fill_hole);
> -       if (!ro_header) {
> -               prog = orig_prog;
> +       if (!ro_header)
>                 goto out_offset;
> -       }
>
>         /* 2. Now, the actual pass to generate final JIT code */
>         /*
> @@ -2027,17 +2004,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         ctx.num_exentries = 0;
>
>         build_prologue(&ctx);
> -       if (build_body(&ctx, extra_pass)) {
> -               prog = orig_prog;
> +       if (build_body(&ctx, extra_pass))
>                 goto out_free;
> -       }
>         build_epilogue(&ctx);
>
>         /* 3. Extra pass to validate JITed code */
> -       if (validate_ctx(&ctx)) {
> -               prog = orig_prog;
> +       if (validate_ctx(&ctx))
>                 goto out_free;
> -       }
>
>         /* And we're done */
>         if (bpf_jit_enable > 1)
> @@ -2050,9 +2023,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                         goto out_free;
>                 }
>                 if (WARN_ON(bpf_jit_binary_pack_finalize(ro_header, header))) {
> -                       /* ro_header has been freed */
> +                       /* ro_header and header have been freed */
>                         ro_header = NULL;
> -                       prog = orig_prog;
> +                       header = NULL;
>                         goto out_free;
>                 }
>                 /*
> @@ -2084,13 +2057,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 prog->aux->jit_data = NULL;
>         }
>
> -out:
> -       if (tmp_blinded)
> -               bpf_jit_prog_release_other(prog, prog == orig_prog ? tmp : orig_prog);
> -
>         return prog;
>
>  out_free:
> +       if (extra_pass) {
> +               prog->bpf_func = NULL;
> +               prog->jited = 0;
> +               prog->jited_len = 0;
> +       }
> +
>         if (header) {
>                 bpf_arch_text_copy(&ro_header->size, &header->size, sizeof(header->size));
>                 bpf_jit_binary_pack_free(ro_header, header);
> diff --git a/arch/mips/net/bpf_jit_comp.c b/arch/mips/net/bpf_jit_comp.c
> index e355dfca4400..d2b6c955f18e 100644
> --- a/arch/mips/net/bpf_jit_comp.c
> +++ b/arch/mips/net/bpf_jit_comp.c
> @@ -911,10 +911,8 @@ bool bpf_jit_needs_zext(void)
>
>  struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>  {
> -       struct bpf_prog *tmp, *orig_prog = prog;
>         struct bpf_binary_header *header = NULL;
>         struct jit_context ctx;
> -       bool tmp_blinded = false;
>         unsigned int tmp_idx;
>         unsigned int image_size;
>         u8 *image_ptr;
> @@ -925,19 +923,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>          * the interpreter.
>          */
>         if (!prog->jit_requested)
> -               return orig_prog;
> -       /*
> -        * If constant blinding was enabled and we failed during blinding
> -        * then we must fall back to the interpreter. Otherwise, we save
> -        * the new JITed code.
> -        */
> -       tmp = bpf_jit_blind_constants(prog);
> -       if (IS_ERR(tmp))
> -               return orig_prog;
> -       if (tmp != prog) {
> -               tmp_blinded = true;
> -               prog = tmp;
> -       }
> +               return prog;
>
>         memset(&ctx, 0, sizeof(ctx));
>         ctx.program = prog;
> @@ -1025,14 +1011,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         prog->jited_len = image_size;
>
>  out:
> -       if (tmp_blinded)
> -               bpf_jit_prog_release_other(prog, prog == orig_prog ?
> -                                          tmp : orig_prog);
>         kfree(ctx.descriptors);
>         return prog;
>
>  out_err:
> -       prog = orig_prog;
>         if (header)
>                 bpf_jit_binary_free(header);
>         goto out;
> diff --git a/arch/parisc/net/bpf_jit_core.c b/arch/parisc/net/bpf_jit_core.c
> index a5eb6b51e27a..35dca372b5df 100644
> --- a/arch/parisc/net/bpf_jit_core.c
> +++ b/arch/parisc/net/bpf_jit_core.c
> @@ -44,30 +44,19 @@ bool bpf_jit_needs_zext(void)
>  struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>  {
>         unsigned int prog_size = 0, extable_size = 0;
> -       bool tmp_blinded = false, extra_pass = false;
> -       struct bpf_prog *tmp, *orig_prog = prog;
> +       bool extra_pass = false;
>         int pass = 0, prev_ninsns = 0, prologue_len, i;
>         struct hppa_jit_data *jit_data;
>         struct hppa_jit_context *ctx;
>
>         if (!prog->jit_requested)
> -               return orig_prog;
> -
> -       tmp = bpf_jit_blind_constants(prog);
> -       if (IS_ERR(tmp))
> -               return orig_prog;
> -       if (tmp != prog) {
> -               tmp_blinded = true;
> -               prog = tmp;
> -       }
> +               return prog;
>
>         jit_data = prog->aux->jit_data;
>         if (!jit_data) {
>                 jit_data = kzalloc_obj(*jit_data);
> -               if (!jit_data) {
> -                       prog = orig_prog;
> -                       goto out;
> -               }
> +               if (!jit_data)
> +                       return prog;
>                 prog->aux->jit_data = jit_data;
>         }
>
> @@ -81,10 +70,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>
>         ctx->prog = prog;
>         ctx->offset = kzalloc_objs(int, prog->len);
> -       if (!ctx->offset) {
> -               prog = orig_prog;
> -               goto out_offset;
> -       }
> +       if (!ctx->offset)
> +               goto out_err;
>         for (i = 0; i < prog->len; i++) {
>                 prev_ninsns += 20;
>                 ctx->offset[i] = prev_ninsns;
> @@ -93,10 +80,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         for (i = 0; i < NR_JIT_ITERATIONS; i++) {
>                 pass++;
>                 ctx->ninsns = 0;
> -               if (build_body(ctx, extra_pass, ctx->offset)) {
> -                       prog = orig_prog;
> -                       goto out_offset;
> -               }
> +               if (build_body(ctx, extra_pass, ctx->offset))
> +                       goto out_err;
>                 ctx->body_len = ctx->ninsns;
>                 bpf_jit_build_prologue(ctx);
>                 ctx->prologue_len = ctx->ninsns - ctx->body_len;
> @@ -116,10 +101,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                                                      &jit_data->image,
>                                                      sizeof(long),
>                                                      bpf_fill_ill_insns);
> -                       if (!jit_data->header) {
> -                               prog = orig_prog;
> -                               goto out_offset;
> -                       }
> +                       if (!jit_data->header)
> +                               goto out_err;
>
>                         ctx->insns = (u32 *)jit_data->image;
>                         /*
> @@ -134,8 +117,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 pr_err("bpf-jit: image did not converge in <%d passes!\n", i);
>                 if (jit_data->header)
>                         bpf_jit_binary_free(jit_data->header);
> -               prog = orig_prog;
> -               goto out_offset;
> +               goto out_err;
>         }
>
>         if (extable_size)
> @@ -148,8 +130,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         bpf_jit_build_prologue(ctx);
>         if (build_body(ctx, extra_pass, NULL)) {
>                 bpf_jit_binary_free(jit_data->header);
> -               prog = orig_prog;
> -               goto out_offset;
> +               goto out_err;
>         }
>         bpf_jit_build_epilogue(ctx);
>
> @@ -160,20 +141,19 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                         { extern int machine_restart(char *); machine_restart(""); }
>         }
>
> +       if (!prog->is_func || extra_pass) {
> +               if (bpf_jit_binary_lock_ro(jit_data->header)) {
> +                       bpf_jit_binary_free(jit_data->header);
> +                       goto out_err;
> +               }
> +               bpf_flush_icache(jit_data->header, ctx->insns + ctx->ninsns);
> +       }
> +
>         prog->bpf_func = (void *)ctx->insns;
>         prog->jited = 1;
>         prog->jited_len = prog_size;
>
> -       bpf_flush_icache(jit_data->header, ctx->insns + ctx->ninsns);
> -
>         if (!prog->is_func || extra_pass) {
> -               if (bpf_jit_binary_lock_ro(jit_data->header)) {
> -                       bpf_jit_binary_free(jit_data->header);
> -                       prog->bpf_func = NULL;
> -                       prog->jited = 0;
> -                       prog->jited_len = 0;
> -                       goto out_offset;
> -               }
>                 prologue_len = ctx->epilogue_offset - ctx->body_len;
>                 for (i = 0; i < prog->len; i++)
>                         ctx->offset[i] += prologue_len;
> @@ -183,14 +163,19 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 kfree(jit_data);
>                 prog->aux->jit_data = NULL;
>         }
> -out:
> +
>         if (HPPA_JIT_REBOOT)
>                 { extern int machine_restart(char *); machine_restart(""); }
>
> -       if (tmp_blinded)
> -               bpf_jit_prog_release_other(prog, prog == orig_prog ?
> -                                          tmp : orig_prog);
>         return prog;
> +
> +out_err:
> +       if (extra_pass) {
> +               prog->bpf_func = NULL;
> +               prog->jited = 0;
> +               prog->jited_len = 0;
> +       }
> +       goto out_offset;
>  }
>
>  u64 hppa_div64(u64 div, u64 divisor)
> diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
> index a62a9a92b7b5..711028bebea3 100644
> --- a/arch/powerpc/net/bpf_jit_comp.c
> +++ b/arch/powerpc/net/bpf_jit_comp.c
> @@ -142,9 +142,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>         int flen;
>         struct bpf_binary_header *fhdr = NULL;
>         struct bpf_binary_header *hdr = NULL;
> -       struct bpf_prog *org_fp = fp;
> -       struct bpf_prog *tmp_fp;
> -       bool bpf_blinded = false;
>         bool extra_pass = false;
>         u8 *fimage = NULL;
>         u32 *fcode_base;
> @@ -152,24 +149,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>         u32 fixup_len;
>
>         if (!fp->jit_requested)
> -               return org_fp;
> -
> -       tmp_fp = bpf_jit_blind_constants(org_fp);
> -       if (IS_ERR(tmp_fp))
> -               return org_fp;
> -
> -       if (tmp_fp != org_fp) {
> -               bpf_blinded = true;
> -               fp = tmp_fp;
> -       }
> +               return fp;
>
>         jit_data = fp->aux->jit_data;
>         if (!jit_data) {
>                 jit_data = kzalloc_obj(*jit_data);
> -               if (!jit_data) {
> -                       fp = org_fp;
> -                       goto out;
> -               }
> +               if (!jit_data)
> +                       return fp;
>                 fp->aux->jit_data = jit_data;
>         }
>
> @@ -194,10 +180,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>         }
>
>         addrs = kcalloc(flen + 1, sizeof(*addrs), GFP_KERNEL);
> -       if (addrs == NULL) {
> -               fp = org_fp;
> -               goto out_addrs;
> -       }
> +       if (addrs == NULL)
> +               goto out_err;
>
>         memset(&cgctx, 0, sizeof(struct codegen_context));
>         bpf_jit_init_reg_mapping(&cgctx);
> @@ -211,11 +195,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>         cgctx.exception_cb = fp->aux->exception_cb;
>
>         /* Scouting faux-generate pass 0 */
> -       if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false)) {
> +       if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false))
>                 /* We hit something illegal or unsupported. */
> -               fp = org_fp;
> -               goto out_addrs;
> -       }
> +               goto out_err;
>
>         /*
>          * If we have seen a tail call, we need a second pass.
> @@ -226,10 +208,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>          */
>         if (cgctx.seen & SEEN_TAILCALL || !is_offset_in_branch_range((long)cgctx.idx * 4)) {
>                 cgctx.idx = 0;
> -               if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false)) {
> -                       fp = org_fp;
> -                       goto out_addrs;
> -               }
> +               if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false))
> +                       goto out_err;
>         }
>
>         bpf_jit_realloc_regs(&cgctx);
> @@ -250,10 +230,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>
>         fhdr = bpf_jit_binary_pack_alloc(alloclen, &fimage, 4, &hdr, &image,
>                                               bpf_jit_fill_ill_insns);
> -       if (!fhdr) {
> -               fp = org_fp;
> -               goto out_addrs;
> -       }
> +       if (!fhdr)
> +               goto out_err;
>
>         if (extable_len)
>                 fp->aux->extable = (void *)fimage + FUNCTION_DESCR_SIZE + proglen + fixup_len;
> @@ -272,8 +250,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>                                        extra_pass)) {
>                         bpf_arch_text_copy(&fhdr->size, &hdr->size, sizeof(hdr->size));
>                         bpf_jit_binary_pack_free(fhdr, hdr);
> -                       fp = org_fp;
> -                       goto out_addrs;
> +                       goto out_err;
>                 }
>                 bpf_jit_build_epilogue(code_base, &cgctx);
>
> @@ -295,15 +272,16 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>         ((u64 *)image)[1] = local_paca->kernel_toc;
>  #endif
>
> +       if (!fp->is_func || extra_pass) {
> +               if (bpf_jit_binary_pack_finalize(fhdr, hdr))
> +                       goto out_err;
> +       }
> +
>         fp->bpf_func = (void *)fimage;
>         fp->jited = 1;
>         fp->jited_len = cgctx.idx * 4 + FUNCTION_DESCR_SIZE;
>
>         if (!fp->is_func || extra_pass) {
> -               if (bpf_jit_binary_pack_finalize(fhdr, hdr)) {
> -                       fp = org_fp;
> -                       goto out_addrs;
> -               }
>                 bpf_prog_fill_jited_linfo(fp, addrs);
>  out_addrs:
>                 kfree(addrs);
> @@ -318,11 +296,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>                 jit_data->hdr = hdr;
>         }
>
> -out:
> -       if (bpf_blinded)
> -               bpf_jit_prog_release_other(fp, fp == org_fp ? tmp_fp : org_fp);
> -
>         return fp;
> +
> +out_err:
> +       if (extra_pass) {
> +               fp->bpf_func = NULL;
> +               fp->jited = 0;
> +               fp->jited_len = 0;
> +       }
> +       goto out_addrs;
>  }
>
>  /*
> diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c
> index b3581e926436..527baa50dc68 100644
> --- a/arch/riscv/net/bpf_jit_core.c
> +++ b/arch/riscv/net/bpf_jit_core.c
> @@ -44,29 +44,19 @@ bool bpf_jit_needs_zext(void)
>  struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>  {
>         unsigned int prog_size = 0, extable_size = 0;
> -       bool tmp_blinded = false, extra_pass = false;
> -       struct bpf_prog *tmp, *orig_prog = prog;
> +       bool extra_pass = false;
>         int pass = 0, prev_ninsns = 0, i;
>         struct rv_jit_data *jit_data;
>         struct rv_jit_context *ctx;
>
>         if (!prog->jit_requested)
> -               return orig_prog;
> -
> -       tmp = bpf_jit_blind_constants(prog);
> -       if (IS_ERR(tmp))
> -               return orig_prog;
> -       if (tmp != prog) {
> -               tmp_blinded = true;
> -               prog = tmp;
> -       }
> +               return prog;
>
>         jit_data = prog->aux->jit_data;
>         if (!jit_data) {
>                 jit_data = kzalloc_obj(*jit_data);
>                 if (!jit_data) {
> -                       prog = orig_prog;
> -                       goto out;
> +                       return prog;
>                 }
>                 prog->aux->jit_data = jit_data;
>         }
> @@ -83,15 +73,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         ctx->user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
>         ctx->prog = prog;
>         ctx->offset = kzalloc_objs(int, prog->len);
> -       if (!ctx->offset) {
> -               prog = orig_prog;
> +       if (!ctx->offset)
>                 goto out_offset;
> -       }
>
> -       if (build_body(ctx, extra_pass, NULL)) {
> -               prog = orig_prog;
> +       if (build_body(ctx, extra_pass, NULL))
>                 goto out_offset;
> -       }
>
>         for (i = 0; i < prog->len; i++) {
>                 prev_ninsns += 32;
> @@ -105,10 +91,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 bpf_jit_build_prologue(ctx, bpf_is_subprog(prog));
>                 ctx->prologue_len = ctx->ninsns;
>
> -               if (build_body(ctx, extra_pass, ctx->offset)) {
> -                       prog = orig_prog;
> +               if (build_body(ctx, extra_pass, ctx->offset))
>                         goto out_offset;
> -               }
>
>                 ctx->epilogue_offset = ctx->ninsns;
>                 bpf_jit_build_epilogue(ctx);
> @@ -126,10 +110,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                                                           &jit_data->ro_image, sizeof(u32),
>                                                           &jit_data->header, &jit_data->image,
>                                                           bpf_fill_ill_insns);
> -                       if (!jit_data->ro_header) {
> -                               prog = orig_prog;
> +                       if (!jit_data->ro_header)
>                                 goto out_offset;
> -                       }
>
>                         /*
>                          * Use the image(RW) for writing the JITed instructions. But also save
> @@ -150,7 +132,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>
>         if (i == NR_JIT_ITERATIONS) {
>                 pr_err("bpf-jit: image did not converge in <%d passes!\n", i);
> -               prog = orig_prog;
>                 goto out_free_hdr;
>         }
>
> @@ -163,26 +144,27 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         ctx->nexentries = 0;
>
>         bpf_jit_build_prologue(ctx, bpf_is_subprog(prog));
> -       if (build_body(ctx, extra_pass, NULL)) {
> -               prog = orig_prog;
> +       if (build_body(ctx, extra_pass, NULL))
>                 goto out_free_hdr;
> -       }
>         bpf_jit_build_epilogue(ctx);
>
>         if (bpf_jit_enable > 1)
>                 bpf_jit_dump(prog->len, prog_size, pass, ctx->insns);
>
> -       prog->bpf_func = (void *)ctx->ro_insns + cfi_get_offset();
> -       prog->jited = 1;
> -       prog->jited_len = prog_size - cfi_get_offset();
> -
>         if (!prog->is_func || extra_pass) {
>                 if (WARN_ON(bpf_jit_binary_pack_finalize(jit_data->ro_header, jit_data->header))) {
>                         /* ro_header has been freed */
>                         jit_data->ro_header = NULL;
> -                       prog = orig_prog;
> -                       goto out_offset;
> +                       jit_data->header = NULL;
> +                       goto out_free_hdr;
>                 }
> +       }
> +
> +       prog->bpf_func = (void *)ctx->ro_insns + cfi_get_offset();
> +       prog->jited = 1;
> +       prog->jited_len = prog_size - cfi_get_offset();
> +
> +       if (!prog->is_func || extra_pass) {
>                 /*
>                  * The instructions have now been copied to the ROX region from
>                  * where they will execute.
> @@ -198,14 +180,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 kfree(jit_data);
>                 prog->aux->jit_data = NULL;
>         }
> -out:
>
> -       if (tmp_blinded)
> -               bpf_jit_prog_release_other(prog, prog == orig_prog ?
> -                                          tmp : orig_prog);
>         return prog;
>
>  out_free_hdr:
> +       if (extra_pass) {
> +               prog->bpf_func = NULL;
> +               prog->jited = 0;
> +               prog->jited_len = 0;
> +       }
>         if (jit_data->header) {
>                 bpf_arch_text_copy(&jit_data->ro_header->size, &jit_data->header->size,
>                                    sizeof(jit_data->header->size));
> diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
> index d08d159b6319..2dfc279b1be2 100644
> --- a/arch/s390/net/bpf_jit_comp.c
> +++ b/arch/s390/net/bpf_jit_comp.c
> @@ -2314,36 +2314,20 @@ static struct bpf_binary_header *bpf_jit_alloc(struct bpf_jit *jit,
>   */
>  struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>  {
> -       struct bpf_prog *tmp, *orig_fp = fp;
>         struct bpf_binary_header *header;
>         struct s390_jit_data *jit_data;
> -       bool tmp_blinded = false;
>         bool extra_pass = false;
>         struct bpf_jit jit;
>         int pass;
>
>         if (!fp->jit_requested)
> -               return orig_fp;
> -
> -       tmp = bpf_jit_blind_constants(fp);
> -       /*
> -        * If blinding was requested and we failed during blinding,
> -        * we must fall back to the interpreter.
> -        */
> -       if (IS_ERR(tmp))
> -               return orig_fp;
> -       if (tmp != fp) {
> -               tmp_blinded = true;
> -               fp = tmp;
> -       }
> +               return fp;
>
>         jit_data = fp->aux->jit_data;
>         if (!jit_data) {
>                 jit_data = kzalloc_obj(*jit_data);
> -               if (!jit_data) {
> -                       fp = orig_fp;
> -                       goto out;
> -               }
> +               if (!jit_data)
> +                       return fp;
>                 fp->aux->jit_data = jit_data;
>         }
>         if (jit_data->ctx.addrs) {
> @@ -2356,34 +2340,27 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>
>         memset(&jit, 0, sizeof(jit));
>         jit.addrs = kvcalloc(fp->len + 1, sizeof(*jit.addrs), GFP_KERNEL);
> -       if (jit.addrs == NULL) {
> -               fp = orig_fp;
> -               goto free_addrs;
> -       }
> +       if (jit.addrs == NULL)
> +               goto out_err;
>         /*
>          * Three initial passes:
>          *   - 1/2: Determine clobbered registers
>          *   - 3:   Calculate program size and addrs array
>          */
>         for (pass = 1; pass <= 3; pass++) {
> -               if (bpf_jit_prog(&jit, fp, extra_pass)) {
> -                       fp = orig_fp;
> -                       goto free_addrs;
> -               }
> +               if (bpf_jit_prog(&jit, fp, extra_pass))
> +                       goto out_err;
>         }
>         /*
>          * Final pass: Allocate and generate program
>          */
>         header = bpf_jit_alloc(&jit, fp);
> -       if (!header) {
> -               fp = orig_fp;
> -               goto free_addrs;
> -       }
> +       if (!header)
> +               goto out_err;
>  skip_init_ctx:
>         if (bpf_jit_prog(&jit, fp, extra_pass)) {
>                 bpf_jit_binary_free(header);
> -               fp = orig_fp;
> -               goto free_addrs;
> +               goto out_err;
>         }
>         if (bpf_jit_enable > 1) {
>                 bpf_jit_dump(fp->len, jit.size, pass, jit.prg_buf);
> @@ -2392,8 +2369,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>         if (!fp->is_func || extra_pass) {
>                 if (bpf_jit_binary_lock_ro(header)) {
>                         bpf_jit_binary_free(header);
> -                       fp = orig_fp;
> -                       goto free_addrs;
> +                       goto out_err;
>                 }
>         } else {
>                 jit_data->header = header;
> @@ -2411,11 +2387,16 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>                 kfree(jit_data);
>                 fp->aux->jit_data = NULL;
>         }
> -out:
> -       if (tmp_blinded)
> -               bpf_jit_prog_release_other(fp, fp == orig_fp ?
> -                                          tmp : orig_fp);
> +
>         return fp;
> +
> +out_err:
> +       if (extra_pass) {
> +               fp->bpf_func = NULL;
> +               fp->jited = 0;
> +               fp->jited_len = 0;
> +       }
> +       goto free_addrs;
>  }
>
>  bool bpf_jit_supports_kfunc_call(void)
> diff --git a/arch/sparc/net/bpf_jit_comp_64.c b/arch/sparc/net/bpf_jit_comp_64.c
> index b23d1c645ae5..e83e29137566 100644
> --- a/arch/sparc/net/bpf_jit_comp_64.c
> +++ b/arch/sparc/net/bpf_jit_comp_64.c
> @@ -1479,37 +1479,22 @@ struct sparc64_jit_data {
>
>  struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>  {
> -       struct bpf_prog *tmp, *orig_prog = prog;
>         struct sparc64_jit_data *jit_data;
>         struct bpf_binary_header *header;
>         u32 prev_image_size, image_size;
> -       bool tmp_blinded = false;
>         bool extra_pass = false;
>         struct jit_ctx ctx;
>         u8 *image_ptr;
>         int pass, i;
>
>         if (!prog->jit_requested)
> -               return orig_prog;
> -
> -       tmp = bpf_jit_blind_constants(prog);
> -       /* If blinding was requested and we failed during blinding,
> -        * we must fall back to the interpreter.
> -        */
> -       if (IS_ERR(tmp))
> -               return orig_prog;
> -       if (tmp != prog) {
> -               tmp_blinded = true;
> -               prog = tmp;
> -       }
> +               return prog;
>
>         jit_data = prog->aux->jit_data;
>         if (!jit_data) {
>                 jit_data = kzalloc_obj(*jit_data);
> -               if (!jit_data) {
> -                       prog = orig_prog;
> -                       goto out;
> -               }
> +               if (!jit_data)
> +                       return prog;
>                 prog->aux->jit_data = jit_data;
>         }
>         if (jit_data->ctx.offset) {
> @@ -1527,10 +1512,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         ctx.prog = prog;
>
>         ctx.offset = kmalloc_array(prog->len, sizeof(unsigned int), GFP_KERNEL);
> -       if (ctx.offset == NULL) {
> -               prog = orig_prog;
> -               goto out_off;
> -       }
> +       if (ctx.offset == NULL)
> +               goto out_err;
>
>         /* Longest sequence emitted is for bswap32, 12 instructions.  Pre-cook
>          * the offset array so that we converge faster.
> @@ -1543,10 +1526,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 ctx.idx = 0;
>
>                 build_prologue(&ctx);
> -               if (build_body(&ctx)) {
> -                       prog = orig_prog;
> -                       goto out_off;
> -               }
> +               if (build_body(&ctx))
> +                       goto out_err;
>                 build_epilogue(&ctx);
>
>                 if (bpf_jit_enable > 1)
> @@ -1569,10 +1550,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         image_size = sizeof(u32) * ctx.idx;
>         header = bpf_jit_binary_alloc(image_size, &image_ptr,
>                                       sizeof(u32), jit_fill_hole);
> -       if (header == NULL) {
> -               prog = orig_prog;
> -               goto out_off;
> -       }
> +       if (header == NULL)
> +               goto out_err;
>
>         ctx.image = (u32 *)image_ptr;
>  skip_init_ctx:
> @@ -1582,8 +1561,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>
>         if (build_body(&ctx)) {
>                 bpf_jit_binary_free(header);
> -               prog = orig_prog;
> -               goto out_off;
> +               goto out_err;
>         }
>
>         build_epilogue(&ctx);
> @@ -1592,8 +1570,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 pr_err("bpf_jit: Failed to converge, prev_size=%u size=%d\n",
>                        prev_image_size, ctx.idx * 4);
>                 bpf_jit_binary_free(header);
> -               prog = orig_prog;
> -               goto out_off;
> +               goto out_err;
>         }
>
>         if (bpf_jit_enable > 1)
> @@ -1604,8 +1581,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         if (!prog->is_func || extra_pass) {
>                 if (bpf_jit_binary_lock_ro(header)) {
>                         bpf_jit_binary_free(header);
> -                       prog = orig_prog;
> -                       goto out_off;
> +                       goto out_err;
>                 }
>         } else {
>                 jit_data->ctx = ctx;
> @@ -1624,9 +1600,14 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 kfree(jit_data);
>                 prog->aux->jit_data = NULL;
>         }
> -out:
> -       if (tmp_blinded)
> -               bpf_jit_prog_release_other(prog, prog == orig_prog ?
> -                                          tmp : orig_prog);
> +
>         return prog;
> +
> +out_err:
> +       if (extra_pass) {
> +               prog->bpf_func = NULL;
> +               prog->jited = 0;
> +               prog->jited_len = 0;
> +       }
> +       goto out_off;
>  }
> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> index e9b78040d703..77d00a8dec87 100644
> --- a/arch/x86/net/bpf_jit_comp.c
> +++ b/arch/x86/net/bpf_jit_comp.c
> @@ -3717,13 +3717,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>  {
>         struct bpf_binary_header *rw_header = NULL;
>         struct bpf_binary_header *header = NULL;
> -       struct bpf_prog *tmp, *orig_prog = prog;
>         void __percpu *priv_stack_ptr = NULL;
>         struct x64_jit_data *jit_data;
>         int priv_stack_alloc_sz;
>         int proglen, oldproglen = 0;
>         struct jit_context ctx = {};
> -       bool tmp_blinded = false;
>         bool extra_pass = false;
>         bool padding = false;
>         u8 *rw_image = NULL;
> @@ -3733,27 +3731,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>         int i;
>
>         if (!prog->jit_requested)
> -               return orig_prog;
> -
> -       tmp = bpf_jit_blind_constants(prog);
> -       /*
> -        * If blinding was requested and we failed during blinding,
> -        * we must fall back to the interpreter.
> -        */
> -       if (IS_ERR(tmp))
> -               return orig_prog;
> -       if (tmp != prog) {
> -               tmp_blinded = true;
> -               prog = tmp;
> -       }
> +               return prog;
>
>         jit_data = prog->aux->jit_data;
>         if (!jit_data) {
>                 jit_data = kzalloc_obj(*jit_data);
> -               if (!jit_data) {
> -                       prog = orig_prog;
> -                       goto out;
> -               }
> +               if (!jit_data)
> +                       return prog;
>                 prog->aux->jit_data = jit_data;
>         }
>         priv_stack_ptr = prog->aux->priv_stack_ptr;
> @@ -3765,10 +3749,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 priv_stack_alloc_sz = round_up(prog->aux->stack_depth, 8) +
>                                       2 * PRIV_STACK_GUARD_SZ;
>                 priv_stack_ptr = __alloc_percpu_gfp(priv_stack_alloc_sz, 8, GFP_KERNEL);
> -               if (!priv_stack_ptr) {
> -                       prog = orig_prog;
> +               if (!priv_stack_ptr)
>                         goto out_priv_stack;
> -               }
>
>                 priv_stack_init_guard(priv_stack_ptr, priv_stack_alloc_sz);
>                 prog->aux->priv_stack_ptr = priv_stack_ptr;
> @@ -3786,10 +3768,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 goto skip_init_addrs;
>         }
>         addrs = kvmalloc_objs(*addrs, prog->len + 1);
> -       if (!addrs) {
> -               prog = orig_prog;
> +       if (!addrs)
>                 goto out_addrs;
> -       }
>
>         /*
>          * Before first pass, make a rough estimation of addrs[]
> @@ -3820,8 +3800,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                                                    sizeof(rw_header->size));
>                                 bpf_jit_binary_pack_free(header, rw_header);
>                         }
> -                       /* Fall back to interpreter mode */
> -                       prog = orig_prog;
>                         if (extra_pass) {
>                                 prog->bpf_func = NULL;
>                                 prog->jited = 0;
> @@ -3852,10 +3830,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                         header = bpf_jit_binary_pack_alloc(roundup(proglen, align) + extable_size,
>                                                            &image, align, &rw_header, &rw_image,
>                                                            jit_fill_hole);
> -                       if (!header) {
> -                               prog = orig_prog;
> +                       if (!header)
>                                 goto out_addrs;
> -                       }
>                         prog->aux->extable = (void *) image + roundup(proglen, align);
>                 }
>                 oldproglen = proglen;
> @@ -3908,8 +3884,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 prog->bpf_func = (void *)image + cfi_get_offset();
>                 prog->jited = 1;
>                 prog->jited_len = proglen - cfi_get_offset();
> -       } else {
> -               prog = orig_prog;
>         }
>
>         if (!image || !prog->is_func || extra_pass) {
> @@ -3925,10 +3899,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 kfree(jit_data);
>                 prog->aux->jit_data = NULL;
>         }
> -out:
> -       if (tmp_blinded)
> -               bpf_jit_prog_release_other(prog, prog == orig_prog ?
> -                                          tmp : orig_prog);
> +
>         return prog;
>  }
>
> diff --git a/arch/x86/net/bpf_jit_comp32.c b/arch/x86/net/bpf_jit_comp32.c
> index dda423025c3d..5f259577614a 100644
> --- a/arch/x86/net/bpf_jit_comp32.c
> +++ b/arch/x86/net/bpf_jit_comp32.c
> @@ -2521,35 +2521,19 @@ bool bpf_jit_needs_zext(void)
>  struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>  {
>         struct bpf_binary_header *header = NULL;
> -       struct bpf_prog *tmp, *orig_prog = prog;
>         int proglen, oldproglen = 0;
>         struct jit_context ctx = {};
> -       bool tmp_blinded = false;
>         u8 *image = NULL;
>         int *addrs;
>         int pass;
>         int i;
>
>         if (!prog->jit_requested)
> -               return orig_prog;
> -
> -       tmp = bpf_jit_blind_constants(prog);
> -       /*
> -        * If blinding was requested and we failed during blinding,
> -        * we must fall back to the interpreter.
> -        */
> -       if (IS_ERR(tmp))
> -               return orig_prog;
> -       if (tmp != prog) {
> -               tmp_blinded = true;
> -               prog = tmp;
> -       }
> +               return prog;
>
>         addrs = kmalloc_objs(*addrs, prog->len);
> -       if (!addrs) {
> -               prog = orig_prog;
> -               goto out;
> -       }
> +       if (!addrs)
> +               return prog;
>
>         /*
>          * Before first pass, make a rough estimation of addrs[]
> @@ -2574,7 +2558,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                         image = NULL;
>                         if (header)
>                                 bpf_jit_binary_free(header);
> -                       prog = orig_prog;
>                         goto out_addrs;
>                 }
>                 if (image) {
> @@ -2588,10 +2571,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 if (proglen == oldproglen) {
>                         header = bpf_jit_binary_alloc(proglen, &image,
>                                                       1, jit_fill_hole);
> -                       if (!header) {
> -                               prog = orig_prog;
> +                       if (!header)
>                                 goto out_addrs;
> -                       }
>                 }
>                 oldproglen = proglen;
>                 cond_resched();
> @@ -2604,16 +2585,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>                 prog->bpf_func = (void *)image;
>                 prog->jited = 1;
>                 prog->jited_len = proglen;
> -       } else {
> -               prog = orig_prog;
>         }
>
>  out_addrs:
>         kfree(addrs);
> -out:
> -       if (tmp_blinded)
> -               bpf_jit_prog_release_other(prog, prog == orig_prog ?
> -                                          tmp : orig_prog);
>         return prog;
>  }
>
> diff --git a/include/linux/filter.h b/include/linux/filter.h
> index e40d4071a345..d396e55c9a1d 100644
> --- a/include/linux/filter.h
> +++ b/include/linux/filter.h
> @@ -1183,6 +1183,18 @@ static inline bool bpf_dump_raw_ok(const struct cred *cred)
>
>  struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
>                                        const struct bpf_insn *patch, u32 len);
> +
> +#ifdef CONFIG_BPF_SYSCALL
> +struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
> +                                    const struct bpf_insn *patch, u32 len);
> +#else
> +static inline struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
> +                                                  const struct bpf_insn *patch, u32 len)
> +{
> +       return ERR_PTR(-ENOTSUPP);
> +}
> +#endif /* CONFIG_BPF_SYSCALL */
> +
>  int bpf_remove_insns(struct bpf_prog *prog, u32 off, u32 cnt);
>
>  static inline bool xdp_return_frame_no_direct(void)
> @@ -1309,9 +1321,14 @@ int bpf_jit_get_func_addr(const struct bpf_prog *prog,
>
>  const char *bpf_jit_get_prog_name(struct bpf_prog *prog);
>
> -struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *fp);
> +struct bpf_prog *bpf_jit_blind_constants(struct bpf_verifier_env *env, struct bpf_prog *prog);
>  void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other);
>
> +static inline bool bpf_prog_need_blind(const struct bpf_prog *prog)
> +{
> +       return prog->blinding_requested && !prog->blinded;
> +}
> +
>  static inline void bpf_jit_dump(unsigned int flen, unsigned int proglen,
>                                 u32 pass, void *image)
>  {
> @@ -1450,6 +1467,20 @@ static inline void bpf_prog_kallsyms_del(struct bpf_prog *fp)
>  {
>  }
>
> +static inline bool bpf_prog_need_blind(const struct bpf_prog *prog)
> +{
> +       return false;
> +}
> +
> +static inline
> +struct bpf_prog *bpf_jit_blind_constants(struct bpf_verifier_env *env, struct bpf_prog *prog)
> +{
> +       return prog;
> +}
> +
> +static inline void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other)
> +{
> +}
>  #endif /* CONFIG_BPF_JIT */
>
>  void bpf_prog_kallsyms_del_all(struct bpf_prog *fp);
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index 066b86e7233c..fc9fb3c07866 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -1508,7 +1508,11 @@ static void adjust_insn_arrays(struct bpf_prog *prog, u32 off, u32 len)
>  #endif
>  }
>
> -struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
> +/*
> + * Now this function is used only to blind the main prog and must be invoked only when
> + * bpf_prog_need_blind() returns true.
> + */
> +struct bpf_prog *bpf_jit_blind_constants(struct bpf_verifier_env *env, struct bpf_prog *prog)
>  {
>         struct bpf_insn insn_buff[16], aux[2];
>         struct bpf_prog *clone, *tmp;
> @@ -1516,13 +1520,17 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
>         struct bpf_insn *insn;
>         int i, rewritten;
>
> -       if (!prog->blinding_requested || prog->blinded)
> -               return prog;
> +       if (WARN_ON_ONCE(env && env->prog != prog))
> +               return ERR_PTR(-EINVAL);
>
>         clone = bpf_prog_clone_create(prog, GFP_USER);
>         if (!clone)
>                 return ERR_PTR(-ENOMEM);
>
> +       /* make sure bpf_patch_insn_data() patches the correct prog */
> +       if (env)
> +               env->prog = clone;
> +
>         insn_cnt = clone->len;
>         insn = clone->insnsi;
>
> @@ -1550,21 +1558,35 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
>                 if (!rewritten)
>                         continue;
>
> -               tmp = bpf_patch_insn_single(clone, i, insn_buff, rewritten);
> -               if (IS_ERR(tmp)) {
> +               if (env)
> +                       tmp = bpf_patch_insn_data(env, i, insn_buff, rewritten);
> +               else
> +                       tmp = bpf_patch_insn_single(clone, i, insn_buff, rewritten);
> +
> +               if (IS_ERR_OR_NULL(tmp)) {
> +                       if (env)
> +                               /* restore the original prog */
> +                               env->prog = prog;
>                         /* Patching may have repointed aux->prog during
>                          * realloc from the original one, so we need to
>                          * fix it up here on error.
>                          */
>                         bpf_jit_prog_release_other(prog, clone);
> -                       return tmp;
> +                       return IS_ERR(tmp) ? tmp : ERR_PTR(-ENOMEM);
>                 }
>
>                 clone = tmp;
>                 insn_delta = rewritten - 1;
>
> -               /* Instructions arrays must be updated using absolute xlated offsets */
> -               adjust_insn_arrays(clone, prog->aux->subprog_start + i, rewritten);
> +               if (env)
> +                       env->prog = clone;
> +               else
> +                       /*
> +                        * Instructions arrays must be updated using absolute xlated offsets.
> +                        * The arrays have already been adjusted by bpf_patch_insn_data() when
> +                        * env is not NULL.
> +                        */
> +                       adjust_insn_arrays(clone, i, rewritten);
>
>                 /* Walk new program and skip insns we just inserted. */
>                 insn = clone->insnsi + i + insn_delta;
> @@ -2533,6 +2555,35 @@ static bool bpf_prog_select_interpreter(struct bpf_prog *fp)
>         return select_interpreter;
>  }
>
> +static struct bpf_prog *bpf_prog_jit_compile(struct bpf_prog *prog)
> +{
> +#ifdef CONFIG_BPF_JIT
> +       struct bpf_prog *orig_prog;
> +
> +       if (!bpf_prog_need_blind(prog))
> +               return bpf_int_jit_compile(prog);
> +
> +       orig_prog = prog;
> +       prog = bpf_jit_blind_constants(NULL, prog);
> +       /*
> +        * If blinding was requested and we failed during blinding, we must fall
> +        * back to the interpreter.
> +        */
> +       if (IS_ERR(prog))
> +               return orig_prog;
> +
> +       prog = bpf_int_jit_compile(prog);
> +       if (prog->jited) {
> +               bpf_jit_prog_release_other(prog, orig_prog);
> +               return prog;
> +       }
> +
> +       bpf_jit_prog_release_other(orig_prog, prog);
> +       prog = orig_prog;
> +#endif
> +       return prog;
> +}
> +
>  /**
>   *     bpf_prog_select_runtime - select exec runtime for BPF program
>   *     @fp: bpf_prog populated with BPF program
> @@ -2572,7 +2623,7 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
>                 if (*err)
>                         return fp;
>
> -               fp = bpf_int_jit_compile(fp);
> +               fp = bpf_prog_jit_compile(fp);
>                 bpf_prog_jit_attempt_done(fp);
>                 if (!fp->jited && jit_needed) {
>                         *err = -ENOTSUPP;
> diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
> index 67c9b28767e1..ec8afd6a9369 100644
> --- a/kernel/bpf/fixups.c
> +++ b/kernel/bpf/fixups.c
> @@ -232,8 +232,8 @@ static void adjust_poke_descs(struct bpf_prog *prog, u32 off, u32 len)
>         }
>  }
>
> -static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
> -                                           const struct bpf_insn *patch, u32 len)
> +struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
> +                                    const struct bpf_insn *patch, u32 len)
>  {
>         struct bpf_prog *new_prog;
>         struct bpf_insn_aux_data *new_data = NULL;
> @@ -973,7 +973,45 @@ int bpf_convert_ctx_accesses(struct bpf_verifier_env *env)
>         return 0;
>  }
>
> -int bpf_jit_subprogs(struct bpf_verifier_env *env)
> +static u32 *bpf_dup_subprog_starts(struct bpf_verifier_env *env)
> +{
> +       u32 *starts = NULL;
> +
> +       starts = kvmalloc_objs(u32, env->subprog_cnt, GFP_KERNEL_ACCOUNT);
> +       if (starts) {
> +               for (int i = 0; i < env->subprog_cnt; i++)
> +                       starts[i] = env->subprog_info[i].start;
> +       }
> +       return starts;
> +}
> +
> +static void bpf_restore_subprog_starts(struct bpf_verifier_env *env, u32 *orig_starts)
> +{
> +       for (int i = 0; i < env->subprog_cnt; i++)
> +               env->subprog_info[i].start = orig_starts[i];
> +}
> +
> +static struct bpf_insn_aux_data *bpf_dup_insn_aux_data(struct bpf_verifier_env *env)
> +{
> +       size_t size;
> +       void *new_aux;
> +
> +       size = array_size(sizeof(struct bpf_insn_aux_data), env->prog->len);
> +       new_aux = __vmalloc(size, GFP_KERNEL_ACCOUNT);
> +       if (new_aux)
> +               memcpy(new_aux, env->insn_aux_data, size);
> +       return new_aux;
> +}
> +
> +static void bpf_restore_insn_aux_data(struct bpf_verifier_env *env,
> +                                     struct bpf_insn_aux_data *orig_insn_aux)
> +{
> +       /* the expanded elements are zero-filled, so no special handling is required */
> +       vfree(env->insn_aux_data);
> +       env->insn_aux_data = orig_insn_aux;
> +}
> +
> +static int jit_subprogs(struct bpf_verifier_env *env)
>  {
>         struct bpf_prog *prog = env->prog, **func, *tmp;
>         int i, j, subprog_start, subprog_end = 0, len, subprog;
> @@ -981,10 +1019,6 @@ int bpf_jit_subprogs(struct bpf_verifier_env *env)
>         struct bpf_insn *insn;
>         void *old_bpf_func;
>         int err, num_exentries;
> -       int old_len, subprog_start_adjustment = 0;
> -
> -       if (env->subprog_cnt <= 1)
> -               return 0;
>
>         for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
>                 if (!bpf_pseudo_func(insn) && !bpf_pseudo_call(insn))
> @@ -1053,10 +1087,11 @@ int bpf_jit_subprogs(struct bpf_verifier_env *env)
>                         goto out_free;
>                 func[i]->is_func = 1;
>                 func[i]->sleepable = prog->sleepable;
> +               func[i]->blinded = prog->blinded;
>                 func[i]->aux->func_idx = i;
>                 /* Below members will be freed only at prog->aux */
>                 func[i]->aux->btf = prog->aux->btf;
> -               func[i]->aux->subprog_start = subprog_start + subprog_start_adjustment;
> +               func[i]->aux->subprog_start = subprog_start;
>                 func[i]->aux->func_info = prog->aux->func_info;
>                 func[i]->aux->func_info_cnt = prog->aux->func_info_cnt;
>                 func[i]->aux->poke_tab = prog->aux->poke_tab;
> @@ -1112,15 +1147,7 @@ int bpf_jit_subprogs(struct bpf_verifier_env *env)
>                 func[i]->aux->might_sleep = env->subprog_info[i].might_sleep;
>                 if (!i)
>                         func[i]->aux->exception_boundary = env->seen_exception;
> -
> -               /*
> -                * To properly pass the absolute subprog start to jit
> -                * all instruction adjustments should be accumulated
> -                */
> -               old_len = func[i]->len;
>                 func[i] = bpf_int_jit_compile(func[i]);
> -               subprog_start_adjustment += func[i]->len - old_len;
> -
>                 if (!func[i]->jited) {
>                         err = -ENOTSUPP;
>                         goto out_free;
> @@ -1246,16 +1273,87 @@ int bpf_jit_subprogs(struct bpf_verifier_env *env)
>         }
>         kfree(func);
>  out_undo_insn:
> +       bpf_prog_jit_attempt_done(prog);
> +       return err;
> +}
> +
> +int bpf_jit_subprogs(struct bpf_verifier_env *env)
> +{
> +       int err, i;
> +       bool blinded = false;
> +       struct bpf_insn *insn;
> +       struct bpf_prog *prog, *orig_prog;
> +       struct bpf_insn_aux_data *orig_insn_aux;
> +       u32 *orig_subprog_starts;
> +
> +       if (env->subprog_cnt <= 1)
> +               return 0;
> +
> +       prog = orig_prog = env->prog;
> +       if (bpf_prog_need_blind(prog)) {
> +               orig_insn_aux = bpf_dup_insn_aux_data(env);
> +               if (!orig_insn_aux) {
> +                       err = -ENOMEM;
> +                       goto out_cleanup;
> +               }
> +               orig_subprog_starts = bpf_dup_subprog_starts(env);
> +               if (!orig_subprog_starts) {
> +                       vfree(orig_insn_aux);
> +                       err = -ENOMEM;
> +                       goto out_cleanup;
> +               }
> +               prog = bpf_jit_blind_constants(env, prog);
> +               if (IS_ERR(prog)) {
> +                       err = -ENOMEM;
> +                       prog = orig_prog;
> +                       goto out_restore;
> +               }
> +               blinded = true;
> +       }
> +
> +       err = jit_subprogs(env);
> +       if (err)
> +               goto out_jit_err;
> +
> +       if (blinded) {
> +               bpf_jit_prog_release_other(prog, orig_prog);
> +               kvfree(orig_subprog_starts);
> +               vfree(orig_insn_aux);
> +       }
> +
> +       return 0;
> +
> +out_jit_err:
> +       if (blinded) {
> +               bpf_jit_prog_release_other(orig_prog, prog);
> +               /* roll back to the clean original prog */
> +               prog = env->prog = orig_prog;
> +               goto out_restore;
> +       } else {
> +               if (err != -EFAULT) {
> +                       /*
> +                        * We will fall back to interpreter mode when err is not -EFAULT, before
> +                        * that, insn->off and insn->imm should be restored to their original
> +                        * values since they were modified by __jit_subprogs.
> +                        */
> +                       for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
> +                               if (!bpf_pseudo_call(insn))
> +                                       continue;
> +                               insn->off = 0;
> +                               insn->imm = env->insn_aux_data[i].call_imm;
> +                       }
> +               }
> +               goto out_cleanup;
> +       }
> +
> +out_restore:
> +       bpf_restore_subprog_starts(env, orig_subprog_starts);
> +       bpf_restore_insn_aux_data(env, orig_insn_aux);
> +       kvfree(orig_subprog_starts);
> +out_cleanup:
>         /* cleanup main prog to be interpreted */
>         prog->jit_requested = 0;
>         prog->blinding_requested = 0;
> -       for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
> -               if (!bpf_pseudo_call(insn))
> -                       continue;
> -               insn->off = 0;
> -               insn->imm = env->insn_aux_data[i].call_imm;
> -       }
> -       bpf_prog_jit_attempt_done(prog);
>         return err;
>  }
>
> --
> 2.47.3
>


^ permalink raw reply

* Re: [PATCH bpf-next v14 2/5] bpf: Pass bpf_verifier_env to JIT
From: Hengqi Chen @ 2026-04-15  1:55 UTC (permalink / raw)
  To: Xu Kuohai
  Cc: bpf, linux-kernel, linux-arm-kernel, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Yonghong Song,
	Puranjay Mohan, Anton Protopopov, Alexis Lothoré,
	Shahab Vahedi, Russell King, Tiezhu Yang, Johan Almbladh,
	Paul Burton, Hari Bathini, Christophe Leroy, Naveen N Rao,
	Luke Nelson, Xi Wang, Björn Töpel, Pu Lehui,
	Ilya Leoshkevich, Heiko Carstens, Vasily Gorbik, David S . Miller,
	Wang YanQing
In-Reply-To: <e99d594bcedfc0d818242ca6dda26f8f45f44062.1776062885.git.xukuohai@hotmail.com>

On Mon, Apr 13, 2026 at 9:07 PM Xu Kuohai <xukuohai@huaweicloud.com> wrote:
>
> From: Xu Kuohai <xukuohai@huawei.com>
>
> Pass bpf_verifier_env to bpf_int_jit_compile(). The follow-up patch will
> use env->insn_aux_data in the JIT stage to detect indirect jump targets.
>
> Since bpf_prog_select_runtime() can be called by cbpf and lib/test_bpf.c
> code without verifier, introduce helper __bpf_prog_select_runtime()
> to accept the env parameter.
>
> Remove the call to bpf_prog_select_runtime() in bpf_prog_load(), and
> switch to call __bpf_prog_select_runtime() in the verifier, with env
> variable passed. The original bpf_prog_select_runtime() is preserved for
> cbpf and lib/test_bpf.c, where env is NULL.
>
> Now all constants blinding calls are moved into the verifier, except
> the cbpf and lib/test_bpf.c cases. The instructions arrays are adjusted
> by bpf_patch_insn_data() function for normal cases, so there is no need
> to call adjust_insn_arrays() in bpf_jit_blind_constants(). Remove it.
>
> Reviewed-by: Anton Protopopov <a.s.protopopov@gmail.com> # v8
> Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com> # v12
> Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
> ---

Acked-by: Hengqi Chen <hengqi.chen@gmail.com>

>  arch/arc/net/bpf_jit_core.c      |  2 +-
>  arch/arm/net/bpf_jit_32.c        |  2 +-
>  arch/arm64/net/bpf_jit_comp.c    |  2 +-
>  arch/loongarch/net/bpf_jit.c     |  2 +-
>  arch/mips/net/bpf_jit_comp.c     |  2 +-
>  arch/parisc/net/bpf_jit_core.c   |  2 +-
>  arch/powerpc/net/bpf_jit_comp.c  |  2 +-
>  arch/riscv/net/bpf_jit_core.c    |  2 +-
>  arch/s390/net/bpf_jit_comp.c     |  2 +-
>  arch/sparc/net/bpf_jit_comp_64.c |  2 +-
>  arch/x86/net/bpf_jit_comp.c      |  2 +-
>  arch/x86/net/bpf_jit_comp32.c    |  2 +-
>  include/linux/filter.h           | 17 ++++++-
>  kernel/bpf/core.c                | 86 ++++++++++++++++----------------
>  kernel/bpf/fixups.c              | 10 ++--
>  kernel/bpf/syscall.c             |  4 --
>  kernel/bpf/verifier.c            | 14 +++---
>  17 files changed, 84 insertions(+), 71 deletions(-)
>
> diff --git a/arch/arc/net/bpf_jit_core.c b/arch/arc/net/bpf_jit_core.c
> index 973ceae48675..639a2736f029 100644
> --- a/arch/arc/net/bpf_jit_core.c
> +++ b/arch/arc/net/bpf_jit_core.c
> @@ -1400,7 +1400,7 @@ static struct bpf_prog *do_extra_pass(struct bpf_prog *prog)
>   * (re)locations involved that their addresses are not known
>   * during the first run.
>   */
> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
>  {
>         vm_dump(prog);
>
> diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
> index e6b1bb2de627..1628b6fc70a4 100644
> --- a/arch/arm/net/bpf_jit_32.c
> +++ b/arch/arm/net/bpf_jit_32.c
> @@ -2142,7 +2142,7 @@ bool bpf_jit_needs_zext(void)
>         return true;
>  }
>
> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
>  {
>         struct bpf_binary_header *header;
>         struct jit_ctx ctx;
> diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
> index cd5a72fff500..7212ec89dfe3 100644
> --- a/arch/arm64/net/bpf_jit_comp.c
> +++ b/arch/arm64/net/bpf_jit_comp.c
> @@ -2006,7 +2006,7 @@ struct arm64_jit_data {
>         struct jit_ctx ctx;
>  };
>
> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
>  {
>         int image_size, prog_size, extable_size, extable_align, extable_offset;
>         struct bpf_binary_header *header;
> diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
> index fcc8c0c29fb0..5149ce4cef7e 100644
> --- a/arch/loongarch/net/bpf_jit.c
> +++ b/arch/loongarch/net/bpf_jit.c
> @@ -1920,7 +1920,7 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
>         return ret < 0 ? ret : ret * LOONGARCH_INSN_SIZE;
>  }
>
> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
>  {
>         bool extra_pass = false;
>         u8 *image_ptr, *ro_image_ptr;
> diff --git a/arch/mips/net/bpf_jit_comp.c b/arch/mips/net/bpf_jit_comp.c
> index d2b6c955f18e..6ee4abe6a1f7 100644
> --- a/arch/mips/net/bpf_jit_comp.c
> +++ b/arch/mips/net/bpf_jit_comp.c
> @@ -909,7 +909,7 @@ bool bpf_jit_needs_zext(void)
>         return true;
>  }
>
> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
>  {
>         struct bpf_binary_header *header = NULL;
>         struct jit_context ctx;
> diff --git a/arch/parisc/net/bpf_jit_core.c b/arch/parisc/net/bpf_jit_core.c
> index 35dca372b5df..172770132440 100644
> --- a/arch/parisc/net/bpf_jit_core.c
> +++ b/arch/parisc/net/bpf_jit_core.c
> @@ -41,7 +41,7 @@ bool bpf_jit_needs_zext(void)
>         return true;
>  }
>
> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
>  {
>         unsigned int prog_size = 0, extable_size = 0;
>         bool extra_pass = false;
> diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
> index 711028bebea3..27fecb4cc063 100644
> --- a/arch/powerpc/net/bpf_jit_comp.c
> +++ b/arch/powerpc/net/bpf_jit_comp.c
> @@ -129,7 +129,7 @@ bool bpf_jit_needs_zext(void)
>         return true;
>  }
>
> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *fp)
>  {
>         u32 proglen;
>         u32 alloclen;
> diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c
> index 527baa50dc68..768ac686b359 100644
> --- a/arch/riscv/net/bpf_jit_core.c
> +++ b/arch/riscv/net/bpf_jit_core.c
> @@ -41,7 +41,7 @@ bool bpf_jit_needs_zext(void)
>         return true;
>  }
>
> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
>  {
>         unsigned int prog_size = 0, extable_size = 0;
>         bool extra_pass = false;
> diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
> index 2dfc279b1be2..94128fe6be23 100644
> --- a/arch/s390/net/bpf_jit_comp.c
> +++ b/arch/s390/net/bpf_jit_comp.c
> @@ -2312,7 +2312,7 @@ static struct bpf_binary_header *bpf_jit_alloc(struct bpf_jit *jit,
>  /*
>   * Compile eBPF program "fp"
>   */
> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *fp)
>  {
>         struct bpf_binary_header *header;
>         struct s390_jit_data *jit_data;
> diff --git a/arch/sparc/net/bpf_jit_comp_64.c b/arch/sparc/net/bpf_jit_comp_64.c
> index e83e29137566..2fa0e9375127 100644
> --- a/arch/sparc/net/bpf_jit_comp_64.c
> +++ b/arch/sparc/net/bpf_jit_comp_64.c
> @@ -1477,7 +1477,7 @@ struct sparc64_jit_data {
>         struct jit_ctx ctx;
>  };
>
> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
>  {
>         struct sparc64_jit_data *jit_data;
>         struct bpf_binary_header *header;
> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> index 77d00a8dec87..72d9a5faa230 100644
> --- a/arch/x86/net/bpf_jit_comp.c
> +++ b/arch/x86/net/bpf_jit_comp.c
> @@ -3713,7 +3713,7 @@ struct x64_jit_data {
>  #define MAX_PASSES 20
>  #define PADDING_PASSES (MAX_PASSES - 5)
>
> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
>  {
>         struct bpf_binary_header *rw_header = NULL;
>         struct bpf_binary_header *header = NULL;
> diff --git a/arch/x86/net/bpf_jit_comp32.c b/arch/x86/net/bpf_jit_comp32.c
> index 5f259577614a..852baf2e4db4 100644
> --- a/arch/x86/net/bpf_jit_comp32.c
> +++ b/arch/x86/net/bpf_jit_comp32.c
> @@ -2518,7 +2518,7 @@ bool bpf_jit_needs_zext(void)
>         return true;
>  }
>
> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
>  {
>         struct bpf_binary_header *header = NULL;
>         int proglen, oldproglen = 0;
> diff --git a/include/linux/filter.h b/include/linux/filter.h
> index d396e55c9a1d..83f37d38c5c1 100644
> --- a/include/linux/filter.h
> +++ b/include/linux/filter.h
> @@ -1107,6 +1107,8 @@ static inline int sk_filter_reason(struct sock *sk, struct sk_buff *skb,
>         return sk_filter_trim_cap(sk, skb, 1, reason);
>  }
>
> +struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct bpf_prog *fp,
> +                                          int *err);
>  struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err);
>  void bpf_prog_free(struct bpf_prog *fp);
>
> @@ -1152,7 +1154,7 @@ u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
>         ((u64 (*)(u64, u64, u64, u64, u64, const struct bpf_insn *)) \
>          (void *)__bpf_call_base)
>
> -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog);
> +struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog);
>  void bpf_jit_compile(struct bpf_prog *prog);
>  bool bpf_jit_needs_zext(void);
>  bool bpf_jit_inlines_helper_call(s32 imm);
> @@ -1187,12 +1189,25 @@ struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
>  #ifdef CONFIG_BPF_SYSCALL
>  struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
>                                      const struct bpf_insn *patch, u32 len);
> +struct bpf_insn_aux_data *bpf_dup_insn_aux_data(struct bpf_verifier_env *env);
> +void bpf_restore_insn_aux_data(struct bpf_verifier_env *env,
> +                              struct bpf_insn_aux_data *orig_insn_aux);
>  #else
>  static inline struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
>                                                    const struct bpf_insn *patch, u32 len)
>  {
>         return ERR_PTR(-ENOTSUPP);
>  }
> +
> +static inline struct bpf_insn_aux_data *bpf_dup_insn_aux_data(struct bpf_verifier_env *env)
> +{
> +       return NULL;
> +}
> +
> +static inline void bpf_restore_insn_aux_data(struct bpf_verifier_env *env,
> +                                            struct bpf_insn_aux_data *orig_insn_aux)
> +{
> +}
>  #endif /* CONFIG_BPF_SYSCALL */
>
>  int bpf_remove_insns(struct bpf_prog *prog, u32 off, u32 cnt);
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index fc9fb3c07866..79361aa11757 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -1491,23 +1491,6 @@ void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other)
>         bpf_prog_clone_free(fp_other);
>  }
>
> -static void adjust_insn_arrays(struct bpf_prog *prog, u32 off, u32 len)
> -{
> -#ifdef CONFIG_BPF_SYSCALL
> -       struct bpf_map *map;
> -       int i;
> -
> -       if (len <= 1)
> -               return;
> -
> -       for (i = 0; i < prog->aux->used_map_cnt; i++) {
> -               map = prog->aux->used_maps[i];
> -               if (map->map_type == BPF_MAP_TYPE_INSN_ARRAY)
> -                       bpf_insn_array_adjust(map, off, len);
> -       }
> -#endif
> -}
> -
>  /*
>   * Now this function is used only to blind the main prog and must be invoked only when
>   * bpf_prog_need_blind() returns true.
> @@ -1580,13 +1563,6 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_verifier_env *env, struct bp
>
>                 if (env)
>                         env->prog = clone;
> -               else
> -                       /*
> -                        * Instructions arrays must be updated using absolute xlated offsets.
> -                        * The arrays have already been adjusted by bpf_patch_insn_data() when
> -                        * env is not NULL.
> -                        */
> -                       adjust_insn_arrays(clone, i, rewritten);
>
>                 /* Walk new program and skip insns we just inserted. */
>                 insn = clone->insnsi + i + insn_delta;
> @@ -2555,47 +2531,55 @@ static bool bpf_prog_select_interpreter(struct bpf_prog *fp)
>         return select_interpreter;
>  }
>
> -static struct bpf_prog *bpf_prog_jit_compile(struct bpf_prog *prog)
> +static struct bpf_prog *bpf_prog_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
>  {
>  #ifdef CONFIG_BPF_JIT
>         struct bpf_prog *orig_prog;
> +       struct bpf_insn_aux_data *orig_insn_aux;
>
>         if (!bpf_prog_need_blind(prog))
> -               return bpf_int_jit_compile(prog);
> +               return bpf_int_jit_compile(env, prog);
> +
> +       if (env) {
> +               /*
> +                * If env is not NULL, we are called from the end of bpf_check(), at this
> +                * point, only insn_aux_data is used after failure, so it should be restored
> +                * on failure.
> +                */
> +               orig_insn_aux = bpf_dup_insn_aux_data(env);
> +               if (!orig_insn_aux)
> +                       return prog;
> +       }
>
>         orig_prog = prog;
> -       prog = bpf_jit_blind_constants(NULL, prog);
> +       prog = bpf_jit_blind_constants(env, prog);
>         /*
>          * If blinding was requested and we failed during blinding, we must fall
>          * back to the interpreter.
>          */
>         if (IS_ERR(prog))
> -               return orig_prog;
> +               goto out_restore;
>
> -       prog = bpf_int_jit_compile(prog);
> +       prog = bpf_int_jit_compile(env, prog);
>         if (prog->jited) {
>                 bpf_jit_prog_release_other(prog, orig_prog);
> +               if (env)
> +                       vfree(orig_insn_aux);
>                 return prog;
>         }
>
>         bpf_jit_prog_release_other(orig_prog, prog);
> +
> +out_restore:
>         prog = orig_prog;
> +       if (env)
> +               bpf_restore_insn_aux_data(env, orig_insn_aux);
>  #endif
>         return prog;
>  }
>
> -/**
> - *     bpf_prog_select_runtime - select exec runtime for BPF program
> - *     @fp: bpf_prog populated with BPF program
> - *     @err: pointer to error variable
> - *
> - * Try to JIT eBPF program, if JIT is not available, use interpreter.
> - * The BPF program will be executed via bpf_prog_run() function.
> - *
> - * Return: the &fp argument along with &err set to 0 for success or
> - * a negative errno code on failure
> - */
> -struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
> +struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct bpf_prog *fp,
> +                                          int *err)
>  {
>         /* In case of BPF to BPF calls, verifier did all the prep
>          * work with regards to JITing, etc.
> @@ -2623,7 +2607,7 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
>                 if (*err)
>                         return fp;
>
> -               fp = bpf_prog_jit_compile(fp);
> +               fp = bpf_prog_jit_compile(env, fp);
>                 bpf_prog_jit_attempt_done(fp);
>                 if (!fp->jited && jit_needed) {
>                         *err = -ENOTSUPP;
> @@ -2649,6 +2633,22 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
>
>         return fp;
>  }
> +
> +/**
> + *     bpf_prog_select_runtime - select exec runtime for BPF program
> + *     @fp: bpf_prog populated with BPF program
> + *     @err: pointer to error variable
> + *
> + * Try to JIT eBPF program, if JIT is not available, use interpreter.
> + * The BPF program will be executed via bpf_prog_run() function.
> + *
> + * Return: the &fp argument along with &err set to 0 for success or
> + * a negative errno code on failure
> + */
> +struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
> +{
> +       return __bpf_prog_select_runtime(NULL, fp, err);
> +}
>  EXPORT_SYMBOL_GPL(bpf_prog_select_runtime);
>
>  static unsigned int __bpf_prog_ret1(const void *ctx,
> @@ -3136,7 +3136,7 @@ const struct bpf_func_proto bpf_tail_call_proto = {
>   * It is encouraged to implement bpf_int_jit_compile() instead, so that
>   * eBPF and implicitly also cBPF can get JITed!
>   */
> -struct bpf_prog * __weak bpf_int_jit_compile(struct bpf_prog *prog)
> +struct bpf_prog * __weak bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
>  {
>         return prog;
>  }
> diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
> index ec8afd6a9369..6ef213429a2a 100644
> --- a/kernel/bpf/fixups.c
> +++ b/kernel/bpf/fixups.c
> @@ -991,7 +991,7 @@ static void bpf_restore_subprog_starts(struct bpf_verifier_env *env, u32 *orig_s
>                 env->subprog_info[i].start = orig_starts[i];
>  }
>
> -static struct bpf_insn_aux_data *bpf_dup_insn_aux_data(struct bpf_verifier_env *env)
> +struct bpf_insn_aux_data *bpf_dup_insn_aux_data(struct bpf_verifier_env *env)
>  {
>         size_t size;
>         void *new_aux;
> @@ -1003,8 +1003,8 @@ static struct bpf_insn_aux_data *bpf_dup_insn_aux_data(struct bpf_verifier_env *
>         return new_aux;
>  }
>
> -static void bpf_restore_insn_aux_data(struct bpf_verifier_env *env,
> -                                     struct bpf_insn_aux_data *orig_insn_aux)
> +void bpf_restore_insn_aux_data(struct bpf_verifier_env *env,
> +                              struct bpf_insn_aux_data *orig_insn_aux)
>  {
>         /* the expanded elements are zero-filled, so no special handling is required */
>         vfree(env->insn_aux_data);
> @@ -1147,7 +1147,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
>                 func[i]->aux->might_sleep = env->subprog_info[i].might_sleep;
>                 if (!i)
>                         func[i]->aux->exception_boundary = env->seen_exception;
> -               func[i] = bpf_int_jit_compile(func[i]);
> +               func[i] = bpf_int_jit_compile(env, func[i]);
>                 if (!func[i]->jited) {
>                         err = -ENOTSUPP;
>                         goto out_free;
> @@ -1191,7 +1191,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
>         }
>         for (i = 0; i < env->subprog_cnt; i++) {
>                 old_bpf_func = func[i]->bpf_func;
> -               tmp = bpf_int_jit_compile(func[i]);
> +               tmp = bpf_int_jit_compile(env, func[i]);
>                 if (tmp != func[i] || func[i]->bpf_func != old_bpf_func) {
>                         verbose(env, "JIT doesn't support bpf-to-bpf calls\n");
>                         err = -ENOTSUPP;
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index b73b25c63073..a3c0214ca934 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -3083,10 +3083,6 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
>         if (err < 0)
>                 goto free_used_maps;
>
> -       prog = bpf_prog_select_runtime(prog, &err);
> -       if (err < 0)
> -               goto free_used_maps;
> -
>         err = bpf_prog_mark_insn_arrays_ready(prog);
>         if (err < 0)
>                 goto free_used_maps;
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 9e4980128151..e804e0da3500 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -20155,6 +20155,14 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
>
>         adjust_btf_func(env);
>
> +       /* extension progs temporarily inherit the attach_type of their targets
> +          for verification purposes, so set it back to zero before returning
> +        */
> +       if (env->prog->type == BPF_PROG_TYPE_EXT)
> +               env->prog->expected_attach_type = 0;
> +
> +       env->prog = __bpf_prog_select_runtime(env, env->prog, &ret);
> +
>  err_release_maps:
>         if (ret)
>                 release_insn_arrays(env);
> @@ -20166,12 +20174,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
>         if (!env->prog->aux->used_btfs)
>                 release_btfs(env);
>
> -       /* extension progs temporarily inherit the attach_type of their targets
> -          for verification purposes, so set it back to zero before returning
> -        */
> -       if (env->prog->type == BPF_PROG_TYPE_EXT)
> -               env->prog->expected_attach_type = 0;
> -
>         *prog = env->prog;
>
>         module_put(env->attach_btf_mod);
> --
> 2.47.3
>


^ permalink raw reply

* Re: [PATCH net-next] net: stmmac: enable RPS and RBU interrupts
From: Sam Edwards @ 2026-04-15  2:12 UTC (permalink / raw)
  To: Russell King (Oracle)
  Cc: Jakub Kicinski, Andrew Lunn, Alexandre Torgue, Andrew Lunn,
	David S. Miller, Eric Dumazet,
	moderated list:BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE,
	linux-stm32, Linux Network Development Mailing List, Paolo Abeni
In-Reply-To: <ad7nsUQvksJF7JFK@shell.armlinux.org.uk>

On Tue, Apr 14, 2026 at 6:19 PM Russell King (Oracle)
<linux@armlinux.org.uk> wrote:
> Okay, just a quick note to say that nvidia's 5.10.216-tegra kernel
> survives iperf3 -c -R to the imx6.

Hi Russell,

Aw, you beat me to it! I was about to report that 5.10.104-tegra is
unaffected. And my iperf3 server is a multi-GbE amd64 machine.

> Dumping the registers and comparing, and then forcing the RQS and TQS
> values to 0x23 (+1 = 36, *256 = 9216 bytes) and 0x8f (+1 = 144,
> *256 = 36864 ytes) respectively seems to solve the problem. Under
> net-next, these both end up being 0xff (+1 = 256, *256 = 65536 bytes.)
> Suspiciously, 36 * 4 = 144, and I also see that this kernel programs
> all four of the MTL receive operation mode registers, but only the
> first MTL transmit operation mode register. However, DMA channels 1-3
> aren't initialised.

Wow, great! I wonder if the problem is that the MTL FIFOs are smaller
than that, so when the DMA suffers a momentary hiccup, the FIFOs are
allowed to overflow, putting the hardware in a bad state.

Though I suspect this is only half of the problem: do you still see
RBUs? Everything you've shared so far suggests the DMA failures are
_not_ because the rx ring is drying up. My gut's telling me the DMA
unit is encountering an AXI error, triggering RBU plus some kind of
recovery behavior, and the recovery takes the DMA offline long enough
for the FIFO to overflow (without triggering RPS because the RQS
threshold is unreachable).

It seems that the problem happens less frequently on my test setup
when I boot with iommu.passthrough=1 but that could be my imagination.
But if the hardware remains stable with RQS and TQS set correctly, I
don't feel an urgent need to dig deeper. :)

> Looking back at 5.10, I don't see any code that would account for these
> values being programmed for TQS and RQS, it looks like the calculations
> are basically the same as we have today.

Note that Nvidia have their own "nvethernet" driver for their vendor
kernel, which appears to pick the FIFO sizes from hardcoded tables in
its eqos_configure_mtl_queue() [1] function.

Cheers,
Sam

[1] https://github.com/proski/nvethernet/blob/main/nvethernetrm/osi/core/eqos_core.c#L263


^ permalink raw reply

* [PATCH net v5] net: stmmac: Prevent NULL deref when RX memory exhausted
From: Sam Edwards @ 2026-04-15  2:39 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: Maxime Coquelin, Alexandre Torgue, Russell King (Oracle),
	Maxime Chevallier, Ovidiu Panait, Vladimir Oltean, Baruch Siach,
	Serge Semin, Giuseppe Cavallaro, netdev, linux-stm32,
	linux-arm-kernel, linux-kernel, Sam Edwards, stable

The CPU receives frames from the MAC through conventional DMA: the CPU
allocates buffers for the MAC, then the MAC fills them and returns
ownership to the CPU. For each hardware RX queue, the CPU and MAC
coordinate through a shared ring array of DMA descriptors: one
descriptor per DMA buffer. Each descriptor includes the buffer's
physical address and a status flag ("OWN") indicating which side owns
the buffer: OWN=0 for CPU, OWN=1 for MAC. The CPU is only allowed to set
the flag and the MAC is only allowed to clear it, and both must move
through the ring in sequence: thus the ring is used for both
"submissions" and "completions."

In the stmmac driver, stmmac_rx() bookmarks its position in the ring
with the `cur_rx` index. The main receive loop in that function checks
for rx_descs[cur_rx].own=0, gives the corresponding buffer to the
network stack (NULLing the pointer), and increments `cur_rx` modulo the
ring size. After the loop exits, stmmac_rx_refill(), which bookmarks its
position with `dirty_rx`, allocates fresh buffers and rearms the
descriptors (setting OWN=1). If it fails any allocation, it simply stops
early (leaving OWN=0) and will retry where it left off when next called.

This means descriptors have a three-stage lifecycle (terms my own):
- `empty` (OWN=1, buffer valid)
- `full` (OWN=0, buffer valid and populated)
- `dirty` (OWN=0, buffer NULL)

But because stmmac_rx() only checks OWN, it confuses `full`/`dirty`. In
the past (see 'Fixes:'), there was a bug where the loop could cycle
`cur_rx` all the way back to the first descriptor it dirtied, resulting
in a NULL dereference when mistaken for `full`. The aforementioned
commit resolved that *specific* failure by capping the loop's iteration
limit at `dma_rx_size - 1`, but this is only a partial fix: if the
previous stmmac_rx_refill() didn't complete, then there are leftover
`dirty` descriptors that the loop might encounter without needing to
cycle fully around. The current code therefore panics (see 'Closes:')
when stmmac_rx_refill() is memory-starved long enough for `cur_rx` to
catch up to `dirty_rx`.

Fix this by further tightening the clamp from `dma_rx_size - 1` to
`dma_rx_size - stmmac_rx_dirty() - 1`, subtracting any remnant dirty
entries and limiting the loop so that `cur_rx` cannot catch back up to
`dirty_rx`. This carries no risk of arithmetic underflow: since the
maximum possible return value of stmmac_rx_dirty() is `dma_rx_size - 1`,
the worst the clamp can do is prevent the loop from running at all.

Fixes: b6cb4541853c7 ("net: stmmac: avoid rx queue overrun")
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221010
Cc: stable@vger.kernel.org
Signed-off-by: Sam Edwards <CFSworks@gmail.com>
---

Hi list,

This is a single patch broken out of [1]. The second patch in that series,
which proactively refills the RX ring buffer when memory is low, still has some
unresolved feedback: it should use a timer to avoid nuisance polling while the
system is suffering OOM.

Further discussion makes me wonder whether that second patch should even be
threshold-triggered at all, or if it should be a handler for the RBU
("Receive Buffer Unavailable") interrupt instead.

So, while that patch is back at the drawing board, I am submitting this one
(which is higher-priority as it resolves a *panic*) separately.

Regards,
Sam

[1] https://lore.kernel.org/all/20260401041929.12392-1-CFSworks@gmail.com/

---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 13d3cac056be..fc11f75f7dc0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -5609,7 +5609,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
 
 	dma_dir = page_pool_get_dma_dir(rx_q->page_pool);
 	bufsz = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE) * PAGE_SIZE;
-	limit = min(priv->dma_conf.dma_rx_size - 1, (unsigned int)limit);
+	limit = min(priv->dma_conf.dma_rx_size - stmmac_rx_dirty(priv, queue) - 1,
+		    (unsigned int)limit);
 
 	if (netif_msg_rx_status(priv)) {
 		void *rx_head;
-- 
2.52.0



^ permalink raw reply related

* Re: [PATCH v7 0/4] Add Qualcomm extended CTI support
From: Yingchao Deng (Consultant) @ 2026-04-15  3:22 UTC (permalink / raw)
  To: Yingchao Deng, Suzuki K Poulose, Mike Leach, James Clark, Leo Yan,
	Alexander Shishkin
  Cc: coresight, linux-arm-kernel, linux-kernel, linux-arm-msm,
	Jinlong Mao, Tingwei Zhang, Jie Gan, Yingchao Deng
In-Reply-To: <20260325-extended_cti-v7-0-bb406005089f@oss.qualcomm.com>


On 3/25/2026 1:43 PM, Yingchao Deng wrote:
> The Qualcomm extended CTI is a heavily parameterized version of ARM’s
> CSCTI. It allows a debugger to send to trigger events to a processor or to
> send a trigger event to one or more processors when a trigger event occurs
> on another processor on the same SoC, or even between SoCs.
>
> Qualcomm extended CTI supports up to 128 triggers. And some of the register
> offsets are changed.
>
> The commands to configure CTI triggers are the same as ARM's CTI.
>
> Prerequisites:
>     This series depends on the following CoreSight fix:
>     [PATCH v2 1/1] coresight: fix issue where coresight component has no claimtags
> Link: https://lore.kernel.org/all/20251027223545.2801-2-mike.leach@linaro.org/
>
> Changes in v7:
> 1. Split the extended CTI support into smaller, logically independent
>     patches to improve reviewability.
> 2. Removed the dual offset-array based register access used in v6 for
>     standard and Qualcomm CTIs. Register addressing is now unified through
>     a single code path by encoding the register index together with the base
>     offset and applying variant-specific translation at the final MMIO
>     access point.
> 3. Removed ext_reg_sel, extend the CTI sysfs interface to expose banked
>     register instances on Qualcomm CTIs only. Numbered sysfs nodes are
>     hidden on standard ARM CTIs, and on Qualcomm CTIs their visibility is
>     derived from nr_trig_max (32 triggers per bank), ensuring that only
>     registers backed by hardware are exposed.
> Link to v6 - https://lore.kernel.org/all/20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com/
>
> Changes in v6:
> 1. Rename regs_idx to ext_reg_sel and add information in documentation
>     file.
> 2. Reset CLAIMSET to zero for qcom-cti during probe.
> 3. Retrieve idx value under spinlock.
> 4. Use yearless copyright for qcom-cti.h.
> Link to v5 - https://lore.kernel.org/all/20251020-extended_cti-v5-0-6f193da2d467@oss.qualcomm.com/
>
> Changes in v5:
> 1. Move common part in qcom-cti.h to coresight-cti.h.
> 2. Convert trigger usage fields to dynamic bitmaps and arrays.
> 3. Fix holes in struct cti_config to save some space.
> 4. Revert the previous changes related to the claim tag in
>     cti_enable/disable_hw.
> Link to v4 - https://lore.kernel.org/linux-arm-msm/20250902-extended_cti-v4-1-7677de04b416@oss.qualcomm.com/
>
> Changes in v4:
> 1. Read the DEVARCH registers to identify Qualcomm CTI.
> 2. Add a reg_idx node, and refactor the coresight_cti_reg_show() and
> coresight_cti_reg_store() functions accordingly.
> 3. The register offsets specific to Qualcomm CTI are moved to qcom_cti.h.
> Link to v3 - https://lore.kernel.org/linux-arm-msm/20250722081405.2947294-1-quic_jinlmao@quicinc.com/
>
> Changes in v3:
> 1. Rename is_extended_cti() to of_is_extended_cti().
> 2. Add the missing 'i' when write the CTI trigger registers.
> 3. Convert the multi-line output in sysfs to single line.
> 4. Initialize offset arrays using designated initializer.
> Link to V2 - https://lore.kernel.org/all/20250429071841.1158315-3-quic_jinlmao@quicinc.com/
>
> Changes in V2:
> 1. Add enum for compatible items.
> 2. Move offset arrays to coresight-cti-core
>
> Signed-off-by: Yingchao Deng <yingchao.deng@oss.qualcomm.com>
> ---
> Yingchao Deng (4):
>        coresight: cti: Convert trigger usage fields to dynamic bitmaps and arrays
>        coresight: cti: encode trigger register index in register offsets
>        coresight: cti: add Qualcomm extended CTI identification and quirks
>        coresight: cti: expose banked sysfs registers for Qualcomm extended CTI
>
>   drivers/hwtracing/coresight/coresight-cti-core.c   | 114 ++++++++++++++++-----
>   .../hwtracing/coresight/coresight-cti-platform.c   |  16 +--
>   drivers/hwtracing/coresight/coresight-cti-sysfs.c  |  75 ++++++++++++--
>   drivers/hwtracing/coresight/coresight-cti.h        |  30 ++++--
>   drivers/hwtracing/coresight/qcom-cti.h             |  65 ++++++++++++
>   5 files changed, 247 insertions(+), 53 deletions(-)
> ---
> base-commit: 5bca1f031b65a4a8caf700537cbbc770252af475
> change-id: 20260324-extended_cti-707638ceee9e
>
> Best regards,

Gentle reminder.

thanks,
Yingchao.



^ permalink raw reply

* [PATCH 0/5] media: synopsys: enhancements and i.MX95 support
From: Guoniu Zhou @ 2026-04-15  3:46 UTC (permalink / raw)
  To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
	Laurent Pinchart, Frank Li
  Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
	linux-rockchip, Guoniu Zhou

This series enhances the Synopsys DesignWare MIPI CSI-2 receiver driver
with multiple stream support and adds i.MX95 platform support.

The i.MX95 variant is similar to i.MX93 but uses IDI instead of IPI. Since
IDI is software transparent, only a different register map is needed.

Tested on i.MX93 and i.MX95 platforms.

Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
Guoniu Zhou (5):
      media: synopsys: Add support for RAW16 Bayer formats
      media: synopsys: Add support for multiple streams
      media: synopsys: Add PHY stopstate wait for i.MX93
      media: dt-bindings: add NXP i.MX95 compatible string
      media: synopsys: Add support for i.MX95

 .../bindings/media/rockchip,rk3568-mipi-csi2.yaml  |   5 +-
 drivers/media/platform/synopsys/dw-mipi-csi2rx.c   | 125 ++++++++++++++++++---
 2 files changed, 111 insertions(+), 19 deletions(-)
---
base-commit: 4fbeef21f5387234111b5d52924e77757626faa5
change-id: 20260414-csi2_imx95-65ad0e7f630a

Best regards,
-- 
Guoniu Zhou <guoniu.zhou@oss.nxp.com>



^ permalink raw reply

* [PATCH 1/5] media: synopsys: Add support for RAW16 Bayer formats
From: Guoniu Zhou @ 2026-04-15  3:46 UTC (permalink / raw)
  To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
	Laurent Pinchart, Frank Li
  Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
	linux-rockchip, Guoniu Zhou
In-Reply-To: <20260415-csi2_imx95-v1-0-7d63f3508719@oss.nxp.com>

This enables the driver to handle higher bit-depth raw image data
from image sensors that support 16-bit output.

Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
 drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index ce17f986279e..46e2a4315ac2 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -252,6 +252,26 @@ static const struct dw_mipi_csi2rx_format formats[] = {
 		.depth = 12,
 		.csi_dt = MIPI_CSI2_DT_RAW12,
 	},
+	{
+		.code = MEDIA_BUS_FMT_SBGGR16_1X16,
+		.depth = 16,
+		.csi_dt = MIPI_CSI2_DT_RAW16,
+	},
+	{
+		.code = MEDIA_BUS_FMT_SGBRG16_1X16,
+		.depth = 16,
+		.csi_dt = MIPI_CSI2_DT_RAW16,
+	},
+	{
+		.code = MEDIA_BUS_FMT_SGRBG16_1X16,
+		.depth = 16,
+		.csi_dt = MIPI_CSI2_DT_RAW16,
+	},
+	{
+		.code = MEDIA_BUS_FMT_SRGGB16_1X16,
+		.depth = 16,
+		.csi_dt = MIPI_CSI2_DT_RAW16,
+	},
 };
 
 static inline struct dw_mipi_csi2rx_device *to_csi2(struct v4l2_subdev *sd)

-- 
2.34.1



^ permalink raw reply related

* [PATCH 2/5] media: synopsys: Add support for multiple streams
From: Guoniu Zhou @ 2026-04-15  3:46 UTC (permalink / raw)
  To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
	Laurent Pinchart, Frank Li
  Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
	linux-rockchip, Guoniu Zhou
In-Reply-To: <20260415-csi2_imx95-v1-0-7d63f3508719@oss.nxp.com>

The current driver only supports single stream operation. Add support
for multiple concurrent streams by tracking enabled streams with a
bitmask and only initializing the hardware once for the first stream.

This enables use cases such as surround view systems where multiple
camera streams need to be processed simultaneously through the same
CSI-2 receiver interface.

Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
 drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 45 ++++++++++++++----------
 1 file changed, 27 insertions(+), 18 deletions(-)

diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index 46e2a4315ac2..85a2a95bf080 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -113,6 +113,7 @@ struct dw_mipi_csi2rx_device {
 
 	enum v4l2_mbus_type bus_type;
 	u32 lanes_num;
+	u64 enabled_streams;
 
 	const struct dw_mipi_csi2rx_drvdata *drvdata;
 };
@@ -528,28 +529,31 @@ static int dw_mipi_csi2rx_enable_streams(struct v4l2_subdev *sd,
 					       DW_MIPI_CSI2RX_PAD_SRC,
 					       &streams_mask);
 
-	ret = pm_runtime_resume_and_get(dev);
-	if (ret)
-		goto err;
+	if (!csi2->enabled_streams) {
+		ret = pm_runtime_resume_and_get(dev);
+		if (ret)
+			return ret;
 
-	ret = dw_mipi_csi2rx_start(csi2);
-	if (ret) {
-		dev_err(dev, "failed to enable CSI hardware\n");
-		goto err_pm_runtime_put;
+		ret = dw_mipi_csi2rx_start(csi2);
+		if (ret) {
+			pm_runtime_put(dev);
+			dev_err(dev, "failed to enable CSI hardware\n");
+			return ret;
+		}
 	}
 
 	ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index, mask);
-	if (ret)
-		goto err_csi_stop;
+	if (ret) {
+		if (!csi2->enabled_streams) {
+			dw_mipi_csi2rx_stop(csi2);
+			pm_runtime_put(dev);
+		}
+		return ret;
+	}
 
-	return 0;
+	csi2->enabled_streams |= streams_mask;
 
-err_csi_stop:
-	dw_mipi_csi2rx_stop(csi2);
-err_pm_runtime_put:
-	pm_runtime_put(dev);
-err:
-	return ret;
+	return 0;
 }
 
 static int dw_mipi_csi2rx_disable_streams(struct v4l2_subdev *sd,
@@ -572,10 +576,15 @@ static int dw_mipi_csi2rx_disable_streams(struct v4l2_subdev *sd,
 					       &streams_mask);
 
 	ret = v4l2_subdev_disable_streams(remote_sd, remote_pad->index, mask);
+	if (ret)
+		dev_err(dev, "failed to disable streams on remote subdev: %d\n", ret);
 
-	dw_mipi_csi2rx_stop(csi2);
+	csi2->enabled_streams &= ~streams_mask;
 
-	pm_runtime_put(dev);
+	if (!csi2->enabled_streams) {
+		dw_mipi_csi2rx_stop(csi2);
+		pm_runtime_put(dev);
+	}
 
 	return ret;
 }

-- 
2.34.1



^ permalink raw reply related

* [PATCH 3/5] media: synopsys: Add PHY stopstate wait for i.MX93
From: Guoniu Zhou @ 2026-04-15  3:46 UTC (permalink / raw)
  To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
	Laurent Pinchart, Frank Li
  Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
	linux-rockchip, Guoniu Zhou
In-Reply-To: <20260415-csi2_imx95-v1-0-7d63f3508719@oss.nxp.com>

Implement waiting for D-PHY lanes to enter stop state on i.MX93. This
ensures proper PHY initialization by verifying that the clock lane and
all active data lanes have entered the stop state before proceeding with
further operations.

Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
 drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 38 ++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index 85a2a95bf080..27e4c1027816 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -11,6 +11,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/phy/phy.h>
@@ -35,6 +36,8 @@
 #define DW_REG_EXIST		BIT(31)
 #define DW_REG(x)		(DW_REG_EXIST | (x))
 
+#define DPHY_STOPSTATE_CLK_LANE		BIT(16)
+
 #define DPHY_TEST_CTRL0_TEST_CLR	BIT(0)
 
 #define IPI_VCID_VC(x)			FIELD_PREP(GENMASK(1, 0), (x))
@@ -65,6 +68,7 @@ enum dw_mipi_csi2rx_regs_index {
 	DW_MIPI_CSI2RX_PHY_TST_CTRL0,
 	DW_MIPI_CSI2RX_PHY_TST_CTRL1,
 	DW_MIPI_CSI2RX_PHY_SHUTDOWNZ,
+	DW_MIPI_CSI2RX_PHY_STOPSTATE,
 	DW_MIPI_CSI2RX_IPI_DATATYPE,
 	DW_MIPI_CSI2RX_IPI_MEM_FLUSH,
 	DW_MIPI_CSI2RX_IPI_MODE,
@@ -87,6 +91,7 @@ struct dw_mipi_csi2rx_drvdata {
 	void (*dphy_assert_reset)(struct dw_mipi_csi2rx_device *csi2);
 	void (*dphy_deassert_reset)(struct dw_mipi_csi2rx_device *csi2);
 	void (*ipi_enable)(struct dw_mipi_csi2rx_device *csi2);
+	int (*wait_for_phy_stopstate)(struct dw_mipi_csi2rx_device *csi2);
 };
 
 struct dw_mipi_csi2rx_format {
@@ -139,6 +144,7 @@ static const u32 imx93_regs[DW_MIPI_CSI2RX_MAX] = {
 	[DW_MIPI_CSI2RX_PHY_SHUTDOWNZ] = DW_REG(0x40),
 	[DW_MIPI_CSI2RX_DPHY_RSTZ] = DW_REG(0x44),
 	[DW_MIPI_CSI2RX_PHY_STATE] = DW_REG(0x48),
+	[DW_MIPI_CSI2RX_PHY_STOPSTATE] = DW_REG(0x4c),
 	[DW_MIPI_CSI2RX_PHY_TST_CTRL0] = DW_REG(0x50),
 	[DW_MIPI_CSI2RX_PHY_TST_CTRL1] = DW_REG(0x54),
 	[DW_MIPI_CSI2RX_IPI_MODE] = DW_REG(0x80),
@@ -410,6 +416,12 @@ static int dw_mipi_csi2rx_start(struct dw_mipi_csi2rx_device *csi2)
 
 	dw_mipi_csi2rx_write(csi2, DW_MIPI_CSI2RX_RESETN, 1);
 
+	if (csi2->drvdata->wait_for_phy_stopstate) {
+		ret = csi2->drvdata->wait_for_phy_stopstate(csi2);
+		if (ret)
+			return ret;
+	}
+
 	if (csi2->drvdata->ipi_enable)
 		csi2->drvdata->ipi_enable(csi2);
 
@@ -856,11 +868,37 @@ static void imx93_csi2rx_dphy_ipi_enable(struct dw_mipi_csi2rx_device *csi2)
 	dw_mipi_csi2rx_write(csi2, DW_MIPI_CSI2RX_IPI_MODE, val);
 }
 
+static int imx93_csi2rx_wait_for_phy_stopstate(struct dw_mipi_csi2rx_device *csi2)
+{
+	struct device *dev = csi2->dev;
+	void __iomem *addr;
+	u32 stopstate_mask;
+	u32 val;
+	int ret;
+
+	if (!dw_mipi_csi2rx_has_reg(csi2, DW_MIPI_CSI2RX_PHY_STOPSTATE)) {
+		dev_err(dev, "phy_stopstate register not available\n");
+		return -ENXIO;
+	}
+
+	stopstate_mask = DPHY_STOPSTATE_CLK_LANE | GENMASK(csi2->lanes_num - 1, 0);
+	addr = dw_mipi_csi2rx_get_regaddr(csi2, DW_MIPI_CSI2RX_PHY_STOPSTATE);
+
+	ret = readl_poll_timeout(addr, val, (val & stopstate_mask) != stopstate_mask,
+				 1000, 2000000);
+	if (ret)
+		dev_err(dev, "lanes are not in stop state: %#x, expected %#x\n",
+			val, stopstate_mask);
+
+	return ret;
+}
+
 static const struct dw_mipi_csi2rx_drvdata imx93_drvdata = {
 	.regs = imx93_regs,
 	.dphy_assert_reset = imx93_csi2rx_dphy_assert_reset,
 	.dphy_deassert_reset = imx93_csi2rx_dphy_deassert_reset,
 	.ipi_enable = imx93_csi2rx_dphy_ipi_enable,
+	.wait_for_phy_stopstate = imx93_csi2rx_wait_for_phy_stopstate,
 };
 
 static const struct of_device_id dw_mipi_csi2rx_of_match[] = {

-- 
2.34.1



^ permalink raw reply related

* [PATCH 4/5] media: dt-bindings: add NXP i.MX95 compatible string
From: Guoniu Zhou @ 2026-04-15  3:46 UTC (permalink / raw)
  To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
	Laurent Pinchart, Frank Li
  Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
	linux-rockchip, Guoniu Zhou
In-Reply-To: <20260415-csi2_imx95-v1-0-7d63f3508719@oss.nxp.com>

The i.MX95 CSI-2 controller is nearly identical to i.MX93, with the
only difference being the use of IDI (Image Data Interface) instead
of IPI (Image Pixel Interface). The binding constraints are otherwise
the same.

Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
 .../devicetree/bindings/media/rockchip,rk3568-mipi-csi2.yaml         | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/media/rockchip,rk3568-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/rockchip,rk3568-mipi-csi2.yaml
index 4ac4a3b6f406..78371e039e55 100644
--- a/Documentation/devicetree/bindings/media/rockchip,rk3568-mipi-csi2.yaml
+++ b/Documentation/devicetree/bindings/media/rockchip,rk3568-mipi-csi2.yaml
@@ -18,6 +18,7 @@ properties:
   compatible:
     enum:
       - fsl,imx93-mipi-csi2
+      - fsl,imx95-mipi-csi2
       - rockchip,rk3568-mipi-csi2
 
   reg:
@@ -124,7 +125,9 @@ allOf:
       properties:
         compatible:
           contains:
-            const: fsl,imx93-mipi-csi2
+            enum:
+              - fsl,imx93-mipi-csi2
+              - fsl,imx95-mipi-csi2
     then:
       properties:
         interrupts:

-- 
2.34.1



^ permalink raw reply related

* [PATCH 5/5] media: synopsys: Add support for i.MX95
From: Guoniu Zhou @ 2026-04-15  3:46 UTC (permalink / raw)
  To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
	Laurent Pinchart, Frank Li
  Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
	linux-rockchip, Guoniu Zhou
In-Reply-To: <20260415-csi2_imx95-v1-0-7d63f3508719@oss.nxp.com>

Add support for the i.MX95 MIPI CSI-2 receiver. The i.MX95 variant is
nearly identical to i.MX93, with the main difference being the use of
IDI (Image Data Interface) instead of IPI (Image Pixel Interface).
However, the IDI interface is transparent to software, requiring only
a different register map definition while sharing the same PHY control
functions with i.MX93.

Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
 drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index 27e4c1027816..bbb41baf789e 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -154,6 +154,17 @@ static const u32 imx93_regs[DW_MIPI_CSI2RX_MAX] = {
 	[DW_MIPI_CSI2RX_IPI_SOFTRSTN] = DW_REG(0xa0),
 };
 
+static const u32 imx95_regs[DW_MIPI_CSI2RX_MAX] = {
+	[DW_MIPI_CSI2RX_N_LANES] = DW_REG(0x4),
+	[DW_MIPI_CSI2RX_RESETN] = DW_REG(0x8),
+	[DW_MIPI_CSI2RX_PHY_SHUTDOWNZ] = DW_REG(0x40),
+	[DW_MIPI_CSI2RX_DPHY_RSTZ] = DW_REG(0x44),
+	[DW_MIPI_CSI2RX_PHY_STATE] = DW_REG(0x48),
+	[DW_MIPI_CSI2RX_PHY_STOPSTATE] = DW_REG(0x4c),
+	[DW_MIPI_CSI2RX_PHY_TST_CTRL0] = DW_REG(0x50),
+	[DW_MIPI_CSI2RX_PHY_TST_CTRL1] = DW_REG(0x54),
+};
+
 static const struct v4l2_mbus_framefmt default_format = {
 	.width = 3840,
 	.height = 2160,
@@ -901,11 +912,22 @@ static const struct dw_mipi_csi2rx_drvdata imx93_drvdata = {
 	.wait_for_phy_stopstate = imx93_csi2rx_wait_for_phy_stopstate,
 };
 
+static const struct dw_mipi_csi2rx_drvdata imx95_drvdata = {
+	.regs = imx95_regs,
+	.dphy_assert_reset = imx93_csi2rx_dphy_assert_reset,
+	.dphy_deassert_reset = imx93_csi2rx_dphy_deassert_reset,
+	.wait_for_phy_stopstate = imx93_csi2rx_wait_for_phy_stopstate,
+};
+
 static const struct of_device_id dw_mipi_csi2rx_of_match[] = {
 	{
 		.compatible = "fsl,imx93-mipi-csi2",
 		.data = &imx93_drvdata,
 	},
+	{
+		.compatible = "fsl,imx95-mipi-csi2",
+		.data = &imx95_drvdata,
+	},
 	{
 		.compatible = "rockchip,rk3568-mipi-csi2",
 		.data = &rk3568_drvdata,

-- 
2.34.1



^ permalink raw reply related

* Re: [PATCH v4 4/9] coresight: etm4x: fix inconsistencies with sysfs configuration
From: Jie Gan @ 2026-04-15  4:25 UTC (permalink / raw)
  To: Yeoreum Yun, coresight, linux-arm-kernel, linux-kernel
  Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
	leo.yan
In-Reply-To: <20260413142003.3549310-5-yeoreum.yun@arm.com>



On 4/13/2026 10:19 PM, Yeoreum Yun wrote:
> The current ETM4x configuration via sysfs can lead to
> several inconsistencies:
> 
>    - If the configuration is modified via sysfs while a perf session is
>      active, the running configuration may differ before a sched-out and
>      after a subsequent sched-in.
> 
>    - If a perf session and a sysfs session enable tracing concurrently,
>      the configuration from configfs may become corrupted.
> 
>    - There is a risk of corrupting drvdata->config if a perf session enables
>      tracing while cscfg_csdev_disable_active_config() is being handled in
>      etm4_disable_sysfs().
> 
> To resolve these issues, separate the configuration into:
> 
>    - active_config: the configuration applied to the current session
>    - config: the configuration set via sysfs
> 
> Additionally:
> 
>    - Apply the configuration from configfs after taking the appropriate mode.
> 
>    - Since active_config and related fields are accessed only by the local CPU
>      in etm4_enable/disable_sysfs_smp_call() (similar to perf enable/disable),
>      remove the lock/unlock from the sysfs enable/disable path and
>      startup/dying_cpu except when to access config fields.
> 
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
>   .../hwtracing/coresight/coresight-etm4x-cfg.c |   2 +-
>   .../coresight/coresight-etm4x-core.c          | 107 ++++++++++--------
>   drivers/hwtracing/coresight/coresight-etm4x.h |   2 +
>   3 files changed, 62 insertions(+), 49 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> index d14d7c8a23e5..0553771d04e7 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> @@ -47,7 +47,7 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
>   				   struct cscfg_regval_csdev *reg_csdev, u32 offset)
>   {
>   	int err = -EINVAL, idx;
> -	struct etmv4_config *drvcfg = &drvdata->config;
> +	struct etmv4_config *drvcfg = &drvdata->active_config;
>   	u32 off_mask;
>   
>   	if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) ||
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index 1bc9f13e33f7..01099689525b 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -245,6 +245,10 @@ void etm4_release_trace_id(struct etmv4_drvdata *drvdata)
>   
>   struct etm4_enable_arg {
>   	struct etmv4_drvdata *drvdata;
> +	unsigned long cfg_hash;
> +	int preset;
> +	u8 trace_id;
> +	struct etmv4_config config;
>   	int rc;
>   };
>   
> @@ -270,10 +274,11 @@ static void etm4x_prohibit_trace(struct etmv4_drvdata *drvdata)
>   static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
>   {
>   	u64 trfcr = drvdata->trfcr;
> +	struct etmv4_config *config = &drvdata->active_config;
>   
> -	if (drvdata->config.mode & ETM_MODE_EXCL_KERN)
> +	if (config->mode & ETM_MODE_EXCL_KERN)
>   		trfcr &= ~TRFCR_EL1_ExTRE;
> -	if (drvdata->config.mode & ETM_MODE_EXCL_USER)
> +	if (config->mode & ETM_MODE_EXCL_USER)
>   		trfcr &= ~TRFCR_EL1_E0TRE;
>   
>   	return trfcr;
> @@ -281,7 +286,7 @@ static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
>   
>   /*
>    * etm4x_allow_trace - Allow CPU tracing in the respective ELs,
> - * as configured by the drvdata->config.mode for the current
> + * as configured by the drvdata->active_config.mode for the current
>    * session. Even though we have TRCVICTLR bits to filter the
>    * trace in the ELs, it doesn't prevent the ETM from generating
>    * a packet (e.g, TraceInfo) that might contain the addresses from
> @@ -292,12 +297,13 @@ static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
>   static void etm4x_allow_trace(struct etmv4_drvdata *drvdata)
>   {
>   	u64 trfcr, guest_trfcr;
> +	struct etmv4_config *config = &drvdata->active_config;
>   
>   	/* If the CPU doesn't support FEAT_TRF, nothing to do */
>   	if (!drvdata->trfcr)
>   		return;
>   
> -	if (drvdata->config.mode & ETM_MODE_EXCL_HOST)
> +	if (config->mode & ETM_MODE_EXCL_HOST)
>   		trfcr = drvdata->trfcr & ~(TRFCR_EL1_ExTRE | TRFCR_EL1_E0TRE);
>   	else
>   		trfcr = etm4x_get_kern_user_filter(drvdata);
> @@ -305,7 +311,7 @@ static void etm4x_allow_trace(struct etmv4_drvdata *drvdata)
>   	write_trfcr(trfcr);
>   
>   	/* Set filters for guests and pass to KVM */
> -	if (drvdata->config.mode & ETM_MODE_EXCL_GUEST)
> +	if (config->mode & ETM_MODE_EXCL_GUEST)
>   		guest_trfcr = drvdata->trfcr & ~(TRFCR_EL1_ExTRE | TRFCR_EL1_E0TRE);
>   	else
>   		guest_trfcr = etm4x_get_kern_user_filter(drvdata);
> @@ -499,7 +505,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
>   {
>   	int i, rc;
>   	const struct etmv4_caps *caps = &drvdata->caps;
> -	struct etmv4_config *config = &drvdata->config;
> +	struct etmv4_config *config = &drvdata->active_config;
>   	struct coresight_device *csdev = drvdata->csdev;
>   	struct device *etm_dev = &csdev->dev;
>   	struct csdev_access *csa = &csdev->access;
> @@ -616,23 +622,46 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
>   static void etm4_enable_sysfs_smp_call(void *info)
>   {
>   	struct etm4_enable_arg *arg = info;
> +	struct etmv4_drvdata *drvdata;
>   	struct coresight_device *csdev;
>   
>   	if (WARN_ON(!arg))
>   		return;
>   
> -	csdev = arg->drvdata->csdev;
> +	drvdata = arg->drvdata;
> +	csdev = drvdata->csdev;
>   	if (!coresight_take_mode(csdev, CS_MODE_SYSFS)) {
>   		/* Someone is already using the tracer */
>   		arg->rc = -EBUSY;
>   		return;
>   	}
>   
> -	arg->rc = etm4_enable_hw(arg->drvdata);
> +	drvdata->active_config = arg->config;
>   
> -	/* The tracer didn't start */
> +	if (arg->cfg_hash) {
> +		arg->rc = cscfg_csdev_enable_active_config(csdev,
> +							   arg->cfg_hash,
> +							   arg->preset);
> +		if (arg->rc)
> +			goto err;
> +	}
> +
> +	drvdata->trcid = arg->trace_id;
> +
> +	/* Tracer will never be paused in sysfs mode */
> +	drvdata->paused = false;
> +
> +	arg->rc = etm4_enable_hw(drvdata);
>   	if (arg->rc)
> -		coresight_set_mode(csdev, CS_MODE_DISABLED);
> +		goto err;
> +
> +	drvdata->sticky_enable = true;
> +
> +	return;
> +err:
> +	/* The tracer didn't start */
> +	etm4_release_trace_id(drvdata);

[NIT] better move this error handle to etm4_enable_sysfs.

smp_call_function_single possible return before call 
etm4_enable_sysfs_smp_call if the cpu is offline. The error path here 
cannot handle this error, breaking previous logic(handle all errors in 
etm4_enable_sysfs by releasing trace id).

There is no harm in not releasing the trace id here because ETM can 
re-use the allocated trace ID. But it's better to fix the inconsistent 
logic.

Thanks,
Jie

> +	coresight_set_mode(csdev, CS_MODE_DISABLED);
>   }
>   
>   /*
> @@ -670,7 +699,7 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata,
>   	int ctridx;
>   	int rselector;
>   	const struct etmv4_caps *caps = &drvdata->caps;
> -	struct etmv4_config *config = &drvdata->config;
> +	struct etmv4_config *config = &drvdata->active_config;
>   
>   	/* No point in trying if we don't have at least one counter */
>   	if (!caps->nr_cntr)
> @@ -754,7 +783,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
>   	int ret = 0;
>   	struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>   	const struct etmv4_caps *caps = &drvdata->caps;
> -	struct etmv4_config *config = &drvdata->config;
> +	struct etmv4_config *config = &drvdata->active_config;
>   	struct perf_event_attr max_timestamp = {
>   		.ATTR_CFG_FLD_timestamp_CFG = U64_MAX,
>   	};
> @@ -916,38 +945,24 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
>   
>   	/* enable any config activated by configfs */
>   	cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
> -	if (cfg_hash) {
> -		ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
> -		if (ret) {
> -			etm4_release_trace_id(drvdata);
> -			return ret;
> -		}
> -	}
> -
> -	raw_spin_lock(&drvdata->spinlock);
> -
> -	drvdata->trcid = path->trace_id;
> -
> -	/* Tracer will never be paused in sysfs mode */
> -	drvdata->paused = false;
>   
>   	/*
>   	 * Executing etm4_enable_hw on the cpu whose ETM is being enabled
>   	 * ensures that register writes occur when cpu is powered.
>   	 */
>   	arg.drvdata = drvdata;
> +	arg.cfg_hash = cfg_hash;
> +	arg.preset = preset;
> +	arg.trace_id = path->trace_id;
> +
> +	raw_spin_lock(&drvdata->spinlock);
> +	arg.config = drvdata->config;
> +	raw_spin_unlock(&drvdata->spinlock);
> +
>   	ret = smp_call_function_single(drvdata->cpu,
>   				       etm4_enable_sysfs_smp_call, &arg, 1);
>   	if (!ret)
>   		ret = arg.rc;
> -	if (!ret)
> -		drvdata->sticky_enable = true;
> -
> -	if (ret)
> -		etm4_release_trace_id(drvdata);
> -
> -	raw_spin_unlock(&drvdata->spinlock);
> -
>   	if (!ret)
>   		dev_dbg(&csdev->dev, "ETM tracing enabled\n");
>   	return ret;
> @@ -1036,7 +1051,7 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
>   {
>   	u32 control;
>   	const struct etmv4_caps *caps = &drvdata->caps;
> -	struct etmv4_config *config = &drvdata->config;
> +	struct etmv4_config *config = &drvdata->active_config;
>   	struct coresight_device *csdev = drvdata->csdev;
>   	struct csdev_access *csa = &csdev->access;
>   	int i;
> @@ -1072,6 +1087,8 @@ static void etm4_disable_sysfs_smp_call(void *info)
>   
>   	etm4_disable_hw(drvdata);
>   
> +	cscfg_csdev_disable_active_config(drvdata->csdev);
> +
>   	coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED);
>   }
>   
> @@ -1122,7 +1139,6 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
>   	 * DYING hotplug callback is serviced by the ETM driver.
>   	 */
>   	cpus_read_lock();
> -	raw_spin_lock(&drvdata->spinlock);
>   
>   	/*
>   	 * Executing etm4_disable_hw on the cpu whose ETM is being disabled
> @@ -1131,10 +1147,6 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
>   	smp_call_function_single(drvdata->cpu, etm4_disable_sysfs_smp_call,
>   				 drvdata, 1);
>   
> -	raw_spin_unlock(&drvdata->spinlock);
> -
> -	cscfg_csdev_disable_active_config(csdev);
> -
>   	cpus_read_unlock();
>   
>   	/*
> @@ -1377,6 +1389,7 @@ static void etm4_init_arch_data(void *info)
>   	struct etm4_init_arg *init_arg = info;
>   	struct etmv4_drvdata *drvdata;
>   	struct etmv4_caps *caps;
> +	struct etmv4_config *config;
>   	struct csdev_access *csa;
>   	struct device *dev = init_arg->dev;
>   	int i;
> @@ -1384,6 +1397,7 @@ static void etm4_init_arch_data(void *info)
>   	drvdata = dev_get_drvdata(init_arg->dev);
>   	caps = &drvdata->caps;
>   	csa = init_arg->csa;
> +	config = &drvdata->active_config;
>   
>   	/*
>   	 * If we are unable to detect the access mechanism,
> @@ -1444,7 +1458,7 @@ static void etm4_init_arch_data(void *info)
>   
>   	/* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
>   	caps->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
> -	drvdata->config.s_ex_level = caps->s_ex_level;
> +	config->s_ex_level = caps->s_ex_level;
>   	/* EXLEVEL_NS, bits[23:20] Non-secure state instruction tracing */
>   	caps->ns_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_NS_MASK, etmidr3);
>   	/*
> @@ -1689,7 +1703,7 @@ static void etm4_set_default(struct etmv4_config *config)
>   static int etm4_get_next_comparator(struct etmv4_drvdata *drvdata, u32 type)
>   {
>   	int nr_comparator, index = 0;
> -	struct etmv4_config *config = &drvdata->config;
> +	struct etmv4_config *config = &drvdata->active_config;
>   
>   	/*
>   	 * nr_addr_cmp holds the number of comparator _pair_, so time 2
> @@ -1730,7 +1744,7 @@ static int etm4_set_event_filters(struct etmv4_drvdata *drvdata,
>   {
>   	int i, comparator, ret = 0;
>   	u64 address;
> -	struct etmv4_config *config = &drvdata->config;
> +	struct etmv4_config *config = &drvdata->active_config;
>   	struct etm_filters *filters = event->hw.addr_filters;
>   
>   	if (!filters)
> @@ -1848,13 +1862,11 @@ static int etm4_starting_cpu(unsigned int cpu)
>   	if (!etmdrvdata[cpu])
>   		return 0;
>   
> -	raw_spin_lock(&etmdrvdata[cpu]->spinlock);
>   	if (!etmdrvdata[cpu]->os_unlock)
>   		etm4_os_unlock(etmdrvdata[cpu]);
>   
>   	if (coresight_get_mode(etmdrvdata[cpu]->csdev))
>   		etm4_enable_hw(etmdrvdata[cpu]);
> -	raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
>   	return 0;
>   }
>   
> @@ -1863,10 +1875,8 @@ static int etm4_dying_cpu(unsigned int cpu)
>   	if (!etmdrvdata[cpu])
>   		return 0;
>   
> -	raw_spin_lock(&etmdrvdata[cpu]->spinlock);
>   	if (coresight_get_mode(etmdrvdata[cpu]->csdev))
>   		etm4_disable_hw(etmdrvdata[cpu]);
> -	raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
>   	return 0;
>   }
>   
> @@ -2252,7 +2262,8 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
>   	if (!desc.name)
>   		return -ENOMEM;
>   
> -	etm4_set_default(&drvdata->config);
> +	etm4_set_default(&drvdata->active_config);
> +	drvdata->config = drvdata->active_config;
>   
>   	pdata = coresight_get_platform_data(dev);
>   	if (IS_ERR(pdata))
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> index 8864cfb76bad..725e6360a8b9 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> @@ -1071,6 +1071,7 @@ struct etmv4_save_state {
>    *		allows tracing at all ELs. We don't want to compute this
>    *		at runtime, due to the additional setting of TRFCR_CX when
>    *		in EL2. Otherwise, 0.
> + * @active_config:	structure holding current applied configuration parameters.
>    * @config:	structure holding configuration parameters.
>    * @save_state:	State to be preserved across power loss
>    * @paused:	Indicates if the trace unit is paused.
> @@ -1091,6 +1092,7 @@ struct etmv4_drvdata {
>   	bool				os_unlock : 1;
>   	bool				paused : 1;
>   	u64				trfcr;
> +	struct etmv4_config		active_config;
>   	struct etmv4_config		config;
>   	struct etmv4_save_state		*save_state;
>   	DECLARE_BITMAP(arch_features, ETM4_IMPDEF_FEATURE_MAX);



^ permalink raw reply


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