LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
From: Aneesh Kumar K.V @ 2026-07-21 14:20 UTC (permalink / raw)
  To: Leon Romanovsky
  Cc: iommu, linux-arm-kernel, linux-kernel, linux-coco, Robin Murphy,
	Marek Szyprowski, Will Deacon, Marc Zyngier, Steven Price,
	Suzuki K Poulose, Catalin Marinas, Jiri Pirko, Jason Gunthorpe,
	Mostafa Saleh, Petr Tesarik, Alexey Kardashevskiy, Dan Williams,
	Xu Yilun, linuxppc-dev, linux-s390, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Alexander Gordeev, Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger, Sven Schnelle, x86, stable, Michael Kelley,
	Jason Gunthorpe
In-Reply-To: <20260721115456.GI110966@unreal>

Leon Romanovsky <leon@kernel.org> writes:

> On Fri, Jul 17, 2026 at 11:34:19PM +0530, Aneesh Kumar K.V (Arm) wrote:
>> Commit 5b138c534fda ("dma-direct: factor out a dma_direct_alloc_from_pool
>> helper") changed dma_direct_alloc_from_pool() to return the CPU address
>> from dma_alloc_from_pool(). That fits dma_direct_alloc(), but
>> dma_direct_alloc_pages() also uses the helper and expects a struct page *.
>> 
>> Fix this by making dma_direct_alloc_from_pool() return the struct page *
>> again, and pass the CPU address back through an out-parameter for the
>> dma_direct_alloc() caller.
>> 
>> Fixes: 5b138c534fda ("dma-direct: factor out a dma_direct_alloc_from_pool helper")
>> Cc: stable@vger.kernel.org
>> Tested-by: Michael Kelley <mhklinux@outlook.com>
>> Tested-by: Mostafa Saleh <smostafa@google.com>
>> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
>> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
>> ---
>>  kernel/dma/direct.c | 18 ++++++++++--------
>>  1 file changed, 10 insertions(+), 8 deletions(-)
>> 
>> diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
>> index d8219efe3273..363d984d90e7 100644
>> --- a/kernel/dma/direct.c
>> +++ b/kernel/dma/direct.c
>> @@ -164,22 +164,21 @@ static bool dma_direct_use_pool(struct device *dev, gfp_t gfp)
>>  	return !gfpflags_allow_blocking(gfp) && !is_swiotlb_for_alloc(dev);
>>  }
>>  
>> -static void *dma_direct_alloc_from_pool(struct device *dev, size_t size,
>> -		dma_addr_t *dma_handle, gfp_t gfp)
>> +static struct page *dma_direct_alloc_from_pool(struct device *dev, size_t size,
>> +		dma_addr_t *dma_handle, void **cpu_addr, gfp_t gfp)
>>  {
>>  	struct page *page;
>>  	u64 phys_limit;
>> -	void *ret;
>>  
>>  	if (WARN_ON_ONCE(!IS_ENABLED(CONFIG_DMA_COHERENT_POOL)))
>>  		return NULL;
>>  
>>  	gfp |= dma_direct_optimal_gfp_mask(dev, &phys_limit);
>> -	page = dma_alloc_from_pool(dev, size, &ret, gfp, dma_coherent_ok);
>> +	page = dma_alloc_from_pool(dev, size, cpu_addr, gfp, dma_coherent_ok);
>>  	if (!page)
>>  		return NULL;
>>  	*dma_handle = phys_to_dma_direct(dev, page_to_phys(page));
>> -	return ret;
>> +	return page;
>>  }
>>  
>>  static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size,
>> @@ -247,8 +246,11 @@ void *dma_direct_alloc(struct device *dev, size_t size,
>>  	 * the atomic pools instead if we aren't allowed block.
>>  	 */
>>  	if ((remap || force_dma_unencrypted(dev)) &&
>> -	    dma_direct_use_pool(dev, gfp))
>> -		return dma_direct_alloc_from_pool(dev, size, dma_handle, gfp);
>> +	    dma_direct_use_pool(dev, gfp)) {
>> +		page = dma_direct_alloc_from_pool(dev, size, dma_handle,
>> +						  &ret, gfp);
>> +		return page ? ret : NULL;
>
> Sorry for joining the discussion late, but the line above caught my
> attention.
>
> Why do we need both ret and page? We can derive cpu_addr from page and
> vice versa. Do we really need the &ret parameter? Or, more generally, do
> we really need "struct page *"?
>
> static struct page *__dma_alloc_from_pool(struct device *dev, size_t size,
> 		struct gen_pool *pool, void **cpu_addr,
> 		bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t))
> {
> ...
> 	*cpu_addr = (void *)addr;
> 	memset(*cpu_addr, 0, size);
> 	return pfn_to_page(__phys_to_pfn(phys));
> }
>
> Why
>

With CONFIG_DMA_DIRECT_REMAP the cpu_addr can be different from
page_address.

-aneesh


^ permalink raw reply

* Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
From: Leon Romanovsky @ 2026-07-21 14:29 UTC (permalink / raw)
  To: Aneesh Kumar K.V
  Cc: iommu, linux-arm-kernel, linux-kernel, linux-coco, Robin Murphy,
	Marek Szyprowski, Will Deacon, Marc Zyngier, Steven Price,
	Suzuki K Poulose, Catalin Marinas, Jiri Pirko, Jason Gunthorpe,
	Mostafa Saleh, Petr Tesarik, Alexey Kardashevskiy, Dan Williams,
	Xu Yilun, linuxppc-dev, linux-s390, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Alexander Gordeev, Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger, Sven Schnelle, x86, stable, Michael Kelley,
	Jason Gunthorpe
In-Reply-To: <yq5atsps77c5.fsf@kernel.org>

On Tue, Jul 21, 2026 at 07:50:10PM +0530, Aneesh Kumar K.V wrote:
> Leon Romanovsky <leon@kernel.org> writes:
> 
> > On Fri, Jul 17, 2026 at 11:34:19PM +0530, Aneesh Kumar K.V (Arm) wrote:
> >> Commit 5b138c534fda ("dma-direct: factor out a dma_direct_alloc_from_pool
> >> helper") changed dma_direct_alloc_from_pool() to return the CPU address
> >> from dma_alloc_from_pool(). That fits dma_direct_alloc(), but
> >> dma_direct_alloc_pages() also uses the helper and expects a struct page *.
> >> 
> >> Fix this by making dma_direct_alloc_from_pool() return the struct page *
> >> again, and pass the CPU address back through an out-parameter for the
> >> dma_direct_alloc() caller.
> >> 
> >> Fixes: 5b138c534fda ("dma-direct: factor out a dma_direct_alloc_from_pool helper")
> >> Cc: stable@vger.kernel.org
> >> Tested-by: Michael Kelley <mhklinux@outlook.com>
> >> Tested-by: Mostafa Saleh <smostafa@google.com>
> >> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
> >> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
> >> ---
> >>  kernel/dma/direct.c | 18 ++++++++++--------
> >>  1 file changed, 10 insertions(+), 8 deletions(-)
> >> 
> >> diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
> >> index d8219efe3273..363d984d90e7 100644
> >> --- a/kernel/dma/direct.c
> >> +++ b/kernel/dma/direct.c
> >> @@ -164,22 +164,21 @@ static bool dma_direct_use_pool(struct device *dev, gfp_t gfp)
> >>  	return !gfpflags_allow_blocking(gfp) && !is_swiotlb_for_alloc(dev);
> >>  }
> >>  
> >> -static void *dma_direct_alloc_from_pool(struct device *dev, size_t size,
> >> -		dma_addr_t *dma_handle, gfp_t gfp)
> >> +static struct page *dma_direct_alloc_from_pool(struct device *dev, size_t size,
> >> +		dma_addr_t *dma_handle, void **cpu_addr, gfp_t gfp)
> >>  {
> >>  	struct page *page;
> >>  	u64 phys_limit;
> >> -	void *ret;
> >>  
> >>  	if (WARN_ON_ONCE(!IS_ENABLED(CONFIG_DMA_COHERENT_POOL)))
> >>  		return NULL;
> >>  
> >>  	gfp |= dma_direct_optimal_gfp_mask(dev, &phys_limit);
> >> -	page = dma_alloc_from_pool(dev, size, &ret, gfp, dma_coherent_ok);
> >> +	page = dma_alloc_from_pool(dev, size, cpu_addr, gfp, dma_coherent_ok);
> >>  	if (!page)
> >>  		return NULL;
> >>  	*dma_handle = phys_to_dma_direct(dev, page_to_phys(page));
> >> -	return ret;
> >> +	return page;
> >>  }
> >>  
> >>  static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size,
> >> @@ -247,8 +246,11 @@ void *dma_direct_alloc(struct device *dev, size_t size,
> >>  	 * the atomic pools instead if we aren't allowed block.
> >>  	 */
> >>  	if ((remap || force_dma_unencrypted(dev)) &&
> >> -	    dma_direct_use_pool(dev, gfp))
> >> -		return dma_direct_alloc_from_pool(dev, size, dma_handle, gfp);
> >> +	    dma_direct_use_pool(dev, gfp)) {
> >> +		page = dma_direct_alloc_from_pool(dev, size, dma_handle,
> >> +						  &ret, gfp);
> >> +		return page ? ret : NULL;
> >
> > Sorry for joining the discussion late, but the line above caught my
> > attention.
> >
> > Why do we need both ret and page? We can derive cpu_addr from page and
> > vice versa. Do we really need the &ret parameter? Or, more generally, do
> > we really need "struct page *"?
> >
> > static struct page *__dma_alloc_from_pool(struct device *dev, size_t size,
> > 		struct gen_pool *pool, void **cpu_addr,
> > 		bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t))
> > {
> > ...
> > 	*cpu_addr = (void *)addr;
> > 	memset(*cpu_addr, 0, size);
> > 	return pfn_to_page(__phys_to_pfn(phys));
> > }
> >
> > Why
> >
> 
> With CONFIG_DMA_DIRECT_REMAP the cpu_addr can be different from
> page_address.

Can you please point to the code there it can happen?
__dma_alloc_from_pool() has direct connection between physical address
and struct page.

Thanks

> 
> -aneesh
> 


^ permalink raw reply

* Re: [PATCH v8 02/23] dma-pool: fix page leak in atomic_pool_expand() cleanup
From: Aneesh Kumar K.V @ 2026-07-21 14:41 UTC (permalink / raw)
  To: Leon Romanovsky
  Cc: iommu, linux-arm-kernel, linux-kernel, linux-coco, Robin Murphy,
	Marek Szyprowski, Will Deacon, Marc Zyngier, Steven Price,
	Suzuki K Poulose, Catalin Marinas, Jiri Pirko, Jason Gunthorpe,
	Mostafa Saleh, Petr Tesarik, Alexey Kardashevskiy, Dan Williams,
	Xu Yilun, linuxppc-dev, linux-s390, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Alexander Gordeev, Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger, Sven Schnelle, x86, Jason Gunthorpe,
	Michael Kelley
In-Reply-To: <20260721123107.GJ110966@unreal>

Leon Romanovsky <leon@kernel.org> writes:

> On Fri, Jul 17, 2026 at 11:34:20PM +0530, Aneesh Kumar K.V (Arm) wrote:
>> atomic_pool_expand() frees the allocated pages from the remove_mapping
>> error path only when CONFIG_DMA_DIRECT_REMAP is enabled.
>> 
>> When CONFIG_DMA_DIRECT_REMAP is disabled, failures after page allocation,
>> such as gen_pool_add_virt(), jump to remove_mapping and return without
>> freeing the pages.
>> 
>> Move __free_pages(page, order) out of the CONFIG_DMA_DIRECT_REMAP block so
>> that cleanup paths always release the allocation.
>> 
>> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
>> Tested-by: Michael Kelley <mhklinux@outlook.com>
>> Tested-by: Mostafa Saleh <smostafa@google.com>
>> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
>> ---
>>  kernel/dma/pool.c | 10 +++++++---
>>  1 file changed, 7 insertions(+), 3 deletions(-)
>> 
>> diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c
>> index 2b2fbb709242..b0303efbc153 100644
>> --- a/kernel/dma/pool.c
>> +++ b/kernel/dma/pool.c
>> @@ -81,6 +81,7 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
>>  {
>>  	unsigned int order;
>>  	struct page *page = NULL;
>> +	bool leak_pages = false;
>>  	void *addr;
>>  	int ret = -ENOMEM;
>>  
>> @@ -115,8 +116,10 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
>>  	 */
>>  	ret = set_memory_decrypted((unsigned long)page_to_virt(page),
>>  				   1 << order);
>> -	if (ret)
>> +	if (ret) {
>> +		leak_pages = true;
>>  		goto remove_mapping;
>> +	}
>>  	ret = gen_pool_add_virt(pool, (unsigned long)addr, page_to_phys(page),
>>  				pool_size, NUMA_NO_NODE);
>>  	if (ret)
>> @@ -130,14 +133,15 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
>>  				   1 << order);
>>  	if (WARN_ON_ONCE(ret)) {
>>  		/* Decrypt succeeded but encrypt failed, purposely leak */
>> -		goto out;
>> +		leak_pages = true;
>
> Instead of doing this dance with temporal variable, change "goto out" to
> be "return true".
>


I didn't follow the return true part. A failure in
set_memory_encrypted() or set_memory_decrypted() requires the pages to
be leaked, so this is not the only call site that sets leak_pages =
true. There is a similar case a few lines above.


>
>>  	}
>>  remove_mapping:
>>  #ifdef CONFIG_DMA_DIRECT_REMAP
>>  	dma_common_free_remap(addr, pool_size);
>>  free_page:
>
> Remove free_page label, and change leftover of "goto free_page" to be
> "goto out"
>
>> -	__free_pages(page, order);
>>  #endif
>> +	if (!leak_pages)
>> +		__free_pages(page, order);
>
> Put these checks under out label and rely on page != NULL as a marker.
> if (page)
>  __free_pages(page, order);
>
>>  out:
>>  	return ret;
>>  }
>> -- 
>> 2.43.0
>> 
>> 

-aneesh


^ permalink raw reply

* Re: [PATCH 01/22] mm: drop unused __mm_flags_set_mask_bits_word()
From: David Hildenbrand (Arm) @ 2026-07-21 14:57 UTC (permalink / raw)
  To: Kevin Brodsky, linux-mm
  Cc: Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Pasha Tatashin,
	Russell King, Catalin Marinas, Will Deacon, Ryan Roberts,
	linux-arm-kernel, Huacai Chen, loongarch, James E.J. Bottomley,
	Helge Deller, linux-parisc, Madhavan Srinivasan, Michael Ellerman,
	linuxppc-dev, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-riscv, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Gerald Schaefer, linux-s390, David S. Miller, Andreas Larsson,
	sparclinux, Richard Weinberger, Anton Ivanov, Johannes Berg,
	linux-um, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
	Ning Sun, x86, tboot-devel, Ard Biesheuvel, Ilias Apalodimas,
	linux-efi, Vishal Moola, Alistair Popple, Matthew Wilcox (Oracle),
	linux-kernel, linux-arch
In-Reply-To: <20260714-remove_pgtable_cdtor-v1-1-44be8a7685d7@arm.com>

On 7/14/26 16:03, Kevin Brodsky wrote:
> Commit 39f8049cd49f ("mm: update coredump logic to correctly
> use bitmap mm flags") added coredump-specific helpers for the
> remaining masked mm-flags update users.
> 
> That left __mm_flags_set_mask_bits_word() without any callers.
> This is a special-purpose helper that is unlikely to be useful for
> other purposes; best to remove it.
> 
> Assisted-by: Codex:GPT-5.5
> Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
> ---

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

-- 
Cheers,

David


^ permalink raw reply

* Re: [PATCH 02/22] mm: move mm_flags helpers to mm_types.h
From: David Hildenbrand (Arm) @ 2026-07-21 14:57 UTC (permalink / raw)
  To: Kevin Brodsky, linux-mm
  Cc: Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Pasha Tatashin,
	Russell King, Catalin Marinas, Will Deacon, Ryan Roberts,
	linux-arm-kernel, Huacai Chen, loongarch, James E.J. Bottomley,
	Helge Deller, linux-parisc, Madhavan Srinivasan, Michael Ellerman,
	linuxppc-dev, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-riscv, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Gerald Schaefer, linux-s390, David S. Miller, Andreas Larsson,
	sparclinux, Richard Weinberger, Anton Ivanov, Johannes Berg,
	linux-um, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
	Ning Sun, x86, tboot-devel, Ard Biesheuvel, Ilias Apalodimas,
	linux-efi, Vishal Moola, Alistair Popple, Matthew Wilcox (Oracle),
	linux-kernel, linux-arch
In-Reply-To: <20260714-remove_pgtable_cdtor-v1-2-44be8a7685d7@arm.com>

On 7/14/26 16:03, Kevin Brodsky wrote:
> Some of the mm_flags helpers are defined in <linux/mm_types.h>,
> while others are defined in <linux/mm.h>. We will soon need to call
> one of the latter helpers from mm_types.h.
> 
> Regroup all the helpers in mm_types.h to keep things simple.
> 
> Also remove #include's that were added specifically for these
> helpers in mm.h.
> 
> Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
> ---

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

-- 
Cheers,

David


^ permalink raw reply

* Re: [PATCH 03/22] mm: introduce MMF_KERNEL flag and set it for init_mm
From: David Hildenbrand (Arm) @ 2026-07-21 15:04 UTC (permalink / raw)
  To: Kevin Brodsky, Lorenzo Stoakes (ARM), Dave Hansen
  Cc: linux-mm, Andrew Morton, Liam R. Howlett, Vlastimil Babka,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Pasha Tatashin,
	Russell King, Catalin Marinas, Will Deacon, Ryan Roberts,
	linux-arm-kernel, Huacai Chen, loongarch, James E.J. Bottomley,
	Helge Deller, linux-parisc, Madhavan Srinivasan, Michael Ellerman,
	linuxppc-dev, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-riscv, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Gerald Schaefer, linux-s390, David S. Miller, Andreas Larsson,
	sparclinux, Richard Weinberger, Anton Ivanov, Johannes Berg,
	linux-um, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
	Ning Sun, x86, tboot-devel, Ard Biesheuvel, Ilias Apalodimas,
	linux-efi, Vishal Moola, Alistair Popple, Matthew Wilcox (Oracle),
	linux-kernel, linux-arch
In-Reply-To: <5ce00109-c0ea-43f0-881d-f58a0fda8dcb@arm.com>

On 7/16/26 11:33, Kevin Brodsky wrote:
> On 14/07/2026 17:04, Lorenzo Stoakes (ARM) wrote:
>> On Tue, Jul 14, 2026 at 07:47:43AM -0700, Dave Hansen wrote:
>>> Could we give this some nice comments explaining what a kernel mm is,
>>> please? Part of the problem with the init_mm checks is that they're
>>> magic and it's not always clear what's special about init_mm.
> 
> Agreed, we need to define what this property means exactly, and your
> comments on patch 14 show that extending it to efi_mm isn't necessarily
> as benign as it appeared to me at first.
> 
> My motivation really is about how page tables are handled (in particular
> whether ptlocks are used), so as you suggested on patch 19 maybe this
> flag should be narrower in scope, and the naming should reflect it.
> Possibly MMF_KERNEL_PGTABLES? That's at least one thing that should be
> true of all of init_mm, efi_mm and tboot_mm: their page tables use
> kernel permissions, not user, and should follow the same rules including
> not using ptlocks.
> 
>>> Maybe start with this list?
>>>
>>> 1. There's only one of them.
>>> 2. All kernel threads share it. tsk->mm is the same for all kernel
>>>    threads.
>>> 3. It holds the reference copy of the kernel page tables
>>> 4. Userspace can't be entered when it is the current mm
>>> 5. It has different TLB flushing rules than userspace mms
>>>
>>> I _think_ those are universal across all architectures.
>> Well point 1 isn't true of efimm or tboot_mm so we possibly need a better
>> name :)
>>
>> "Special" is overloaded too much already. I quite like "eternal" so:
>>
>> 	static inline bool mm_is_eternal(const struct mm_struct *mm)
>> 	{
>> 		return mm && mm_flags_test(MMF_ETERNAL, mm);
>> 	}
> 
> Cheeky but why not! I do wonder whether this conveys the right idea
> though. The main point of this flag is that page tables are
> allocated/initialised/locked differently; in principle you could have a
> temporary non-user mm.

I mean, we talk about MMs that are not used for actual user space processes?

IOW, the following:

arch/x86/kernel/tboot.c:static struct mm_struct tboot_mm = {
drivers/firmware/efi/efi.c:struct mm_struct efi_mm = {
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c:static struct mm_struct sva_mm = {
mm/init-mm.c:struct mm_struct init_mm = {


So "user" vs. "kernel" is quite intuitive. Sure, there can be multiple
"kernel" ones, but each with a distinct purpose (IOW, we don't have multiple init_mm MMs).

-- 
Cheers,

David


^ permalink raw reply

* Re: [PATCH 04/22] mm: use mm_is_kernel() in generic page table code
From: David Hildenbrand (Arm) @ 2026-07-21 15:07 UTC (permalink / raw)
  To: Kevin Brodsky, linux-mm
  Cc: Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Pasha Tatashin,
	Russell King, Catalin Marinas, Will Deacon, Ryan Roberts,
	linux-arm-kernel, Huacai Chen, loongarch, James E.J. Bottomley,
	Helge Deller, linux-parisc, Madhavan Srinivasan, Michael Ellerman,
	linuxppc-dev, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-riscv, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Gerald Schaefer, linux-s390, David S. Miller, Andreas Larsson,
	sparclinux, Richard Weinberger, Anton Ivanov, Johannes Berg,
	linux-um, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
	Ning Sun, x86, tboot-devel, Ard Biesheuvel, Ilias Apalodimas,
	linux-efi, Vishal Moola, Alistair Popple, Matthew Wilcox (Oracle),
	linux-kernel, linux-arch
In-Reply-To: <02565237-d777-4c63-8b17-817df59feac4@arm.com>

On 7/16/26 11:35, Kevin Brodsky wrote:
> On 14/07/2026 16:03, Kevin Brodsky wrote:
>> diff --git a/mm/memory.c b/mm/memory.c
>> index d5e87624f692..c0244c0b0756 100644
>> --- a/mm/memory.c
>> +++ b/mm/memory.c
>> @@ -3394,13 +3394,13 @@ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
>>  	spinlock_t *ptl;
>>  
>>  	if (create) {
>> - mapped_pte = pte = (mm == &init_mm) ?
>> + mapped_pte = pte = mm_is_kernel(mm) ?
>>  			pte_alloc_kernel_track(pmd, addr, mask) :
>>  			pte_alloc_map_lock(mm, pmd, addr, &ptl);
> 
> As noted by Sashiko, this is a little problematic because if
> apply_to_page_range() is called on efi_mm, then we will end up with
> __pte_alloc_kernel() taking the init_mm lock, since that's hardcoded.
> 
> That probably means we should pass the mm to __pte_alloc_kernel().

Agreed.

I guess we have to audit all existing init_mm usage?

-- 
Cheers,

David


^ permalink raw reply

* Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
From: Aneesh Kumar K.V @ 2026-07-21 15:10 UTC (permalink / raw)
  To: Leon Romanovsky
  Cc: iommu, linux-arm-kernel, linux-kernel, linux-coco, Robin Murphy,
	Marek Szyprowski, Will Deacon, Marc Zyngier, Steven Price,
	Suzuki K Poulose, Catalin Marinas, Jiri Pirko, Jason Gunthorpe,
	Mostafa Saleh, Petr Tesarik, Alexey Kardashevskiy, Dan Williams,
	Xu Yilun, linuxppc-dev, linux-s390, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Alexander Gordeev, Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger, Sven Schnelle, x86, stable, Michael Kelley,
	Jason Gunthorpe
In-Reply-To: <20260721142921.GN110966@unreal>

Leon Romanovsky <leon@kernel.org> writes:

> On Tue, Jul 21, 2026 at 07:50:10PM +0530, Aneesh Kumar K.V wrote:
>> Leon Romanovsky <leon@kernel.org> writes:
>> 
>> > On Fri, Jul 17, 2026 at 11:34:19PM +0530, Aneesh Kumar K.V (Arm) wrote:
....
>> >>  static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size,
>> >> @@ -247,8 +246,11 @@ void *dma_direct_alloc(struct device *dev, size_t size,
>> >>  	 * the atomic pools instead if we aren't allowed block.
>> >>  	 */
>> >>  	if ((remap || force_dma_unencrypted(dev)) &&
>> >> -	    dma_direct_use_pool(dev, gfp))
>> >> -		return dma_direct_alloc_from_pool(dev, size, dma_handle, gfp);
>> >> +	    dma_direct_use_pool(dev, gfp)) {
>> >> +		page = dma_direct_alloc_from_pool(dev, size, dma_handle,
>> >> +						  &ret, gfp);
>> >> +		return page ? ret : NULL;
>> >
>> > Sorry for joining the discussion late, but the line above caught my
>> > attention.
>> >
>> > Why do we need both ret and page? We can derive cpu_addr from page and
>> > vice versa. Do we really need the &ret parameter? Or, more generally, do
>> > we really need "struct page *"?
>> >
>> > static struct page *__dma_alloc_from_pool(struct device *dev, size_t size,
>> > 		struct gen_pool *pool, void **cpu_addr,
>> > 		bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t))
>> > {
>> > ...
>> > 	*cpu_addr = (void *)addr;
>> > 	memset(*cpu_addr, 0, size);
>> > 	return pfn_to_page(__phys_to_pfn(phys));
>> > }
>> >
>> > Why
>> >
>> 
>> With CONFIG_DMA_DIRECT_REMAP the cpu_addr can be different from
>> page_address.
>
> Can you please point to the code there it can happen?
> __dma_alloc_from_pool() has direct connection between physical address
> and struct page.
>

dma_direct_alloc -> 	remap = IS_ENABLED(CONFIG_DMA_DIRECT_REMAP);
	if ((remap && dma_direct_use_pool(dev, gfp)) {
		page = dma_direct_alloc_from_pool(dev, size,

..
__dma_alloc_from_pool -> 
	addr = gen_pool_alloc(pool, size);
	if (!addr)


We expand the pool as below..

atomic_pool_expand ->

#ifdef CONFIG_DMA_DIRECT_REMAP
	addr = dma_common_contiguous_remap(page, pool_size,
			pgprot_decrypted(pgprot_dmacoherent(PAGE_KERNEL)),
			__builtin_return_address(0));
	if (!addr)
		goto free_page;
#else
	addr = page_to_virt(page);
#endif


-aneesh


^ permalink raw reply

* Re: [PATCH 15/22] mm: only initialise pt_share_count for user pgtables
From: David Hildenbrand (Arm) @ 2026-07-21 15:12 UTC (permalink / raw)
  To: Kevin Brodsky, linux-mm
  Cc: Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Pasha Tatashin,
	Russell King, Catalin Marinas, Will Deacon, Ryan Roberts,
	linux-arm-kernel, Huacai Chen, loongarch, James E.J. Bottomley,
	Helge Deller, linux-parisc, Madhavan Srinivasan, Michael Ellerman,
	linuxppc-dev, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	linux-riscv, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Gerald Schaefer, linux-s390, David S. Miller, Andreas Larsson,
	sparclinux, Richard Weinberger, Anton Ivanov, Johannes Berg,
	linux-um, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
	Ning Sun, x86, tboot-devel, Ard Biesheuvel, Ilias Apalodimas,
	linux-efi, Vishal Moola, Alistair Popple, Matthew Wilcox (Oracle),
	linux-kernel, linux-arch
In-Reply-To: <20260714-remove_pgtable_cdtor-v1-15-44be8a7685d7@arm.com>

On 7/14/26 16:04, Kevin Brodsky wrote:
> ptdesc_pmd_pts_init() initialises the pt_share_count ptdesc field.
> That field is only used for hugetlb tracking purposes, so there is
> no need to initialise it for kernel page tables. Skip the call for
> kernel page tables, like pmd_ptlock_init().
> 
> From now on pagetable_*_ctor() and pagetable_dtor() do nothing for
> kernel page tables.
> 
> Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
> ---
>  include/linux/mm.h | 9 ++++++---
>  1 file changed, 6 insertions(+), 3 deletions(-)
> 
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 94f0fb1c662a..b217ccbed5a3 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -3905,9 +3905,12 @@ static inline spinlock_t *pmd_lock(struct mm_struct *mm, pmd_t *pmd)
>  static inline bool pagetable_pmd_ctor(struct mm_struct *mm,
>  				      struct ptdesc *ptdesc)
>  {
> -	if (!mm_is_kernel(mm) && !pmd_ptlock_init(ptdesc))
> -		return false;
> -	ptdesc_pmd_pts_init(ptdesc);
> +	if (!mm_is_kernel(mm)) {
> +		if (!pmd_ptlock_init(ptdesc))
> +			return false;
> +		ptdesc_pmd_pts_init(ptdesc);
> +	}
> +

I'd have said "the initialization is cheap, why bother", but we already do have
the mm_is_kernel() check in place, so

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

-- 
Cheers,

David


^ permalink raw reply

* Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
From: Leon Romanovsky @ 2026-07-21 15:33 UTC (permalink / raw)
  To: Aneesh Kumar K.V
  Cc: iommu, linux-arm-kernel, linux-kernel, linux-coco, Robin Murphy,
	Marek Szyprowski, Will Deacon, Marc Zyngier, Steven Price,
	Suzuki K Poulose, Catalin Marinas, Jiri Pirko, Jason Gunthorpe,
	Mostafa Saleh, Petr Tesarik, Alexey Kardashevskiy, Dan Williams,
	Xu Yilun, linuxppc-dev, linux-s390, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Alexander Gordeev, Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger, Sven Schnelle, x86, stable, Michael Kelley,
	Jason Gunthorpe
In-Reply-To: <yq5ao6g0750v.fsf@kernel.org>

On Tue, Jul 21, 2026 at 08:40:08PM +0530, Aneesh Kumar K.V wrote:
> Leon Romanovsky <leon@kernel.org> writes:
> 
> > On Tue, Jul 21, 2026 at 07:50:10PM +0530, Aneesh Kumar K.V wrote:
> >> Leon Romanovsky <leon@kernel.org> writes:
> >> 
> >> > On Fri, Jul 17, 2026 at 11:34:19PM +0530, Aneesh Kumar K.V (Arm) wrote:
> ....
> >> >>  static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size,
> >> >> @@ -247,8 +246,11 @@ void *dma_direct_alloc(struct device *dev, size_t size,
> >> >>  	 * the atomic pools instead if we aren't allowed block.
> >> >>  	 */
> >> >>  	if ((remap || force_dma_unencrypted(dev)) &&
> >> >> -	    dma_direct_use_pool(dev, gfp))
> >> >> -		return dma_direct_alloc_from_pool(dev, size, dma_handle, gfp);
> >> >> +	    dma_direct_use_pool(dev, gfp)) {
> >> >> +		page = dma_direct_alloc_from_pool(dev, size, dma_handle,
> >> >> +						  &ret, gfp);
> >> >> +		return page ? ret : NULL;
> >> >
> >> > Sorry for joining the discussion late, but the line above caught my
> >> > attention.
> >> >
> >> > Why do we need both ret and page? We can derive cpu_addr from page and
> >> > vice versa. Do we really need the &ret parameter? Or, more generally, do
> >> > we really need "struct page *"?
> >> >
> >> > static struct page *__dma_alloc_from_pool(struct device *dev, size_t size,
> >> > 		struct gen_pool *pool, void **cpu_addr,
> >> > 		bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t))
> >> > {
> >> > ...
> >> > 	*cpu_addr = (void *)addr;
> >> > 	memset(*cpu_addr, 0, size);
> >> > 	return pfn_to_page(__phys_to_pfn(phys));
> >> > }
> >> >
> >> > Why
> >> >
> >> 
> >> With CONFIG_DMA_DIRECT_REMAP the cpu_addr can be different from
> >> page_address.
> >
> > Can you please point to the code there it can happen?
> > __dma_alloc_from_pool() has direct connection between physical address
> > and struct page.
> >
> 
> dma_direct_alloc -> 	remap = IS_ENABLED(CONFIG_DMA_DIRECT_REMAP);
> 	if ((remap && dma_direct_use_pool(dev, gfp)) {
> 		page = dma_direct_alloc_from_pool(dev, size,
> 
> ..
> __dma_alloc_from_pool -> 
> 	addr = gen_pool_alloc(pool, size);
> 	if (!addr)
> 
> 
> We expand the pool as below..
> 
> atomic_pool_expand ->
> 
> #ifdef CONFIG_DMA_DIRECT_REMAP
> 	addr = dma_common_contiguous_remap(page, pool_size,
> 			pgprot_decrypted(pgprot_dmacoherent(PAGE_KERNEL)),
> 			__builtin_return_address(0));
> 	if (!addr)
> 		goto free_page;
> #else
> 	addr = page_to_virt(page);
> #endif

Right, and nothing prevents you from adding a small DMA helper
that translates mapped/direct addresses back to struct page.

Something like, but probably void* needs to be phys_addr_t:

static inline struct page *dma_phys_to_page(void *addr)
{
#ifdef CONFIG_DMA_DIRECT_REMAP
	return vmalloc_to_page(addr);
#else
	return virt_to_page(addr);
#endif
}

Architecture code already does this throughout the tree.

Thanks


> 
> 
> -aneesh
> 


^ permalink raw reply

* Re: [PATCH v8 02/23] dma-pool: fix page leak in atomic_pool_expand() cleanup
From: Leon Romanovsky @ 2026-07-21 15:34 UTC (permalink / raw)
  To: Aneesh Kumar K.V
  Cc: iommu, linux-arm-kernel, linux-kernel, linux-coco, Robin Murphy,
	Marek Szyprowski, Will Deacon, Marc Zyngier, Steven Price,
	Suzuki K Poulose, Catalin Marinas, Jiri Pirko, Jason Gunthorpe,
	Mostafa Saleh, Petr Tesarik, Alexey Kardashevskiy, Dan Williams,
	Xu Yilun, linuxppc-dev, linux-s390, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Alexander Gordeev, Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger, Sven Schnelle, x86, Jason Gunthorpe,
	Michael Kelley
In-Reply-To: <yq5aqzkw76ch.fsf@kernel.org>

On Tue, Jul 21, 2026 at 08:11:34PM +0530, Aneesh Kumar K.V wrote:
> Leon Romanovsky <leon@kernel.org> writes:
> 
> > On Fri, Jul 17, 2026 at 11:34:20PM +0530, Aneesh Kumar K.V (Arm) wrote:
> >> atomic_pool_expand() frees the allocated pages from the remove_mapping
> >> error path only when CONFIG_DMA_DIRECT_REMAP is enabled.
> >> 
> >> When CONFIG_DMA_DIRECT_REMAP is disabled, failures after page allocation,
> >> such as gen_pool_add_virt(), jump to remove_mapping and return without
> >> freeing the pages.
> >> 
> >> Move __free_pages(page, order) out of the CONFIG_DMA_DIRECT_REMAP block so
> >> that cleanup paths always release the allocation.
> >> 
> >> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
> >> Tested-by: Michael Kelley <mhklinux@outlook.com>
> >> Tested-by: Mostafa Saleh <smostafa@google.com>
> >> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
> >> ---
> >>  kernel/dma/pool.c | 10 +++++++---
> >>  1 file changed, 7 insertions(+), 3 deletions(-)
> >> 
> >> diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c
> >> index 2b2fbb709242..b0303efbc153 100644
> >> --- a/kernel/dma/pool.c
> >> +++ b/kernel/dma/pool.c
> >> @@ -81,6 +81,7 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
> >>  {
> >>  	unsigned int order;
> >>  	struct page *page = NULL;
> >> +	bool leak_pages = false;
> >>  	void *addr;
> >>  	int ret = -ENOMEM;
> >>  
> >> @@ -115,8 +116,10 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
> >>  	 */
> >>  	ret = set_memory_decrypted((unsigned long)page_to_virt(page),
> >>  				   1 << order);
> >> -	if (ret)
> >> +	if (ret) {
> >> +		leak_pages = true;
> >>  		goto remove_mapping;
> >> +	}
> >>  	ret = gen_pool_add_virt(pool, (unsigned long)addr, page_to_phys(page),
> >>  				pool_size, NUMA_NO_NODE);
> >>  	if (ret)
> >> @@ -130,14 +133,15 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
> >>  				   1 << order);
> >>  	if (WARN_ON_ONCE(ret)) {
> >>  		/* Decrypt succeeded but encrypt failed, purposely leak */
> >> -		goto out;
> >> +		leak_pages = true;
> >
> > Instead of doing this dance with temporal variable, change "goto out" to
> > be "return true".
> >
> 
> 
> I didn't follow the return true part. A failure in
> set_memory_encrypted() or set_memory_decrypted() requires the pages to
> be leaked, so this is not the only call site that sets leak_pages =
> true. There is a similar case a few lines above.

Comment about "leaked" is enough. There is no need to introduce
convoluted flow just to check that page != NULL.

Thanks

> 
> 
> >
> >>  	}
> >>  remove_mapping:
> >>  #ifdef CONFIG_DMA_DIRECT_REMAP
> >>  	dma_common_free_remap(addr, pool_size);
> >>  free_page:
> >
> > Remove free_page label, and change leftover of "goto free_page" to be
> > "goto out"
> >
> >> -	__free_pages(page, order);
> >>  #endif
> >> +	if (!leak_pages)
> >> +		__free_pages(page, order);
> >
> > Put these checks under out label and rely on page != NULL as a marker.
> > if (page)
> >  __free_pages(page, order);
> >
> >>  out:
> >>  	return ret;
> >>  }
> >> -- 
> >> 2.43.0
> >> 
> >> 
> 
> -aneesh
> 


^ permalink raw reply

* [PATCH 2/2] powerpc/pseries: Avoid strlen() in do_{remove,update}_property()
From: Thorsten Blum @ 2026-07-21 15:53 UTC (permalink / raw)
  To: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Kees Cook
  Cc: Thorsten Blum, linuxppc-dev, linux-kernel
In-Reply-To: <20260721155346.121975-3-thorsten.blum@linux.dev>

Check only the first byte instead of scanning the entire string with
strlen().

Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
---
 arch/powerpc/platforms/pseries/reconfig.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index 7faebcffc9df..18e3f1a036e3 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -307,7 +307,7 @@ static int do_remove_property(char *buf, size_t bufsize)
 	if (tmp)
 		*tmp = '\0';
 
-	if (strlen(buf) == 0)
+	if (*buf == '\0')
 		return -EINVAL;
 
 	return of_remove_property(np, of_find_property(np, buf, NULL));
@@ -330,7 +330,7 @@ static int do_update_property(char *buf, size_t bufsize)
 	if (!next_prop)
 		return -EINVAL;
 
-	if (!strlen(name))
+	if (*name == '\0')
 		return -ENODEV;
 
 	newprop = new_property(name, length, value, NULL);


^ permalink raw reply related

* [PATCH 1/2] powerpc/powernv: Avoid strlen() in pnv_restart()
From: Thorsten Blum @ 2026-07-21 15:53 UTC (permalink / raw)
  To: Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Aboorva Devarajan
  Cc: Thorsten Blum, linuxppc-dev, linux-kernel

Check only the first byte instead of scanning the entire string with
strlen().

Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
---
 arch/powerpc/platforms/powernv/setup.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index 06ed5e2aa265..2af92e7ba4ee 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -312,7 +312,7 @@ static void  __noreturn pnv_restart(char *cmd)
 	pnv_prepare_going_down();
 
 	do {
-		if (!cmd || !strlen(cmd))
+		if (!cmd || *cmd == '\0')
 			rc = opal_cec_reboot();
 		else if (strcmp(cmd, "full") == 0)
 			rc = opal_cec_reboot2(OPAL_REBOOT_FULL_IPL, NULL);


^ permalink raw reply related

* [PATCH 6.18 0617/1611] powerpc tools perf: Initialize error code in auxtrace_record_init function
From: Greg Kroah-Hartman @ 2026-07-21 15:12 UTC (permalink / raw)
  To: stable
  Cc: Greg Kroah-Hartman, patches, Adrian Hunter, Athira Rajeev,
	Namhyung Kim, Hari Bathini, Ian Rogers, Jiri Olsa, linuxppc-dev,
	Madhavan Srinivasan, Michael Petlan, Shivani Nittor,
	Tanushree Shah, Tejas Manhas, Thomas Richter,
	Arnaldo Carvalho de Melo, Sasha Levin
In-Reply-To: <20260721152514.750365251@linuxfoundation.org>

6.18-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Athira Rajeev <atrajeev@linux.ibm.com>

[ Upstream commit 789d22d77879eabb042627f6627cdb62787bc142 ]

perf trace record fails some cases in powerpc

 # perf test "perf trace record and replay"
 128: perf trace record and replay                                    : FAILED!

  # perf trace record sleep 1
  # echo $?
    32

This is happening because of non-zero err value from
auxtrace_record__init() function.

 static int record__auxtrace_init(struct record *rec)
 {
        int err;

        if ((rec->opts.auxtrace_snapshot_opts || rec->opts.auxtrace_sample_opts)
            && record__threads_enabled(rec)) {
                pr_err("AUX area tracing options are not available in parallel streaming mode.\n");
                return -EINVAL;
        }

        if (!rec->itr) {
                rec->itr = auxtrace_record__init(rec->evlist, &err);
                if (err)
                        return err;
        }

Here "int err" is not initialised. The code expects "err" to be set from
auxtrace_record__init() function.

Update auxtrace_record__init() in arch/powerpc/util/auxtrace.c to clear
err value in the beginning.

- Clear err value in beginning of function. Any fail later will
set appropriate return code to err.

- Even if we haven't found any event for auxtrace, perf record
should continue for other events. NULL return
will indicate that there is no auxtrace record initialized.

- Not having "err" set here will affect monitoring of other events
also because perf record will fail seeing random value in err.

Set err to -EINVAL before invoking auxtrace_record__init() in
builtin-record.c

With the fix,

  # perf trace record sleep 1
  [ perf record: Woken up 2 times to write data ]
  [ perf record: Captured and wrote 0.033 MB perf.data (228 samples) ]

Fixes: 1dbfaf94cf66ec4b ("perf powerpc: Add basic CONFIG_AUXTRACE support for VPA pmu on powerpc")
Reviewed-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Athira Rajeev <atrajeev@linux.ibm.com>
Cc: Hari Bathini <hbathini@linux.vnet.ibm.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: linuxppc-dev@lists.ozlabs.org
Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Michael Petlan <mpetlan@redhat.com>
Cc: Shivani Nittor <shivani@linux.ibm.com>
Cc: Tanushree Shah <tanushree.shah@ibm.com>
Cc: Tejas Manhas <tejas.manhas1@ibm.com>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 tools/perf/arch/powerpc/util/auxtrace.c | 6 ++++++
 tools/perf/builtin-record.c             | 1 +
 2 files changed, 7 insertions(+)

diff --git a/tools/perf/arch/powerpc/util/auxtrace.c b/tools/perf/arch/powerpc/util/auxtrace.c
index 62c6f67f1bbe66..57f2910c0b0198 100644
--- a/tools/perf/arch/powerpc/util/auxtrace.c
+++ b/tools/perf/arch/powerpc/util/auxtrace.c
@@ -70,6 +70,12 @@ struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
 	struct evsel *pos;
 	int found = 0;
 
+	/*
+	 * Set err value to zero here. Any fail later
+	 * will set appropriate return code to err.
+	 */
+	*err = 0;
+
 	evlist__for_each_entry(evlist, pos) {
 		if (strstarts(pos->name, "vpa_dtl")) {
 			found = 1;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index b1fb87016d5aa9..2563ef66a4d946 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -867,6 +867,7 @@ static int record__auxtrace_init(struct record *rec)
 	}
 
 	if (!rec->itr) {
+		err = -EINVAL;
 		rec->itr = auxtrace_record__init(rec->evlist, &err);
 		if (err)
 			return err;
-- 
2.53.0





^ permalink raw reply related

* [PATCH 7.1 0901/2077] powerpc tools perf: Initialize error code in auxtrace_record_init function
From: Greg Kroah-Hartman @ 2026-07-21 15:09 UTC (permalink / raw)
  To: stable
  Cc: Greg Kroah-Hartman, patches, Adrian Hunter, Athira Rajeev,
	Namhyung Kim, Hari Bathini, Ian Rogers, Jiri Olsa, linuxppc-dev,
	Madhavan Srinivasan, Michael Petlan, Shivani Nittor,
	Tanushree Shah, Tejas Manhas, Thomas Richter,
	Arnaldo Carvalho de Melo, Sasha Levin
In-Reply-To: <20260721152552.646164743@linuxfoundation.org>

7.1-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Athira Rajeev <atrajeev@linux.ibm.com>

[ Upstream commit 789d22d77879eabb042627f6627cdb62787bc142 ]

perf trace record fails some cases in powerpc

 # perf test "perf trace record and replay"
 128: perf trace record and replay                                    : FAILED!

  # perf trace record sleep 1
  # echo $?
    32

This is happening because of non-zero err value from
auxtrace_record__init() function.

 static int record__auxtrace_init(struct record *rec)
 {
        int err;

        if ((rec->opts.auxtrace_snapshot_opts || rec->opts.auxtrace_sample_opts)
            && record__threads_enabled(rec)) {
                pr_err("AUX area tracing options are not available in parallel streaming mode.\n");
                return -EINVAL;
        }

        if (!rec->itr) {
                rec->itr = auxtrace_record__init(rec->evlist, &err);
                if (err)
                        return err;
        }

Here "int err" is not initialised. The code expects "err" to be set from
auxtrace_record__init() function.

Update auxtrace_record__init() in arch/powerpc/util/auxtrace.c to clear
err value in the beginning.

- Clear err value in beginning of function. Any fail later will
set appropriate return code to err.

- Even if we haven't found any event for auxtrace, perf record
should continue for other events. NULL return
will indicate that there is no auxtrace record initialized.

- Not having "err" set here will affect monitoring of other events
also because perf record will fail seeing random value in err.

Set err to -EINVAL before invoking auxtrace_record__init() in
builtin-record.c

With the fix,

  # perf trace record sleep 1
  [ perf record: Woken up 2 times to write data ]
  [ perf record: Captured and wrote 0.033 MB perf.data (228 samples) ]

Fixes: 1dbfaf94cf66ec4b ("perf powerpc: Add basic CONFIG_AUXTRACE support for VPA pmu on powerpc")
Reviewed-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Athira Rajeev <atrajeev@linux.ibm.com>
Cc: Hari Bathini <hbathini@linux.vnet.ibm.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: linuxppc-dev@lists.ozlabs.org
Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Michael Petlan <mpetlan@redhat.com>
Cc: Shivani Nittor <shivani@linux.ibm.com>
Cc: Tanushree Shah <tanushree.shah@ibm.com>
Cc: Tejas Manhas <tejas.manhas1@ibm.com>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 tools/perf/arch/powerpc/util/auxtrace.c | 6 ++++++
 tools/perf/builtin-record.c             | 1 +
 2 files changed, 7 insertions(+)

diff --git a/tools/perf/arch/powerpc/util/auxtrace.c b/tools/perf/arch/powerpc/util/auxtrace.c
index e39deff6c857a8..4600a1661b4fe3 100644
--- a/tools/perf/arch/powerpc/util/auxtrace.c
+++ b/tools/perf/arch/powerpc/util/auxtrace.c
@@ -71,6 +71,12 @@ struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
 	struct evsel *pos;
 	int found = 0;
 
+	/*
+	 * Set err value to zero here. Any fail later
+	 * will set appropriate return code to err.
+	 */
+	*err = 0;
+
 	evlist__for_each_entry(evlist, pos) {
 		if (strstarts(pos->name, "vpa_dtl")) {
 			found = 1;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4a5eba498c0259..708825747af5da 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -865,6 +865,7 @@ static int record__auxtrace_init(struct record *rec)
 	}
 
 	if (!rec->itr) {
+		err = -EINVAL;
 		rec->itr = auxtrace_record__init(rec->evlist, &err);
 		if (err)
 			return err;
-- 
2.53.0





^ permalink raw reply related

* Re: [PATCH v18 10/13] cxl: Add port and dport identifiers to CXL AER trace events
From: Bowman, Terry @ 2026-07-21 20:59 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Bjorn Helgaas, Dan Williams, Dave Jiang, Ira Weiny, Len Brown,
	Rafael J . Wysocki, Robert Richter, linux-acpi, linux-cxl,
	linux-doc, linux-kernel, linux-pci, linuxppc-dev,
	Alejandro Lucero, Alison Schofield, Ankit Agrawal, Ard Biesheuvel,
	Ben Cheatham, Borislav Petkov, Breno Leitao, Davidlohr Bueso,
	Fabio M . De Francesco, Gregory Price, Hanjun Guo,
	Jonathan Corbet, Kees Cook, Kuppuswamy Sathyanarayanan, Li Ming,
	Mahesh J Salgaonkar, Mauro Carvalho Chehab, Oliver O'Halloran,
	Shiju Jose, Shuah Khan, Shuai Xue, Smita Koralahalli, Tony Luck,
	Vishal Verma, linux-acpi, linux-cxl@vger.kernel.org, linux-doc,
	linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
In-Reply-To: <20260721010050.7b5654fb@jic23-huawei>

On 7/20/2026 7:00 PM, Jonathan Cameron wrote:
> On Fri, 17 Jul 2026 17:27:03 -0500
> Terry Bowman <terry.bowman@amd.com> wrote:
> 
>> From: Dan Williams <djbw@kernel.org>
>>
>> Pass struct cxl_port * and struct cxl_dport * to the cxl_aer_*
>> trace events instead of a plain struct device * derived at the
>> caller. The trace event helpers then derive the right strings for
>> endpoints, switch ports, root ports, and RCH downstream ports
>> consistently across the CPER and native AER paths.
>>
>> The unified cxl_aer_* events keep "memdev" as the legacy field
>> (endpoint events populate it with the memdev name; non-endpoint
>> events emit memdev="") and add new "port" and "dport" string fields
>> populated for all CXL device classes. Updated userspace can key
>> off "port" and "dport" without a parallel set of events.
>>
>> Remove the separate cxl_port_aer_uncorrectable_error and
>> cxl_port_aer_correctable_error trace events. All CXL AER events now
>> use the unified cxl_aer_* events with port and dport fields.
>>
>> Rework cxl_cper_handle_prot_err() to use find_cxl_port_by_dev() and
>> the unified trace helpers, replacing the per-port-type branching and
>> bus_find_device() memdev lookup.
>>
>> The TP_printk format string places "port=%s dport=%s" between
>> "memdev=%s" and "host=%s", changing the text-mode field order from
>> the pre-patch output. This does not affect consumers such as
>> rasdaemon that use libtraceevent to parse fields by name rather than
>> by fixed text position.
>>
>> For non-endpoint events (switch port, root port, RCH dport),
>> "memdev" is empty and "port"/"dport" carry the topology information.
>>
>> The serial number is retrieved via pci_get_dsn() which performs live
>> PCI configuration space reads. A following patch ("PCI: Cache PCI
>> DSN into pci_dev->dsn during probe") replaces these with a cached
>> serial number to avoid config space access in error handlers and panic
>> paths.
>>
>> Below are examples of the different CXL devices' error trace logs
>> after this patch:
>>
>>      ---------------------
>>      | CXL RP - 0C:00.0  |
>>      ---------------------
>>                |
>>      ---------------------
>>      | CXL USP - 0D:00.0 |
>>      ---------------------
>>                |
>>      --------------------
>>      | CXL DSP - 0E:00.0 |
>>      --------------------
>>                |
>>      ---------------------
>>      | CXL EP - 0F:00.0  |
>>      ---------------------
>>
>> Root Port:
>> cxl_aer_correctable_error: memdev= port=port1 dport=0000:0c:00.0 \
>>    host=pci0000:0c serial=0: status: 'Memory Data ECC Error'
>>
>> cxl_aer_uncorrectable_error: memdev= port=port1 dport=0000:0c:00.0 \
>>    host=pci0000:0c serial=0: status: 'Cache Address Parity Error'  \
>>    first_error: 'Cache Address Parity Error'
>>
>> Upstream Switch Port:
>> cxl_aer_correctable_error: memdev= port=port2 dport= host=0000:0d:00.0 \
>>    serial=0: status: 'Memory Data ECC Error'
>>
>> UCE NA - Upstream Switch Port UCE's are handled in the portdrv driver's
>> PCI AER callbacks that are not CXL aware.
>>
>> Downstream Switch Port:
>> cxl_aer_correctable_error: memdev= port=port2 dport=0000:0e:00.0 \
>>    host=0000:0d:00.0 serial=0: status: 'Memory Data ECC Error'
>>
>> cxl_aer_uncorrectable_error: memdev= port=port2 dport=0000:0e:00.0 \
>>    host=0000:0d:00.0 serial=0: status: 'Cache Address Parity Error' \
>>    first_error: 'Cache Address Parity Error'
>>
>> Endpoint:
>> cxl_aer_uncorrectable_error: memdev=mem1 port=endpoint4 dport= \
>>    host=0000:0f:00.0 serial=0: status: 'Cache Address Parity Error' \
>>    first_error: 'Cache Address Parity Error'
>>
>> cxl_aer_correctable_error: memdev=mem1 port=endpoint4 dport= host=0000:0f:00.0 \
>>    serial=0: status: 'Memory Data ECC Error'
>>
>> Co-developed-by: Terry Bowman <terry.bowman@amd.com>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> Signed-off-by: Dan Williams <djbw@kernel.org>
> 
> One question inline about reference counts for the port.
> 
>>
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index d5dc2c22565da..acf40b2396c3b 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
> ...
>>  
>> @@ -109,47 +77,34 @@ static struct cxl_port *find_cxl_port_by_dev(struct device *dev, struct cxl_dpor
>>  
>>  void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data)
>>  {
>> +	struct cxl_dport *dport;
>>  	unsigned int devfn = PCI_DEVFN(data->prot_err.agent_addr.device,
>>  				       data->prot_err.agent_addr.function);
>> -	struct pci_dev *pdev __free(pci_dev_put) =
>> -		pci_get_domain_bus_and_slot(data->prot_err.agent_addr.segment,
>> -					    data->prot_err.agent_addr.bus,
>> -					    devfn);
>> -	struct cxl_memdev *cxlmd;
>> -	int port_type;
>> -
>> -	if (!pdev)
>> -		return;
>> -
>> -	port_type = pci_pcie_type(pdev);
>> -	if (port_type == PCI_EXP_TYPE_ROOT_PORT ||
>> -	    port_type == PCI_EXP_TYPE_DOWNSTREAM ||
>> -	    port_type == PCI_EXP_TYPE_UPSTREAM) {
>> -		if (data->severity == AER_CORRECTABLE)
>> -			cxl_cper_trace_corr_port_prot_err(pdev, data->ras_cap);
>> -		else
>> -			cxl_cper_trace_uncorr_port_prot_err(pdev, data->ras_cap);
>> -
>> +	struct pci_dev *pdev __free(pci_dev_put) = pci_get_domain_bus_and_slot(
>> +		data->prot_err.agent_addr.segment, data->prot_err.agent_addr.bus, devfn);
>> +	if (!pdev) {
>> +		pr_err_ratelimited("Failed to find CPER device in CXL topology\n");
>>  		return;
>>  	}
>>  
>> -	guard(device)(&pdev->dev);
>> -	if (!pdev->dev.driver) {
>> -		dev_warn_ratelimited(&pdev->dev,
>> -				     "Device is unbound, abort CPER error handling\n");
>> +	struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_dev(&pdev->dev, NULL);
>> +	if (!port) {
>> +		dev_err_ratelimited(&pdev->dev,
>> +				    "Failed to find parent port device in CXL topology\n");
>>  		return;
>>  	}
>>  
>> -	struct device *mem_dev __free(put_device) = bus_find_device(
>> -		&cxl_bus_type, NULL, pdev, match_memdev_by_parent);
>> -	if (!mem_dev)
>> -		return;
>> +	guard(device)(&port->dev);
> 
> Don't we have a reference for this from find_cxl_port_by_dev()?
> 
> Superficially scope looks the same.
> 
> 

I somehow missed this yesterday. Yes, find_cxl_port_by_dev() ref increments. 

>> +
>> +	/* dport is NULL for Endpoint and Upstream Port devices */
>> +	dport = cxl_find_dport_by_dev(port, &pdev->dev);
>>  
>> -	cxlmd = to_cxl_memdev(mem_dev);
>>  	if (data->severity == AER_CORRECTABLE)
>> -		cxl_cper_trace_corr_prot_err(cxlmd, data->ras_cap);
>> +		cxl_cper_trace_corr_prot_err(port, dport, pci_get_dsn(pdev),
>> +					     &data->ras_cap);
>>  	else
>> -		cxl_cper_trace_uncorr_prot_err(cxlmd, data->ras_cap);
>> +		cxl_cper_trace_uncorr_prot_err(port, dport, pci_get_dsn(pdev),
>> +					       &data->ras_cap);
>>  }
>>  EXPORT_SYMBOL_GPL(cxl_cper_handle_prot_err);
>>  
>> @@ -240,14 +195,14 @@ void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dpo
>>  		return;
>>  	}
>>  
>> -	if (cxl_handle_ras(port, dport, ras_base))
>> +	if (cxl_handle_ras(port, dport, ras_base, pci_get_dsn(pdev)))
>>  		panic("CXL cachemem error");
>>  
>>  	dev_dbg(&pdev->dev,
>>  		"CXL UCE signaled but no CXL RAS status bits set\n");
>>  }
>>  
>> -void cxl_handle_cor_ras(struct cxl_port *port, struct cxl_dport *dport, void __iomem *ras_base)
>> +void cxl_handle_cor_ras(struct cxl_port *port, struct cxl_dport *dport, void __iomem *ras_base, u64 serial)
> That's over even the modern 100 char limit. Needs a line break.
>>  {
> 

Yup, I'll linewrap at 75-80. Thanks.

- Terry



^ permalink raw reply

* Re: [kvm-unit-tests PATCH v2 0/6] powerpc improvements
From: Aniket Sahu @ 2026-07-21 17:12 UTC (permalink / raw)
  To: Chinmay Rath, thuth
  Cc: npiggin, harshpb, lvivier, linuxppc-dev, kvm, andrew.jones, sbhat,
	asahu1x
In-Reply-To: <7cf674d9-6928-47a3-9d80-c1bd22ae6f7b@linux.ibm.com>

Sorry for the formatting mess in my previous email, my mail client 
stripped the linebreaks. Here is the readable version:

On Sun, 19 Jul 2026, Chinmay Rath wrote:
 > This series aims to add a couple of new powerpc tests and improve
 > the powerpc build structure.

Tested on POWER10 (native KVM, ppc64le).

Tested-by: Aniket Sahu <asahu1x@linux.ibm.com>

--- Environment ---

   Host CPU   : POWER10 (architected), altivec supported
   Kernel     : Linux 7.0.0-27-generic #27-Ubuntu SMP PREEMPT_DYNAMIC
                Thu Jun 18 19:14:19 UTC 2026 ppc64le GNU/Linux
   OS         : Ubuntu 26.04 LTS (Resolute Raccoon)
   QEMU       : 10.2.1 (Debian 1:10.2.1+ds-1ubuntu3.1)
   Accelerator: KVM (-accel kvm -machine pseries,cap-ccf-assist=off)
   Branch     : origin/ppc64 @ dde8f397

--- Test: pmu (Patch 1) ---

   $ ./run_tests.sh -a powerpc pmu
   PASS pmu (22 tests, 1 known failure)

Full log:

   timeout -k 1s --foreground 90s \
     /usr/bin/qemu-system-ppc64 -nodefaults -accel kvm \
     -machine pseries,cap-ccf-assist=off -bios powerpc/boot_rom.bin \
     -display none -serial stdio -kernel powerpc/pmu.elf -smp 1

   PASS: pmu: pmc56: PMC5 zeroed
   PASS: pmu: pmc56: PMC6 zeroed
   PASS: pmu: pmc56: PMC5 frozen
   PASS: pmu: pmc56: PMC6 frozen
   PASS: pmu: pmc56: PMC5 counting
   PASS: pmu: pmc56: PMC6 counting
   PASS: pmu: pmc56: PMC6 ratio to reported clock frequency is 116%
   PASS: pmu: pmc56: PMC5 counts instructions precisely 900
   PASS: pmu: pmc56: PMC5 counts instructions exactly 21
   PASS: pmu: pmc56: PMC5 counts instructions with branch 21
   PASS: pmu: pmc56: PMC5 counts instructions wth conditional branch 24
   PASS: pmu: pmc56: PMC5 counts instructions with illegal instruction
   PASS: pmu: pmc56: PMC5 counts instructions with fault
   PASS: pmu: pmc56: PMC5 counts instructions with syscall
   PASS: pmu: pmc56: PMC5 counts instructions with rfid 2
   PASS: pmu: pmc56: PMC5 counts instructions with ldat
   PASS: pmu: pmi: PMAO caused interrupt
   PASS: pmu: bhrb: BHRB is frozen
   PASS: pmu: bhrb: BHRB has been written
   KFAIL: pmu: bhrb: BHRB has written 8 entries
   PASS: pmu: bhrb: BHRB has written 4 entries
   PASS: pmu: bhrb: correct conditional branch address
   SUMMARY: 22 tests, 1 known failure

   EXIT: STATUS=1

Note: The KFAIL on "BHRB has written 8 entries" is expected. POWER10
records 4 BHRB entries when other threads are active on the core; the
test explicitly accounts for this with a fallback 4-entry check which
passes. STATUS=1 is the correct exit code when known failures exist.

--- Test: selftest-setup (Patch 3/build structure) ---

   $ ./run_tests.sh -a powerpc selftest-setup
   PASS selftest-setup (2 tests)

Full log:

   timeout -k 1s --foreground 90s \
     /usr/bin/qemu-system-ppc64 -nodefaults -accel kvm \
     -machine pseries,cap-ccf-assist=off -bios powerpc/boot_rom.bin \
     -display none -serial stdio -kernel powerpc/selftest.elf \
     -smp 2 -append setup smp=2 mem=1024 -m 1g

   PASS: selftest: setup: smp: nr_cpus_present = 2
   PASS: selftest: setup: mem: size = 1024 MB
   SUMMARY: 2 tests

   EXIT: STATUS=1

--- Test: selftest-panic (Patches 5 & 6) ---

   $ ./run_tests.sh -a powerpc selftest-panic
   PASS selftest-panic

Full log:

   run_panic timeout -k 1s --foreground 90s \
     /usr/bin/qemu-system-ppc64 -nodefaults -accel kvm \
     -machine pseries,cap-ccf-assist=off -bios powerpc/boot_rom.bin \
     -display none -serial stdio -kernel powerpc/selftest.elf \
     -smp 1 -append panic

   qemu-system-ppc64: OS terminated: rtas_os_panic
   PASS: guest panicked

   EXIT: STATUS=1

Note: The panic test validates both the new rtas_os_panic() RTAS call
(Patch 6) and the run_panic() exit status fix (Patch 5). QEMU exits
with "OS terminated: rtas_os_panic" confirming the ibm,os-term RTAS
token is correctly invoked, and the test runner correctly identifies
this as a successful (expected) panic.

Aniket Sahu


^ permalink raw reply

* [PATCH] ASoC: fsl: dma: use platform helpers and devm cleanup
From: Rosen Penev @ 2026-07-21 22:54 UTC (permalink / raw)
  To: linux-sound
  Cc: Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen,
	Liam Girdwood, Mark Brown, Jaroslav Kysela, Takashi Iwai,
	Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
	open list:FREESCALE SOC SOUND DRIVERS, open list,
	open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b

Convert fsl_soc_dma_probe() to managed APIs. Replace the open-coded
of_address_to_resource()/of_iomap() of the DMA channel registers with
devm_platform_ioremap_resource(), and irq_of_parse_and_map() with
platform_get_irq() (which returns a negative errno instead of 0).
Switch the allocation to devm_kzalloc() and register the component via
the devm variant, dropping the now-unneeded error-path cleanup and the
manual fsl_soc_dma_remove().

The SSI node's register resource is still read via of_address_to_resource()
to compute the SSI FIFO physical addresses (dma->ssi_stx_phys /
ssi_srx_phys); only the DMA controller window is mapped.

The DMA controller register window is owned solely by this driver, so the
new region request from devm_platform_ioremap_resource() cannot conflict
with another claimant, and it is mapped exactly once (no double mapping).

The local channel pointer is declared as void __iomem * so the
devm_platform_ioremap_resource() result can be stored before assignment
to dma->channel.

No functional change; built for powerpc (allmodconfig + CONFIG_SND_SOC_FSL_DMA)
with LLVM=1 and sound/soc/fsl/fsl_dma.o compiles cleanly.

Assisted-by: opencode:hy3-free
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 sound/soc/fsl/fsl_dma.c | 68 ++++++++++++++++-------------------------
 1 file changed, 27 insertions(+), 41 deletions(-)

diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index b12474880185..b1b341132dd6 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -18,8 +18,6 @@
 #include <linux/delay.h>
 #include <linux/gfp.h>
 #include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
 #include <linux/list.h>
 #include <linux/slab.h>
 
@@ -824,9 +822,34 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
 	struct device_node *np = pdev->dev.of_node;
 	struct device_node *ssi_np;
 	struct resource res;
+	void __iomem *channel;
 	const uint32_t *iprop;
+	int irq;
 	int ret;
 
+	channel = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(channel))
+		return PTR_ERR(channel);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	dma = devm_kzalloc(&pdev->dev, sizeof(*dma), GFP_KERNEL);
+	if (!dma)
+		return -ENOMEM;
+
+	dma->dai.name = DRV_NAME;
+	dma->dai.open = fsl_dma_open;
+	dma->dai.close = fsl_dma_close;
+	dma->dai.hw_params = fsl_dma_hw_params;
+	dma->dai.hw_free = fsl_dma_hw_free;
+	dma->dai.pointer = fsl_dma_pointer;
+	dma->dai.pcm_new = fsl_dma_new;
+
+	dma->channel = channel;
+	dma->irq = irq;
+
 	/* Find the SSI node that points to us. */
 	ssi_np = find_ssi_node(np);
 	if (!ssi_np) {
@@ -842,55 +865,19 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	dma = kzalloc_obj(*dma);
-	if (!dma) {
-		of_node_put(ssi_np);
-		return -ENOMEM;
-	}
-
-	dma->dai.name = DRV_NAME;
-	dma->dai.open = fsl_dma_open;
-	dma->dai.close = fsl_dma_close;
-	dma->dai.hw_params = fsl_dma_hw_params;
-	dma->dai.hw_free = fsl_dma_hw_free;
-	dma->dai.pointer = fsl_dma_pointer;
-	dma->dai.pcm_new = fsl_dma_new;
-
 	/* Store the SSI-specific information that we need */
 	dma->ssi_stx_phys = res.start + REG_SSI_STX0;
 	dma->ssi_srx_phys = res.start + REG_SSI_SRX0;
 
 	iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL);
+	of_node_put(ssi_np);
 	if (iprop)
 		dma->ssi_fifo_depth = be32_to_cpup(iprop);
 	else
                 /* Older 8610 DTs didn't have the fifo-depth property */
 		dma->ssi_fifo_depth = 8;
 
-	of_node_put(ssi_np);
-
-	ret = devm_snd_soc_register_component(&pdev->dev, &dma->dai, NULL, 0);
-	if (ret) {
-		dev_err(&pdev->dev, "could not register platform\n");
-		kfree(dma);
-		return ret;
-	}
-
-	dma->channel = of_iomap(np, 0);
-	dma->irq = irq_of_parse_and_map(np, 0);
-
-	dev_set_drvdata(&pdev->dev, dma);
-
-	return 0;
-}
-
-static void fsl_soc_dma_remove(struct platform_device *pdev)
-{
-	struct dma_object *dma = dev_get_drvdata(&pdev->dev);
-
-	iounmap(dma->channel);
-	irq_dispose_mapping(dma->irq);
-	kfree(dma);
+	return devm_snd_soc_register_component(&pdev->dev, &dma->dai, NULL, 0);
 }
 
 static const struct of_device_id fsl_soc_dma_ids[] = {
@@ -905,7 +892,6 @@ static struct platform_driver fsl_soc_dma_driver = {
 		.of_match_table = fsl_soc_dma_ids,
 	},
 	.probe = fsl_soc_dma_probe,
-	.remove = fsl_soc_dma_remove,
 };
 
 module_platform_driver(fsl_soc_dma_driver);
-- 
2.55.0



^ permalink raw reply related

* [PATCH v4 phy-next 1/9] soc: fsl: guts: perform fsl_guts_init() error teardown in reverse order of setup
From: Vladimir Oltean @ 2026-07-21 23:15 UTC (permalink / raw)
  To: linux-phy
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
	Vinod Koul, Neil Armstrong, Tanjeff Moos,
	Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
	linux-kernel
In-Reply-To: <20260721231603.67865-1-vladimir.oltean@nxp.com>

fsl_guts_init() is about to get much more complicated and the central
error handling procedure cannot scale in its current design, unless we
add a lot of "if" conditions to detect what has been allocated and what
hasn't.

Currently the code relies on the fact that kfree(NULL) is safe, but this
doesn't scale to the case where "soc_dev_attr" itself is NULL, because
this would dereference "soc_dev_attr->family" and friends of a NULL
pointer.

Convert to the more typical error handling pattern where the teardown is
in the strict reverse order of setup, and a teardown step is only called
if its corresponding setup step was executed.

At the same time, maintain the optionality of soc_dev_attr->serial_number
by not checking whether that kasprintf() has returned NULL. In the error
path, kfree(NULL) is safe, so we don't need to add an "if" condition for
it. Michael Walle has confirmed that ignoring the error was intentional,
and we preserve that:
https://lore.kernel.org/linux-phy/DK44809N7Y8I.J2Z3U4N32H0Q@kernel.org/

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v3->v4: patch is new
---
 drivers/soc/fsl/guts.c | 33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index 9bee7baec2b9..453456f31800 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -227,17 +227,23 @@ static int __init fsl_guts_init(void)
 	} else {
 		soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ");
 	}
-	if (!soc_dev_attr->family)
-		goto err_nomem;
+	if (!soc_dev_attr->family) {
+		ret = -ENOMEM;
+		goto err_free_soc_dev_attr;
+	}
 
 	soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", svr);
-	if (!soc_dev_attr->soc_id)
-		goto err_nomem;
+	if (!soc_dev_attr->soc_id) {
+		ret = -ENOMEM;
+		goto err_free_family;
+	}
 
 	soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
 					   (svr >>  4) & 0xf, svr & 0xf);
-	if (!soc_dev_attr->revision)
-		goto err_nomem;
+	if (!soc_dev_attr->revision) {
+		ret = -ENOMEM;
+		goto err_free_soc_id;
+	}
 
 	if (soc_data)
 		soc_uid = fsl_guts_get_soc_uid(soc_data->sfp_compat,
@@ -249,7 +255,7 @@ static int __init fsl_guts_init(void)
 	soc_dev = soc_device_register(soc_dev_attr);
 	if (IS_ERR(soc_dev)) {
 		ret = PTR_ERR(soc_dev);
-		goto err;
+		goto err_free_serial_number;
 	}
 
 	pr_info("Machine: %s\n", soc_dev_attr->machine);
@@ -259,13 +265,14 @@ static int __init fsl_guts_init(void)
 
 	return 0;
 
-err_nomem:
-	ret = -ENOMEM;
-err:
-	kfree(soc_dev_attr->family);
-	kfree(soc_dev_attr->soc_id);
-	kfree(soc_dev_attr->revision);
+err_free_serial_number:
 	kfree(soc_dev_attr->serial_number);
+	kfree(soc_dev_attr->revision);
+err_free_soc_id:
+	kfree(soc_dev_attr->soc_id);
+err_free_family:
+	kfree(soc_dev_attr->family);
+err_free_soc_dev_attr:
 	kfree(soc_dev_attr);
 
 	return ret;
-- 
2.34.1



^ permalink raw reply related

* [PATCH v4 phy-next 0/9] RCW override for 10G Lynx dynamic protocol reconfiguration
From: Vladimir Oltean @ 2026-07-21 23:15 UTC (permalink / raw)
  To: linux-phy
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
	Vinod Koul, Neil Armstrong, Tanjeff Moos,
	Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
	linux-kernel, Conor Dooley, Krzysztof Kozlowski, Rob Herring

Previous set "New Generic PHY driver for Lynx 10G SerDes":
https://lore.kernel.org/linux-phy/20260610151952.2141019-1-vladimir.oltean@nxp.com/
introduced the 10G Lynx SerDes driver with a reduced functionality set.
Namely, only minor protocol changes are supported (1GbE <-> 2.5GbE).
The major protocol changes need a procedure named RCW override,
explained in more detail in commits 6/8 and 7/8.

This series adds kernel and device tree binding support for RCW
override, completing the SerDes PHY driver functionality.

Two components are involved:
- drivers/soc/fsl/guts.c (binding is fsl,layerscape-dcfg.yaml) - Device
  Configuration Unit, this is API provider for the SerDes driver to
  request RCW override depending on SoC
- drivers/phy/freescale/phy-fsl-lynx-10g.c - SerDes PHY driver, this is
  API consumer

The guts driver probes on DCFG blocks from multiple Freescale SoC
generations:
- MPC85xx, BSC and QorIQ (PowerPC) are all covered by the
  Documentation/devicetree/bindings/soc/fsl/guts.txt schema
- Layerscape (Arm) is covered by
  Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml

It is ultimately the same hardware block, just that (from what I can
tell) the Layerscape nodes are also compatible with syscon, and PowerPC
aren't.

RCW override has only been validated on select Layerscape SoCs, so
converting guts.txt to a PowerPC schema is out of scope for this
series - we don't even touch that (just in case it gets asked).

Using syscon to map the DCFG_DCSR register block in the Lynx SerDes
driver instead of creating this guts <-> lynx API was considered, but
because the RCW procedure is SoC-specific, it was ruled out for
polluting the SerDes driver. The guts driver is all about SoC awareness
anyway, and it offers some abstraction of all the gory details.

Changes since v3:
- new patch (1/9) to improve the fsl_guts_init() error path. The entire
  patch set is adapted to use the new convention.
- patch 8/9: avoid accessing an invalid soc.rcwcr_lock if
  fsl_guts_lane_set_mode() would be called too early
- patch 8/9: fix serdes block and lane count bounds
- patch 8/9 and 9/9: reimplement LS2088A RCW override in a way that is
  self-contained within the guts driver (based on reading and decoding
  RCWSR29[SRDS_PRTCL_S1]). Only a subset of SRDS_PRTCL_S1 values is
  supported for RCW override, due to availabilty of hardware to test on
  my side. Notably, protocols with XAUI and QSGMII are deliberately
  omitted from the SerDes table because only testing can show whether
  these protocols require RCWSR30_SRDS_CLK_SEL set to GMII or XGMII.
  This new method completely replaces fsl_guts_lane_init(), and has the
  advantage of also figuring out the initial protocol of unmanaged lanes,
  thereby not breaking them on RCW overrides.

v3 at:
https://lore.kernel.org/linux-phy/20260720133642.136324-1-vladimir.oltean@nxp.com/

Changes since v2:
- fix error handling in fsl_guts_init() and make sure that all newly
  introduced RCW override API functions fail if fsl_guts_init() failed.
- replace __bf_shf() use with __ffs()
- use read_poll_timeout_atomic() in fsl_guts_rcw_rmw() to clarify that
  DCFG_DCSR writes are supposed to reflect back in DCFG_CCSR
- only operate on lanes on which fsl_guts_lane_init() was called in
  ls2088a_serdes_init_rcwcr()
- put parentheses around (lane) in LS1088A_RCWSR29_SRDS_PRTCL_S1_LNn()
  and LS1088A_RCWSR30_SRDS_PRTCL_S2_LNn() macro expressions

v2 at:
https://lore.kernel.org/linux-phy/20260612210859.266759-8-vladimir.oltean@nxp.com/

Changes since v1:
- add Conor's review tag on 6/8
- update email addresses of DT maintainers
- drop DT maintainers from explicit CC on patch 7/8
- keep devicetree@vger.kernel.org CCed on entire series
- include missing <linux/bitfield.h> in patch 7/8
- namespace SRDS_PRTCL values for LS1046A and LS1088A, even if they are
  the same. For LS1028A (not covered here) they are not.
- prefix SRDS_CLK_SEL_{GMII,XGMII} with LS2088A_
- reorder alphanumerically (LS1046A should come before LS1088A)

Change logs also in individual patches.

v1 at:
https://lore.kernel.org/linux-phy/20260611193940.44416-1-vladimir.oltean@nxp.com/

Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Rob Herring <robh@kernel.org>

Ioana Ciornei (4):
  soc: fsl: guts: use a macro to encode the DCFG CCSR space
  soc: fsl: guts: add a global structure to hold state
  soc: fsl: guts: add a central fsl_guts_read() function
  soc: fsl: guts: make it easier to determine on which SoC we are
    running

Vladimir Oltean (5):
  soc: fsl: guts: perform fsl_guts_init() error teardown in reverse
    order of setup
  soc: fsl: guts: make fsl_soc_data available after fsl_guts_init()
  dt-bindings: fsl: layerscape-dcfg: define DCFG_DCSR region
  soc: fsl: guts: implement the RCW override procedure
  phy: lynx-10g: use RCW override procedure for dynamic protocol change

 .../bindings/soc/fsl/fsl,layerscape-dcfg.yaml |  15 +-
 drivers/phy/freescale/Kconfig                 |   1 +
 drivers/phy/freescale/phy-fsl-lynx-10g.c      |  23 +-
 drivers/soc/fsl/guts.c                        | 528 ++++++++++++++++--
 include/linux/fsl/guts.h                      |  18 +-
 5 files changed, 532 insertions(+), 53 deletions(-)

-- 
2.34.1



^ permalink raw reply

* [PATCH v4 phy-next 2/9] soc: fsl: guts: use a macro to encode the DCFG CCSR space
From: Vladimir Oltean @ 2026-07-21 23:15 UTC (permalink / raw)
  To: linux-phy
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
	Vinod Koul, Neil Armstrong, Tanjeff Moos,
	Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
	linux-kernel
In-Reply-To: <20260721231603.67865-1-vladimir.oltean@nxp.com>

From: Ioana Ciornei <ioana.ciornei@nxp.com>

Instead of using a hardcoded value when iomapping the DCFG CCSR space,
add a new macro for it. The code will be easier to follow this way,
especially when we add support for the DCFG DCSR space as well.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v4: none
---
 drivers/soc/fsl/guts.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index 453456f31800..b97eb80cea95 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -14,6 +14,8 @@
 #include <linux/platform_device.h>
 #include <linux/fsl/guts.h>
 
+#define DCFG_CCSR	0
+
 struct fsl_soc_die_attr {
 	char	*die;
 	u32	svr;
@@ -197,7 +199,7 @@ static int __init fsl_guts_init(void)
 		return 0;
 	soc_data = match->data;
 
-	regs = of_iomap(np, 0);
+	regs = of_iomap(np, DCFG_CCSR);
 	if (!regs) {
 		of_node_put(np);
 		return -ENOMEM;
-- 
2.34.1



^ permalink raw reply related

* [PATCH v4 phy-next 3/9] soc: fsl: guts: add a global structure to hold state
From: Vladimir Oltean @ 2026-07-21 23:15 UTC (permalink / raw)
  To: linux-phy
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
	Vinod Koul, Neil Armstrong, Tanjeff Moos,
	Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
	linux-kernel
In-Reply-To: <20260721231603.67865-1-vladimir.oltean@nxp.com>

From: Ioana Ciornei <ioana.ciornei@nxp.com>

Add the fsl_soc_guts structure in order to pass information like base
addresses, endianness etc between the init time and the runtime
operations (RCW override) which will get added in future patches.
There is no point in mapping and unmapping the DCFG CCSR space every
time we need to make a read, just map it once and keep its reference in
this new global struture.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v3->v4:
- change error handling to a dedicated 'err_unmap_dcfg_ccsr' label
v2->v3:
- fix error handling in fsl_guts_init() - iounmap() the CCSR range and
  set it to NULL on the "err" label rather than "err_nomem"
v1->v2: none
---
 drivers/soc/fsl/guts.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index b97eb80cea95..bb65b62ed805 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -106,6 +106,11 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
 	{ },
 };
 
+static struct fsl_soc_guts {
+	struct ccsr_guts __iomem *dcfg_ccsr;
+	bool little_endian;
+} soc;
+
 static const struct fsl_soc_die_attr *fsl_soc_die_match(
 	u32 svr, const struct fsl_soc_die_attr *matches)
 {
@@ -187,9 +192,7 @@ static int __init fsl_guts_init(void)
 	const struct fsl_soc_die_attr *soc_die;
 	const struct fsl_soc_data *soc_data;
 	const struct of_device_id *match;
-	struct ccsr_guts __iomem *regs;
 	struct device_node *np;
-	bool little_endian;
 	u64 soc_uid = 0;
 	u32 svr;
 	int ret;
@@ -199,24 +202,25 @@ static int __init fsl_guts_init(void)
 		return 0;
 	soc_data = match->data;
 
-	regs = of_iomap(np, DCFG_CCSR);
-	if (!regs) {
+	soc.dcfg_ccsr = of_iomap(np, DCFG_CCSR);
+	if (!soc.dcfg_ccsr) {
 		of_node_put(np);
 		return -ENOMEM;
 	}
 
-	little_endian = of_property_read_bool(np, "little-endian");
-	if (little_endian)
-		svr = ioread32(&regs->svr);
+	soc.little_endian = of_property_read_bool(np, "little-endian");
+	if (soc.little_endian)
+		svr = ioread32(&soc.dcfg_ccsr->svr);
 	else
-		svr = ioread32be(&regs->svr);
-	iounmap(regs);
+		svr = ioread32be(&soc.dcfg_ccsr->svr);
 	of_node_put(np);
 
 	/* Register soc device */
 	soc_dev_attr = kzalloc_obj(*soc_dev_attr);
-	if (!soc_dev_attr)
-		return -ENOMEM;
+	if (!soc_dev_attr) {
+		ret = -ENOMEM;
+		goto err_unmap_dcfg_ccsr;
+	}
 
 	ret = soc_attr_read_machine(soc_dev_attr);
 	if (ret)
@@ -276,6 +280,9 @@ static int __init fsl_guts_init(void)
 	kfree(soc_dev_attr->family);
 err_free_soc_dev_attr:
 	kfree(soc_dev_attr);
+err_unmap_dcfg_ccsr:
+	iounmap(soc.dcfg_ccsr);
+	soc.dcfg_ccsr = NULL;
 
 	return ret;
 }
-- 
2.34.1



^ permalink raw reply related

* [PATCH v4 phy-next 4/9] soc: fsl: guts: add a central fsl_guts_read() function
From: Vladimir Oltean @ 2026-07-21 23:15 UTC (permalink / raw)
  To: linux-phy
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
	Vinod Koul, Neil Armstrong, Tanjeff Moos,
	Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
	linux-kernel
In-Reply-To: <20260721231603.67865-1-vladimir.oltean@nxp.com>

From: Ioana Ciornei <ioana.ciornei@nxp.com>

Add a central fsl_guts_read() function which will take into account the
endianness that was already determined. No point is duplicating the
if-else statement each time we need to read a DCFG register.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v4: none
---
 drivers/soc/fsl/guts.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index bb65b62ed805..8e5c3cae811e 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -111,6 +111,14 @@ static struct fsl_soc_guts {
 	bool little_endian;
 } soc;
 
+static unsigned int fsl_guts_read(const void __iomem *reg)
+{
+	if (soc.little_endian)
+		return ioread32(reg);
+
+	return ioread32be(reg);
+}
+
 static const struct fsl_soc_die_attr *fsl_soc_die_match(
 	u32 svr, const struct fsl_soc_die_attr *matches)
 {
@@ -209,10 +217,7 @@ static int __init fsl_guts_init(void)
 	}
 
 	soc.little_endian = of_property_read_bool(np, "little-endian");
-	if (soc.little_endian)
-		svr = ioread32(&soc.dcfg_ccsr->svr);
-	else
-		svr = ioread32be(&soc.dcfg_ccsr->svr);
+	svr = fsl_guts_read(&soc.dcfg_ccsr->svr);
 	of_node_put(np);
 
 	/* Register soc device */
-- 
2.34.1



^ permalink raw reply related

* [PATCH v4 phy-next 5/9] soc: fsl: guts: make it easier to determine on which SoC we are running
From: Vladimir Oltean @ 2026-07-21 23:15 UTC (permalink / raw)
  To: linux-phy
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
	Vinod Koul, Neil Armstrong, Tanjeff Moos,
	Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
	linux-kernel
In-Reply-To: <20260721231603.67865-1-vladimir.oltean@nxp.com>

From: Ioana Ciornei <ioana.ciornei@nxp.com>

The guts driver will need to easily determine on which SoC it's running
when it will need to perform RCW override at runtime. The guts driver
knows this already because fsl_guts_init() reads the QorIQ/Layerscape
architectural System Version Register (SVR), but it doesn't save this
for later lookups.

Add a new qoriq_die enum to be used as an index in the fsl_soc_die
array. A new fsl_soc_die_match_one() function is also added so that we
can directly determine if the SVR is a match with a specific die.
The SVR value read from the DCFG CCSR is also kept in the global soc
structure so that it can be accessed when needed.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v3->v4: adapt to different error handling scheme
v1->v3: none
---
 drivers/soc/fsl/guts.c | 47 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 41 insertions(+), 6 deletions(-)

diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index 8e5c3cae811e..15674c6734c6 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -27,6 +27,23 @@ struct fsl_soc_data {
 	u32 uid_offset;
 };
 
+enum qoriq_die {
+	DIE_T4240,
+	DIE_T1040,
+	DIE_T2080,
+	DIE_T1024,
+	DIE_LS1043A,
+	DIE_LS2080A,
+	DIE_LS1088A,
+	DIE_LS1012A,
+	DIE_LS1046A,
+	DIE_LS2088A,
+	DIE_LS1021A,
+	DIE_LX2160A,
+	DIE_LS1028A,
+	DIE_MAX,
+};
+
 /* SoC die attribute definition for QorIQ platform */
 static const struct fsl_soc_die_attr fsl_soc_die[] = {
 	/*
@@ -34,21 +51,25 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
 	 */
 
 	/* Die: T4240, SoC: T4240/T4160/T4080 */
+	[DIE_T4240] =
 	{ .die		= "T4240",
 	  .svr		= 0x82400000,
 	  .mask		= 0xfff00000,
 	},
 	/* Die: T1040, SoC: T1040/T1020/T1042/T1022 */
+	[DIE_T1040] =
 	{ .die		= "T1040",
 	  .svr		= 0x85200000,
 	  .mask		= 0xfff00000,
 	},
 	/* Die: T2080, SoC: T2080/T2081 */
+	[DIE_T2080] =
 	{ .die		= "T2080",
 	  .svr		= 0x85300000,
 	  .mask		= 0xfff00000,
 	},
 	/* Die: T1024, SoC: T1024/T1014/T1023/T1013 */
+	[DIE_T1024] =
 	{ .die		= "T1024",
 	  .svr		= 0x85400000,
 	  .mask		= 0xfff00000,
@@ -59,46 +80,55 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
 	 */
 
 	/* Die: LS1043A, SoC: LS1043A/LS1023A */
+	[DIE_LS1043A] =
 	{ .die		= "LS1043A",
 	  .svr		= 0x87920000,
 	  .mask		= 0xffff0000,
 	},
 	/* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */
+	[DIE_LS2080A] =
 	{ .die		= "LS2080A",
 	  .svr		= 0x87010000,
 	  .mask		= 0xff3f0000,
 	},
 	/* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */
+	[DIE_LS1088A] =
 	{ .die		= "LS1088A",
 	  .svr		= 0x87030000,
 	  .mask		= 0xff3f0000,
 	},
 	/* Die: LS1012A, SoC: LS1012A */
+	[DIE_LS1012A] =
 	{ .die		= "LS1012A",
 	  .svr		= 0x87040000,
 	  .mask		= 0xffff0000,
 	},
 	/* Die: LS1046A, SoC: LS1046A/LS1026A */
+	[DIE_LS1046A] =
 	{ .die		= "LS1046A",
 	  .svr		= 0x87070000,
 	  .mask		= 0xffff0000,
 	},
 	/* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */
+	[DIE_LS2088A] =
 	{ .die		= "LS2088A",
 	  .svr		= 0x87090000,
 	  .mask		= 0xff3f0000,
 	},
 	/* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */
+	[DIE_LS1021A] =
 	{ .die		= "LS1021A",
 	  .svr		= 0x87000000,
 	  .mask		= 0xfff70000,
 	},
 	/* Die: LX2160A, SoC: LX2160A/LX2120A/LX2080A */
+	[DIE_LX2160A] =
 	{ .die          = "LX2160A",
 	  .svr          = 0x87360000,
 	  .mask         = 0xff3f0000,
 	},
 	/* Die: LS1028A, SoC: LS1028A */
+	[DIE_LS1028A] =
 	{ .die          = "LS1028A",
 	  .svr          = 0x870b0000,
 	  .mask         = 0xff3f0000,
@@ -109,6 +139,7 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
 static struct fsl_soc_guts {
 	struct ccsr_guts __iomem *dcfg_ccsr;
 	bool little_endian;
+	u32 svr;
 } soc;
 
 static unsigned int fsl_guts_read(const void __iomem *reg)
@@ -119,11 +150,16 @@ static unsigned int fsl_guts_read(const void __iomem *reg)
 	return ioread32be(reg);
 }
 
+static bool fsl_soc_die_match_one(u32 svr, const struct fsl_soc_die_attr *match)
+{
+	return match->svr == (svr & match->mask);
+}
+
 static const struct fsl_soc_die_attr *fsl_soc_die_match(
 	u32 svr, const struct fsl_soc_die_attr *matches)
 {
 	while (matches->svr) {
-		if (matches->svr == (svr & matches->mask))
+		if (fsl_soc_die_match_one(svr, matches))
 			return matches;
 		matches++;
 	}
@@ -202,7 +238,6 @@ static int __init fsl_guts_init(void)
 	const struct of_device_id *match;
 	struct device_node *np;
 	u64 soc_uid = 0;
-	u32 svr;
 	int ret;
 
 	np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match);
@@ -217,7 +252,7 @@ static int __init fsl_guts_init(void)
 	}
 
 	soc.little_endian = of_property_read_bool(np, "little-endian");
-	svr = fsl_guts_read(&soc.dcfg_ccsr->svr);
+	soc.svr = fsl_guts_read(&soc.dcfg_ccsr->svr);
 	of_node_put(np);
 
 	/* Register soc device */
@@ -231,7 +266,7 @@ static int __init fsl_guts_init(void)
 	if (ret)
 		of_machine_read_compatible(&soc_dev_attr->machine, 0);
 
-	soc_die = fsl_soc_die_match(svr, fsl_soc_die);
+	soc_die = fsl_soc_die_match(soc.svr, fsl_soc_die);
 	if (soc_die) {
 		soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ %s",
 						 soc_die->die);
@@ -243,14 +278,14 @@ static int __init fsl_guts_init(void)
 		goto err_free_soc_dev_attr;
 	}
 
-	soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", svr);
+	soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", soc.svr);
 	if (!soc_dev_attr->soc_id) {
 		ret = -ENOMEM;
 		goto err_free_family;
 	}
 
 	soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
-					   (svr >>  4) & 0xf, svr & 0xf);
+					   (soc.svr >>  4) & 0xf, soc.svr & 0xf);
 	if (!soc_dev_attr->revision) {
 		ret = -ENOMEM;
 		goto err_free_soc_id;
-- 
2.34.1



^ permalink raw reply related

* [PATCH v4 phy-next 6/9] soc: fsl: guts: make fsl_soc_data available after fsl_guts_init()
From: Vladimir Oltean @ 2026-07-21 23:16 UTC (permalink / raw)
  To: linux-phy
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
	Vinod Koul, Neil Armstrong, Tanjeff Moos,
	Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
	linux-kernel
In-Reply-To: <20260721231603.67865-1-vladimir.oltean@nxp.com>

In a future change, struct fsl_soc_data will be extended with methods
for performing RCW override.

Since this will be performed from a calling context outside
fsl_guts_init(), we need to keep track of the soc_data that we determine
at fsl_guts_init() time, so we can reference it later.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v3->v4: adapt to new error handling scheme
v2->v3: don't leave soc.data a valid pointer if fsl_guts_init() fails
v1->v2: none
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 drivers/soc/fsl/guts.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index 15674c6734c6..c283d44b68a3 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -138,6 +138,7 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
 
 static struct fsl_soc_guts {
 	struct ccsr_guts __iomem *dcfg_ccsr;
+	const struct fsl_soc_data *data;
 	bool little_endian;
 	u32 svr;
 } soc;
@@ -231,10 +232,9 @@ static const struct of_device_id fsl_guts_of_match[] = {
 
 static int __init fsl_guts_init(void)
 {
-	struct soc_device_attribute *soc_dev_attr;
+	struct soc_device_attribute *soc_dev_attr = NULL;
 	static struct soc_device *soc_dev;
 	const struct fsl_soc_die_attr *soc_die;
-	const struct fsl_soc_data *soc_data;
 	const struct of_device_id *match;
 	struct device_node *np;
 	u64 soc_uid = 0;
@@ -243,12 +243,13 @@ static int __init fsl_guts_init(void)
 	np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match);
 	if (!np)
 		return 0;
-	soc_data = match->data;
+	soc.data = match->data;
 
 	soc.dcfg_ccsr = of_iomap(np, DCFG_CCSR);
 	if (!soc.dcfg_ccsr) {
 		of_node_put(np);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto err_clear_soc_data;
 	}
 
 	soc.little_endian = of_property_read_bool(np, "little-endian");
@@ -291,9 +292,9 @@ static int __init fsl_guts_init(void)
 		goto err_free_soc_id;
 	}
 
-	if (soc_data)
-		soc_uid = fsl_guts_get_soc_uid(soc_data->sfp_compat,
-					       soc_data->uid_offset);
+	if (soc.data)
+		soc_uid = fsl_guts_get_soc_uid(soc.data->sfp_compat,
+					       soc.data->uid_offset);
 	if (soc_uid)
 		soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX",
 							soc_uid);
@@ -323,6 +324,8 @@ static int __init fsl_guts_init(void)
 err_unmap_dcfg_ccsr:
 	iounmap(soc.dcfg_ccsr);
 	soc.dcfg_ccsr = NULL;
+err_clear_soc_data:
+	soc.data = NULL;
 
 	return ret;
 }
-- 
2.34.1



^ 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