Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v2 4/6] mm/migrate: use huge_ptep_get() in remove_migration_pte()
From: David Hildenbrand (Arm) @ 2026-07-02 15:44 UTC (permalink / raw)
  To: Dev Jain, muchun.song, osalvador, akpm, ljs, liam
  Cc: riel, vbabka, harry, jannh, lance.yang, kas, linux-mm,
	linux-kernel, rcampbell, apopple, ziy, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, j-nomura,
	nao.horiguchi, ak, mel, pfalcato, jpoimboe, dave.hansen, tglx,
	catalin.marinas, will, linux-arm-kernel, ryan.roberts,
	anshuman.khandual, stable
In-Reply-To: <20260702051341.126509-5-dev.jain@arm.com>

On 7/2/26 07:13, Dev Jain wrote:
> remove_migration_pte() converts migration entries back to present PTEs
> after folio migration completes. For hugetlb folios,
> page_vma_mapped_walk() returns the pte pointer to the hugetlb folio in
> pvmw.pte, but the code reads it with ptep_get().
> 
> On arches which provide their own huge_ptep_get() to dereference a huge
> pte pointer, accessing via ptep_get() would cause pte_pfn(),
> pte_present() etc to misbehave.
> 
> It is not clear whether this has a trivially visible effect to userspace.

Right, for non-present entries it's even weirder. Fortunately your patch #1 also
handles that.

Acked-by: David Hildenbrand (Arm) <david@kernel.org>

-- 
Cheers,

David


^ permalink raw reply

* Re: [PATCH v2 5/6] mm/page_vma_mapped: use huge_ptep_get() for hugetlb
From: David Hildenbrand (Arm) @ 2026-07-02 15:44 UTC (permalink / raw)
  To: Dev Jain, muchun.song, osalvador, akpm, ljs, liam
  Cc: riel, vbabka, harry, jannh, lance.yang, kas, linux-mm,
	linux-kernel, rcampbell, apopple, ziy, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, j-nomura,
	nao.horiguchi, ak, mel, pfalcato, jpoimboe, dave.hansen, tglx,
	catalin.marinas, will, linux-arm-kernel, ryan.roberts,
	anshuman.khandual, stable
In-Reply-To: <20260702051341.126509-6-dev.jain@arm.com>

On 7/2/26 07:13, Dev Jain wrote:
> check_pte() is the final validation step in page_vma_mapped_walk().
> It reads pvmw->pte with ptep_get() to decide whether the entry maps
> the PFN range being walked. For hugetlb VMAs, that pointer refers
> to a hugetlb entry.
> 
> On arches which provide their own huge_ptep_get() to dereference a huge
> pte pointer, accessing via ptep_get() would cause pte_pfn(),
> pte_present() etc to misbehave.
> 
> It is not clear whether this has a trivially visible effect to userspace.
> 
> Use huge_ptep_get() to dereference a huge pte pointer.
> 
> Fixes: ace71a19cec5 ("mm: introduce page_vma_mapped_walk()")
> Cc: stable@vger.kernel.org
> Signed-off-by: Dev Jain <dev.jain@arm.com>
> ---

Acked-by: David Hildenbrand (Arm) <david@kernel.org>

-- 
Cheers,

David


^ permalink raw reply

* Re: [PATCH RFC 0/8] clk: sunxi-ng: Add support for Allwinner A733 CCU and PRCM
From: Junhui Liu @ 2026-07-02 15:44 UTC (permalink / raw)
  To: Enzo Adriano, Junhui Liu
  Cc: Michael Turquette, Stephen Boyd, Brian Masney, Chen-Yu Tsai,
	Jernej Skrabec, Samuel Holland, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Philipp Zabel, Andre Przywara, Jerome Brunet,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	Richard Cochran, linux-clk, devicetree, linux-arm-kernel,
	linux-sunxi, linux-kernel, linux-riscv, netdev
In-Reply-To: <20260701160055.320000-a733-ccu-status-enzo.adriano.code@gmail.com>

Hi Enzo,

On Thu Jul 2, 2026 at 12:07 AM CST, Enzo Adriano wrote:
> Hi Junhui,
>
> Thanks for the A733 CCU/PRCM RFC v1. I've been reading through the
> series and the review feedback, including the NSI clock/reset handling,
> the binding naming and ordering comments, the SDM macro cleanup, and the
> question around modeled but otherwise-unused clocks such as the GIC clock.
>
> I do not see a v2 on the list yet, so I wanted to check in: are you still
> planning to take this series forward? No rush at all, and I am happy to
> leave it entirely with you if so.
>
> If you have moved on to other things, I would be glad to help carry the
> series forward and address the review comments, keeping your authorship
> and prior work intact. I have A733 hardware here and can help test the
> changes.
>
> Either way, please let me know what works best for you.

Thanks for reaching out. I have already been preparing a v2 based on
Jerome's new RTC patch series. I moved to a new city this week though,
so there may be some delay, but I will try to get it out as soon as
possible.

>
> Thanks,
> Enzo

-- 
Best regards,
Junhui Liu



^ permalink raw reply

* [GIT PULL] Reset controller fixes for v7.2
From: Philipp Zabel @ 2026-07-02 15:46 UTC (permalink / raw)
  To: soc; +Cc: linux-arm-kernel, kernel, Philipp Zabel

Dear arm-soc maintainers,

The following changes since commit dc59e4fea9d83f03bad6bddf3fa2e52491777482:

  Linux 7.2-rc1 (2026-06-28 12:01:31 -0700)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/pza/linux.git tags/reset-fixes-for-v7.2

for you to fetch changes up to 71827776667f4e4677a4fa806bcfb24d4b8dd9d7:

  reset: imx7: Correct polarity of MIPI CSI resets on i.MX8MQ (2026-07-01 15:08:14 +0200)

----------------------------------------------------------------
Reset controller fixes for v7.2

* Fix the SpacemiT K3 USB2 AHB reset bit location.
* Add missing COMBOPHY_RESET definition for Altera Agilex5.
* Fix the reset-sunxi initialization error path to release the
  requested memory region.
* Correct polarity of MIPI CSI resets on NXP i.MX8MQ. The corresponding
  fix in the CSI2 driver, 6d79bb8fd2aa, is already contained in v7.2-rc1.

----------------------------------------------------------------
Robby Cai (1):
      reset: imx7: Correct polarity of MIPI CSI resets on i.MX8MQ

Tanmay Kathpalia (1):
      dt-bindings: reset: altr: add COMBOPHY_RESET for Agilex5

Yixun Lan (1):
      reset: spacemit: k3: fix USB2 ahb reset

Zhao Dongdong (1):
      reset: sunxi: fix memory region leak on ioremap failure

 drivers/reset/reset-imx7.c                   | 6 ++++++
 drivers/reset/reset-sunxi.c                  | 4 +++-
 drivers/reset/spacemit/reset-spacemit-k3.c   | 2 +-
 include/dt-bindings/reset/altr,rst-mgr-s10.h | 2 +-
 4 files changed, 11 insertions(+), 3 deletions(-)


^ permalink raw reply

* Re: [PATCH v4 5/5] arm64: mpam: Add memory bandwidth usage (MBWU) documentation
From: Fenghua Yu @ 2026-07-02 15:46 UTC (permalink / raw)
  To: Ben Horgan, Reinette Chatre
  Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
	dfustini, gshan, james.morse, jic23, kobak, lcherian,
	linux-arm-kernel, linux-kernel, peternewman, punit.agrawal,
	quic_jiles, rohit.mathew, scott, sdonthineni, tan.shaopeng, xhao,
	zengheng4, x86
In-Reply-To: <5bba66e2-f671-4bdb-a2e5-f2cf9fb1f9f4@arm.com>

Hi, Ben,

On 7/2/26 07:58, Ben Horgan wrote:
> Hi Reinette,
> 
> On 7/2/26 15:46, Reinette Chatre wrote:
>> Hi Ben,
>>
>> On 7/2/26 2:20 AM, Ben Horgan wrote:
>>> On 7/1/26 23:38, Reinette Chatre wrote:
>>>> On 5/20/26 2:24 PM, Ben Horgan wrote:
>>
>> ...
>>
>>>>> --- a/Documentation/arch/arm64/mpam.rst
>>>>> +++ b/Documentation/arch/arm64/mpam.rst
>>>>> @@ -65,6 +65,23 @@ The supported features are:
>>>>>     there is at least one CSU monitor on each MSC that makes up the L3 group.
>>>>>     Exposing CSU counters from other caches or devices is not supported.
>>>>>   
>>>>> +* Memory Bandwidth Usage (MBWU) on or after the L3 cache.  resctrl uses the
>>>>> +  L3 cache-id to identify where the memory bandwidth is measured. For this
>>>>> +  reason the platform must have an L3 cache with cache-id's supplied by
>>>>> +  firmware. (It doesn't need to support MPAM.)

s/It/The platform/?

>>>>> +
>>>>> +  Memory bandwidth monitoring makes use of MBWU monitors in each MSC that
>>>>> +  makes up the L3 group. If the memory bandwidth monitoring is on the memory
>>>>> +  rather than the L3 then there must be a single global L3 as otherwise it

s/a single global L3/a single global L3 cache id/?

>>>>> +  is unknown which L3 the traffic came from.
>>>>> +
>>>>> +  To expose 'mbm_total_bytes', the topology of the group of MSC chosen must
>>>>> +  match the topology of the L3 cache so that the cache-id's can be
>>>>> +  repainted. For example: Platforms with Memory bandwidth monitors on
>>>>> +  CPU-less NUMA nodes cannot expose 'mbm_total_bytes' as these nodes do not
>>>>> +  have a corresponding L3 cache. 'mbm_local_bytes' is not exposed as MPAM

Maybe remove the CPU-less example here since you will add CPU-less info 
later?

The CPU-less patches will update this document accordingly.

>>>>> +  cannot distinguish local traffic from global traffic.
>>>>
>>>> Hopefully we can get to a point where memory bandwidth monitoring data from
>>>> CPU-less NUMA nodes can be exposed via resctrl. When considering such possible
>>>
>>> Thank you for your interest here. I hope so too.
>>>
>>>> future I think it may make this work easier to build on if the documentation
>>>> focuses on what the current implementation supports and leave room for
>>>> future enhancements by not constraining user space expectation with an absolute
>>>> like "CPU-less NUMA nodes cannot expose 'mbm_total_bytes'".
>>>
>>> The intention was to describe the current limitations but I do see how
>>> this can come across as fundamental problems rather than just that we
>>> need to do some more work to establish how this can be done and
>>> implement it.
>>>
>>> How about if I add this paragraph at the end?
>>>
>>> All these restrictions based on L3 cache are due to resctrl, currently,
>>> only supporting monitoring at the scope of the L3 scope. It is expected
>>
>> How about "at L3 scope" instead of "at the scope of the L3 scope"?
> 
> Sure, that reads better.
> 
> Ben
> 
>>
>>> that going forward more MBWU monitors can be exposed to the user after
>>> support for more monitoring scopes is added to resctrl.
>> Looks good to me, thank you.
>>
>> Reinette
> 
Thanks.

-Fenghua


^ permalink raw reply

* Re: [PATCH] mfd: db8500-prcmu: Fold dbx500 header into db8500
From: Lee Jones @ 2026-07-02 15:47 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Russell King, Ulf Hansson, Michael Turquette, Stephen Boyd,
	Brian Masney, Rafael J. Wysocki, Daniel Lezcano, Christian Loehle,
	Liam Girdwood, Mark Brown, Zhang Rui, Lukasz Luba,
	Wim Van Sebroeck, Guenter Roeck, Jaroslav Kysela, Takashi Iwai,
	linux-arm-kernel, linux-clk, linux-pm, linux-watchdog,
	linux-sound, kernel test robot
In-Reply-To: <20260619-mfd-prcmu-merge-headers-v1-1-8ea0ee23b4d6@kernel.org>

I won't hold you to these for this submission, but they're probably
worth looking at:

/* Sashiko Automation: Reviewed (4 Findings) */

On Fri, 19 Jun 2026, Linus Walleij wrote:

> Move the DBx500 PRCMU definitions into the DB8500 PRCMU
> header and delete the wrapper header.
> 
> Convert users of simple PRCMU wrappers to call the DB8500 helpers
> directly.
> 
> The dbx500-prcmu.h header was the result of an earlier attempt to
> abstract several DBx5x SoC PRCMU units to use the same abstract
> header. They are deleted from the kernel and this is not just
> causing maintenance burden and build errors.
> 
> The stub code is using -ENOSYS in a way checkpatch complains about
> so replace these with -EINVAL while we're at it.
> 
> Assisted-by: Codex:gpt-5-5
> Reported-by: kernel test robot <lkp@intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202606180825.vUSQntkJ-lkp@intel.com/
> Signed-off-by: Linus Walleij <linusw@kernel.org>
> ---
>  arch/arm/mach-ux500/cpu-db8500.c |   6 +-
>  drivers/clk/ux500/clk-prcmu.c    |  20 +-
>  drivers/clk/ux500/u8500_of_clk.c |   2 +-
>  drivers/cpuidle/cpuidle-ux500.c  |   6 +-
>  drivers/mfd/ab8500-core.c        |   2 +-
>  drivers/mfd/db8500-prcmu.c       |   6 +-
>  drivers/regulator/db8500-prcmu.c |  12 +-
>  drivers/thermal/db8500_thermal.c |  10 +-
>  drivers/watchdog/db8500_wdt.c    |  22 +-
>  include/linux/mfd/db8500-prcmu.h | 252 ++++++++++++++++-
>  include/linux/mfd/dbx500-prcmu.h | 575 ---------------------------------------
>  sound/soc/ux500/ux500_msp_dai.c  |   2 +-
>  12 files changed, 294 insertions(+), 621 deletions(-)
> 
> diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
> index b1a70f203372..0d7530fb6ad0 100644
> --- a/arch/arm/mach-ux500/cpu-db8500.c
> +++ b/arch/arm/mach-ux500/cpu-db8500.c
> @@ -12,7 +12,7 @@
>  #include <linux/irq.h>
>  #include <linux/irqchip.h>
>  #include <linux/irqchip/arm-gic.h>
> -#include <linux/mfd/dbx500-prcmu.h>
> +#include <linux/mfd/db8500-prcmu.h>
>  #include <linux/platform_data/arm-ux500-pm.h>
>  #include <linux/platform_device.h>
>  #include <linux/io.h>
> @@ -81,7 +81,7 @@ static void __init ux500_init_irq(void)
>  	struct resource r;
>  
>  	irqchip_init();
> -	prcmu_early_init();
> +	db8500_prcmu_early_init();
>  	np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu");
>  	of_address_to_resource(np, 0, &r);
>  	of_node_put(np);

[Severity: High]
This isn't a bug introduced by this patch, but does this code use an
uninitialized resource if of_address_to_resource() fails?

In ux500_init_irq(), struct resource r is declared on the stack without
initialization. If of_address_to_resource() returns an error (for example, if
the device tree node is missing a reg property), it does not populate r.

The return value of of_address_to_resource() is ignored, and the code later
checks:
    if (!r.start) {

Because r.start contains uninitialized stack memory, could it evaluate to a
non-zero value, causing the kernel to call ux500_pm_init() with garbage
physical memory addresses?


> @@ -101,7 +101,7 @@ static void ux500_restart(enum reboot_mode mode, const char *cmd)
>  	local_irq_disable();
>  	local_fiq_disable();
>  
> -	prcmu_system_reset(0);
> +	db8500_prcmu_system_reset(0);
>  }
>  
>  static const struct of_device_id u8500_local_bus_nodes[] = {
> diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c
> index ddc86551bf57..ac96c46bd1bb 100644
> --- a/drivers/clk/ux500/clk-prcmu.c
> +++ b/drivers/clk/ux500/clk-prcmu.c
> @@ -7,7 +7,7 @@
>   */
>  
>  #include <linux/clk-provider.h>
> -#include <linux/mfd/dbx500-prcmu.h>
> +#include <linux/mfd/db8500-prcmu.h>
>  #include <linux/slab.h>
>  #include <linux/io.h>
>  #include <linux/err.h>
> @@ -35,13 +35,13 @@ static int clk_prcmu_prepare(struct clk_hw *hw)
>  {
>  	struct clk_prcmu *clk = to_clk_prcmu(hw);
>  
> -	return prcmu_request_clock(clk->cg_sel, true);
> +	return db8500_prcmu_request_clock(clk->cg_sel, true);
>  }
>  
>  static void clk_prcmu_unprepare(struct clk_hw *hw)
>  {
>  	struct clk_prcmu *clk = to_clk_prcmu(hw);
> -	if (prcmu_request_clock(clk->cg_sel, false))
> +	if (db8500_prcmu_request_clock(clk->cg_sel, false))
>  		pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
>  		       clk_hw_get_name(hw));
>  }
> @@ -86,7 +86,7 @@ static int clk_prcmu_opp_prepare(struct clk_hw *hw)
>  		clk->opp_requested = 1;
>  	}
>  
> -	err = prcmu_request_clock(clk->cg_sel, true);
> +	err = db8500_prcmu_request_clock(clk->cg_sel, true);
>  	if (err) {
>  		prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
>  					(char *)clk_hw_get_name(hw));
> @@ -101,7 +101,7 @@ static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
>  {
>  	struct clk_prcmu *clk = to_clk_prcmu(hw);
>  
> -	if (prcmu_request_clock(clk->cg_sel, false)) {
> +	if (db8500_prcmu_request_clock(clk->cg_sel, false)) {
>  		pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
>  			clk_hw_get_name(hw));
>  		return;
> @@ -120,7 +120,7 @@ static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
>  	struct clk_prcmu *clk = to_clk_prcmu(hw);
>  
>  	if (!clk->opp_requested) {
> -		err = prcmu_request_ape_opp_100_voltage(true);
> +		err = db8500_prcmu_request_ape_opp_100_voltage(true);

[Severity: High]
This is a pre-existing issue, but does db8500_prcmu_request_ape_opp_100_voltage()
fail to rollback the requests counter on error?

When enable is true and requests is 0, the static requests counter is
incremented to 1 before sending the hardware mailbox request:

drivers/mfd/db8500-prcmu.c:db8500_prcmu_request_ape_opp_100_voltage() {
    if (enable) {
        if (0 != requests++)
            goto unlock_and_return;
    ...
    if ((mb1_transfer.ack.header != header) ||
        ((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0))
        r = -EIO;

    unlock_and_return:

If the hardware responds with an error, the function returns -EIO but appears
to fail to decrement the requests counter back to 0.


>  		if (err) {
>  			pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n",
>  				__func__, clk_hw_get_name(hw));
> @@ -129,9 +129,9 @@ static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
>  		clk->opp_requested = 1;
>  	}
>  
> -	err = prcmu_request_clock(clk->cg_sel, true);
> +	err = db8500_prcmu_request_clock(clk->cg_sel, true);
>  	if (err) {
> -		prcmu_request_ape_opp_100_voltage(false);
> +		db8500_prcmu_request_ape_opp_100_voltage(false);
>  		clk->opp_requested = 0;
>  		return err;
>  	}
> @@ -143,14 +143,14 @@ static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw)
>  {
>  	struct clk_prcmu *clk = to_clk_prcmu(hw);
>  
> -	if (prcmu_request_clock(clk->cg_sel, false)) {
> +	if (db8500_prcmu_request_clock(clk->cg_sel, false)) {
>  		pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
>  			clk_hw_get_name(hw));
>  		return;
>  	}
>  
>  	if (clk->opp_requested) {
> -		prcmu_request_ape_opp_100_voltage(false);
> +		db8500_prcmu_request_ape_opp_100_voltage(false);
>  		clk->opp_requested = 0;
>  	}
>  }
> diff --git a/drivers/clk/ux500/u8500_of_clk.c b/drivers/clk/ux500/u8500_of_clk.c
> index 6f78808387b1..d2499815226f 100644
> --- a/drivers/clk/ux500/u8500_of_clk.c
> +++ b/drivers/clk/ux500/u8500_of_clk.c
> @@ -9,7 +9,7 @@
>  #include <linux/of.h>
>  #include <linux/of_address.h>
>  #include <linux/clk-provider.h>
> -#include <linux/mfd/dbx500-prcmu.h>
> +#include <linux/mfd/db8500-prcmu.h>
>  
>  #include "clk.h"
>  #include "prcc.h"
> diff --git a/drivers/cpuidle/cpuidle-ux500.c b/drivers/cpuidle/cpuidle-ux500.c
> index f7d778580e9b..6d6c52c0bcc2 100644
> --- a/drivers/cpuidle/cpuidle-ux500.c
> +++ b/drivers/cpuidle/cpuidle-ux500.c
> @@ -11,7 +11,7 @@
>  #include <linux/spinlock.h>
>  #include <linux/atomic.h>
>  #include <linux/smp.h>
> -#include <linux/mfd/dbx500-prcmu.h>
> +#include <linux/mfd/db8500-prcmu.h>
>  #include <linux/platform_data/arm-ux500-pm.h>
>  #include <linux/platform_device.h>
>  
> @@ -66,7 +66,7 @@ static inline int ux500_enter_idle(struct cpuidle_device *dev,
>  		/* Go to the retention state, the prcmu will wait for the
>  		 * cpu to go WFI and this is what happens after exiting this
>  		 * 'master' critical section */
> -		if (prcmu_set_power_state(PRCMU_AP_IDLE, true, true))
> +		if (db8500_prcmu_set_power_state(PRCMU_AP_IDLE, true, true))
>  			goto out;

[Severity: High]
This isn't a bug introduced by this patch, but does calling this function
acquire a standard spinlock in the cpuidle execution path?

The cpuidle callback ux500_enter_idle() executes with local hardware interrupts
disabled. It calls db8500_prcmu_set_power_state(), which acquires a spinlock:

drivers/mfd/db8500-prcmu.c:db8500_prcmu_set_power_state() {
    ...
    spin_lock_irqsave(&mb0_transfer.lock, flags);


>  
>  		/* When we switch to retention, the prcmu is in charge
> @@ -109,7 +109,7 @@ static struct cpuidle_driver ux500_idle_driver = {
>  static int dbx500_cpuidle_probe(struct platform_device *pdev)
>  {
>  	/* Configure wake up reasons */
> -	prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) |
> +	db8500_prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) |
>  			     PRCMU_WAKEUP(ABB));
>  
>  	return cpuidle_register(&ux500_idle_driver, NULL);
> diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
> index f0bc0b5a6f4a..86fa99022cb3 100644
> --- a/drivers/mfd/ab8500-core.c
> +++ b/drivers/mfd/ab8500-core.c
> @@ -19,7 +19,7 @@
>  #include <linux/mfd/core.h>
>  #include <linux/mfd/abx500.h>
>  #include <linux/mfd/abx500/ab8500.h>
> -#include <linux/mfd/dbx500-prcmu.h>
> +#include <linux/mfd/db8500-prcmu.h>
>  #include <linux/of.h>
>  
>  /*
> diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
> index 21e68a382b11..6672c55f2ebc 100644
> --- a/drivers/mfd/db8500-prcmu.c
> +++ b/drivers/mfd/db8500-prcmu.c
> @@ -32,7 +32,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/uaccess.h>
>  #include <linux/mfd/core.h>
> -#include <linux/mfd/dbx500-prcmu.h>
> +#include <linux/mfd/db8500-prcmu.h>
>  #include <linux/mfd/abx500/ab8500.h>
>  #include <linux/regulator/db8500-prcmu.h>
>  #include <linux/regulator/machine.h>
> @@ -2285,7 +2285,7 @@ void db8500_prcmu_system_reset(u16 reset_code)
>  /**
>   * db8500_prcmu_get_reset_code - Retrieve SW reset reason code
>   *
> - * Retrieves the reset reason code stored by prcmu_system_reset() before
> + * Retrieves the reset reason code stored by db8500_prcmu_system_reset() before
>   * last restart.
>   */
>  u16 db8500_prcmu_get_reset_code(void)
> @@ -3041,7 +3041,7 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
>  
>  	db8500_irq_init(np);
>  
> -	prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
> +	db8500_prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
>  
>  	err = mfd_add_devices(&pdev->dev, 0, common_prcmu_devs,
>  			      ARRAY_SIZE(common_prcmu_devs), NULL, 0, db8500_irq_domain);
> diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c
> index 1ec2e1348891..751fe36580fa 100644
> --- a/drivers/regulator/db8500-prcmu.c
> +++ b/drivers/regulator/db8500-prcmu.c
> @@ -13,7 +13,7 @@
>  #include <linux/err.h>
>  #include <linux/spinlock.h>
>  #include <linux/platform_device.h>
> -#include <linux/mfd/dbx500-prcmu.h>
> +#include <linux/mfd/db8500-prcmu.h>
>  #include <linux/regulator/driver.h>
>  #include <linux/regulator/machine.h>
>  #include <linux/regulator/db8500-prcmu.h>
> @@ -93,13 +93,13 @@ static int enable_epod(u16 epod_id, bool ramret)
>  
>  	if (ramret) {
>  		if (!epod_on[epod_id]) {
> -			ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
> +			ret = db8500_prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
>  			if (ret < 0)
>  				return ret;
>  		}
>  		epod_ramret[epod_id] = true;
>  	} else {
> -		ret = prcmu_set_epod(epod_id, EPOD_STATE_ON);
> +		ret = db8500_prcmu_set_epod(epod_id, EPOD_STATE_ON);
>  		if (ret < 0)
>  			return ret;
>  		epod_on[epod_id] = true;
> @@ -114,18 +114,18 @@ static int disable_epod(u16 epod_id, bool ramret)
>  
>  	if (ramret) {
>  		if (!epod_on[epod_id]) {
> -			ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
> +			ret = db8500_prcmu_set_epod(epod_id, EPOD_STATE_OFF);
>  			if (ret < 0)
>  				return ret;
>  		}
>  		epod_ramret[epod_id] = false;
>  	} else {
>  		if (epod_ramret[epod_id]) {
> -			ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
> +			ret = db8500_prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
>  			if (ret < 0)
>  				return ret;
>  		} else {
> -			ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
> +			ret = db8500_prcmu_set_epod(epod_id, EPOD_STATE_OFF);
>  			if (ret < 0)
>  				return ret;
>  		}
> diff --git a/drivers/thermal/db8500_thermal.c b/drivers/thermal/db8500_thermal.c
> index 576f88b6a1b3..cf1706569e6d 100644
> --- a/drivers/thermal/db8500_thermal.c
> +++ b/drivers/thermal/db8500_thermal.c
> @@ -10,7 +10,7 @@
>  
>  #include <linux/cpu_cooling.h>
>  #include <linux/interrupt.h>
> -#include <linux/mfd/dbx500-prcmu.h>
> +#include <linux/mfd/db8500-prcmu.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <linux/platform_device.h>
> @@ -82,7 +82,7 @@ static void db8500_thermal_update_config(struct db8500_thermal_zone *th,
>  					 unsigned long next_low,
>  					 unsigned long next_high)
>  {
> -	prcmu_stop_temp_sense();
> +	db8500_prcmu_stop_temp_sense();
>  
>  	th->cur_index = idx;
>  	th->interpolated_temp = (next_low + next_high)/2;
> @@ -91,8 +91,8 @@ static void db8500_thermal_update_config(struct db8500_thermal_zone *th,
>  	 * The PRCMU accept absolute temperatures in celsius so divide
>  	 * down the millicelsius with 1000
>  	 */
> -	prcmu_config_hotmon((u8)(next_low/1000), (u8)(next_high/1000));
> -	prcmu_start_temp_sense(PRCMU_DEFAULT_MEASURE_TIME);
> +	db8500_prcmu_config_hotmon((u8)(next_low / 1000), (u8)(next_high / 1000));
> +	db8500_prcmu_start_temp_sense(PRCMU_DEFAULT_MEASURE_TIME);
>  }
>  
>  static irqreturn_t prcmu_low_irq_handler(int irq, void *irq_data)

[Severity: High]
This is a pre-existing issue, but do prcmu_low_irq_handler() and
prcmu_high_irq_handler() race to update the shared thermal state without
locking?

These two threaded IRQ handlers are registered for separate interrupt lines and
can be scheduled concurrently on different CPUs. Both handlers read and modify
th->cur_index and invoke hardware configuration functions without any
synchronization:

drivers/thermal/db8500_thermal.c:prcmu_low_irq_handler() {
    struct db8500_thermal_zone *th = irq_data;
    unsigned int idx = th->cur_index;
    ...
    db8500_thermal_update_config(th, idx, next_low, next_high);

drivers/thermal/db8500_thermal.c:prcmu_high_irq_handler() {
    struct db8500_thermal_zone *th = irq_data;
    unsigned int idx = th->cur_index;
    ...
    db8500_thermal_update_config(th, idx, next_low, next_high);

Could this data race corrupt the thermal zone state machine, leading to
incorrect temperature thresholds being programmed and out-of-sync
software/hardware states?

> @@ -204,7 +204,7 @@ static int db8500_thermal_probe(struct platform_device *pdev)
>  static int db8500_thermal_suspend(struct platform_device *pdev,
>  		pm_message_t state)
>  {
> -	prcmu_stop_temp_sense();
> +	db8500_prcmu_stop_temp_sense();
>  
>  	return 0;
>  }
> diff --git a/drivers/watchdog/db8500_wdt.c b/drivers/watchdog/db8500_wdt.c
> index 97148ac0aa54..70ccea13288d 100644
> --- a/drivers/watchdog/db8500_wdt.c
> +++ b/drivers/watchdog/db8500_wdt.c
> @@ -16,7 +16,7 @@
>  #include <linux/watchdog.h>
>  #include <linux/platform_device.h>
>  
> -#include <linux/mfd/dbx500-prcmu.h>
> +#include <linux/mfd/db8500-prcmu.h>
>  
>  #define WATCHDOG_TIMEOUT 600 /* 10 minutes */
>  
> @@ -37,24 +37,24 @@ MODULE_PARM_DESC(nowayout,
>  
>  static int db8500_wdt_start(struct watchdog_device *wdd)
>  {
> -	return prcmu_enable_a9wdog(PRCMU_WDOG_ALL);
> +	return db8500_prcmu_enable_a9wdog(PRCMU_WDOG_ALL);
>  }
>  
>  static int db8500_wdt_stop(struct watchdog_device *wdd)
>  {
> -	return prcmu_disable_a9wdog(PRCMU_WDOG_ALL);
> +	return db8500_prcmu_disable_a9wdog(PRCMU_WDOG_ALL);
>  }
>  
>  static int db8500_wdt_keepalive(struct watchdog_device *wdd)
>  {
> -	return prcmu_kick_a9wdog(PRCMU_WDOG_ALL);
> +	return db8500_prcmu_kick_a9wdog(PRCMU_WDOG_ALL);
>  }
>  
>  static int db8500_wdt_set_timeout(struct watchdog_device *wdd,
>  				 unsigned int timeout)
>  {
>  	db8500_wdt_stop(wdd);
> -	prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
> +	db8500_prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
>  	db8500_wdt_start(wdd);
>  
>  	return 0;
> @@ -91,10 +91,10 @@ static int db8500_wdt_probe(struct platform_device *pdev)
>  	watchdog_set_nowayout(&db8500_wdt, nowayout);
>  
>  	/* disable auto off on sleep */
> -	prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false);
> +	db8500_prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false);
>  
>  	/* set HW initial value */
> -	prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
> +	db8500_prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
>  
>  	ret = devm_watchdog_register_device(dev, &db8500_wdt);
>  	if (ret)
> @@ -110,9 +110,9 @@ static int db8500_wdt_suspend(struct platform_device *pdev,
>  {
>  	if (watchdog_active(&db8500_wdt)) {
>  		db8500_wdt_stop(&db8500_wdt);
> -		prcmu_config_a9wdog(PRCMU_WDOG_CPU1, true);
> +		db8500_prcmu_config_a9wdog(PRCMU_WDOG_CPU1, true);
>  
> -		prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
> +		db8500_prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
>  		db8500_wdt_start(&db8500_wdt);
>  	}
>  	return 0;
> @@ -122,9 +122,9 @@ static int db8500_wdt_resume(struct platform_device *pdev)
>  {
>  	if (watchdog_active(&db8500_wdt)) {
>  		db8500_wdt_stop(&db8500_wdt);
> -		prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false);
> +		db8500_prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false);
>  
> -		prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
> +		db8500_prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
>  		db8500_wdt_start(&db8500_wdt);
>  	}
>  	return 0;
> diff --git a/include/linux/mfd/db8500-prcmu.h b/include/linux/mfd/db8500-prcmu.h
> index a62de3d155ed..c939c9a1170a 100644
> --- a/include/linux/mfd/db8500-prcmu.h
> +++ b/include/linux/mfd/db8500-prcmu.h
> @@ -12,6 +12,9 @@
>  
>  #include <linux/interrupt.h>
>  #include <linux/bitops.h>
> +#include <linux/err.h>
> +
> +#include <dt-bindings/mfd/dbx500-prcmu.h> /* For clock identifiers */
>  
>  /*
>   * Registers
> @@ -24,6 +27,38 @@
>  #define DB8500_PRCM_DSI_SW_RESET_DSI1_SW_RESETN BIT(1)
>  #define DB8500_PRCM_DSI_SW_RESET_DSI2_SW_RESETN BIT(2)
>  
> +/* Offset for the firmware version within the TCPM */
> +#define DB8500_PRCMU_FW_VERSION_OFFSET 0xA4
> +
> +#define DB8500_PRCMU_LEGACY_OFFSET		0xDD4
> +
> +/*
> + * CLKOUT sources
> + */
> +#define PRCMU_CLKSRC_CLK38M		0x00
> +#define PRCMU_CLKSRC_ACLK		0x01
> +#define PRCMU_CLKSRC_SYSCLK		0x02
> +#define PRCMU_CLKSRC_LCDCLK		0x03
> +#define PRCMU_CLKSRC_SDMMCCLK		0x04
> +#define PRCMU_CLKSRC_TVCLK		0x05
> +#define PRCMU_CLKSRC_TIMCLK		0x06
> +#define PRCMU_CLKSRC_CLK009		0x07
> +/* These are only valid for CLKOUT1: */
> +#define PRCMU_CLKSRC_SIAMMDSPCLK	0x40
> +#define PRCMU_CLKSRC_I2CCLK		0x41
> +#define PRCMU_CLKSRC_MSP02CLK		0x42
> +#define PRCMU_CLKSRC_ARMPLL_OBSCLK	0x43
> +#define PRCMU_CLKSRC_HSIRXCLK		0x44
> +#define PRCMU_CLKSRC_HSITXCLK		0x45
> +#define PRCMU_CLKSRC_ARMCLKFIX		0x46
> +#define PRCMU_CLKSRC_HDMICLK		0x47
> +
> +/*
> + * Definitions for controlling ESRAM0 in deep sleep.
> + */
> +#define ESRAM0_DEEP_SLEEP_STATE_OFF 1
> +#define ESRAM0_DEEP_SLEEP_STATE_RET 2
> +
>  /* This portion previously known as <mach/prcmu-fw-defs_v1.h> */
>  
>  /**
> @@ -451,10 +486,173 @@ enum prcmu_power_status {
>  	PRCMU_ARMPENDINGIT_ER		= 0x93,
>  };
>  
> +/* PRCMU Wakeup defines */
> +enum prcmu_wakeup_index {
> +	PRCMU_WAKEUP_INDEX_RTC,
> +	PRCMU_WAKEUP_INDEX_RTT0,
> +	PRCMU_WAKEUP_INDEX_RTT1,
> +	PRCMU_WAKEUP_INDEX_HSI0,
> +	PRCMU_WAKEUP_INDEX_HSI1,
> +	PRCMU_WAKEUP_INDEX_USB,
> +	PRCMU_WAKEUP_INDEX_ABB,
> +	PRCMU_WAKEUP_INDEX_ABB_FIFO,
> +	PRCMU_WAKEUP_INDEX_ARM,
> +	PRCMU_WAKEUP_INDEX_CD_IRQ,
> +	NUM_PRCMU_WAKEUP_INDICES
> +};
> +
> +#define PRCMU_WAKEUP(_name) (BIT(PRCMU_WAKEUP_INDEX_##_name))
> +
> +/**
> + * enum prcmu_wdog_id - PRCMU watchdog IDs
> + * @PRCMU_WDOG_ALL: use all timers
> + * @PRCMU_WDOG_CPU1: use first CPU timer only
> + * @PRCMU_WDOG_CPU2: use second CPU timer conly
> + */
> +enum prcmu_wdog_id {
> +	PRCMU_WDOG_ALL = 0x00,
> +	PRCMU_WDOG_CPU1 = 0x01,
> +	PRCMU_WDOG_CPU2 = 0x02,
> +};
> +
> +/**
> + * enum ape_opp - APE OPP states definition
> + * @APE_OPP_INIT:
> + * @APE_NO_CHANGE: The APE operating point is unchanged
> + * @APE_100_OPP: The new APE operating point is ape100opp
> + * @APE_50_OPP: 50%
> + * @APE_50_PARTLY_25_OPP: 50%, except some clocks at 25%.
> + */
> +enum ape_opp {
> +	APE_OPP_INIT = 0x00,
> +	APE_NO_CHANGE = 0x01,
> +	APE_100_OPP = 0x02,
> +	APE_50_OPP = 0x03,
> +	APE_50_PARTLY_25_OPP = 0xFF,
> +};
> +
> +/**
> + * enum arm_opp - ARM OPP states definition
> + * @ARM_OPP_INIT:
> + * @ARM_NO_CHANGE: The ARM operating point is unchanged
> + * @ARM_100_OPP: The new ARM operating point is arm100opp
> + * @ARM_50_OPP: The new ARM operating point is arm50opp
> + * @ARM_MAX_OPP: Operating point is "max" (more than 100)
> + * @ARM_MAX_FREQ100OPP: Set max opp if available, else 100
> + * @ARM_EXTCLK: The new ARM operating point is armExtClk
> + */
> +enum arm_opp {
> +	ARM_OPP_INIT = 0x00,
> +	ARM_NO_CHANGE = 0x01,
> +	ARM_100_OPP = 0x02,
> +	ARM_50_OPP = 0x03,
> +	ARM_MAX_OPP = 0x04,
> +	ARM_MAX_FREQ100OPP = 0x05,
> +	ARM_EXTCLK = 0x07
> +};
> +
> +/**
> + * enum ddr_opp - DDR OPP states definition
> + * @DDR_100_OPP: The new DDR operating point is ddr100opp
> + * @DDR_50_OPP: The new DDR operating point is ddr50opp
> + * @DDR_25_OPP: The new DDR operating point is ddr25opp
> + */
> +enum ddr_opp {
> +	DDR_100_OPP = 0x00,
> +	DDR_50_OPP = 0x01,
> +	DDR_25_OPP = 0x02,
> +};
> +
> +/**
> + * enum ddr_pwrst - DDR power states definition
> + * @DDR_PWR_STATE_UNCHANGED: SDRAM and DDR controller state is unchanged
> + * @DDR_PWR_STATE_ON:
> + * @DDR_PWR_STATE_OFFLOWLAT:
> + * @DDR_PWR_STATE_OFFHIGHLAT:
> + */
> +enum ddr_pwrst {
> +	DDR_PWR_STATE_UNCHANGED     = 0x00,
> +	DDR_PWR_STATE_ON            = 0x01,
> +	DDR_PWR_STATE_OFFLOWLAT     = 0x02,
> +	DDR_PWR_STATE_OFFHIGHLAT    = 0x03
> +};
> +
>  /*
>   * Definitions for autonomous power management configuration.
>   */
>  
> +/* EPOD (power domain) IDs */
> +
> +/*
> + * DB8500 EPODs
> + * - EPOD_ID_SVAMMDSP: power domain for SVA MMDSP
> + * - EPOD_ID_SVAPIPE: power domain for SVA pipe
> + * - EPOD_ID_SIAMMDSP: power domain for SIA MMDSP
> + * - EPOD_ID_SIAPIPE: power domain for SIA pipe
> + * - EPOD_ID_SGA: power domain for SGA
> + * - EPOD_ID_B2R2_MCDE: power domain for B2R2 and MCDE
> + * - EPOD_ID_ESRAM12: power domain for ESRAM 1 and 2
> + * - EPOD_ID_ESRAM34: power domain for ESRAM 3 and 4
> + * - NUM_EPOD_ID: number of power domains
> + *
> + * TODO: These should be prefixed.
> + */
> +#define EPOD_ID_SVAMMDSP	0
> +#define EPOD_ID_SVAPIPE		1
> +#define EPOD_ID_SIAMMDSP	2
> +#define EPOD_ID_SIAPIPE		3
> +#define EPOD_ID_SGA		4
> +#define EPOD_ID_B2R2_MCDE	5
> +#define EPOD_ID_ESRAM12		6
> +#define EPOD_ID_ESRAM34		7
> +#define NUM_EPOD_ID		8
> +
> +/*
> + * state definition for EPOD (power domain)
> + * - EPOD_STATE_NO_CHANGE: The EPOD should remain unchanged
> + * - EPOD_STATE_OFF: The EPOD is switched off
> + * - EPOD_STATE_RAMRET: The EPOD is switched off with its internal RAM in
> + *                         retention
> + * - EPOD_STATE_ON_CLK_OFF: The EPOD is switched on, clock is still off
> + * - EPOD_STATE_ON: Same as above, but with clock enabled
> + */
> +#define EPOD_STATE_NO_CHANGE	0x00
> +#define EPOD_STATE_OFF		0x01
> +#define EPOD_STATE_RAMRET	0x02
> +#define EPOD_STATE_ON_CLK_OFF	0x03
> +#define EPOD_STATE_ON		0x04
> +
> +#define PRCMU_FW_PROJECT_U8500		2
> +#define PRCMU_FW_PROJECT_U8400		3
> +#define PRCMU_FW_PROJECT_U9500		4 /* Customer specific */
> +#define PRCMU_FW_PROJECT_U8500_MBB	5
> +#define PRCMU_FW_PROJECT_U8500_C1	6
> +#define PRCMU_FW_PROJECT_U8500_C2	7
> +#define PRCMU_FW_PROJECT_U8500_C3	8
> +#define PRCMU_FW_PROJECT_U8500_C4	9
> +#define PRCMU_FW_PROJECT_U9500_MBL	10
> +#define PRCMU_FW_PROJECT_U8500_SSG1	11 /* Samsung specific */
> +#define PRCMU_FW_PROJECT_U8500_MBL2	12 /* Customer specific */
> +#define PRCMU_FW_PROJECT_U8520		13
> +#define PRCMU_FW_PROJECT_U8420		14
> +#define PRCMU_FW_PROJECT_U8500_SSG2	15 /* Samsung specific */
> +#define PRCMU_FW_PROJECT_U8420_SYSCLK	17
> +#define PRCMU_FW_PROJECT_A9420		20
> +/* [32..63] 9540 and derivatives */
> +#define PRCMU_FW_PROJECT_U9540		32
> +/* [64..95] 8540 and derivatives */
> +#define PRCMU_FW_PROJECT_L8540		64
> +/* [96..126] 8580 and derivatives */
> +#define PRCMU_FW_PROJECT_L8580		96
> +
> +#define PRCMU_FW_PROJECT_NAME_LEN	20
> +
> +/* PRCMU QoS APE OPP class */
> +#define PRCMU_QOS_APE_OPP 1
> +#define PRCMU_QOS_DDR_OPP 2
> +#define PRCMU_QOS_ARM_OPP 3
> +#define PRCMU_QOS_DEFAULT_VALUE -1
> +
>  #define PRCMU_AUTO_PM_OFF 0
>  #define PRCMU_AUTO_PM_ON 1
>  
> @@ -469,6 +667,14 @@ enum prcmu_auto_pm_policy {
>  	PRCMU_AUTO_PM_POLICY_DSP_CLK_OFF_HWP_CLK_OFF,
>  };
>  
> +struct prcmu_fw_version {
> +	u32 project; /* Notice, project shifted with 8 on ux540 */
> +	u8 api_version;
> +	u8 func_version;
> +	u8 errata;
> +	char project_name[PRCMU_FW_PROJECT_NAME_LEN];
> +};
> +
>  /**
>   * struct prcmu_auto_pm_config - Autonomous power management configuration.
>   * @sia_auto_pm_enable: SIA autonomous pm enable. (PRCMU_AUTO_PM_{OFF,ON})
> @@ -501,6 +707,9 @@ void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
>  bool prcmu_is_auto_pm_enabled(void);
>  
>  int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
> +unsigned long prcmu_clock_rate(u8 clock);
> +long prcmu_round_clock_rate(u8 clock, unsigned long rate);
> +int prcmu_set_clock_rate(u8 clock, unsigned long rate);
>  int prcmu_set_clock_divider(u8 clock, u8 divider);
>  int db8500_prcmu_config_hotdog(u8 threshold);
>  int db8500_prcmu_config_hotmon(u8 low, u8 high);
> @@ -508,6 +717,8 @@ int db8500_prcmu_start_temp_sense(u16 cycles32k);
>  int db8500_prcmu_stop_temp_sense(void);
>  int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
>  int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
> +int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value,
> +			   u8 *mask, u8 size);
>  
>  int prcmu_ac_wake_req(void);
>  void prcmu_ac_sleep_req(void);
> @@ -610,6 +821,21 @@ static inline int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
>  	return 0;
>  }
>  
> +static inline unsigned long prcmu_clock_rate(u8 clock)
> +{
> +	return 0;
> +}
> +
> +static inline long prcmu_round_clock_rate(u8 clock, unsigned long rate)
> +{
> +	return 0;
> +}
> +
> +static inline int prcmu_set_clock_rate(u8 clock, unsigned long rate)
> +{
> +	return 0;
> +}
> +
>  static inline int prcmu_set_clock_divider(u8 clock, u8 divider)
>  {
>  	return 0;
> @@ -637,12 +863,18 @@ static inline int db8500_prcmu_stop_temp_sense(void)
>  
>  static inline int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
>  {
> -	return -ENOSYS;
> +	return -EINVAL;
>  }
>  
>  static inline int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
>  {
> -	return -ENOSYS;
> +	return -EINVAL;
> +}
> +
> +static inline int prcmu_abb_write_masked(u8 slave, u8 reg,
> +					 u8 *value, u8 *mask, u8 size)
> +{
> +	return -EINVAL;
>  }
>  
>  static inline int prcmu_ac_wake_req(void)
> @@ -745,4 +977,20 @@ static inline void db8500_prcmu_write_masked(unsigned int reg, u32 mask,
>  
>  #endif /* !CONFIG_MFD_DB8500_PRCMU */
>  
> +static inline int prcmu_qos_add_requirement(int prcmu_qos_class,
> +					    char *name, s32 value)
> +{
> +	return 0;
> +}
> +
> +static inline int prcmu_qos_update_requirement(int prcmu_qos_class,
> +					       char *name, s32 new_value)
> +{
> +	return 0;
> +}
> +
> +static inline void prcmu_qos_remove_requirement(int prcmu_qos_class, char *name)
> +{
> +}
> +
>  #endif /* __MFD_DB8500_PRCMU_H */
> diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h
> deleted file mode 100644
> index 828362b7860c..000000000000
> --- a/include/linux/mfd/dbx500-prcmu.h
> +++ /dev/null
> @@ -1,575 +0,0 @@
> -/* SPDX-License-Identifier: GPL-2.0-only */
> -/*
> - * Copyright (C) ST Ericsson SA 2011
> - *
> - * STE Ux500 PRCMU API
> - */
> -#ifndef __MACH_PRCMU_H
> -#define __MACH_PRCMU_H
> -
> -#include <linux/interrupt.h>
> -#include <linux/notifier.h>
> -#include <linux/err.h>
> -
> -#include <dt-bindings/mfd/dbx500-prcmu.h> /* For clock identifiers */
> -
> -/* Offset for the firmware version within the TCPM */
> -#define DB8500_PRCMU_FW_VERSION_OFFSET 0xA4
> -#define DBX540_PRCMU_FW_VERSION_OFFSET 0xA8
> -
> -/* PRCMU Wakeup defines */
> -enum prcmu_wakeup_index {
> -	PRCMU_WAKEUP_INDEX_RTC,
> -	PRCMU_WAKEUP_INDEX_RTT0,
> -	PRCMU_WAKEUP_INDEX_RTT1,
> -	PRCMU_WAKEUP_INDEX_HSI0,
> -	PRCMU_WAKEUP_INDEX_HSI1,
> -	PRCMU_WAKEUP_INDEX_USB,
> -	PRCMU_WAKEUP_INDEX_ABB,
> -	PRCMU_WAKEUP_INDEX_ABB_FIFO,
> -	PRCMU_WAKEUP_INDEX_ARM,
> -	PRCMU_WAKEUP_INDEX_CD_IRQ,
> -	NUM_PRCMU_WAKEUP_INDICES
> -};
> -#define PRCMU_WAKEUP(_name) (BIT(PRCMU_WAKEUP_INDEX_##_name))
> -
> -/* EPOD (power domain) IDs */
> -
> -/*
> - * DB8500 EPODs
> - * - EPOD_ID_SVAMMDSP: power domain for SVA MMDSP
> - * - EPOD_ID_SVAPIPE: power domain for SVA pipe
> - * - EPOD_ID_SIAMMDSP: power domain for SIA MMDSP
> - * - EPOD_ID_SIAPIPE: power domain for SIA pipe
> - * - EPOD_ID_SGA: power domain for SGA
> - * - EPOD_ID_B2R2_MCDE: power domain for B2R2 and MCDE
> - * - EPOD_ID_ESRAM12: power domain for ESRAM 1 and 2
> - * - EPOD_ID_ESRAM34: power domain for ESRAM 3 and 4
> - * - NUM_EPOD_ID: number of power domains
> - *
> - * TODO: These should be prefixed.
> - */
> -#define EPOD_ID_SVAMMDSP	0
> -#define EPOD_ID_SVAPIPE		1
> -#define EPOD_ID_SIAMMDSP	2
> -#define EPOD_ID_SIAPIPE		3
> -#define EPOD_ID_SGA		4
> -#define EPOD_ID_B2R2_MCDE	5
> -#define EPOD_ID_ESRAM12		6
> -#define EPOD_ID_ESRAM34		7
> -#define NUM_EPOD_ID		8
> -
> -/*
> - * state definition for EPOD (power domain)
> - * - EPOD_STATE_NO_CHANGE: The EPOD should remain unchanged
> - * - EPOD_STATE_OFF: The EPOD is switched off
> - * - EPOD_STATE_RAMRET: The EPOD is switched off with its internal RAM in
> - *                         retention
> - * - EPOD_STATE_ON_CLK_OFF: The EPOD is switched on, clock is still off
> - * - EPOD_STATE_ON: Same as above, but with clock enabled
> - */
> -#define EPOD_STATE_NO_CHANGE	0x00
> -#define EPOD_STATE_OFF		0x01
> -#define EPOD_STATE_RAMRET	0x02
> -#define EPOD_STATE_ON_CLK_OFF	0x03
> -#define EPOD_STATE_ON		0x04
> -
> -/*
> - * CLKOUT sources
> - */
> -#define PRCMU_CLKSRC_CLK38M		0x00
> -#define PRCMU_CLKSRC_ACLK		0x01
> -#define PRCMU_CLKSRC_SYSCLK		0x02
> -#define PRCMU_CLKSRC_LCDCLK		0x03
> -#define PRCMU_CLKSRC_SDMMCCLK		0x04
> -#define PRCMU_CLKSRC_TVCLK		0x05
> -#define PRCMU_CLKSRC_TIMCLK		0x06
> -#define PRCMU_CLKSRC_CLK009		0x07
> -/* These are only valid for CLKOUT1: */
> -#define PRCMU_CLKSRC_SIAMMDSPCLK	0x40
> -#define PRCMU_CLKSRC_I2CCLK		0x41
> -#define PRCMU_CLKSRC_MSP02CLK		0x42
> -#define PRCMU_CLKSRC_ARMPLL_OBSCLK	0x43
> -#define PRCMU_CLKSRC_HSIRXCLK		0x44
> -#define PRCMU_CLKSRC_HSITXCLK		0x45
> -#define PRCMU_CLKSRC_ARMCLKFIX		0x46
> -#define PRCMU_CLKSRC_HDMICLK		0x47
> -
> -/**
> - * enum prcmu_wdog_id - PRCMU watchdog IDs
> - * @PRCMU_WDOG_ALL: use all timers
> - * @PRCMU_WDOG_CPU1: use first CPU timer only
> - * @PRCMU_WDOG_CPU2: use second CPU timer conly
> - */
> -enum prcmu_wdog_id {
> -	PRCMU_WDOG_ALL = 0x00,
> -	PRCMU_WDOG_CPU1 = 0x01,
> -	PRCMU_WDOG_CPU2 = 0x02,
> -};
> -
> -/**
> - * enum ape_opp - APE OPP states definition
> - * @APE_OPP_INIT:
> - * @APE_NO_CHANGE: The APE operating point is unchanged
> - * @APE_100_OPP: The new APE operating point is ape100opp
> - * @APE_50_OPP: 50%
> - * @APE_50_PARTLY_25_OPP: 50%, except some clocks at 25%.
> - */
> -enum ape_opp {
> -	APE_OPP_INIT = 0x00,
> -	APE_NO_CHANGE = 0x01,
> -	APE_100_OPP = 0x02,
> -	APE_50_OPP = 0x03,
> -	APE_50_PARTLY_25_OPP = 0xFF,
> -};
> -
> -/**
> - * enum arm_opp - ARM OPP states definition
> - * @ARM_OPP_INIT:
> - * @ARM_NO_CHANGE: The ARM operating point is unchanged
> - * @ARM_100_OPP: The new ARM operating point is arm100opp
> - * @ARM_50_OPP: The new ARM operating point is arm50opp
> - * @ARM_MAX_OPP: Operating point is "max" (more than 100)
> - * @ARM_MAX_FREQ100OPP: Set max opp if available, else 100
> - * @ARM_EXTCLK: The new ARM operating point is armExtClk
> - */
> -enum arm_opp {
> -	ARM_OPP_INIT = 0x00,
> -	ARM_NO_CHANGE = 0x01,
> -	ARM_100_OPP = 0x02,
> -	ARM_50_OPP = 0x03,
> -	ARM_MAX_OPP = 0x04,
> -	ARM_MAX_FREQ100OPP = 0x05,
> -	ARM_EXTCLK = 0x07
> -};
> -
> -/**
> - * enum ddr_opp - DDR OPP states definition
> - * @DDR_100_OPP: The new DDR operating point is ddr100opp
> - * @DDR_50_OPP: The new DDR operating point is ddr50opp
> - * @DDR_25_OPP: The new DDR operating point is ddr25opp
> - */
> -enum ddr_opp {
> -	DDR_100_OPP = 0x00,
> -	DDR_50_OPP = 0x01,
> -	DDR_25_OPP = 0x02,
> -};
> -
> -/*
> - * Definitions for controlling ESRAM0 in deep sleep.
> - */
> -#define ESRAM0_DEEP_SLEEP_STATE_OFF 1
> -#define ESRAM0_DEEP_SLEEP_STATE_RET 2
> -
> -/**
> - * enum ddr_pwrst - DDR power states definition
> - * @DDR_PWR_STATE_UNCHANGED: SDRAM and DDR controller state is unchanged
> - * @DDR_PWR_STATE_ON:
> - * @DDR_PWR_STATE_OFFLOWLAT:
> - * @DDR_PWR_STATE_OFFHIGHLAT:
> - */
> -enum ddr_pwrst {
> -	DDR_PWR_STATE_UNCHANGED     = 0x00,
> -	DDR_PWR_STATE_ON            = 0x01,
> -	DDR_PWR_STATE_OFFLOWLAT     = 0x02,
> -	DDR_PWR_STATE_OFFHIGHLAT    = 0x03
> -};
> -
> -#define DB8500_PRCMU_LEGACY_OFFSET		0xDD4
> -
> -#define PRCMU_FW_PROJECT_U8500		2
> -#define PRCMU_FW_PROJECT_U8400		3
> -#define PRCMU_FW_PROJECT_U9500		4 /* Customer specific */
> -#define PRCMU_FW_PROJECT_U8500_MBB	5
> -#define PRCMU_FW_PROJECT_U8500_C1	6
> -#define PRCMU_FW_PROJECT_U8500_C2	7
> -#define PRCMU_FW_PROJECT_U8500_C3	8
> -#define PRCMU_FW_PROJECT_U8500_C4	9
> -#define PRCMU_FW_PROJECT_U9500_MBL	10
> -#define PRCMU_FW_PROJECT_U8500_SSG1	11 /* Samsung specific */
> -#define PRCMU_FW_PROJECT_U8500_MBL2	12 /* Customer specific */
> -#define PRCMU_FW_PROJECT_U8520		13
> -#define PRCMU_FW_PROJECT_U8420		14
> -#define PRCMU_FW_PROJECT_U8500_SSG2	15 /* Samsung specific */
> -#define PRCMU_FW_PROJECT_U8420_SYSCLK	17
> -#define PRCMU_FW_PROJECT_A9420		20
> -/* [32..63] 9540 and derivatives */
> -#define PRCMU_FW_PROJECT_U9540		32
> -/* [64..95] 8540 and derivatives */
> -#define PRCMU_FW_PROJECT_L8540		64
> -/* [96..126] 8580 and derivatives */
> -#define PRCMU_FW_PROJECT_L8580		96
> -
> -#define PRCMU_FW_PROJECT_NAME_LEN	20
> -struct prcmu_fw_version {
> -	u32 project; /* Notice, project shifted with 8 on ux540 */
> -	u8 api_version;
> -	u8 func_version;
> -	u8 errata;
> -	char project_name[PRCMU_FW_PROJECT_NAME_LEN];
> -};
> -
> -#include <linux/mfd/db8500-prcmu.h>
> -
> -#if defined(CONFIG_UX500_SOC_DB8500)
> -
> -static inline void __init prcmu_early_init(void)
> -{
> -	db8500_prcmu_early_init();
> -}
> -
> -static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
> -		bool keep_ap_pll)
> -{
> -	return db8500_prcmu_set_power_state(state, keep_ulp_clk,
> -		keep_ap_pll);
> -}
> -
> -static inline u8 prcmu_get_power_state_result(void)
> -{
> -	return db8500_prcmu_get_power_state_result();
> -}
> -
> -static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
> -{
> -	return db8500_prcmu_set_epod(epod_id, epod_state);
> -}
> -
> -static inline void prcmu_enable_wakeups(u32 wakeups)
> -{
> -	db8500_prcmu_enable_wakeups(wakeups);
> -}
> -
> -static inline void prcmu_disable_wakeups(void)
> -{
> -	prcmu_enable_wakeups(0);
> -}
> -
> -static inline void prcmu_config_abb_event_readout(u32 abb_events)
> -{
> -	db8500_prcmu_config_abb_event_readout(abb_events);
> -}
> -
> -static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
> -{
> -	db8500_prcmu_get_abb_event_buffer(buf);
> -}
> -
> -int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
> -int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
> -int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask, u8 size);
> -
> -int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
> -
> -static inline int prcmu_request_clock(u8 clock, bool enable)
> -{
> -	return db8500_prcmu_request_clock(clock, enable);
> -}
> -
> -unsigned long prcmu_clock_rate(u8 clock);
> -long prcmu_round_clock_rate(u8 clock, unsigned long rate);
> -int prcmu_set_clock_rate(u8 clock, unsigned long rate);
> -
> -static inline int prcmu_get_ddr_opp(void)
> -{
> -	return db8500_prcmu_get_ddr_opp();
> -}
> -
> -static inline int prcmu_set_arm_opp(u8 opp)
> -{
> -	return db8500_prcmu_set_arm_opp(opp);
> -}
> -
> -static inline int prcmu_get_arm_opp(void)
> -{
> -	return db8500_prcmu_get_arm_opp();
> -}
> -
> -static inline int prcmu_set_ape_opp(u8 opp)
> -{
> -	return db8500_prcmu_set_ape_opp(opp);
> -}
> -
> -static inline int prcmu_get_ape_opp(void)
> -{
> -	return db8500_prcmu_get_ape_opp();
> -}
> -
> -static inline int prcmu_request_ape_opp_100_voltage(bool enable)
> -{
> -	return db8500_prcmu_request_ape_opp_100_voltage(enable);
> -}
> -
> -static inline void prcmu_system_reset(u16 reset_code)
> -{
> -	db8500_prcmu_system_reset(reset_code);
> -}
> -
> -static inline u16 prcmu_get_reset_code(void)
> -{
> -	return db8500_prcmu_get_reset_code();
> -}
> -
> -int prcmu_ac_wake_req(void);
> -void prcmu_ac_sleep_req(void);
> -static inline void prcmu_modem_reset(void)
> -{
> -	db8500_prcmu_modem_reset();
> -}
> -
> -static inline bool prcmu_is_ac_wake_requested(void)
> -{
> -	return db8500_prcmu_is_ac_wake_requested();
> -}
> -
> -static inline int prcmu_config_esram0_deep_sleep(u8 state)
> -{
> -	return db8500_prcmu_config_esram0_deep_sleep(state);
> -}
> -
> -static inline int prcmu_config_hotdog(u8 threshold)
> -{
> -	return db8500_prcmu_config_hotdog(threshold);
> -}
> -
> -static inline int prcmu_config_hotmon(u8 low, u8 high)
> -{
> -	return db8500_prcmu_config_hotmon(low, high);
> -}
> -
> -static inline int prcmu_start_temp_sense(u16 cycles32k)
> -{
> -	return  db8500_prcmu_start_temp_sense(cycles32k);
> -}
> -
> -static inline int prcmu_stop_temp_sense(void)
> -{
> -	return  db8500_prcmu_stop_temp_sense();
> -}
> -
> -static inline u32 prcmu_read(unsigned int reg)
> -{
> -	return db8500_prcmu_read(reg);
> -}
> -
> -static inline void prcmu_write(unsigned int reg, u32 value)
> -{
> -	db8500_prcmu_write(reg, value);
> -}
> -
> -static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
> -{
> -	db8500_prcmu_write_masked(reg, mask, value);
> -}
> -
> -static inline int prcmu_enable_a9wdog(u8 id)
> -{
> -	return db8500_prcmu_enable_a9wdog(id);
> -}
> -
> -static inline int prcmu_disable_a9wdog(u8 id)
> -{
> -	return db8500_prcmu_disable_a9wdog(id);
> -}
> -
> -static inline int prcmu_kick_a9wdog(u8 id)
> -{
> -	return db8500_prcmu_kick_a9wdog(id);
> -}
> -
> -static inline int prcmu_load_a9wdog(u8 id, u32 timeout)
> -{
> -	return db8500_prcmu_load_a9wdog(id, timeout);
> -}
> -
> -static inline int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
> -{
> -	return db8500_prcmu_config_a9wdog(num, sleep_auto_off);
> -}
> -#else
> -
> -static inline void prcmu_early_init(void) {}
> -
> -static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
> -	bool keep_ap_pll)
> -{
> -	return 0;
> -}
> -
> -static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
> -{
> -	return 0;
> -}
> -
> -static inline void prcmu_enable_wakeups(u32 wakeups) {}
> -
> -static inline void prcmu_disable_wakeups(void) {}
> -
> -static inline int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
> -{
> -	return -ENOSYS;
> -}
> -
> -static inline int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
> -{
> -	return -ENOSYS;
> -}
> -
> -static inline int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask,
> -	u8 size)
> -{
> -	return -ENOSYS;
> -}
> -
> -static inline int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
> -{
> -	return 0;
> -}
> -
> -static inline int prcmu_request_clock(u8 clock, bool enable)
> -{
> -	return 0;
> -}
> -
> -static inline long prcmu_round_clock_rate(u8 clock, unsigned long rate)
> -{
> -	return 0;
> -}
> -
> -static inline int prcmu_set_clock_rate(u8 clock, unsigned long rate)
> -{
> -	return 0;
> -}
> -
> -static inline unsigned long prcmu_clock_rate(u8 clock)
> -{
> -	return 0;
> -}
> -
> -static inline int prcmu_set_ape_opp(u8 opp)
> -{
> -	return 0;
> -}
> -
> -static inline int prcmu_get_ape_opp(void)
> -{
> -	return APE_100_OPP;
> -}
> -
> -static inline int prcmu_request_ape_opp_100_voltage(bool enable)
> -{
> -	return 0;
> -}
> -
> -static inline int prcmu_set_arm_opp(u8 opp)
> -{
> -	return 0;
> -}
> -
> -static inline int prcmu_get_arm_opp(void)
> -{
> -	return ARM_100_OPP;
> -}
> -
> -static inline int prcmu_get_ddr_opp(void)
> -{
> -	return DDR_100_OPP;
> -}
> -
> -static inline void prcmu_system_reset(u16 reset_code) {}
> -
> -static inline u16 prcmu_get_reset_code(void)
> -{
> -	return 0;
> -}
> -
> -static inline int prcmu_ac_wake_req(void)
> -{
> -	return 0;
> -}
> -
> -static inline void prcmu_ac_sleep_req(void) {}
> -
> -static inline void prcmu_modem_reset(void) {}
> -
> -static inline bool prcmu_is_ac_wake_requested(void)
> -{
> -	return false;
> -}
> -
> -static inline int prcmu_config_esram0_deep_sleep(u8 state)
> -{
> -	return 0;
> -}
> -
> -static inline void prcmu_config_abb_event_readout(u32 abb_events) {}
> -
> -static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
> -{
> -	*buf = NULL;
> -}
> -
> -static inline int prcmu_config_hotdog(u8 threshold)
> -{
> -	return 0;
> -}
> -
> -static inline int prcmu_config_hotmon(u8 low, u8 high)
> -{
> -	return 0;
> -}
> -
> -static inline int prcmu_start_temp_sense(u16 cycles32k)
> -{
> -	return 0;
> -}
> -
> -static inline int prcmu_stop_temp_sense(void)
> -{
> -	return 0;
> -}
> -
> -static inline u32 prcmu_read(unsigned int reg)
> -{
> -	return 0;
> -}
> -
> -static inline void prcmu_write(unsigned int reg, u32 value) {}
> -
> -static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {}
> -
> -#endif
> -
> -static inline void prcmu_set(unsigned int reg, u32 bits)
> -{
> -	prcmu_write_masked(reg, bits, bits);
> -}
> -
> -static inline void prcmu_clear(unsigned int reg, u32 bits)
> -{
> -	prcmu_write_masked(reg, bits, 0);
> -}
> -
> -/* PRCMU QoS APE OPP class */
> -#define PRCMU_QOS_APE_OPP 1
> -#define PRCMU_QOS_DDR_OPP 2
> -#define PRCMU_QOS_ARM_OPP 3
> -#define PRCMU_QOS_DEFAULT_VALUE -1
> -
> -static inline int prcmu_qos_add_requirement(int prcmu_qos_class,
> -					    char *name, s32 value)
> -{
> -	return 0;
> -}
> -
> -static inline int prcmu_qos_update_requirement(int prcmu_qos_class,
> -					       char *name, s32 new_value)
> -{
> -	return 0;
> -}
> -
> -static inline void prcmu_qos_remove_requirement(int prcmu_qos_class, char *name)
> -{
> -}
> -
> -#endif /* __MACH_PRCMU_H */
> diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
> index 7798957c6504..499e826d7120 100644
> --- a/sound/soc/ux500/ux500_msp_dai.c
> +++ b/sound/soc/ux500/ux500_msp_dai.c
> @@ -14,7 +14,7 @@
>  #include <linux/clk.h>
>  #include <linux/of.h>
>  #include <linux/regulator/consumer.h>
> -#include <linux/mfd/dbx500-prcmu.h>
> +#include <linux/mfd/db8500-prcmu.h>
>  
>  #include <sound/soc.h>
>  #include <sound/soc-dai.h>
> 
> ---
> base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
> change-id: 20260619-mfd-prcmu-merge-headers-bc84905195b4
> 
> Best regards,
> -- 
> Linus Walleij <linusw@kernel.org>
> 

-- 
Lee Jones


^ permalink raw reply

* Re: [PATCH v2 6/6] mm/mprotect: use huge_ptep_get() for hugetlb
From: David Hildenbrand (Arm) @ 2026-07-02 15:47 UTC (permalink / raw)
  To: Dev Jain, muchun.song, osalvador, akpm, ljs, liam
  Cc: riel, vbabka, harry, jannh, lance.yang, kas, linux-mm,
	linux-kernel, rcampbell, apopple, ziy, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, j-nomura,
	nao.horiguchi, ak, mel, pfalcato, jpoimboe, dave.hansen, tglx,
	catalin.marinas, will, linux-arm-kernel, ryan.roberts,
	anshuman.khandual
In-Reply-To: <20260702051341.126509-7-dev.jain@arm.com>

On 7/2/26 07:13, Dev Jain wrote:
> prot_none_hugetlb_entry() is the hugetlb callback for the early
> mprotect(PROT_NONE) PFN permission walk on x86.
> 
> The callback passes the decoded PFN to pfn_modify_allowed(). For a
> hugetlb callback, the pte pointer refers to a hugetlb entry. On
> architectures where hugetlb entries need huge_ptep_get(), reading that
> entry with ptep_get() can make the permission check use the wrong PFN.
> 
> Use huge_ptep_get() before decoding the hugetlb PFN.
> 
> Currently there is no path which can trigger a bug: huge_ptep_get() is a
> simple ptep_get() for x86, and the prot_none walk occurs only for x86.
> 
> So no need to backport - use the correct helper anyways.
> 
> Fixes: 42e4089c7890 ("x86/speculation/l1tf: Disallow non privileged high MMIO PROT_NONE mappings")
> Signed-off-by: Dev Jain <dev.jain@arm.com>
> ---
>  mm/mprotect.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/mm/mprotect.c b/mm/mprotect.c
> index 9cbf932b028cf..23779632d18bf 100644
> --- a/mm/mprotect.c
> +++ b/mm/mprotect.c
> @@ -699,14 +699,20 @@ static int prot_none_pte_entry(pte_t *pte, unsigned long addr,
>  		0 : -EACCES;
>  }
>  
> +#ifdef CONFIG_HUGETLB_PAGE
>  static int prot_none_hugetlb_entry(pte_t *pte, unsigned long hmask,
>  				   unsigned long addr, unsigned long next,
>  				   struct mm_walk *walk)
>  {
> -	return pfn_modify_allowed(pte_pfn(ptep_get(pte)),
> +	pte_t entry = huge_ptep_get(walk->mm, addr, pte);

Nit: can be const :)

> +
> +	return pfn_modify_allowed(pte_pfn(entry),
>  				  *(pgprot_t *)(walk->private)) ?
>  		0 : -EACCES;

Indentation is odd.

Can we just make this readable?

if (pfn_modify_allowed ...)
	return 0
return -EACCESS;


-- 
Cheers,

David


^ permalink raw reply

* Re: (subset) [PATCH] mfd: db8500-prcmu: Fold dbx500 header into db8500
From: Lee Jones @ 2026-07-02 15:48 UTC (permalink / raw)
  To: Russell King, Ulf Hansson, Michael Turquette, Stephen Boyd,
	Brian Masney, Rafael J. Wysocki, Daniel Lezcano, Christian Loehle,
	Lee Jones, Liam Girdwood, Mark Brown, Zhang Rui, Lukasz Luba,
	Wim Van Sebroeck, Guenter Roeck, Jaroslav Kysela, Takashi Iwai,
	Linus Walleij
  Cc: linux-arm-kernel, linux-clk, linux-pm, linux-watchdog,
	linux-sound, kernel test robot
In-Reply-To: <20260619-mfd-prcmu-merge-headers-v1-1-8ea0ee23b4d6@kernel.org>

On Fri, 19 Jun 2026 22:27:10 +0200, Linus Walleij wrote:
> Move the DBx500 PRCMU definitions into the DB8500 PRCMU
> header and delete the wrapper header.
> 
> Convert users of simple PRCMU wrappers to call the DB8500 helpers
> directly.
> 
> The dbx500-prcmu.h header was the result of an earlier attempt to
> abstract several DBx5x SoC PRCMU units to use the same abstract
> header. They are deleted from the kernel and this is not just
> causing maintenance burden and build errors.
> 
> [...]

Applied, thanks!

[1/1] mfd: db8500-prcmu: Fold dbx500 header into db8500
      commit: 6fd345e209284bc939693989bb7144133a8e93fd

--
Lee Jones [李琼斯]



^ permalink raw reply

* Re: [PATCH 09/11] regulator: db8500-prcmu: Remove EPOD regulators
From: Lee Jones @ 2026-07-02 15:51 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
	Mark Brown, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Vinod Koul, Frank Li,
	linux-arm-kernel, devicetree, linux-pm, dri-devel, dmaengine
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-9-eb5e50b1a588@kernel.org>

On Thu, 18 Jun 2026, Linus Walleij wrote:

> Remove the obsolete DB8500 PRCMU regulator drivers.
> 
> Drop the regulator build hooks now that EPODs are power domains.
> 
> Keep the MFD cell around because a later patch reuses it for a
> small compatibility regulator driver.
> 
> Assisted-by: Codex:gpt-5-5
> Signed-off-by: Linus Walleij <linusw@kernel.org>
> ---
>  drivers/mfd/db8500-prcmu.c             | 239 +---------------
>  drivers/regulator/Kconfig              |  12 -
>  drivers/regulator/Makefile             |   2 -
>  drivers/regulator/db8500-prcmu.c       | 501 ---------------------------------
>  drivers/regulator/dbx500-prcmu.c       | 155 ----------
>  drivers/regulator/dbx500-prcmu.h       |  55 ----
>  include/linux/regulator/db8500-prcmu.h |  38 ---
>  7 files changed, 1 insertion(+), 1001 deletions(-)

Any deps?

-- 
Lee Jones


^ permalink raw reply

* [PATCH v8 09/39] drm/display: hdmi-state-helper: Add fallback TMDS rate validation
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
	Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
	Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
  Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>

Validate the computed TMDS character rate against
connector->hdmi.max_tmds_char_rate when no driver-specific
tmds_char_rate_valid() hook is provided.

This gives HDMI connectors a common fallback for rejecting modes whose
TMDS character rate exceeds the connector limit, while still allowing
drivers with custom validation requirements to implement their own
tmds_char_rate_valid() callback.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index ce17eeefc2da..db76699093e8 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -566,6 +566,9 @@ hdmi_clock_valid(const struct drm_connector *connector,
 		status = funcs->tmds_char_rate_valid(connector, mode, clock);
 		if (status != MODE_OK)
 			return status;
+	} else if (connector->hdmi.max_tmds_char_rate) {
+		if (clock > connector->hdmi.max_tmds_char_rate)
+			return MODE_CLOCK_HIGH;
 	}
 
 	return MODE_OK;

-- 
2.54.0



^ permalink raw reply related

* Re: [PATCH v3 1/1] reset: imx7: Correct polarity of MIPI CSI resets on i.MX8MQ
From: Philipp Zabel @ 2026-07-02 15:53 UTC (permalink / raw)
  To: robby.cai, Frank.Li, s.hauer, festevam
  Cc: krzk+dt, andrew.smirnov, kernel, imx, linux-arm-kernel,
	linux-kernel, aisheng.dong, guoniu.zhou
In-Reply-To: <20260619073115.3778313-1-robby.cai@oss.nxp.com>

On Fr, 2026-06-19 at 15:31 +0800, robby.cai@oss.nxp.com wrote:
> From: Robby Cai <robby.cai@nxp.com>
> 
> On i.MX8MQ, the MIPI CSI reset lines are active-low and not self-clearing.
> Writing '0' asserts reset and it remains asserted until explicitly
> deasserted by software.
> 
> This driver previously treated the MIPI CSI reset signals as active-high,
> which led to incorrect reset assert/deassert sequencing. This issue was
> exposed by commit 6d79bb8fd2aa ("media: imx8mq-mipi-csi2: Explicitly
> release reset").
> 
> Fix this by reflecting the correct reset polarity and ensuring proper
> reset handling.
[...]

Applied to reset/fixes, thanks!

[1/1] reset: imx7: Correct polarity of MIPI CSI resets on i.MX8MQ
      https://git.kernel.org/pub/scm/linux/kernel/git/pza/linux.git/commit/?id=71827776667f

regards
Philipp


^ permalink raw reply

* [PATCH v8 06/39] drm/display: scdc-helper: Add helper to set SCDC version information
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
	Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
	Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
  Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>

The HDMI 2.x specs mandate that compliant Sink devices report their SCDC
version in the Sink Version register, which reads as 1 on any
SCDC-capable sink.

There is also a dedicated Source Version register.  Writing it is not
compulsory, but the spec advises that compliant Source devices do so, in
which case the value must be 1.

Add drm_scdc_set_source_version() to follow this recommendation.  The
Sink Version register is read first, both to log the advertised SCDC
version and to guard against non-conformant devices: a sink reporting
version 0 is either not SCDC-version-aware or broken, so writing the
source version gains nothing and risks upsetting such hardware.  In that
case the write is skipped.

The source version is passed as a parameter rather than hardcoded, as
future spec revisions may define additional rules for the allowable
version values.  The written value is additionally clamped to the sink's
reported version so the source never advertises a version the sink does
not understand.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
 drivers/gpu/drm/display/drm_scdc_helper.c | 46 ++++++++++++++++++++++++++++++-
 include/drm/display/drm_scdc_helper.h     |  2 ++
 2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/display/drm_scdc_helper.c b/drivers/gpu/drm/display/drm_scdc_helper.c
index cb6632346aad..6d804ee19420 100644
--- a/drivers/gpu/drm/display/drm_scdc_helper.c
+++ b/drivers/gpu/drm/display/drm_scdc_helper.c
@@ -21,10 +21,11 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/i2c.h>
+#include <linux/minmax.h>
 #include <linux/slab.h>
-#include <linux/delay.h>
 
 #include <drm/display/drm_scdc_helper.h>
 #include <drm/drm_connector.h>
@@ -270,3 +271,46 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
 	return true;
 }
 EXPORT_SYMBOL(drm_scdc_set_high_tmds_clock_ratio);
+
+/**
+ * drm_scdc_set_source_version - set SCDC source version on the sink
+ * @connector: connector
+ * @ver: source version to advertise (per spec, 1)
+ *
+ * Reads the sink version for diagnostics and as a guard, then writes
+ * the source version unless the sink reports version 0.
+ *
+ * Returns:
+ * 0 on success or when skipped; a negative error code when either
+ * the read or the write failed.
+ */
+int drm_scdc_set_source_version(struct drm_connector *connector, u8 ver)
+{
+	u8 sink_ver;
+	int ret;
+
+	ret = drm_scdc_readb(connector->ddc, SCDC_SINK_VERSION, &sink_ver);
+	if (ret) {
+		drm_scdc_dbg(connector, "Failed to read SCDC_SINK_VERSION: %d\n", ret);
+		return ret;
+	}
+
+	drm_scdc_dbg(connector, "Sink reported SCDC ver. %u\n", sink_ver);
+
+	/*
+	 * Only advertise our source version to sinks that report a
+	 * non-zero sink version.  A sink reporting version 0 is either
+	 * not SCDC-version-aware or non-conformant; writing the source
+	 * version gains nothing and may upset broken hardware.
+	 */
+	if (sink_ver) {
+		ret = drm_scdc_writeb(connector->ddc, SCDC_SOURCE_VERSION,
+				      min_t(u8, sink_ver, ver));
+		if (ret)
+			drm_scdc_dbg(connector,
+				     "Failed to write SCDC_SOURCE_VERSION: %d\n", ret);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_scdc_set_source_version);
diff --git a/include/drm/display/drm_scdc_helper.h b/include/drm/display/drm_scdc_helper.h
index 34600476a1b9..90b0828364c2 100644
--- a/include/drm/display/drm_scdc_helper.h
+++ b/include/drm/display/drm_scdc_helper.h
@@ -77,4 +77,6 @@ bool drm_scdc_get_scrambling_status(struct drm_connector *connector);
 bool drm_scdc_set_scrambling(struct drm_connector *connector, bool enable);
 bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector, bool set);
 
+int drm_scdc_set_source_version(struct drm_connector *connector, u8 ver);
+
 #endif

-- 
2.54.0



^ permalink raw reply related

* Re: [PATCH v2 1/4] dt-bindings: can: rockchip: add rk3588 CAN-FD compatible
From: Heiko Stübner @ 2026-07-02 16:01 UTC (permalink / raw)
  To: Marc Kleine-Budde, linux-can, 1579567540
  Cc: Vincent Mailhol, Rob Herring, Krzysztof Kozlowski, kernel,
	Conor Dooley, Dmitry Torokhov, Shengjiu Wang, Pengpeng Hou,
	Russell King, Eric Biggers, Mario Limonciello, Karl Mehltretter,
	Yixun Lan, Stephen Boyd, devicetree, linux-arm-kernel,
	linux-rockchip, linux-kernel, Cunhao Lu
In-Reply-To: <tencent_3B2B6003D1DE4FB7A984665A062581766405@qq.com>

Am Donnerstag, 2. Juli 2026, 16:06:51 Mitteleuropäische Sommerzeit schrieb 1579567540@qq.com:
> From: Cunhao Lu <1579567540@qq.com>
> 
> RK3588 integrates a Rockchip CAN-FD controller variant that is not
> fully compatible with RK3568v2. The RX FIFO count register field is
> encoded in bits 7:5 on RK3588, while RK3568v2 uses bits 6:4.
> 
> Add a dedicated rockchip,rk3588-canfd compatible to describe this
> variant. Do not use rockchip,rk3568v2-canfd as a fallback, because that
> would describe a register layout that does not match the hardware.
> 
> Changes in v2:
> - Use enum for the single-compatible entries, as suggested by Krzysztof.
> - Reword the commit message to explain the hardware difference instead
>   of referring to Linux driver match data.
> 
> Signed-off-by: Cunhao Lu <1579567540@qq.com>

after fixing  Krzysztof's comment:
Reviewed-by: Heiko Stuebner <heiko@sntech.de>

and doing dtbscheck of the binding against the dt-patches:
Tested-by: Heiko Stuebner <heiko@sntech.de>






^ permalink raw reply

* Re: [PATCH v2 2/4] can: rockchip: add RK3588 CAN support
From: Heiko Stübner @ 2026-07-02 16:02 UTC (permalink / raw)
  To: Marc Kleine-Budde, linux-can, 1579567540
  Cc: Vincent Mailhol, Rob Herring, Krzysztof Kozlowski, kernel,
	Conor Dooley, Dmitry Torokhov, Shengjiu Wang, Pengpeng Hou,
	Russell King, Eric Biggers, Mario Limonciello, Karl Mehltretter,
	Yixun Lan, Stephen Boyd, devicetree, linux-arm-kernel,
	linux-rockchip, linux-kernel, Cunhao Lu, Heiko Stuebner
In-Reply-To: <tencent_F077D309CDB6CC4802CC086D8009E29BDF06@qq.com>

Am Donnerstag, 2. Juli 2026, 16:06:52 Mitteleuropäische Sommerzeit schrieb 1579567540@qq.com:
> From: Cunhao Lu <1579567540@qq.com>
> 
> Add support for the RK3588 CAN controller by introducing a dedicated
> model ID and OF match entry.
> 
> The block is closely related to the existing RK3568 variants, but it
> cannot reuse their match data unchanged. In particular, RK3588
> encodes RX_FIFO_CNT in bits 7:5 instead of 6:4, so the RX path needs
> SoC-specific handling.
> 
> The RX FIFO count bitfield difference was found by comparing Rockchip's
> vendor kernel 6.1 CAN support for RK3568 and RK3588. Runtime testing on
> RK3588 also confirms that bits 7:5 are needed.
> 
> Enable the existing erratum 5 empty-FIFO workaround for RK3588.
> Heiko reproduced erratum 6 on RK3588, so enable that workaround as
> well.
> 
> Keep RKCANFD_QUIRK_CANFD_BROKEN enabled for RK3588, so CAN-FD stays
> disabled for now. Local testing did not reproduce the two known CAN-FD
> trigger frames that cause Error Interrupts on RK3568 variants. Instead,
> RK3588 shows a different CAN-FD failure mode: CAN-FD frames without BRS
> work in this setup, but BRS with a data bitrate different from the
> nominal bitrate immediately drives the controller bus-off.
> 
> Reported-by: Heiko Stuebner <heiko.stuebner@cherry.de>
> Link: https://lore.kernel.org/lkml/20260630164336.3444550-4-heiko@sntech.de/

I think you might want to drop that above. If anything a Co-developed-by
would be applicable, but from the (small) size of the change, that also
isn't really necessary for me :-)


> Signed-off-by: Cunhao Lu <1579567540@qq.com>

Tested-by: Heiko Stuebner <heiko@sntech.de>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>






^ permalink raw reply

* [PATCH 00/28] KVM: arm64: Add support for FEAT_NV2p1 and FEAT_NV3
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu

This series adds support for two extensions targeting Nested Virt on
arm64:

- FEAT_NV2p1 is effectively a bug fix for two registers (CNTHCTL_EL2
  and CPTR_EL2) that are missing stateful bits when accessed from EL1
  in a NV configuration. When this is present, the hypervisor can
  avoid a bunch of traps.

- FEAT_NV3 is much more ambitious, and changes the way ERET behaves in
  a NV environment. By moving EL1 accesses to HCR_EL2 from memory (via
  VNCR) to a dedicated register (NVHCR_EL2), the HW can detect whether
  the guest is performing an ERET for itself (NVHCR_EL2.TGE==1) or to
  its own guest (NVHCR_EL2.TGE==0). In the former case, ERET is done
  directly, and no trap occurs. Similar optimisations are available
  for a class of TLBI instructions.

The whole thing has been tested on an FVP model, and shown measurable
improvements for an L1 guest (about 1.5% fewer instructions).

Given that this isn't very convincing on its own, I have built an
approximate emulation of FEAT_NV3 that L1 (and deeper levels) can use
on actual production hardware. For these deeper levels, the numbers
are in the double digit of percentage point reduction (those
interested can look at the patches in the kvm-arm64/nv3 branch in my
tree).

Does it make NV better? Yes!
Does it make NV good? Get real!

Anyway, patches on top of -rc1 plus the current state of kvmarm/fixes.

Marc Zyngier (28):
  arm64: sysreg: Emit RESx/UNKN values for Mapping definitions
  arm64: Update ID_AA64MMFR4_EL1 description to 2026-03 JSON release
  KVM: arm64: Merge guest's HCRX_EL2 using NV_HCRX_GUEST_EXCLUDE
  KVM: arm64: Drop __HCRX_EL2_* masks
  KVM: arm64: Plumb HCRX_EL2.SRMASKEn in HCRX_EL2 sanitisation
  KVM: arm64: Classify CPTR_EL2 as a SR_LOC_SPECIAL register
  KVM: arm64: Don't evaluate HCR_EL2.NV on ERET fast path
  arm64: Add ARM64_HAS_NV2P1 capability
  KVM: arm64: Relax CPTR_EL2 handling when FEAT_NV2p1 is present
  KVM: arm64: Relax CNTHCTL_EL2 handling when FEAT_NV2p1 is present
  KVM: arm64: Expose FEAT_NV2p1 to NV guests
  arm64: Add FEAT_NV2p1 detection
  arm64: sysreg: Add NVHCR_EL2 description as a mirror of HCR_EL2
  arm64: sysreg: Add HCRX_EL2 bits related to FEAT_NV3
  arm64: Add ARM64_HAS_NV3 capability
  KVM: arm64: Split NV-specific exit fixups from the non-NV handling
  KVM: arm64: Add NV3 control bits to HCRX_EL2 sanitisation
  KVM: arm64: Add kvm_has_nv{2,3}() predicates
  KVM: arm64: Make HCR_EL2 a non-VNCR register
  KVM: arm64: Add sanitisation for NVHCR_EL2
  KVM: arm64: Add NVHCR_EL2 handling to the sysreg array
  KVM: arm64: Add routing for NVHCR_EL2 trap
  KVM: arm64: Add NVHCR_EL2 context switching
  KVM: arm64: Engage NV3 ERET trap elision
  KVM: arm64: Engage NV3 TLBI trap elision
  KVM: arm64: Add FEAT_NV3 detection
  KVM: arm64: Expose FEAT_NV3 to guests
  arm64: Add override for ID_AA64MMFR4_EL1.NV_frac

 arch/arm64/include/asm/cpufeature.h        |  1 +
 arch/arm64/include/asm/kvm_arm.h           | 15 ------
 arch/arm64/include/asm/kvm_emulate.h       | 41 +++++++++++++++-
 arch/arm64/include/asm/kvm_host.h          |  3 +-
 arch/arm64/include/asm/vncr_mapping.h      |  2 +-
 arch/arm64/kernel/cpufeature.c             | 18 ++++++-
 arch/arm64/kernel/image-vars.h             |  1 +
 arch/arm64/kernel/pi/idreg-override.c      | 10 ++++
 arch/arm64/kvm/arch_timer.c                | 10 +++-
 arch/arm64/kvm/config.c                    | 25 +++++++++-
 arch/arm64/kvm/emulate-nested.c            | 16 ++++--
 arch/arm64/kvm/hyp/include/hyp/switch.h    | 27 ++++++++--
 arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 11 +++++
 arch/arm64/kvm/hyp/vhe/switch.c            | 44 +++++++++++++----
 arch/arm64/kvm/hyp/vhe/sysreg-sr.c         | 21 +++++---
 arch/arm64/kvm/nested.c                    | 14 +++++-
 arch/arm64/kvm/sys_regs.c                  | 57 ++++++++++++++++++++--
 arch/arm64/tools/cpucaps                   |  2 +
 arch/arm64/tools/gen-sysreg.awk            | 14 ++++--
 arch/arm64/tools/sysreg                    | 42 ++++++++++++++--
 20 files changed, 313 insertions(+), 61 deletions(-)

-- 
2.47.3



^ permalink raw reply

* [PATCH 01/28] arm64: sysreg: Emit RESx/UNKN values for Mapping definitions
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>

The sysreg file is using the Mapping qualifier to indicate that
a given encoding is only a mapping to a particular register.
As a result, we don't output any definition, and instead expect
the canonical definitions to be used.

This works rather well for individual fields, but creates problems
for macros that refer to more generic classes of bits such as RESx.

Relax the above rule by emitting the RESx and UNKN values for Mapping
qualifiers as well.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/tools/gen-sysreg.awk | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/tools/gen-sysreg.awk b/arch/arm64/tools/gen-sysreg.awk
index 86860ab672dc7..d7f7ceb768fe5 100755
--- a/arch/arm64/tools/gen-sysreg.awk
+++ b/arch/arm64/tools/gen-sysreg.awk
@@ -228,7 +228,7 @@ $1 == "EndSysreg" && block_current() == "Sysreg" {
 }
 
 # Currently this is effectivey a comment, in future we may want to emit
-# defines for the fields.
+# defines for the fields. "Mapping" does emit the RESx/UNKN definitions.
 ($1 == "Fields" || $1 == "Mapping") && block_current() == "Sysreg" {
 	expect_fields(2)
 
@@ -239,9 +239,15 @@ $1 == "EndSysreg" && block_current() == "Sysreg" {
 	print ""
 
 	next_bit = -1
-	res0 = null
-	res1 = null
-	unkn = null
+	if ($1 == "Mapping") {
+		res0 = $2 "_RES0"
+		res1 = $2 "_RES1"
+		unkn = $2 "_UNKN"
+	} else {
+		res0 = null
+		res1 = null
+		unkn = null
+	}
 
 	next
 }
-- 
2.47.3



^ permalink raw reply related

* [PATCH 04/28] KVM: arm64: Drop __HCRX_EL2_* masks
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>

The __HCRX_EL2_* masks are a leftover from a time where we didn't
have much sanitisation for the system registers. Since we are now
in a better place, rely on the existing checks to detect unhandled
bits in HCRX_EL2.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_arm.h | 15 ---------------
 arch/arm64/kvm/config.c          |  3 +--
 arch/arm64/kvm/emulate-nested.c  |  5 -----
 3 files changed, 1 insertion(+), 22 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 3f9233b5a1308..f6cd851047947 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -287,21 +287,6 @@
 				 GENMASK(19, 18) |	\
 				 GENMASK(15, 0))
 
-/*
- * Polarity masks for HCRX_EL2, limited to the bits that we know about
- * at this point in time. It doesn't mean that we actually *handle*
- * them, but that at least those that are not advertised to a guest
- * will be RES0 for that guest.
- */
-#define __HCRX_EL2_MASK		(BIT_ULL(6))
-#define __HCRX_EL2_nMASK	(GENMASK_ULL(24, 14) | \
-				 GENMASK_ULL(11, 7)  | \
-				 GENMASK_ULL(5, 0))
-#define __HCRX_EL2_RES0		~(__HCRX_EL2_nMASK | __HCRX_EL2_MASK)
-#define __HCRX_EL2_RES1		~(__HCRX_EL2_nMASK | \
-				  __HCRX_EL2_MASK  | \
-				  __HCRX_EL2_RES0)
-
 /* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
 #define HPFAR_MASK	(~UL(0xf))
 /*
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 0622162b089e5..16d8148dc3f12 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -933,7 +933,7 @@ static const struct reg_bits_to_feat_map hcrx_feat_map[] = {
 };
 
 
-static const DECLARE_FEAT_MAP(hcrx_desc, __HCRX_EL2,
+static const DECLARE_FEAT_MAP(hcrx_desc, HCRX_EL2,
 			      hcrx_feat_map, FEAT_HCX);
 
 static const struct reg_bits_to_feat_map hcr_feat_map[] = {
@@ -1579,7 +1579,6 @@ struct resx get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg)
 		break;
 	case HCRX_EL2:
 		resx = compute_reg_resx_bits(kvm, &hcrx_desc, 0, 0);
-		resx.res1 |= __HCRX_EL2_RES1;
 		break;
 	case HCR_EL2:
 		resx = compute_reg_resx_bits(kvm, &hcr_desc, 0, 0);
diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index 3c82f392845d1..b7f3d86a94031 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -2320,7 +2320,6 @@ int __init populate_nv_trap_config(void)
 	BUILD_BUG_ON(__NR_CGT_GROUP_IDS__ > BIT(TC_CGT_BITS));
 	BUILD_BUG_ON(__NR_FGT_GROUP_IDS__ > BIT(TC_FGT_BITS));
 	BUILD_BUG_ON(__NR_FG_FILTER_IDS__ > BIT(TC_FGF_BITS));
-	BUILD_BUG_ON(__HCRX_EL2_MASK & __HCRX_EL2_nMASK);
 
 	for (int i = 0; i < ARRAY_SIZE(encoding_to_cgt); i++) {
 		const struct encoding_to_trap_config *cgt = &encoding_to_cgt[i];
@@ -2346,10 +2345,6 @@ int __init populate_nv_trap_config(void)
 		}
 	}
 
-	if (__HCRX_EL2_RES0 != HCRX_EL2_RES0)
-		kvm_info("Sanitised HCR_EL2_RES0 = %016llx, expecting %016llx\n",
-			 __HCRX_EL2_RES0, HCRX_EL2_RES0);
-
 	kvm_info("nv: %ld coarse grained trap handlers\n",
 		 ARRAY_SIZE(encoding_to_cgt));
 
-- 
2.47.3



^ permalink raw reply related

* [PATCH 03/28] KVM: arm64: Merge guest's HCRX_EL2 using NV_HCRX_GUEST_EXCLUDE
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>

The way we merge the guest-provided HCRX_EL2 value with the host's
is bonkers. We try to make it look like the FGT registers by using
positive and negative polarities for traps, but most of these bits
are not strictly about trapping, as they actively change the way
some architectural state is managed.

It would be far better to deal with these bits like we do for
HCR_EL2, by enumerating the list of bits we don't allow the guest
to override. This is simplified by the fact that HCRX_EL2 only
affects EL1, and not EL2.

Re-jig the HCRX_EL2 handling with a macro that list the bits excluded
from the merge (TMEA, PTTWI, EnIDCP128).

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/hyp/include/hyp/switch.h | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index 4bf624a49591d..8e5f492f39086 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -325,6 +325,24 @@ static inline void __deactivate_traps_mpam(void)
 		write_sysreg_s(MPAMHCR_HOST_FLAGS, SYS_MPAMHCR_EL2);
 }
 
+/*
+ * Just like for HCR_EL2, we can't let the guest mess with some of the
+ * basics we rely on in HCRX_EL2. However, the major difference is that
+ * HCRX_EL2 only affects EL1, and never EL2 (sudden outburst of sanity, I
+ * guess). So it is always the guest inflicting it on its own guestx.
+ *
+ * Things we don't want to let the guest control are:
+ *
+ * - TMEA: That's for us to decide how an SEA is routed, not the guest.
+ *
+ * - PTTWI: Similarly, it is for us to decide whether Reduced Coherency for
+ *   the PTW is a thing. It really isn't.
+ *
+ * - EnIDCP128: We don't allow IMPDEF sysregs -- full stop.
+ */
+#define NV_HCRX_GUEST_EXCLUDE	(HCRX_EL2_TMEA	    | HCRX_EL2_PTTWI | \
+				 HCRX_EL2_EnIDCP128)
+
 static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
 {
 	struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt);
@@ -350,8 +368,8 @@ static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
 		u64 hcrx = vcpu->arch.hcrx_el2;
 		if (is_nested_ctxt(vcpu)) {
 			u64 val = __vcpu_sys_reg(vcpu, HCRX_EL2);
-			hcrx |= val & __HCRX_EL2_MASK;
-			hcrx &= ~(~val & __HCRX_EL2_nMASK);
+			hcrx |= (val & ~NV_HCRX_GUEST_EXCLUDE);
+			hcrx &= ~(~val & ~NV_HCRX_GUEST_EXCLUDE);
 		}
 
 		ctxt_sys_reg(hctxt, HCRX_EL2) = read_sysreg_s(SYS_HCRX_EL2);
-- 
2.47.3



^ permalink raw reply related

* [PATCH 02/28] arm64: Update ID_AA64MMFR4_EL1 description to 2026-03 JSON release
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>

ID_AA64MMFR4_EL1 has gained a few fields and enum values in the past
few months, so resync its definition with the 2026-03 JSON release.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/tools/sysreg | 30 +++++++++++++++++++++++++++---
 1 file changed, 27 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index bc1788b1662b7..32e2f9856768b 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -2386,17 +2386,40 @@ EndEnum
 EndSysreg
 
 Sysreg	ID_AA64MMFR4_EL1	3	0	0	7	4
-Res0	63:48
+UnsignedEnum	63:60	MTEFGT
+	0b0000	NI
+	0b0001	IMP
+EndEnum
+UnsignedEnum	59:56	SCRX
+	0b0000	NI
+	0b0001	IMP
+EndEnum
+UnsignedEnum	55:52	TEV
+	0b0000	NI
+	0b0001	IMP
+EndEnum
+UnsignedEnum	51:48	TPS
+	0b0000	VAL_0000
+	0b0001	VAL_0001
+	0b0010	VAL_0010
+EndEnum
 UnsignedEnum	47:44	SRMASK
 	0b0000	NI
 	0b0001	IMP
+	0b0010	SRMASK2
+EndEnum
+UnsignedEnum	43:40	TLBID
+	0b0000	NI
+	0b0001	IMP
 EndEnum
-Res0	43:40
 UnsignedEnum	39:36	E3DSE
 	0b0000	NI
 	0b0001	IMP
 EndEnum
-Res0	35:32
+UnsignedEnum	35:32	EAESR
+	0b0000	NI
+	0b0001	IMP
+EndEnum
 UnsignedEnum	31:28	RMEGDI
 	0b0000	NI
 	0b0001	IMP
@@ -2410,6 +2433,7 @@ UnsignedEnum	23:20	NV_frac
 	0b0000	NV_NV2
 	0b0001	NV2_ONLY
 	0b0010	NV2P1
+	0b0011	NV3
 EndEnum
 UnsignedEnum	19:16	FGWTE3
 	0b0000	NI
-- 
2.47.3



^ permalink raw reply related

* [PATCH 06/28] KVM: arm64: Classify CPTR_EL2 as a SR_LOC_SPECIAL register
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>

It may not be obvious unless you look at it closely, but CPTR_EL2
is treated very differently from other registers. It is one the
registers that, despite looking very similar between EL1 and EL2
when E2H==1, have RES0 bits that get in the way.

Make it clear that CPTR_EL2 is odd by classifying it as SR_LOC_SPECIAL,
just like CNTHCTL_EL2 (and for the same reasons). This makes it
possible to use vcpu_read_sys_reg() with it, and will be necessary
once we support FEAT_NV2P1.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_emulate.h |  2 +-
 arch/arm64/kvm/sys_regs.c            | 20 ++++++++++++++++++--
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 5bf3d7e1d92c7..9831166695186 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -617,7 +617,7 @@ static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
  */
 static inline u64 vcpu_sanitised_cptr_el2(const struct kvm_vcpu *vcpu)
 {
-	u64 cptr = __vcpu_sys_reg(vcpu, CPTR_EL2);
+	u64 cptr = vcpu_read_sys_reg(vcpu, CPTR_EL2);
 
 	if (!vcpu_el2_e2h_is_set(vcpu))
 		cptr = translate_cptr_el2_to_cpacr_el1(cptr);
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 5d5c579d45790..6b47d936efb32 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -183,8 +183,6 @@ static void locate_register(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg,
 	switch (reg) {
 		MAPPED_EL2_SYSREG(SCTLR_EL2,   SCTLR_EL1,
 				  translate_sctlr_el2_to_sctlr_el1	     );
-		MAPPED_EL2_SYSREG(CPTR_EL2,    CPACR_EL1,
-				  translate_cptr_el2_to_cpacr_el1	     );
 		MAPPED_EL2_SYSREG(TTBR0_EL2,   TTBR0_EL1,
 				  translate_ttbr0_el2_to_ttbr0_el1	     );
 		MAPPED_EL2_SYSREG(TTBR1_EL2,   TTBR1_EL1,   NULL	     );
@@ -210,6 +208,19 @@ static void locate_register(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg,
 		loc->loc = ((is_hyp_ctxt(vcpu) && vcpu_el2_e2h_is_set(vcpu)) ?
 			    SR_LOC_SPECIAL : SR_LOC_MEMORY);
 		break;
+	case CPTR_EL2:
+		/*
+		 * CPTR_EL2 is just as special, and needs a certain amount
+		 * of handholding. It always lives in memory, due to being
+		 * heavily trapped thanks to CPACR_EL1.TCPAC being RES0.
+		 * FEAT_NV2p1 fixes this.
+		 */
+		locate_mapped_el2_register(vcpu, CPTR_EL2, CPACR_EL1,
+					   translate_cptr_el2_to_cpacr_el1,
+					   loc);
+		if (is_hyp_ctxt(vcpu) && vcpu_el2_e2h_is_set(vcpu))
+			loc->loc = SR_LOC_SPECIAL;
+		break;
 	default:
 		loc->loc = locate_direct_register(vcpu, reg);
 	}
@@ -314,6 +325,8 @@ u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg)
 			val &= CNTKCTL_VALID_BITS;
 			val |= __vcpu_sys_reg(vcpu, reg) & ~CNTKCTL_VALID_BITS;
 			return val;
+		case CPTR_EL2:
+			return __vcpu_sys_reg(vcpu, reg);
 		default:
 			WARN_ON_ONCE(1);
 		}
@@ -359,6 +372,9 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, enum vcpu_sysreg reg)
 			 */
 			write_sysreg_el1(val, SYS_CNTKCTL);
 			break;
+		case CPTR_EL2:
+			write_sysreg_el1(val, SYS_CPACR);
+			break;
 		default:
 			WARN_ON_ONCE(1);
 		}
-- 
2.47.3



^ permalink raw reply related

* [PATCH 05/28] KVM: arm64: Plumb HCRX_EL2.SRMASKEn in HCRX_EL2 sanitisation
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>

HCRX_EL2.SRMASKEn is a new bit enabling FEAT_SRMASK for a guest.
We don't plan to support it any time soon, but it doesn't hurt to
actively document it, specially as we are going to add more bits
we actually care about.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/config.c | 1 +
 arch/arm64/tools/sysreg | 4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 16d8148dc3f12..8d5e4aacf49c4 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -904,6 +904,7 @@ static const DECLARE_FEAT_MAP_FGT(hdfgwtr2_desc, hdfgwtr2_masks,
 
 
 static const struct reg_bits_to_feat_map hcrx_feat_map[] = {
+	NEEDS_FEAT(HCRX_EL2_SRMASKEn, FEAT_SRMASK),
 	NEEDS_FEAT(HCRX_EL2_PACMEn, feat_pauth_lr),
 	NEEDS_FEAT(HCRX_EL2_EnFPM, FEAT_FPMR),
 	NEEDS_FEAT(HCRX_EL2_GCSEn, FEAT_GCS),
diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 32e2f9856768b..c6e8117a6f9cd 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -4545,7 +4545,9 @@ Fields	ZCR_ELx
 EndSysreg
 
 Sysreg	HCRX_EL2	3	4	1	2	2
-Res0	63:25
+Res0	63:27
+Field	26	SRMASKEn
+Res0	25
 Field	24	PACMEn
 Field	23	EnFPM
 Field	22	GCSEn
-- 
2.47.3



^ permalink raw reply related

* [PATCH 14/28] arm64: sysreg: Add HCRX_EL2 bits related to FEAT_NV3
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>

FEAT_NV3 introduces 4 new HCRX_EL2 control bits. Describe them
in the sysreg file.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/tools/sysreg | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 31e4ea455a9ce..afe9337851a2e 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -4548,7 +4548,12 @@ Fields	ZCR_ELx
 EndSysreg
 
 Sysreg	HCRX_EL2	3	4	1	2	2
-Res0	63:27
+Res0	63:35
+Field	34	NVnTTLBOS
+Field	33	NVnTTLBIS
+Field	32	NVnTTLB
+Res0	31:28
+Field	27	NVTGE
 Field	26	SRMASKEn
 Res0	25
 Field	24	PACMEn
-- 
2.47.3



^ permalink raw reply related

* [PATCH 09/28] KVM: arm64: Relax CPTR_EL2 handling when FEAT_NV2p1 is present
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>

With FEAT_NV2P1, it is no longer necessary to trap CPTR_EL2 accesses
via CPACR_EL1, as CPACR_EL1.TCPAC is guaranteed to be stateful.

Prevent such trapping and context switch CPACTR_EL1 in NV contexts
when NV2P1 is present.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/hyp/include/hyp/switch.h | 5 +++--
 arch/arm64/kvm/hyp/vhe/switch.c         | 3 +++
 arch/arm64/kvm/hyp/vhe/sysreg-sr.c      | 8 +++++---
 arch/arm64/kvm/sys_regs.c               | 5 ++++-
 4 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index 8e5f492f39086..7b27296c94607 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -108,9 +108,10 @@ static inline void __activate_cptr_traps_vhe(struct kvm_vcpu *vcpu)
 	 * The architecture is a bit crap (what a surprise): an EL2 guest
 	 * writing to CPTR_EL2 via CPACR_EL1 can't set any of TCPAC or TTA,
 	 * as they are RES0 in the guest's view. To work around it, trap the
-	 * sucker using the very same bit it can't set...
+	 * sucker using the very same bit it can't set. FEAT_NV2p1 fixes it.
 	 */
-	if (vcpu_el2_e2h_is_set(vcpu) && is_hyp_ctxt(vcpu))
+	if (!cpus_have_final_cap(ARM64_HAS_NV2P1) &&
+	    vcpu_el2_e2h_is_set(vcpu) && is_hyp_ctxt(vcpu))
 		val |= CPTR_EL2_TCPAC;
 
 	/*
diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
index 3b76e0468317b..361d3f8344dd8 100644
--- a/arch/arm64/kvm/hyp/vhe/switch.c
+++ b/arch/arm64/kvm/hyp/vhe/switch.c
@@ -441,6 +441,9 @@ static bool kvm_hyp_handle_cpacr_el1(struct kvm_vcpu *vcpu, u64 *exit_code)
 	u64 esr = kvm_vcpu_get_esr(vcpu);
 	int rt;
 
+	if (cpus_have_final_cap(ARM64_HAS_NV2P1))
+		return false;
+
 	if (!is_hyp_ctxt(vcpu) || esr_sys64_to_sysreg(esr) != SYS_CPACR_EL1)
 		return false;
 
diff --git a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
index be685b63e8cf2..6f0f046e4ca4e 100644
--- a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
@@ -42,10 +42,12 @@ static void __sysreg_save_vel2_state(struct kvm_vcpu *vcpu)
 		u64 val;
 
 		/*
-		 * We don't save CPTR_EL2, as accesses to CPACR_EL1
-		 * are always trapped, ensuring that the in-memory
-		 * copy is always up-to-date. A small blessing...
+		 * Without FEAT_NV2p1, we don't save CPTR_EL2, as accesses
+		 * to CPACR_EL1 are always trapped, ensuring that the
+		 * in-memory copy is always up-to-date. A small blessing...
 		 */
+		if (cpus_have_final_cap(ARM64_HAS_NV2P1))
+			__vcpu_assign_sys_reg(vcpu, CPTR_EL2, read_sysreg_el1(SYS_CPACR));
 		__vcpu_assign_sys_reg(vcpu, SCTLR_EL2,	 read_sysreg_el1(SYS_SCTLR));
 		__vcpu_assign_sys_reg(vcpu, TTBR0_EL2,	 read_sysreg_el1(SYS_TTBR0));
 		__vcpu_assign_sys_reg(vcpu, TTBR1_EL2,	 read_sysreg_el1(SYS_TTBR1));
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 6b47d936efb32..1dfc1f88bec82 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -326,7 +326,10 @@ u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg)
 			val |= __vcpu_sys_reg(vcpu, reg) & ~CNTKCTL_VALID_BITS;
 			return val;
 		case CPTR_EL2:
-			return __vcpu_sys_reg(vcpu, reg);
+			if (cpus_have_final_cap(ARM64_HAS_NV2P1))
+				return read_sysreg_el1(SYS_CPACR);
+			else
+				return __vcpu_sys_reg(vcpu, reg);
 		default:
 			WARN_ON_ONCE(1);
 		}
-- 
2.47.3



^ permalink raw reply related

* [PATCH 18/28] KVM: arm64: Add kvm_has_nv{2,3}() predicates
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>

Add a new set of predicates indicating whether VM is capable of
NV2, NV3, and is in a nested NV3 context.

This is going to become useful as we start dealing with a mix of
behaviours (NV2, NV3, NV2 on NV3...).

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/include/asm/kvm_emulate.h | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 9831166695186..c562d8171d5e1 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -266,6 +266,26 @@ static inline bool vserror_state_is_nested(struct kvm_vcpu *vcpu)
 	       (__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TMEA);
 }
 
+static inline bool kvm_has_nv2(struct kvm *kvm)
+{
+	return (cpus_have_final_cap(ARM64_HAS_NESTED_VIRT) &&
+		kvm_has_feat(kvm, ID_AA64MMFR4_EL1, NV_frac, NV2_ONLY));
+}
+
+static inline bool kvm_has_nv3(struct kvm *kvm)
+{
+	return (cpus_have_final_cap(ARM64_HAS_NESTED_VIRT) &&
+		cpus_have_final_cap(ARM64_HAS_NV3) &&
+		kvm_has_feat(kvm, ID_AA64MMFR4_EL1, NV_frac, NV3));
+}
+
+static inline bool is_nested_nv3_ctxt(struct kvm_vcpu *vcpu)
+{
+	return (has_vhe() && kvm_has_nv3(vcpu->kvm) && is_nested_ctxt(vcpu) &&
+		(__vcpu_sys_reg(vcpu, HCR_EL2) & HCR_EL2_NV) &&
+		(__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_NVTGE));
+}
+
 /*
  * The layout of SPSR for an AArch32 state is different when observed from an
  * AArch64 SPSR_ELx or an AArch32 SPSR_*. This function generates the AArch32
-- 
2.47.3



^ permalink raw reply related

* [PATCH 22/28] KVM: arm64: Add routing for NVHCR_EL2 trap
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, kvm
  Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>

NVHCR_EL2 accesses from EL1 are taken to EL2 when HCRX_EL2.NVTGE==0
and HCR_EL2.NV==1. Describe this in the exception routing tables.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/emulate-nested.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index b7f3d86a94031..f5dc578d8c985 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -90,6 +90,7 @@ enum cgt_group_id {
 	CGT_HCRX_EnFPM,
 	CGT_HCRX_TCR2En,
 	CGT_HCRX_SCTLR2En,
+	CGT_HCRX_nNVTGE,
 
 	CGT_CNTHCTL_EL1TVT,
 	CGT_CNTHCTL_EL1TVCT,
@@ -121,6 +122,8 @@ enum cgt_group_id {
 	CGT_MDCR_TDE_TDRA,
 	CGT_MDCR_TDCC_TDE_TDA,
 
+	CGT_HCR_NV_HCRX_nNVTGE,
+
 	CGT_ICH_HCR_TC_TDIR,
 
 	/*
@@ -413,6 +416,12 @@ static const struct trap_bits coarse_trap_bits[] = {
 		.mask		= HCRX_EL2_SCTLR2En,
 		.behaviour	= BEHAVE_FORWARD_RW,
 	},
+	[CGT_HCRX_nNVTGE] = {
+		.index		= HCRX_EL2,
+		.value		= 0,
+		.mask		= HCRX_EL2_NVTGE,
+		.behaviour	= BEHAVE_FORWARD_RW,
+	},
 	[CGT_CNTHCTL_EL1TVT] = {
 		.index		= CNTHCTL_EL2,
 		.value		= CNTHCTL_EL1TVT,
@@ -468,6 +477,7 @@ static const enum cgt_group_id *coarse_control_combo[] = {
 					CGT_HCR_TVM, CGT_HCR_TRVM, CGT_HCRX_SCTLR2En),
 	MCB(CGT_HCR_TPU_TICAB,		CGT_HCR_TPU, CGT_HCR_TICAB),
 	MCB(CGT_HCR_TPU_TOCU,		CGT_HCR_TPU, CGT_HCR_TOCU),
+	MCB(CGT_HCR_NV_HCRX_nNVTGE,	CGT_HCR_NV, CGT_HCRX_nNVTGE),
 	MCB(CGT_HCR_NV1_nNV2_ENSCXT,	CGT_HCR_NV1_nNV2, CGT_HCR_ENSCXT),
 	MCB(CGT_MDCR_TPM_TPMCR,		CGT_MDCR_TPM, CGT_MDCR_TPMCR),
 	MCB(CGT_MDCR_TPM_HPMN,		CGT_MDCR_TPM, CGT_MDCR_HPMN),
@@ -853,6 +863,7 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = {
 	SR_TRAP(SYS_SCTLR2_EL2,		CGT_HCR_NV),
 	SR_RANGE_TRAP(SYS_HCR_EL2,
 		      SYS_HCRX_EL2,	CGT_HCR_NV),
+	SR_TRAP(SYS_NVHCR_EL2,		CGT_HCR_NV_HCRX_nNVTGE),
 	SR_TRAP(SYS_SMPRIMAP_EL2,	CGT_HCR_NV),
 	SR_TRAP(SYS_SMCR_EL2,		CGT_HCR_NV),
 	SR_RANGE_TRAP(SYS_TTBR0_EL2,
-- 
2.47.3



^ permalink raw reply related


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