[PATCH v2] arch/powerpc/kvm: Add support for reading VPA counters for pseries guests

2024-03-19 Thread Gautam Menghani
PAPR hypervisor has introduced three new counters in the VPA area of
LPAR CPUs for KVM L2 guest (see [1] for terminology) observability - 2
for context switches from host to guest and vice versa, and 1 counter
for getting the total time spent inside the KVM guest. Add a tracepoint
that enables reading the counters for use by ftrace/perf. Note that this
tracepoint is only available for nestedv2 API (i.e, KVM on PowerVM).

[1] Terminology:
a. L1 refers to the VM (LPAR) booted on top of PAPR hypervisor
b. L2 refers to the KVM guest booted on top of L1.

Signed-off-by: Vaibhav Jain 
Signed-off-by: Gautam Menghani 
---
V1 -> V2:
1. Fix the build error due to invalid struct member reference.

 arch/powerpc/include/asm/kvm_host.h |  5 +
 arch/powerpc/include/asm/lppaca.h   | 11 ---
 arch/powerpc/kvm/book3s_hv.c| 20 
 arch/powerpc/kvm/trace_hv.h | 24 
 4 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_host.h 
b/arch/powerpc/include/asm/kvm_host.h
index 8abac5321..26d7bb4b9 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -847,6 +847,11 @@ struct kvm_vcpu_arch {
gpa_t nested_io_gpr;
/* For nested APIv2 guests*/
struct kvmhv_nestedv2_io nestedv2_io;
+
+   /* For VPA counters having context switch and guest run time info (in 
ns) */
+   u64 l1_to_l2_cs;
+   u64 l2_to_l1_cs;
+   u64 l2_runtime;
 #endif
 
 #ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
diff --git a/arch/powerpc/include/asm/lppaca.h 
b/arch/powerpc/include/asm/lppaca.h
index 61ec2447d..bda6b86b9 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -62,7 +62,8 @@ struct lppaca {
u8  donate_dedicated_cpu;   /* Donate dedicated CPU cycles */
u8  fpregs_in_use;
u8  pmcregs_in_use;
-   u8  reserved8[28];
+   u8  l2_accumul_cntrs_enable;  /* Enable usage of counters for KVM 
guest */
+   u8  reserved8[27];
__be64  wait_state_cycles;  /* Wait cycles for this proc */
u8  reserved9[28];
__be16  slb_count;  /* # of SLBs to maintain */
@@ -92,9 +93,13 @@ struct lppaca {
/* cacheline 4-5 */
 
__be32  page_ins;   /* CMO Hint - # page ins by OS */
-   u8  reserved12[148];
+   u8  reserved12[28];
+   volatile __be64 l1_to_l2_cs_tb;
+   volatile __be64 l2_to_l1_cs_tb;
+   volatile __be64 l2_runtime_tb;
+   u8 reserved13[96];
volatile __be64 dtl_idx;/* Dispatch Trace Log head index */
-   u8  reserved13[96];
+   u8  reserved14[96];
 } cacheline_aligned;
 
 #define lppaca_of(cpu) (*paca_ptrs[cpu]->lppaca_ptr)
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 8e86eb577..e2ec1f7db 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -4115,6 +4115,7 @@ static int kvmhv_vcpu_entry_nestedv2(struct kvm_vcpu 
*vcpu, u64 time_limit,
unsigned long msr, i;
int trap;
long rc;
+   struct lppaca *lp = get_lppaca();
 
io = >arch.nestedv2_io;
 
@@ -4130,6 +4131,17 @@ static int kvmhv_vcpu_entry_nestedv2(struct kvm_vcpu 
*vcpu, u64 time_limit,
kvmppc_gse_put_u64(io->vcpu_run_input, KVMPPC_GSID_LPCR, lpcr);
 
accumulate_time(vcpu, >arch.in_guest);
+
+   /* Reset the guest host context switch timing */
+   if (unlikely(trace_kvmppc_vcpu_exit_cs_time_enabled())) {
+   lp->l2_accumul_cntrs_enable = 1;
+   lp->l1_to_l2_cs_tb = 0;
+   lp->l2_to_l1_cs_tb = 0;
+   lp->l2_runtime_tb = 0;
+   } else {
+   lp->l2_accumul_cntrs_enable = 0;
+   }
+
rc = plpar_guest_run_vcpu(0, vcpu->kvm->arch.lpid, vcpu->vcpu_id,
  , );
 
@@ -4156,6 +4168,14 @@ static int kvmhv_vcpu_entry_nestedv2(struct kvm_vcpu 
*vcpu, u64 time_limit,
 
timer_rearm_host_dec(*tb);
 
+   /* Record context switch and guest_run_time data */
+   if (unlikely(trace_kvmppc_vcpu_exit_cs_time_enabled())) {
+   vcpu->arch.l1_to_l2_cs = 
tb_to_ns(be64_to_cpu(lp->l1_to_l2_cs_tb));
+   vcpu->arch.l2_to_l1_cs = 
tb_to_ns(be64_to_cpu(lp->l2_to_l1_cs_tb));
+   vcpu->arch.l2_runtime = 
tb_to_ns(be64_to_cpu(lp->l2_runtime_tb));
+   trace_kvmppc_vcpu_exit_cs_time(vcpu);
+   }
+
return trap;
 }
 
diff --git a/arch/powerpc/kvm/trace_hv.h b/arch/powerpc/kvm/trace_hv.h
index 8d57c8428..d411489e5 100644
--- a/arch/powerpc/kvm/trace_hv.h
+++ b/arch/powerpc/kvm/trace_hv.h
@@ -491,6 +491,30 @@ TRACE_EVENT(kvmppc_run_vcpu_enter,
TP_printk("VCPU %d: tgid=%d", __entry->vcpu_id, __entry->tgid)
 );
 
+TRACE_EVENT(kvmppc_vcpu_exit_cs_time,
+   TP_PROTO(struct kvm_vcpu *vcpu),
+
+   TP_ARGS(vcpu),
+
+   TP_STRUCT__entry(
+  

Re: [PATCH 09/13] mm/powerpc: Redefine pXd_huge() with pXd_leaf()

2024-03-19 Thread Jason Gunthorpe
On Tue, Mar 19, 2024 at 11:07:08PM +, Christophe Leroy wrote:
> 
> 
> Le 18/03/2024 à 17:15, Jason Gunthorpe a écrit :
> > On Thu, Mar 14, 2024 at 01:11:59PM +, Christophe Leroy wrote:
> >>
> >>
> >> Le 14/03/2024 à 13:53, Peter Xu a écrit :
> >>> On Thu, Mar 14, 2024 at 08:45:34AM +, Christophe Leroy wrote:
> 
> 
>  Le 13/03/2024 à 22:47, pet...@redhat.com a écrit :
> > From: Peter Xu 
> >
> > PowerPC book3s 4K mostly has the same definition on both, except 
> > pXd_huge()
> > constantly returns 0 for hash MMUs.  As Michael Ellerman pointed out 
> > [1],
> > it is safe to check _PAGE_PTE on hash MMUs, as the bit will never be 
> > set so
> > it will keep returning false.
> >
> > As a reference, __p[mu]d_mkhuge() will trigger a BUG_ON trying to create
> > such huge mappings for 4K hash MMUs.  Meanwhile, the major powerpc 
> > hugetlb
> > pgtable walker __find_linux_pte() already used pXd_leaf() to check 
> > hugetlb
> > mappings.
> >
> > The goal should be that we will have one API pXd_leaf() to detect all 
> > kinds
> > of huge mappings.  AFAICT we need to use the pXd_leaf() impl (rather 
> > than
> > pXd_huge() ones) to make sure ie. THPs on hash MMU will also return 
> > true.
> 
>  All kinds of huge mappings ?
> 
>  pXd_leaf() will detect only leaf mappings (like pXd_huge() ). There are
>  also huge mappings through hugepd. On powerpc 8xx we have 8M huge pages
>  and 512k huge pages. A PGD entry covers 4M so pgd_leaf() won't report
>  those huge pages.
> >>>
> >>> Ah yes, I should always mention this is in the context of leaf huge pages
> >>> only.  Are the examples you provided all fall into hugepd category?  If so
> >>> I can reword the commit message, as:
> >>
> >> On powerpc 8xx, only the 8M huge pages fall into the hugepd case.
> >>
> >> The 512k hugepages are at PTE level, they are handled more or less like
> >> CONT_PTE on ARM. see function set_huge_pte_at() for more context.
> >>
> >> You can also look at pte_leaf_size() and pgd_leaf_size().
> > 
> > IMHO leaf should return false if the thing is pointing to a next level
> > page table, even if that next level is fully populated with contiguous
> > pages.
> > 
> > This seems more aligned with the contig page direction that hugepd
> > should be moved over to..
> 
> Should hugepd be moved to the contig page direction, really ?

Sure? Is there any downside for the reading side to do so?

> Would it be acceptable that a 8M hugepage requires 2048 contig entries
> in 2 page tables, when the hugepd allows a single entry ? 

? I thought we agreed the only difference would be that something new
is needed to merge the two identical sibling page tables into one, ie
you pay 2x the page table memory if that isn't fixed. That is write
side only change and I imagine it could be done with a single PPC
special API.

Honestly not totally sure that is a big deal, it is already really
memory inefficient compared to every other arch's huge page by needing
the child page table in the first place.

> Would it be acceptable performancewise ?

Isn't this particular PPC sub platform ancient? Are there current real
users that are going to have hugetlbfs special code and care about
this performance detail on a 6.20 era kernel?

In today's world wouldn't it be performance better if these platforms
could support THP by aligning to the contig API instead of being
special?

Am I wrong to question why we are polluting the core code for this
special optimization?

Jason


Re: [PATCH 09/13] mm/powerpc: Redefine pXd_huge() with pXd_leaf()

2024-03-19 Thread Christophe Leroy


Le 18/03/2024 à 17:15, Jason Gunthorpe a écrit :
> On Thu, Mar 14, 2024 at 01:11:59PM +, Christophe Leroy wrote:
>>
>>
>> Le 14/03/2024 à 13:53, Peter Xu a écrit :
>>> On Thu, Mar 14, 2024 at 08:45:34AM +, Christophe Leroy wrote:


 Le 13/03/2024 à 22:47, pet...@redhat.com a écrit :
> From: Peter Xu 
>
> PowerPC book3s 4K mostly has the same definition on both, except 
> pXd_huge()
> constantly returns 0 for hash MMUs.  As Michael Ellerman pointed out [1],
> it is safe to check _PAGE_PTE on hash MMUs, as the bit will never be set 
> so
> it will keep returning false.
>
> As a reference, __p[mu]d_mkhuge() will trigger a BUG_ON trying to create
> such huge mappings for 4K hash MMUs.  Meanwhile, the major powerpc hugetlb
> pgtable walker __find_linux_pte() already used pXd_leaf() to check hugetlb
> mappings.
>
> The goal should be that we will have one API pXd_leaf() to detect all 
> kinds
> of huge mappings.  AFAICT we need to use the pXd_leaf() impl (rather than
> pXd_huge() ones) to make sure ie. THPs on hash MMU will also return true.

 All kinds of huge mappings ?

 pXd_leaf() will detect only leaf mappings (like pXd_huge() ). There are
 also huge mappings through hugepd. On powerpc 8xx we have 8M huge pages
 and 512k huge pages. A PGD entry covers 4M so pgd_leaf() won't report
 those huge pages.
>>>
>>> Ah yes, I should always mention this is in the context of leaf huge pages
>>> only.  Are the examples you provided all fall into hugepd category?  If so
>>> I can reword the commit message, as:
>>
>> On powerpc 8xx, only the 8M huge pages fall into the hugepd case.
>>
>> The 512k hugepages are at PTE level, they are handled more or less like
>> CONT_PTE on ARM. see function set_huge_pte_at() for more context.
>>
>> You can also look at pte_leaf_size() and pgd_leaf_size().
> 
> IMHO leaf should return false if the thing is pointing to a next level
> page table, even if that next level is fully populated with contiguous
> pages.
> 
> This seems more aligned with the contig page direction that hugepd
> should be moved over to..

Should hugepd be moved to the contig page direction, really ?

Would it be acceptable that a 8M hugepage requires 2048 contig entries 
in 2 page tables, when the hugepd allows a single entry ? Would it be 
acceptable performancewise ?

> 
>> By the way pgd_leaf_size() looks odd because it is called only when
>> pgd_leaf_size() returns true, which never happens for 8M pages.
> 
> Like this, you should reach the actual final leaf that the HW will
> load and leaf_size() should say it is greater size than the current
> table level. Other levels should return 0.
> 
> If necessary the core MM code should deal with this by iterating over
> adjacent tables.
> 
> Jason


Re: [RFC PATCH 1/3] powerpc/pseries/iommu: Bring back userspace view for single level TCE tables

2024-03-19 Thread Timothy Pearson



- Original Message -
> From: "Jason Gunthorpe" 
> To: "Shivaprasad G Bhat" 
> Cc: "Timothy Pearson" , "Alex Williamson" 
> , "linuxppc-dev"
> , "Michael Ellerman" , 
> "npiggin" , "christophe
> leroy" , "aneesh kumar" 
> , "naveen n rao"
> , "gbatra" , 
> brk...@linux.vnet.ibm.com, "Alexey Kardashevskiy"
> , r...@kernel.org, "linux-kernel" 
> , "kvm" , "aik"
> , msucha...@suse.de, "jroedel" , "vaibhav" 
> , sva...@linux.ibm.com
> Sent: Tuesday, March 19, 2024 9:32:02 AM
> Subject: Re: [RFC PATCH 1/3] powerpc/pseries/iommu: Bring back userspace view 
> for single level TCE tables

> On Tue, Mar 12, 2024 at 01:14:20PM -0500, Shivaprasad G Bhat wrote:
>> The commit 090bad39b237a ("powerpc/powernv: Add indirect levels to
>> it_userspace") which implemented the tce indirect levels
>> support for PowerNV ended up removing the single level support
>> which existed by default(generic tce_iommu_userspace_view_alloc/free()
>> calls). On pSeries the TCEs are single level, and the allocation
>> of userspace view is lost with the removal of generic code.
> 
> :( :(
> 
> If this has been broken since 2018 and nobody cared till now can we
> please go in a direction of moving this code to the new iommu APIs
> instead of doubling down on more of this old stuff that apparently
> almost nobody cares about ??
> 
> Jason

Just FYI Raptor is working on porting things over to the new APIs.  RFC patches 
should be posted in the next week or two.


Re: [RFC PATCH 1/3] powerpc/pseries/iommu: Bring back userspace view for single level TCE tables

2024-03-19 Thread Jason Gunthorpe
On Tue, Mar 12, 2024 at 01:14:20PM -0500, Shivaprasad G Bhat wrote:
> The commit 090bad39b237a ("powerpc/powernv: Add indirect levels to
> it_userspace") which implemented the tce indirect levels
> support for PowerNV ended up removing the single level support
> which existed by default(generic tce_iommu_userspace_view_alloc/free()
> calls). On pSeries the TCEs are single level, and the allocation
> of userspace view is lost with the removal of generic code.

:( :(

If this has been broken since 2018 and nobody cared till now can we
please go in a direction of moving this code to the new iommu APIs
instead of doubling down on more of this old stuff that apparently
almost nobody cares about ??

Jason


Re: [PATCH 4/6] mm/mm_init.c: remove meaningless calculation of zone->managed_pages in free_area_init_core()

2024-03-19 Thread Mike Rapoport
On Mon, Mar 18, 2024 at 10:21:36PM +0800, Baoquan He wrote:
> Currently, in free_area_init_core(), when initialize zone's field, a
> rough value is set to zone->managed_pages. That value is calculated by
> (zone->present_pages - memmap_pages).
> 
> In the meantime, add the value to nr_all_pages and nr_kernel_pages which
> represent all free pages of system (only low memory or including HIGHMEM
> memory separately). Both of them are gonna be used in
> alloc_large_system_hash().
> 
> However, the rough calculation and setting of zone->managed_pages is
> meaningless because
>   a) memmap pages are allocated on units of node in sparse_init() or
>  alloc_node_mem_map(pgdat); The simple (zone->present_pages -
>  memmap_pages) is too rough to make sense for zone;
>   b) the set zone->managed_pages will be zeroed out and reset with
>  acutal value in mem_init() via memblock_free_all(). Before the
>  resetting, no buddy allocation request is issued.
> 
> Here, remove the meaningless and complicated calculation of
> (zone->present_pages - memmap_pages), directly set zone->present_pages to
> zone->managed_pages. It will be adjusted in mem_init().

Do you mean "set zone->managed_pages to zone->present_pages"?

I think we can just set zone->managed_pages to 0 in free_area_init_core().
Anyway it will be reset before the first use.
 
> And also remove the assignment of nr_all_pages and nr_kernel_pages in
> free_area_init_core(). Instead, call the newly added calc_nr_kernel_pages()
> to count up all free but not reserved memory in memblock and assign to
> nr_all_pages and nr_kernel_pages. The counting excludes memmap_pages,
> and other kernel used data, which is more accurate than old way and
> simpler, and can also cover the ppc required arch_reserved_kernel_pages()
> case.
> 
> Signed-off-by: Baoquan He 
> ---
>  mm/mm_init.c | 38 ++
>  1 file changed, 6 insertions(+), 32 deletions(-)
> 
> diff --git a/mm/mm_init.c b/mm/mm_init.c
> index c57a7fc97a16..55a2b886b7a6 100644
> --- a/mm/mm_init.c
> +++ b/mm/mm_init.c
> @@ -1584,41 +1584,14 @@ static void __init free_area_init_core(struct 
> pglist_data *pgdat)
>  
>   for (j = 0; j < MAX_NR_ZONES; j++) {
>   struct zone *zone = pgdat->node_zones + j;
> - unsigned long size, freesize, memmap_pages;
> -
> - size = zone->spanned_pages;
> - freesize = zone->present_pages;
> -
> - /*
> -  * Adjust freesize so that it accounts for how much memory
> -  * is used by this zone for memmap. This affects the watermark
> -  * and per-cpu initialisations
> -  */
> - memmap_pages = calc_memmap_size(size, freesize);
> - if (!is_highmem_idx(j)) {
> - if (freesize >= memmap_pages) {
> - freesize -= memmap_pages;
> - if (memmap_pages)
> - pr_debug("  %s zone: %lu pages used for 
> memmap\n",
> -  zone_names[j], memmap_pages);
> - } else
> - pr_warn("  %s zone: %lu memmap pages exceeds 
> freesize %lu\n",
> - zone_names[j], memmap_pages, freesize);
> - }
> -
> - if (!is_highmem_idx(j))
> - nr_kernel_pages += freesize;
> - /* Charge for highmem memmap if there are enough kernel pages */
> - else if (nr_kernel_pages > memmap_pages * 2)
> - nr_kernel_pages -= memmap_pages;
> - nr_all_pages += freesize;
> + unsigned long size = zone->spanned_pages;
>  
>   /*
> -  * Set an approximate value for lowmem here, it will be adjusted
> -  * when the bootmem allocator frees pages into the buddy system.
> -  * And all highmem pages will be managed by the buddy system.
> +  * Set the zone->managed_pages as zone->present_pages roughly, 
> it
> +  * be zeroed out and reset when memblock allocator frees pages 
> into
> +  * buddy system.
>*/
> - zone_init_internals(zone, j, nid, freesize);
> + zone_init_internals(zone, j, nid, zone->present_pages);
>  
>   if (!size)
>   continue;
> @@ -1915,6 +1888,7 @@ void __init free_area_init(unsigned long *max_zone_pfn)
>   check_for_memory(pgdat);
>   }
>  
> + calc_nr_kernel_pages();
>   memmap_init();
>  
>   /* disable hash distribution for systems with a single node */
> -- 
> 2.41.0
> 

-- 
Sincerely yours,
Mike.


Re: [PATCH 2/6] x86: remove memblock_find_dma_reserve()

2024-03-19 Thread Mike Rapoport
Hi Baoquan,

On Mon, Mar 18, 2024 at 10:21:34PM +0800, Baoquan He wrote:
> This is not needed any more.

I'd swap this and the first patch, so that the first patch would remove
memblock_find_dma_reserve() and it's changelog will explain why it's not
needed and then the second patch will simply drop unused set_dma_reserve()

> Signed-off-by: Baoquan He 
> ---
>  arch/x86/include/asm/pgtable.h |  1 -
>  arch/x86/kernel/setup.c|  2 --
>  arch/x86/mm/init.c | 45 --
>  3 files changed, 48 deletions(-)
> 
> diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
> index 315535ffb258..cefc7a84f7a4 100644
> --- a/arch/x86/include/asm/pgtable.h
> +++ b/arch/x86/include/asm/pgtable.h
> @@ -1200,7 +1200,6 @@ static inline int pgd_none(pgd_t pgd)
>  extern int direct_gbpages;
>  void init_mem_mapping(void);
>  void early_alloc_pgt_buf(void);
> -extern void memblock_find_dma_reserve(void);
>  void __init poking_init(void);
>  unsigned long init_memory_mapping(unsigned long start,
> unsigned long end, pgprot_t prot);
> diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
> index 3e1e96efadfe..5aa00938051f 100644
> --- a/arch/x86/kernel/setup.c
> +++ b/arch/x86/kernel/setup.c
> @@ -1106,8 +1106,6 @@ void __init setup_arch(char **cmdline_p)
>*/
>   arch_reserve_crashkernel();
>  
> - memblock_find_dma_reserve();
> -
>   if (!early_xdbc_setup_hardware())
>   early_xdbc_register_console();
>  
> diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
> index 5209549e8192..615f0bf4bda6 100644
> --- a/arch/x86/mm/init.c
> +++ b/arch/x86/mm/init.c
> @@ -990,51 +990,6 @@ void __init free_initrd_mem(unsigned long start, 
> unsigned long end)
>  }
>  #endif
>  
> -/*
> - * Calculate the precise size of the DMA zone (first 16 MB of RAM),
> - * and pass it to the MM layer - to help it set zone watermarks more
> - * accurately.
> - *
> - * Done on 64-bit systems only for the time being, although 32-bit systems
> - * might benefit from this as well.
> - */
> -void __init memblock_find_dma_reserve(void)
> -{
> -#ifdef CONFIG_X86_64
> - u64 nr_pages = 0, nr_free_pages = 0;
> - unsigned long start_pfn, end_pfn;
> - phys_addr_t start_addr, end_addr;
> - int i;
> - u64 u;
> -
> - /*
> -  * Iterate over all memory ranges (free and reserved ones alike),
> -  * to calculate the total number of pages in the first 16 MB of RAM:
> -  */
> - nr_pages = 0;
> - for_each_mem_pfn_range(i, MAX_NUMNODES, _pfn, _pfn, NULL) {
> - start_pfn = min(start_pfn, MAX_DMA_PFN);
> - end_pfn   = min(end_pfn,   MAX_DMA_PFN);
> -
> - nr_pages += end_pfn - start_pfn;
> - }
> -
> - /*
> -  * Iterate over free memory ranges to calculate the number of free
> -  * pages in the DMA zone, while not counting potential partial
> -  * pages at the beginning or the end of the range:
> -  */
> - nr_free_pages = 0;
> - for_each_free_mem_range(u, NUMA_NO_NODE, MEMBLOCK_NONE, _addr, 
> _addr, NULL) {
> - start_pfn = min_t(unsigned long, PFN_UP(start_addr), 
> MAX_DMA_PFN);
> - end_pfn   = min_t(unsigned long, PFN_DOWN(end_addr), 
> MAX_DMA_PFN);
> -
> - if (start_pfn < end_pfn)
> - nr_free_pages += end_pfn - start_pfn;
> - }
> -#endif
> -}
> -
>  void __init zone_sizes_init(void)
>  {
>   unsigned long max_zone_pfns[MAX_NR_ZONES];
> -- 
> 2.41.0
> 

-- 
Sincerely yours,
Mike.


[PATCH] arch/powerpc/kvm: Add support for reading VPA counters for pseries guests

2024-03-19 Thread Gautam Menghani
PAPR hypervisor has introduced three new counters in the VPA area of
LPAR CPUs for KVM L2 guest (see [1] for terminology) observability - 2
for context switches from host to guest and vice versa, and 1 counter
for getting the total time spent inside the KVM guest. Add a tracepoint
that enables reading the counters for use by ftrace/perf. Note that this
tracepoint is only available for nestedv2 API (i.e, KVM on PowerVM).

[1] Terminology:
a. L1 refers to the VM (LPAR) booted on top of PAPR hypervisor
b. L2 refers to the KVM guest booted on top of L1.

Signed-off-by: Vaibhav Jain 
Signed-off-by: Gautam Menghani 
---
 arch/powerpc/include/asm/kvm_host.h |  5 +
 arch/powerpc/include/asm/lppaca.h   | 11 ---
 arch/powerpc/kvm/book3s_hv.c| 20 
 arch/powerpc/kvm/trace_hv.h | 24 
 4 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_host.h 
b/arch/powerpc/include/asm/kvm_host.h
index 8abac5321..26d7bb4b9 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -847,6 +847,11 @@ struct kvm_vcpu_arch {
gpa_t nested_io_gpr;
/* For nested APIv2 guests*/
struct kvmhv_nestedv2_io nestedv2_io;
+
+   /* For VPA counters having context switch and guest run time info (in 
ns) */
+   u64 l1_to_l2_cs;
+   u64 l2_to_l1_cs;
+   u64 l2_runtime;
 #endif
 
 #ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
diff --git a/arch/powerpc/include/asm/lppaca.h 
b/arch/powerpc/include/asm/lppaca.h
index 61ec2447d..bda6b86b9 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -62,7 +62,8 @@ struct lppaca {
u8  donate_dedicated_cpu;   /* Donate dedicated CPU cycles */
u8  fpregs_in_use;
u8  pmcregs_in_use;
-   u8  reserved8[28];
+   u8  l2_accumul_cntrs_enable;  /* Enable usage of counters for KVM 
guest */
+   u8  reserved8[27];
__be64  wait_state_cycles;  /* Wait cycles for this proc */
u8  reserved9[28];
__be16  slb_count;  /* # of SLBs to maintain */
@@ -92,9 +93,13 @@ struct lppaca {
/* cacheline 4-5 */
 
__be32  page_ins;   /* CMO Hint - # page ins by OS */
-   u8  reserved12[148];
+   u8  reserved12[28];
+   volatile __be64 l1_to_l2_cs_tb;
+   volatile __be64 l2_to_l1_cs_tb;
+   volatile __be64 l2_runtime_tb;
+   u8 reserved13[96];
volatile __be64 dtl_idx;/* Dispatch Trace Log head index */
-   u8  reserved13[96];
+   u8  reserved14[96];
 } cacheline_aligned;
 
 #define lppaca_of(cpu) (*paca_ptrs[cpu]->lppaca_ptr)
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 2b04eba90..b94461b5f 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -4092,6 +4092,7 @@ static int kvmhv_vcpu_entry_nestedv2(struct kvm_vcpu 
*vcpu, u64 time_limit,
unsigned long msr, i;
int trap;
long rc;
+   struct lppaca *lp = get_lppaca();
 
io = >arch.nestedv2_io;
 
@@ -4107,6 +4108,17 @@ static int kvmhv_vcpu_entry_nestedv2(struct kvm_vcpu 
*vcpu, u64 time_limit,
kvmppc_gse_put_u64(io->vcpu_run_input, KVMPPC_GSID_LPCR, lpcr);
 
accumulate_time(vcpu, >arch.in_guest);
+
+   /* Reset the guest host context switch timing */
+   if (unlikely(trace_kvmppc_vcpu_exit_cs_time_enabled())) {
+   lp->l2_accumul_cntrs_enable = 1;
+   lp->l1_to_l2_cs_tb = 0;
+   lp->l2_to_l1_cs_tb = 0;
+   lp->l2_runtime_tb = 0;
+   } else {
+   lp->l2_accumul_cntrs_enable = 0;
+   }
+
rc = plpar_guest_run_vcpu(0, vcpu->kvm->arch.lpid, vcpu->vcpu_id,
  , );
 
@@ -4133,6 +4145,14 @@ static int kvmhv_vcpu_entry_nestedv2(struct kvm_vcpu 
*vcpu, u64 time_limit,
 
timer_rearm_host_dec(*tb);
 
+   /* Record context switch and guest_run_time data */
+   if (unlikely(trace_kvmppc_vcpu_exit_cs_time_enabled())) {
+   vcpu->arch.l1_to_l2_cs = 
tb_to_ns(be64_to_cpu(lp->l1_to_l2_cs_tb));
+   vcpu->arch.l2_to_l1_cs = 
tb_to_ns(be64_to_cpu(lp->l2_to_l1_cs_tb));
+   vcpu->arch.l2_runtime = 
tb_to_ns(be64_to_cpu(lp->l2_runtime_tb));
+   trace_kvmppc_vcpu_exit_cs_time(vcpu);
+   }
+
return trap;
 }
 
diff --git a/arch/powerpc/kvm/trace_hv.h b/arch/powerpc/kvm/trace_hv.h
index 8d57c8428..10b8f6e5a 100644
--- a/arch/powerpc/kvm/trace_hv.h
+++ b/arch/powerpc/kvm/trace_hv.h
@@ -491,6 +491,30 @@ TRACE_EVENT(kvmppc_run_vcpu_enter,
TP_printk("VCPU %d: tgid=%d", __entry->vcpu_id, __entry->tgid)
 );
 
+TRACE_EVENT(kvmppc_vcpu_exit_cs_time,
+   TP_PROTO(struct kvm_vcpu *vcpu),
+
+   TP_ARGS(vcpu),
+
+   TP_STRUCT__entry(
+   __field(int,vcpu_id)
+   __field(__u64,  

Re: [PATCH v2 05/14] mm/sparc: Change pXd_huge() behavior to exclude swap entries

2024-03-19 Thread Peter Xu
On Tue, Mar 19, 2024 at 12:25:39PM +0800, Muchun Song wrote:
> > @@ -409,14 +409,12 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, 
> > unsigned long addr,
> > 
> > int pmd_huge(pmd_t pmd)
> > {
> > -   return !pmd_none(pmd) &&
> > -   (pmd_val(pmd) & (_PAGE_VALID|_PAGE_PMD_HUGE)) != _PAGE_VALID;
> > +   return pmd_leaf(pmd);;
> 
> There is a redundant semicolon in the end.

Will touch it up, thanks.  PS: This will be dropped as a whole in patch 12.

-- 
Peter Xu



Re: [RFC] sched/eevdf: sched feature to dismiss lag on wakeup

2024-03-19 Thread Vincent Guittot
On Tue, 19 Mar 2024 at 10:08, Tobias Huschle  wrote:
>
> On 2024-03-18 15:45, Luis Machado wrote:
> > On 3/14/24 13:45, Tobias Huschle wrote:
> >> On Fri, Mar 08, 2024 at 03:11:38PM +, Luis Machado wrote:
> >>> On 2/28/24 16:10, Tobias Huschle wrote:
> 
>  Questions:
>  1. The kworker getting its negative lag occurs in the following
>  scenario
> - kworker and a cgroup are supposed to execute on the same CPU
> - one task within the cgroup is executing and wakes up the
>  kworker
> - kworker with 0 lag, gets picked immediately and finishes its
>   execution within ~5000ns
> - on dequeue, kworker gets assigned a negative lag
> Is this expected behavior? With this short execution time, I
>  would
> expect the kworker to be fine.
> >>>
> >>> That strikes me as a bit odd as well. Have you been able to determine
> >>> how a negative lag
> >>> is assigned to the kworker after such a short runtime?
> >>>
> >>
> >> I did some more trace reading though and found something.
> >>
> >> What I observed if everything runs regularly:
> >> - vhost and kworker run alternating on the same CPU
> >> - if the kworker is done, it leaves the runqueue
> >> - vhost wakes up the kworker if it needs it
> >> --> this means:
> >>   - vhost starts alone on an otherwise empty runqueue
> >>   - it seems like it never gets dequeued
> >> (unless another unrelated task joins or migration hits)
> >>   - if vhost wakes up the kworker, the kworker gets selected
> >>   - vhost runtime > kworker runtime
> >> --> kworker gets positive lag and gets selected immediately next
> >> time
> >>
> >> What happens if it does go wrong:
> >> From what I gather, there seem to be occasions where the vhost either
> >> executes suprisingly quick, or the kworker surprinsingly slow. If
> >> these
> >> outliers reach critical values, it can happen, that
> >>vhost runtime < kworker runtime
> >> which now causes the kworker to get the negative lag.
> >>
> >> In this case it seems like, that the vhost is very fast in waking up
> >> the kworker. And coincidentally, the kworker takes, more time than
> >> usual
> >> to finish. We speak of 4-digit to low 5-digit nanoseconds.
> >>
> >> So, for these outliers, the scheduler extrapolates that the kworker
> >> out-consumes the vhost and should be slowed down, although in the
> >> majority
> >> of other cases this does not happen.
> >
> > Thanks for providing the above details Tobias. It does seem like EEVDF
> > is strict
> > about the eligibility checks and making tasks wait when their lags are
> > negative, even
> > if just a little bit as in the case of the kworker.
> >
> > There was a patch to disable the eligibility checks
> > (https://lore.kernel.org/lkml/20231013030213.2472697-1-youssefes...@chromium.org/),
> > which would make EEVDF more like EVDF, though the deadline comparison
> > would
> > probably still favor the vhost task instead of the kworker with the
> > negative lag.
> >
> > I'm not sure if you tried it, but I thought I'd mention it.
>
> Haven't seen that one yet. Unfortunately, it does not help to ignore the
> eligibility.
>
> I'm inclined to rather propose propose a documentation change, which
> describes that tasks should not rely on woken up tasks being scheduled
> immediately.

Where do you see such an assumption ? Even before eevdf, there were
nothing that ensures such behavior. When using CFS (legacy or eevdf)
tasks, you can't know if the newly wakeup task will run 1st or not


>
> Changing things in the code to address for the specific scenario I'm
> seeing seems to mostly create unwanted side effects and/or would require
> the definition of some magic cut-off values.
>
>


Re: [RFC] sched/eevdf: sched feature to dismiss lag on wakeup

2024-03-19 Thread Tobias Huschle

On 2024-03-18 15:45, Luis Machado wrote:

On 3/14/24 13:45, Tobias Huschle wrote:

On Fri, Mar 08, 2024 at 03:11:38PM +, Luis Machado wrote:

On 2/28/24 16:10, Tobias Huschle wrote:


Questions:
1. The kworker getting its negative lag occurs in the following 
scenario

   - kworker and a cgroup are supposed to execute on the same CPU
   - one task within the cgroup is executing and wakes up the 
kworker

   - kworker with 0 lag, gets picked immediately and finishes its
 execution within ~5000ns
   - on dequeue, kworker gets assigned a negative lag
   Is this expected behavior? With this short execution time, I 
would

   expect the kworker to be fine.


That strikes me as a bit odd as well. Have you been able to determine 
how a negative lag

is assigned to the kworker after such a short runtime?



I did some more trace reading though and found something.

What I observed if everything runs regularly:
- vhost and kworker run alternating on the same CPU
- if the kworker is done, it leaves the runqueue
- vhost wakes up the kworker if it needs it
--> this means:
  - vhost starts alone on an otherwise empty runqueue
  - it seems like it never gets dequeued
(unless another unrelated task joins or migration hits)
  - if vhost wakes up the kworker, the kworker gets selected
  - vhost runtime > kworker runtime
--> kworker gets positive lag and gets selected immediately next 
time


What happens if it does go wrong:
From what I gather, there seem to be occasions where the vhost either
executes suprisingly quick, or the kworker surprinsingly slow. If 
these

outliers reach critical values, it can happen, that
   vhost runtime < kworker runtime
which now causes the kworker to get the negative lag.

In this case it seems like, that the vhost is very fast in waking up
the kworker. And coincidentally, the kworker takes, more time than 
usual

to finish. We speak of 4-digit to low 5-digit nanoseconds.

So, for these outliers, the scheduler extrapolates that the kworker
out-consumes the vhost and should be slowed down, although in the 
majority

of other cases this does not happen.


Thanks for providing the above details Tobias. It does seem like EEVDF 
is strict

about the eligibility checks and making tasks wait when their lags are
negative, even
if just a little bit as in the case of the kworker.

There was a patch to disable the eligibility checks
(https://lore.kernel.org/lkml/20231013030213.2472697-1-youssefes...@chromium.org/),
which would make EEVDF more like EVDF, though the deadline comparison 
would

probably still favor the vhost task instead of the kworker with the
negative lag.

I'm not sure if you tried it, but I thought I'd mention it.


Haven't seen that one yet. Unfortunately, it does not help to ignore the 
eligibility.


I'm inclined to rather propose propose a documentation change, which 
describes that tasks should not rely on woken up tasks being scheduled 
immediately.


Changing things in the code to address for the specific scenario I'm 
seeing seems to mostly create unwanted side effects and/or would require 
the definition of some magic cut-off values.





[PATCH v15 16/16] media: vim2m-audio: add virtual driver for audio memory to memory

2024-03-19 Thread Shengjiu Wang
Audio memory to memory virtual driver use video memory to memory
virtual driver vim2m.c as example. The main difference is
device type is VFL_TYPE_AUDIO and device cap type is V4L2_CAP_AUDIO_M2M.

The device_run function is a dummy function, which is simply
copy the data from input buffer to output buffer.

Signed-off-by: Shengjiu Wang 
---
 MAINTAINERS  |   9 +
 drivers/media/test-drivers/Kconfig   |  10 +
 drivers/media/test-drivers/Makefile  |   1 +
 drivers/media/test-drivers/vim2m-audio.c | 793 +++
 4 files changed, 813 insertions(+)
 create mode 100644 drivers/media/test-drivers/vim2m-audio.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 7b8b9ee65c61..215d40d80508 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23575,6 +23575,15 @@ L: linux-fsde...@vger.kernel.org
 S: Maintained
 F: fs/vboxsf/*
 
+VIRTUAL MEM2MEM DRIVER FOR AUDIO
+M: Hans Verkuil 
+M: Shengjiu Wang 
+L: linux-me...@vger.kernel.org
+S: Maintained
+W: https://linuxtv.org
+T: git git://linuxtv.org/media_tree.git
+F: drivers/media/test-drivers/vim2m-audio.c
+
 VIRTUAL PCM TEST DRIVER
 M: Ivan Orlov 
 L: linux-so...@vger.kernel.org
diff --git a/drivers/media/test-drivers/Kconfig 
b/drivers/media/test-drivers/Kconfig
index 5a5379524bde..b6b52a7ca042 100644
--- a/drivers/media/test-drivers/Kconfig
+++ b/drivers/media/test-drivers/Kconfig
@@ -16,6 +16,16 @@ config VIDEO_VIM2M
  This is a virtual test device for the memory-to-memory driver
  framework.
 
+config VIDEO_VIM2M_AUDIO
+   tristate "Virtual Memory-to-Memory Driver For Audio"
+   depends on VIDEO_DEV
+   select VIDEOBUF2_VMALLOC
+   select V4L2_MEM2MEM_DEV
+   select MEDIA_CONTROLLER
+   help
+ This is a virtual audio test device for the memory-to-memory driver
+ framework.
+
 source "drivers/media/test-drivers/vicodec/Kconfig"
 source "drivers/media/test-drivers/vimc/Kconfig"
 source "drivers/media/test-drivers/vivid/Kconfig"
diff --git a/drivers/media/test-drivers/Makefile 
b/drivers/media/test-drivers/Makefile
index 740714a4584d..0c61c9ada3e1 100644
--- a/drivers/media/test-drivers/Makefile
+++ b/drivers/media/test-drivers/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_DVB_VIDTV) += vidtv/
 
 obj-$(CONFIG_VIDEO_VICODEC) += vicodec/
 obj-$(CONFIG_VIDEO_VIM2M) += vim2m.o
+obj-$(CONFIG_VIDEO_VIM2M_AUDIO) += vim2m-audio.o
 obj-$(CONFIG_VIDEO_VIMC) += vimc/
 obj-$(CONFIG_VIDEO_VIVID) += vivid/
 obj-$(CONFIG_VIDEO_VISL) += visl/
diff --git a/drivers/media/test-drivers/vim2m-audio.c 
b/drivers/media/test-drivers/vim2m-audio.c
new file mode 100644
index ..6361df6320b3
--- /dev/null
+++ b/drivers/media/test-drivers/vim2m-audio.c
@@ -0,0 +1,793 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * A virtual v4l2-mem2mem example for audio device.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+MODULE_DESCRIPTION("Virtual device for audio mem2mem testing");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "debug level");
+
+#define MEM2MEM_NAME "vim2m-audio"
+
+#define dprintk(dev, lvl, fmt, arg...) \
+   v4l2_dbg(lvl, debug, &(dev)->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+#define SAMPLE_NUM 4096
+
+static void audm2m_dev_release(struct device *dev)
+{}
+
+static struct platform_device audm2m_pdev = {
+   .name   = MEM2MEM_NAME,
+   .dev.release= audm2m_dev_release,
+};
+
+static u32 formats[] = {
+   V4L2_AUDIO_FMT_S16_LE,
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+/* Per-queue, driver-specific private data */
+struct audm2m_q_data {
+   unsigned intrate;
+   unsigned intchannels;
+   unsigned intbuffersize;
+   unsigned intsequence;
+   u32 fourcc;
+};
+
+enum {
+   V4L2_M2M_SRC = 0,
+   V4L2_M2M_DST = 1,
+};
+
+static snd_pcm_format_t find_format(u32 fourcc)
+{
+   snd_pcm_format_t fmt;
+   unsigned int k;
+
+   for (k = 0; k < NUM_FORMATS; k++) {
+   if (formats[k] == fourcc)
+   break;
+   }
+
+   if (k == NUM_FORMATS)
+   return 0;
+
+   fmt = v4l2_fourcc_to_audfmt(formats[k]);
+
+   return fmt;
+}
+
+struct audm2m_dev {
+   struct v4l2_device  v4l2_dev;
+   struct video_device vfd;
+
+   struct mutexdev_mutex;
+
+   struct v4l2_m2m_dev *m2m_dev;
+#ifdef CONFIG_MEDIA_CONTROLLER
+   struct media_device mdev;
+#endif
+};
+
+struct audm2m_ctx {
+   struct v4l2_fh  fh;
+   struct v4l2_ctrl_handlerctrl_handler;
+   struct audm2m_dev   *dev;
+
+   struct mutexvb_mutex;
+
+   /* Source and destination queue data */
+   struct audm2m_q_data   q_data[2];
+};
+

[PATCH v15 15/16] media: imx-asrc: Add memory to memory driver

2024-03-19 Thread Shengjiu Wang
Implement the ASRC memory to memory function using
the v4l2 framework, user can use this function with
v4l2 ioctl interface.

User send the output and capture buffer to driver and
driver store the converted data to the capture buffer.

This feature can be shared by ASRC and EASRC drivers

Signed-off-by: Shengjiu Wang 
---
 MAINTAINERS   |8 +
 drivers/media/platform/nxp/Kconfig|   13 +
 drivers/media/platform/nxp/Makefile   |1 +
 drivers/media/platform/nxp/imx-asrc.c | 1256 +
 4 files changed, 1278 insertions(+)
 create mode 100644 drivers/media/platform/nxp/imx-asrc.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 375d34363777..7b8b9ee65c61 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15821,6 +15821,14 @@ F: drivers/nvmem/
 F: include/linux/nvmem-consumer.h
 F: include/linux/nvmem-provider.h
 
+NXP ASRC V4L2 MEM2MEM DRIVERS
+M: Shengjiu Wang 
+L: linux-me...@vger.kernel.org
+S: Maintained
+W: https://linuxtv.org
+T: git git://linuxtv.org/media_tree.git
+F: drivers/media/platform/nxp/imx-asrc.c
+
 NXP BLUETOOTH WIRELESS DRIVERS
 M: Amitkumar Karwar 
 M: Neeraj Kale 
diff --git a/drivers/media/platform/nxp/Kconfig 
b/drivers/media/platform/nxp/Kconfig
index 40e3436669e2..8d0ca335601f 100644
--- a/drivers/media/platform/nxp/Kconfig
+++ b/drivers/media/platform/nxp/Kconfig
@@ -67,3 +67,16 @@ config VIDEO_MX2_EMMAPRP
 
 source "drivers/media/platform/nxp/dw100/Kconfig"
 source "drivers/media/platform/nxp/imx-jpeg/Kconfig"
+
+config VIDEO_IMX_ASRC
+   tristate "NXP i.MX ASRC M2M support"
+   depends on V4L_MEM2MEM_DRIVERS
+   depends on MEDIA_SUPPORT
+   select VIDEOBUF2_DMA_CONTIG
+   select V4L2_MEM2MEM_DEV
+   select MEDIA_CONTROLLER
+   help
+   Say Y if you want to add ASRC M2M support for NXP CPUs.
+   It is a complement for ASRC M2P and ASRC P2M features.
+   This option is only useful for out-of-tree drivers since
+   in-tree drivers select it automatically.
diff --git a/drivers/media/platform/nxp/Makefile 
b/drivers/media/platform/nxp/Makefile
index 4d90eb713652..1325675e34f5 100644
--- a/drivers/media/platform/nxp/Makefile
+++ b/drivers/media/platform/nxp/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_VIDEO_IMX8MQ_MIPI_CSI2) += imx8mq-mipi-csi2.o
 obj-$(CONFIG_VIDEO_IMX_MIPI_CSIS) += imx-mipi-csis.o
 obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o
 obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
+obj-$(CONFIG_VIDEO_IMX_ASRC) += imx-asrc.o
diff --git a/drivers/media/platform/nxp/imx-asrc.c 
b/drivers/media/platform/nxp/imx-asrc.c
new file mode 100644
index ..0c25a36199b1
--- /dev/null
+++ b/drivers/media/platform/nxp/imx-asrc.c
@@ -0,0 +1,1256 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
+// Copyright (C) 2019-2023 NXP
+//
+// Freescale ASRC Memory to Memory (M2M) driver
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define V4L_CAP OUT
+#define V4L_OUT IN
+
+#define ASRC_xPUT_DMA_CALLBACK(dir) \
+   (((dir) == V4L_OUT) ? asrc_input_dma_callback \
+   : asrc_output_dma_callback)
+
+#define DIR_STR(dir) (dir) == V4L_OUT ? "out" : "cap"
+
+/* Maximum output and capture buffer size */
+#define ASRC_M2M_BUFFER_SIZE (512 * 1024)
+
+/* Maximum output and capture period size */
+#define ASRC_M2M_PERIOD_SIZE (48 * 1024)
+
+struct asrc_pair_m2m {
+   struct fsl_asrc_pair *pair;
+   struct asrc_m2m *m2m;
+   struct v4l2_fh fh;
+   struct v4l2_ctrl_handler ctrl_handler;
+   int channels[2];
+   unsigned int sequence[2];
+   s64 src_rate_off_prev;  /* Q31.32 */
+   s64 dst_rate_off_prev;  /* Q31.32 */
+   s64 src_rate_off_cur;   /* Q31.32 */
+   s64 dst_rate_off_cur;   /* Q31.32 */
+};
+
+struct asrc_m2m {
+   struct fsl_asrc_m2m_pdata pdata;
+   struct v4l2_device v4l2_dev;
+   struct v4l2_m2m_dev *m2m_dev;
+   struct video_device *dec_vdev;
+   struct mutex mlock; /* v4l2 ioctls serialization */
+   struct platform_device *pdev;
+#ifdef CONFIG_MEDIA_CONTROLLER
+   struct media_device mdev;
+#endif
+};
+
+static u32 formats[] = {
+   V4L2_AUDIO_FMT_S8,
+   V4L2_AUDIO_FMT_S16_LE,
+   V4L2_AUDIO_FMT_U16_LE,
+   V4L2_AUDIO_FMT_S24_LE,
+   V4L2_AUDIO_FMT_S24_3LE,
+   V4L2_AUDIO_FMT_U24_LE,
+   V4L2_AUDIO_FMT_U24_3LE,
+   V4L2_AUDIO_FMT_S32_LE,
+   V4L2_AUDIO_FMT_U32_LE,
+   V4L2_AUDIO_FMT_S20_3LE,
+   V4L2_AUDIO_FMT_U20_3LE,
+   V4L2_AUDIO_FMT_FLOAT_LE,
+   V4L2_AUDIO_FMT_IEC958_SUBFRAME_LE,
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+static const s64 asrc_v1_m2m_rates[] = {
+   5512, 8000, 11025, 12000, 16000,
+   22050, 24000, 32000, 44100,
+   48000, 64000, 88200, 96000,
+   128000, 176400, 192000,
+};
+
+static const s64 

[PATCH v15 14/16] media: vivid: add fixed point test controls

2024-03-19 Thread Shengjiu Wang
Add fixed point test controls, one is for Q4.16 format
another one is for Q63 format.

Signed-off-by: Shengjiu Wang 
---
 drivers/media/test-drivers/vivid/vivid-core.h |  2 ++
 .../media/test-drivers/vivid/vivid-ctrls.c| 26 +++
 include/media/v4l2-ctrls.h|  6 +
 3 files changed, 34 insertions(+)

diff --git a/drivers/media/test-drivers/vivid/vivid-core.h 
b/drivers/media/test-drivers/vivid/vivid-core.h
index cfb8e66083f6..f65465191bc9 100644
--- a/drivers/media/test-drivers/vivid/vivid-core.h
+++ b/drivers/media/test-drivers/vivid/vivid-core.h
@@ -222,6 +222,8 @@ struct vivid_dev {
struct v4l2_ctrl*boolean;
struct v4l2_ctrl*int32;
struct v4l2_ctrl*int64;
+   struct v4l2_ctrl*int32_q16;
+   struct v4l2_ctrl*int64_q63;
struct v4l2_ctrl*menu;
struct v4l2_ctrl*string;
struct v4l2_ctrl*bitmask;
diff --git a/drivers/media/test-drivers/vivid/vivid-ctrls.c 
b/drivers/media/test-drivers/vivid/vivid-ctrls.c
index f2b20e25a7a4..2444ea95b285 100644
--- a/drivers/media/test-drivers/vivid/vivid-ctrls.c
+++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c
@@ -38,6 +38,8 @@
 #define VIVID_CID_U8_PIXEL_ARRAY   (VIVID_CID_CUSTOM_BASE + 14)
 #define VIVID_CID_S32_ARRAY(VIVID_CID_CUSTOM_BASE + 15)
 #define VIVID_CID_S64_ARRAY(VIVID_CID_CUSTOM_BASE + 16)
+#define VIVID_CID_INT_Q4_16(VIVID_CID_CUSTOM_BASE + 17)
+#define VIVID_CID_INT64_Q63(VIVID_CID_CUSTOM_BASE + 18)
 
 #define VIVID_CID_VIVID_BASE   (0x00f0 | 0xf000)
 #define VIVID_CID_VIVID_CLASS  (0x00f0 | 1)
@@ -182,6 +184,28 @@ static const struct v4l2_ctrl_config vivid_ctrl_int64 = {
.step = 1,
 };
 
+static const struct v4l2_ctrl_config vivid_ctrl_int32_q16 = {
+   .ops = _user_gen_ctrl_ops,
+   .id = VIVID_CID_INT_Q4_16,
+   .name = "Integer 32 Bits Q4.16",
+   .type = V4L2_CTRL_TYPE_INTEGER,
+   .min = v4l2_ctrl_fp_compose(-16, 0, 16),
+   .max = v4l2_ctrl_fp_compose(15, 0x, 16),
+   .step = 1,
+   .fraction_bits = 16,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_int64_q63 = {
+   .ops = _user_gen_ctrl_ops,
+   .id = VIVID_CID_INT64_Q63,
+   .name = "Integer 64 Bits Q63",
+   .type = V4L2_CTRL_TYPE_INTEGER64,
+   .min = v4l2_ctrl_fp_compose(-1, 0, 63),
+   .max = v4l2_ctrl_fp_compose(0, LLONG_MAX, 63),
+   .step = 1,
+   .fraction_bits = 63,
+};
+
 static const struct v4l2_ctrl_config vivid_ctrl_u32_array = {
.ops = _user_gen_ctrl_ops,
.id = VIVID_CID_U32_ARRAY,
@@ -1670,6 +1694,8 @@ int vivid_create_controls(struct vivid_dev *dev, bool 
show_ccs_cap,
dev->button = v4l2_ctrl_new_custom(hdl_user_gen, _ctrl_button, 
NULL);
dev->int32 = v4l2_ctrl_new_custom(hdl_user_gen, _ctrl_int32, 
NULL);
dev->int64 = v4l2_ctrl_new_custom(hdl_user_gen, _ctrl_int64, 
NULL);
+   dev->int32_q16 = v4l2_ctrl_new_custom(hdl_user_gen, 
_ctrl_int32_q16, NULL);
+   dev->int64_q63 = v4l2_ctrl_new_custom(hdl_user_gen, 
_ctrl_int64_q63, NULL);
dev->boolean = v4l2_ctrl_new_custom(hdl_user_gen, _ctrl_boolean, 
NULL);
dev->menu = v4l2_ctrl_new_custom(hdl_user_gen, _ctrl_menu, NULL);
dev->string = v4l2_ctrl_new_custom(hdl_user_gen, _ctrl_string, 
NULL);
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index c35514c5bf88..197d8b67ac13 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -1593,4 +1593,10 @@ void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl);
  */
 int v4l2_ctrl_type_op_validate(const struct v4l2_ctrl *ctrl, union 
v4l2_ctrl_ptr ptr);
 
+/*
+ * Fixed point compose helper define. This helper maps to the value
+ * i + f / (1 << fraction_bits).
+ */
+#define v4l2_ctrl_fp_compose(i, f, fraction_bits) (((s64)(i) << fraction_bits) 
+ (f))
+
 #endif
-- 
2.34.1



[PATCH v15 13/16] media: uapi: Add an entity type for audio resampler

2024-03-19 Thread Shengjiu Wang
Add and document a media entity type for an audio resampler.
It is MEDIA_ENT_F_PROC_AUDIO_RESAMPLER.

Signed-off-by: Shengjiu Wang 
---
 Documentation/userspace-api/media/mediactl/media-types.rst | 6 ++
 include/uapi/linux/media.h | 1 +
 2 files changed, 7 insertions(+)

diff --git a/Documentation/userspace-api/media/mediactl/media-types.rst 
b/Documentation/userspace-api/media/mediactl/media-types.rst
index adfb37430f8e..d353f17c3344 100644
--- a/Documentation/userspace-api/media/mediactl/media-types.rst
+++ b/Documentation/userspace-api/media/mediactl/media-types.rst
@@ -40,6 +40,7 @@ Types and flags used to represent the media graph elements
 .. _MEDIA-ENT-F-PROC-VIDEO-ENCODER:
 .. _MEDIA-ENT-F-PROC-VIDEO-DECODER:
 .. _MEDIA-ENT-F-PROC-VIDEO-ISP:
+.. _MEDIA-ENT-F-PROC-AUDIO-RESAMPLER:
 .. _MEDIA-ENT-F-VID-MUX:
 .. _MEDIA-ENT-F-VID-IF-BRIDGE:
 .. _MEDIA-ENT-F-DV-DECODER:
@@ -208,6 +209,11 @@ Types and flags used to represent the media graph elements
  combination of custom V4L2 controls and IOCTLs, and parameters
  supplied in a metadata buffer.
 
+*  -  ``MEDIA_ENT_F_PROC_AUDIO_RESAMPLER``
+   -  An Audio Resampler device. An entity capable of
+ resampling an audio stream from one sample rate to another sample
+ rate. Must have one sink pad and at least one source pad.
+
 *  -  ``MEDIA_ENT_F_VID_MUX``
- Video multiplexer. An entity capable of multiplexing must have at
  least two sink pads and one source pad, and must pass the video
diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
index 9ff6dec7393a..a8266eaa8042 100644
--- a/include/uapi/linux/media.h
+++ b/include/uapi/linux/media.h
@@ -125,6 +125,7 @@ struct media_device_info {
 #define MEDIA_ENT_F_PROC_VIDEO_ENCODER (MEDIA_ENT_F_BASE + 0x4007)
 #define MEDIA_ENT_F_PROC_VIDEO_DECODER (MEDIA_ENT_F_BASE + 0x4008)
 #define MEDIA_ENT_F_PROC_VIDEO_ISP (MEDIA_ENT_F_BASE + 0x4009)
+#define MEDIA_ENT_F_PROC_AUDIO_RESAMPLER   (MEDIA_ENT_F_BASE + 0x400a)
 
 /*
  * Switch and bridge entity functions
-- 
2.34.1



[PATCH v15 12/16] media: uapi: Declare interface types for Audio

2024-03-19 Thread Shengjiu Wang
Declare the interface types that will be used by Audio.
The type is MEDIA_INTF_T_V4L_AUDIO.

Signed-off-by: Shengjiu Wang 
---
 .../userspace-api/media/mediactl/media-types.rst|  5 +
 drivers/media/v4l2-core/v4l2-dev.c  |  4 
 drivers/media/v4l2-core/v4l2-mem2mem.c  | 13 +
 include/uapi/linux/media.h  |  1 +
 4 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/Documentation/userspace-api/media/mediactl/media-types.rst 
b/Documentation/userspace-api/media/mediactl/media-types.rst
index 6332e8395263..adfb37430f8e 100644
--- a/Documentation/userspace-api/media/mediactl/media-types.rst
+++ b/Documentation/userspace-api/media/mediactl/media-types.rst
@@ -265,6 +265,7 @@ Types and flags used to represent the media graph elements
 .. _MEDIA-INTF-T-V4L-SUBDEV:
 .. _MEDIA-INTF-T-V4L-SWRADIO:
 .. _MEDIA-INTF-T-V4L-TOUCH:
+.. _MEDIA-INTF-T-V4L-AUDIO:
 .. _MEDIA-INTF-T-ALSA-PCM-CAPTURE:
 .. _MEDIA-INTF-T-ALSA-PCM-PLAYBACK:
 .. _MEDIA-INTF-T-ALSA-CONTROL:
@@ -322,6 +323,10 @@ Types and flags used to represent the media graph elements
-  Device node interface for Touch device (V4L)
-  typically, /dev/v4l-touch?
 
+*  -  ``MEDIA_INTF_T_V4L_AUDIO``
+   -  Device node interface for Audio device (V4L)
+   -  typically, /dev/v4l-audio?
+
 *  -  ``MEDIA_INTF_T_ALSA_PCM_CAPTURE``
-  Device node interface for ALSA PCM Capture
-  typically, /dev/snd/pcmC?D?c
diff --git a/drivers/media/v4l2-core/v4l2-dev.c 
b/drivers/media/v4l2-core/v4l2-dev.c
index bac008fcedc6..ca8462a61e1f 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -844,6 +844,10 @@ static int video_register_media_controller(struct 
video_device *vdev)
intf_type = MEDIA_INTF_T_V4L_SUBDEV;
/* Entity will be created via v4l2_device_register_subdev() */
break;
+   case VFL_TYPE_AUDIO:
+   intf_type = MEDIA_INTF_T_V4L_AUDIO;
+   /* Entity will be created via v4l2_device_register_subdev() */
+   break;
default:
return 0;
}
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c 
b/drivers/media/v4l2-core/v4l2-mem2mem.c
index 75517134a5e9..cda5e255305f 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -1143,10 +1143,15 @@ int v4l2_m2m_register_media_controller(struct 
v4l2_m2m_dev *m2m_dev,
if (ret)
goto err_rm_links0;
 
-   /* Create video interface */
-   m2m_dev->intf_devnode = media_devnode_create(mdev,
-   MEDIA_INTF_T_V4L_VIDEO, 0,
-   VIDEO_MAJOR, vdev->minor);
+   if (vdev->vfl_type == VFL_TYPE_AUDIO)
+   m2m_dev->intf_devnode = media_devnode_create(mdev,
+   MEDIA_INTF_T_V4L_AUDIO, 0,
+   VIDEO_MAJOR, vdev->minor);
+   else
+   /* Create video interface */
+   m2m_dev->intf_devnode = media_devnode_create(mdev,
+   MEDIA_INTF_T_V4L_VIDEO, 0,
+   VIDEO_MAJOR, vdev->minor);
if (!m2m_dev->intf_devnode) {
ret = -ENOMEM;
goto err_rm_links1;
diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
index 1c80b1d6bbaf..9ff6dec7393a 100644
--- a/include/uapi/linux/media.h
+++ b/include/uapi/linux/media.h
@@ -260,6 +260,7 @@ struct media_links_enum {
 #define MEDIA_INTF_T_V4L_SUBDEV(MEDIA_INTF_T_V4L_BASE 
+ 3)
 #define MEDIA_INTF_T_V4L_SWRADIO   (MEDIA_INTF_T_V4L_BASE + 4)
 #define MEDIA_INTF_T_V4L_TOUCH (MEDIA_INTF_T_V4L_BASE + 5)
+#define MEDIA_INTF_T_V4L_AUDIO (MEDIA_INTF_T_V4L_BASE + 6)
 
 #define MEDIA_INTF_T_ALSA_BASE 0x0300
 #define MEDIA_INTF_T_ALSA_PCM_CAPTURE  (MEDIA_INTF_T_ALSA_BASE)
-- 
2.34.1



[PATCH v15 11/16] media: uapi: Add audio rate controls support

2024-03-19 Thread Shengjiu Wang
Add V4L2_CID_M2M_AUDIO_SOURCE_RATE and V4L2_CID_M2M_AUDIO_DEST_RATE
new IDs for rate control.

Add V4L2_CID_M2M_AUDIO_SOURCE_RATE_OFFSET and
V4L2_CID_M2M_AUDIO_DEST_RATE_OFFSET for clock drift.

Signed-off-by: Shengjiu Wang 
---
 .../media/v4l/ext-ctrls-audio-m2m.rst | 38 +++
 drivers/media/v4l2-core/v4l2-ctrls-defs.c |  6 +++
 include/uapi/linux/v4l2-controls.h|  5 +++
 3 files changed, 49 insertions(+)

diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-audio-m2m.rst 
b/Documentation/userspace-api/media/v4l/ext-ctrls-audio-m2m.rst
index 82d2ecedbfee..b137b7c442e6 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-audio-m2m.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-audio-m2m.rst
@@ -19,3 +19,41 @@ Audio M2M Control IDs
 The Audio M2M class descriptor. Calling
 :ref:`VIDIOC_QUERYCTRL` for this control will
 return a description of this control class.
+
+.. _v4l2-audio-asrc:
+
+``V4L2_CID_M2M_AUDIO_SOURCE_RATE (integer menu)``
+This control specifies the audio source sample rate, unit is Hz
+
+``V4L2_CID_M2M_AUDIO_DEST_RATE (integer menu)``
+This control specifies the audio destination sample rate, unit is Hz
+
+``V4L2_CID_M2M_AUDIO_SOURCE_RATE_OFFSET (fixed point)``
+This control specifies the offset from the audio source sample rate,
+unit is Hz.
+
+The offset compensates for any clock drift. The actual source audio
+sample rate is the ideal source audio sample rate from
+``V4L2_CID_M2M_AUDIO_SOURCE_RATE`` plus this fixed point offset.
+
+The audio source clock may have some drift. Reducing or increasing the
+audio sample rate dynamically to ensure that Sample Rate Converter is
+working on the real sample rate, this feature is for the Asynchronous
+Sample Rate Converter module.
+So, userspace would be expected to be monitoring such drift
+and increasing/decreasing the sample frequency as needed by this control.
+
+``V4L2_CID_M2M_AUDIO_DEST_RATE_OFFSET (fixed point)``
+This control specifies the offset from the audio destination sample rate,
+unit is Hz.
+
+The offset compensates for any clock drift. The actual destination audio
+sample rate is the ideal source audio sample rate from
+``V4L2_CID_M2M_AUDIO_DEST_RATE`` plus this fixed point offset.
+
+The audio destination clock may have some drift. Reducing or increasing
+the audio sample rate dynamically to ensure that sample rate converter
+is working on the real sample rate, this feature is for the Asynchronous
+Sample Rate Converter module.
+So, userspace would be expected to be monitoring such drift
+and increasing/decreasing the sample frequency as needed by this control.
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c 
b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
index 2a85ea3dc92f..91e1f5348c23 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
@@ -1245,6 +1245,8 @@ const char *v4l2_ctrl_get_name(u32 id)
 
/* Audio M2M controls */
case V4L2_CID_M2M_AUDIO_CLASS:  return "Audio M2M Controls";
+   case V4L2_CID_M2M_AUDIO_SOURCE_RATE:return "Audio Source Sample 
Rate";
+   case V4L2_CID_M2M_AUDIO_DEST_RATE:  return "Audio Destination 
Sample Rate";
default:
return NULL;
}
@@ -1606,6 +1608,10 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum 
v4l2_ctrl_type *type,
case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY:
*type = V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY;
break;
+   case V4L2_CID_M2M_AUDIO_SOURCE_RATE:
+   case V4L2_CID_M2M_AUDIO_DEST_RATE:
+   *type = V4L2_CTRL_TYPE_INTEGER_MENU;
+   break;
default:
*type = V4L2_CTRL_TYPE_INTEGER;
break;
diff --git a/include/uapi/linux/v4l2-controls.h 
b/include/uapi/linux/v4l2-controls.h
index a8b4b830c757..30129ccdc282 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -3495,6 +3495,11 @@ struct v4l2_ctrl_av1_film_grain {
 #define V4L2_CID_M2M_AUDIO_CLASS_BASE  (V4L2_CTRL_CLASS_M2M_AUDIO | 0x900)
 #define V4L2_CID_M2M_AUDIO_CLASS   (V4L2_CTRL_CLASS_M2M_AUDIO | 1)
 
+#define V4L2_CID_M2M_AUDIO_SOURCE_RATE (V4L2_CID_M2M_AUDIO_CLASS_BASE + 0)
+#define V4L2_CID_M2M_AUDIO_DEST_RATE   (V4L2_CID_M2M_AUDIO_CLASS_BASE + 1)
+#define V4L2_CID_M2M_AUDIO_SOURCE_RATE_OFFSET  (V4L2_CID_M2M_AUDIO_CLASS_BASE 
+ 2)
+#define V4L2_CID_M2M_AUDIO_DEST_RATE_OFFSET(V4L2_CID_M2M_AUDIO_CLASS_BASE 
+ 3)
+
 /* MPEG-compression definitions kept for backwards compatibility */
 #ifndef __KERNEL__
 #define V4L2_CTRL_CLASS_MPEGV4L2_CTRL_CLASS_CODEC
-- 
2.34.1



[PATCH v15 10/16] media: uapi: Add V4L2_CTRL_CLASS_M2M_AUDIO

2024-03-19 Thread Shengjiu Wang
The Audio M2M class includes controls for audio memory-to-memory
use cases. The controls can be used for audio codecs, audio
preprocessing, audio postprocessing.

Signed-off-by: Shengjiu Wang 
---
 .../userspace-api/media/v4l/common.rst|  1 +
 .../media/v4l/ext-ctrls-audio-m2m.rst | 21 +++
 .../media/v4l/vidioc-g-ext-ctrls.rst  |  4 
 drivers/media/v4l2-core/v4l2-ctrls-defs.c |  4 
 include/uapi/linux/v4l2-controls.h|  4 
 5 files changed, 34 insertions(+)
 create mode 100644 
Documentation/userspace-api/media/v4l/ext-ctrls-audio-m2m.rst

diff --git a/Documentation/userspace-api/media/v4l/common.rst 
b/Documentation/userspace-api/media/v4l/common.rst
index ea0435182e44..d5366e96a596 100644
--- a/Documentation/userspace-api/media/v4l/common.rst
+++ b/Documentation/userspace-api/media/v4l/common.rst
@@ -52,6 +52,7 @@ applicable to all devices.
 ext-ctrls-fm-rx
 ext-ctrls-detect
 ext-ctrls-colorimetry
+ext-ctrls-audio-m2m
 fourcc
 format
 planar-apis
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-audio-m2m.rst 
b/Documentation/userspace-api/media/v4l/ext-ctrls-audio-m2m.rst
new file mode 100644
index ..82d2ecedbfee
--- /dev/null
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-audio-m2m.rst
@@ -0,0 +1,21 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+
+.. _audiom2m-controls:
+
+***
+Audio M2M Control Reference
+***
+
+The Audio M2M class includes controls for audio memory-to-memory
+use cases. The controls can be used for audio codecs, audio
+preprocessing, audio postprocessing.
+
+Audio M2M Control IDs
+---
+
+.. _audiom2m-control-id:
+
+``V4L2_CID_M2M_AUDIO_CLASS (class)``
+The Audio M2M class descriptor. Calling
+:ref:`VIDIOC_QUERYCTRL` for this control will
+return a description of this control class.
diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst 
b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
index 4d56c0528ad7..aeb1ad8e7d29 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
@@ -488,6 +488,10 @@ still cause this situation.
   - 0xa5
   - The class containing colorimetry controls. These controls are
described in :ref:`colorimetry-controls`.
+* - ``V4L2_CTRL_CLASS_M2M_AUDIO``
+  - 0xa6
+  - The class containing audio m2m controls. These controls are
+   described in :ref:`audiom2m-controls`.
 
 Return Value
 
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c 
b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
index 8696eb1cdd61..2a85ea3dc92f 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
@@ -1242,6 +1242,9 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_COLORIMETRY_CLASS:return "Colorimetry Controls";
case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO:   return "HDR10 
Content Light Info";
case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY:  return "HDR10 
Mastering Display";
+
+   /* Audio M2M controls */
+   case V4L2_CID_M2M_AUDIO_CLASS:  return "Audio M2M Controls";
default:
return NULL;
}
@@ -1451,6 +1454,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum 
v4l2_ctrl_type *type,
case V4L2_CID_DETECT_CLASS:
case V4L2_CID_CODEC_STATELESS_CLASS:
case V4L2_CID_COLORIMETRY_CLASS:
+   case V4L2_CID_M2M_AUDIO_CLASS:
*type = V4L2_CTRL_TYPE_CTRL_CLASS;
/* You can neither read nor write these */
*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
diff --git a/include/uapi/linux/v4l2-controls.h 
b/include/uapi/linux/v4l2-controls.h
index 99c3f5e99da7..a8b4b830c757 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -30,6 +30,7 @@
 #define V4L2_CTRL_CLASS_DETECT 0x00a3  /* Detection controls */
 #define V4L2_CTRL_CLASS_CODEC_STATELESS 0x00a4 /* Stateless codecs 
controls */
 #define V4L2_CTRL_CLASS_COLORIMETRY0x00a5  /* Colorimetry controls 
*/
+#define V4L2_CTRL_CLASS_M2M_AUDIO  0x00a6  /* Audio M2M controls */
 
 /* User-class control IDs */
 
@@ -3491,6 +3492,9 @@ struct v4l2_ctrl_av1_film_grain {
__u8 reserved[4];
 };
 
+#define V4L2_CID_M2M_AUDIO_CLASS_BASE  (V4L2_CTRL_CLASS_M2M_AUDIO | 0x900)
+#define V4L2_CID_M2M_AUDIO_CLASS   (V4L2_CTRL_CLASS_M2M_AUDIO | 1)
+
 /* MPEG-compression definitions kept for backwards compatibility */
 #ifndef __KERNEL__
 #define V4L2_CTRL_CLASS_MPEGV4L2_CTRL_CLASS_CODEC
-- 
2.34.1



[PATCH v15 09/16] media: uapi: Define audio sample format fourcc type

2024-03-19 Thread Shengjiu Wang
The audio sample format definition is from alsa,
the header file is include/uapi/sound/asound.h, but
don't include this header file directly, because in
user space, there is another copy in alsa-lib.
There will be conflict in userspace for include
videodev2.h & asound.h and asoundlib.h

Here still use the fourcc format.

Signed-off-by: Shengjiu Wang 
---
 .../userspace-api/media/v4l/pixfmt-audio.rst  | 100 ++
 .../userspace-api/media/v4l/pixfmt.rst|   1 +
 drivers/media/v4l2-core/v4l2-ioctl.c  |  13 +++
 include/uapi/linux/videodev2.h|  29 +
 4 files changed, 143 insertions(+)
 create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-audio.rst

diff --git a/Documentation/userspace-api/media/v4l/pixfmt-audio.rst 
b/Documentation/userspace-api/media/v4l/pixfmt-audio.rst
new file mode 100644
index ..a66db9a19936
--- /dev/null
+++ b/Documentation/userspace-api/media/v4l/pixfmt-audio.rst
@@ -0,0 +1,100 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+
+.. _pixfmt-audio:
+
+*
+Audio Formats
+*
+
+These formats are used for :ref:`audiomem2mem` interface only.
+
+All FourCCs starting with 'AU' are reserved for mappings
+of the snd_pcm_format_t type.
+
+The v4l2_audfmt_to_fourcc() is defined to convert the snd_pcm_format_t
+type to a FourCC. The first character is 'A', the second character
+is 'U', and the remaining two characters is the snd_pcm_format_t
+value in ASCII. Example: SNDRV_PCM_FORMAT_S16_LE (with value 2)
+maps to 'AU02' and SNDRV_PCM_FORMAT_S24_3LE (with value 32) maps
+to 'AU32'."
+
+The v4l2_fourcc_to_audfmt() is defined to convert these FourCCs to
+snd_pcm_format_t type.
+
+.. tabularcolumns:: |p{5.8cm}|p{1.2cm}|p{10.3cm}|
+
+.. cssclass:: longtable
+
+.. flat-table:: Audio Format
+:header-rows:  1
+:stub-columns: 0
+:widths:   3 1 4
+
+* - Identifier
+  - Code
+  - Details
+* .. _V4L2-AUDIO-FMT-S8:
+
+  - ``V4L2_AUDIO_FMT_S8``
+  - 'S8'
+  - Corresponds to SNDRV_PCM_FORMAT_S8 in ALSA
+* .. _V4L2-AUDIO-FMT-S16-LE:
+
+  - ``V4L2_AUDIO_FMT_S16_LE``
+  - 'S16_LE'
+  - Corresponds to SNDRV_PCM_FORMAT_S16_LE in ALSA
+* .. _V4L2-AUDIO-FMT-U16-LE:
+
+  - ``V4L2_AUDIO_FMT_U16_LE``
+  - 'U16_LE'
+  - Corresponds to SNDRV_PCM_FORMAT_U16_LE in ALSA
+* .. _V4L2-AUDIO-FMT-S24-LE:
+
+  - ``V4L2_AUDIO_FMT_S24_LE``
+  - 'S24_LE'
+  - Corresponds to SNDRV_PCM_FORMAT_S24_LE in ALSA
+* .. _V4L2-AUDIO-FMT-U24-LE:
+
+  - ``V4L2_AUDIO_FMT_U24_LE``
+  - 'U24_LE'
+  - Corresponds to SNDRV_PCM_FORMAT_U24_LE in ALSA
+* .. _V4L2-AUDIO-FMT-S32-LE:
+
+  - ``V4L2_AUDIO_FMT_S32_LE``
+  - 'S32_LE'
+  - Corresponds to SNDRV_PCM_FORMAT_S32_LE in ALSA
+* .. _V4L2-AUDIO-FMT-U32-LE:
+
+  - ``V4L2_AUDIO_FMT_U32_LE``
+  - 'U32_LE'
+  - Corresponds to SNDRV_PCM_FORMAT_U32_LE in ALSA
+* .. _V4L2-AUDIO-FMT-FLOAT-LE:
+
+  - ``V4L2_AUDIO_FMT_FLOAT_LE``
+  - 'FLOAT_LE'
+  - Corresponds to SNDRV_PCM_FORMAT_FLOAT_LE in ALSA
+* .. _V4L2-AUDIO-FMT-IEC958-SUBFRAME-LE:
+
+  - ``V4L2_AUDIO_FMT_IEC958_SUBFRAME_LE``
+  - 'IEC958_SUBFRAME_LE'
+  - Corresponds to SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE in ALSA
+* .. _V4L2-AUDIO-FMT-S24-3LE:
+
+  - ``V4L2_AUDIO_FMT_S24_3LE``
+  - 'S24_3LE'
+  - Corresponds to SNDRV_PCM_FORMAT_S24_3LE in ALSA
+* .. _V4L2-AUDIO-FMT-U24-3LE:
+
+  - ``V4L2_AUDIO_FMT_U24_3LE``
+  - 'U24_3LE'
+  - Corresponds to SNDRV_PCM_FORMAT_U24_3LE in ALSA
+* .. _V4L2-AUDIO-FMT-S20-3LE:
+
+  - ``V4L2_AUDIO_FMT_S20_3LE``
+  - 'S20_3LE'
+  - Corresponds to SNDRV_PCM_FORMAT_S24_3LE in ALSA
+* .. _V4L2-AUDIO-FMT-U20-3LE:
+
+  - ``V4L2_AUDIO_FMT_U20_3LE``
+  - 'U20_3LE'
+  - Corresponds to SNDRV_PCM_FORMAT_U20_3LE in ALSA
diff --git a/Documentation/userspace-api/media/v4l/pixfmt.rst 
b/Documentation/userspace-api/media/v4l/pixfmt.rst
index 11dab4a90630..2eb6fdd3b43d 100644
--- a/Documentation/userspace-api/media/v4l/pixfmt.rst
+++ b/Documentation/userspace-api/media/v4l/pixfmt.rst
@@ -36,3 +36,4 @@ see also :ref:`VIDIOC_G_FBUF `.)
 colorspaces
 colorspaces-defs
 colorspaces-details
+pixfmt-audio
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c 
b/drivers/media/v4l2-core/v4l2-ioctl.c
index 961abcdf7290..be229c69e991 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1471,6 +1471,19 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_Y210: descr = "10-bit YUYV Packed"; break;
case V4L2_PIX_FMT_Y212: descr = "12-bit YUYV Packed"; break;
case V4L2_PIX_FMT_Y216: descr = "16-bit YUYV Packed"; break;
+   case V4L2_AUDIO_FMT_S8: descr = "8-bit Signed"; break;
+   case V4L2_AUDIO_FMT_S16_LE: descr = "16-bit Signed LE"; break;
+   case V4L2_AUDIO_FMT_U16_LE:   

[PATCH v15 08/16] media: v4l2: Add audio capture and output support

2024-03-19 Thread Shengjiu Wang
Audio signal processing has the requirement for memory to
memory similar as Video.

This patch is to add this support in v4l2 framework, defined
new buffer type V4L2_BUF_TYPE_AUDIO_CAPTURE and
V4L2_BUF_TYPE_AUDIO_OUTPUT, defined new format v4l2_audio_format
for audio case usage.

The created audio device is named "/dev/v4l-audioX".

Signed-off-by: Shengjiu Wang 
---
 .../userspace-api/media/v4l/buffer.rst|  6 ++
 .../media/v4l/dev-audio-mem2mem.rst   | 71 +++
 .../userspace-api/media/v4l/devices.rst   |  1 +
 .../media/v4l/vidioc-enum-fmt.rst |  2 +
 .../userspace-api/media/v4l/vidioc-g-fmt.rst  |  4 ++
 .../media/videodev2.h.rst.exceptions  |  2 +
 .../media/common/videobuf2/videobuf2-v4l2.c   |  4 ++
 drivers/media/v4l2-core/v4l2-compat-ioctl32.c |  9 +++
 drivers/media/v4l2-core/v4l2-dev.c| 17 +
 drivers/media/v4l2-core/v4l2-ioctl.c  | 53 ++
 include/media/v4l2-dev.h  |  2 +
 include/media/v4l2-ioctl.h| 34 +
 include/uapi/linux/videodev2.h| 17 +
 13 files changed, 222 insertions(+)
 create mode 100644 Documentation/userspace-api/media/v4l/dev-audio-mem2mem.rst

diff --git a/Documentation/userspace-api/media/v4l/buffer.rst 
b/Documentation/userspace-api/media/v4l/buffer.rst
index 52bbee81c080..a3754ca6f0d6 100644
--- a/Documentation/userspace-api/media/v4l/buffer.rst
+++ b/Documentation/userspace-api/media/v4l/buffer.rst
@@ -438,6 +438,12 @@ enum v4l2_buf_type
 * - ``V4L2_BUF_TYPE_META_OUTPUT``
   - 14
   - Buffer for metadata output, see :ref:`metadata`.
+* - ``V4L2_BUF_TYPE_AUDIO_CAPTURE``
+  - 15
+  - Buffer for audio capture, see :ref:`audio`.
+* - ``V4L2_BUF_TYPE_AUDIO_OUTPUT``
+  - 16
+  - Buffer for audio output, see :ref:`audio`.
 
 
 .. _buffer-flags:
diff --git a/Documentation/userspace-api/media/v4l/dev-audio-mem2mem.rst 
b/Documentation/userspace-api/media/v4l/dev-audio-mem2mem.rst
new file mode 100644
index ..54cc2abb6c04
--- /dev/null
+++ b/Documentation/userspace-api/media/v4l/dev-audio-mem2mem.rst
@@ -0,0 +1,71 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+
+.. _audiomem2mem:
+
+
+Audio Memory-To-Memory Interface
+
+
+An audio memory-to-memory device can compress, decompress, transform, or
+otherwise convert audio data from one format into another format, in memory.
+Such memory-to-memory devices set the ``V4L2_CAP_AUDIO_M2M`` capability.
+Examples of memory-to-memory devices are audio codecs, audio preprocessing,
+audio postprocessing.
+
+A memory-to-memory audio node supports both output (sending audio frames from
+memory to the hardware) and capture (receiving the processed audio frames
+from the hardware into memory) stream I/O. An application will have to
+setup the stream I/O for both sides and finally call
+:ref:`VIDIOC_STREAMON ` for both capture and output to
+start the hardware.
+
+Memory-to-memory devices function as a shared resource: you can
+open the audio node multiple times, each application setting up their
+own properties that are local to the file handle, and each can use
+it independently from the others. The driver will arbitrate access to
+the hardware and reprogram it whenever another file handler gets access.
+
+Audio memory-to-memory devices are accessed through character device
+special files named ``/dev/v4l-audio``
+
+Querying Capabilities
+=
+
+Device nodes supporting the audio memory-to-memory interface set the
+``V4L2_CAP_AUDIO_M2M`` flag in the ``device_caps`` field of the
+:c:type:`v4l2_capability` structure returned by the :c:func:`VIDIOC_QUERYCAP`
+ioctl.
+
+Data Format Negotiation
+===
+
+The audio device uses the :ref:`format` ioctls to select the capture format.
+The audio buffer content format is bound to that selected format. In addition
+to the basic :ref:`format` ioctls, the :c:func:`VIDIOC_ENUM_FMT` ioctl must be
+supported as well.
+
+To use the :ref:`format` ioctls applications set the ``type`` field of the
+:c:type:`v4l2_format` structure to ``V4L2_BUF_TYPE_AUDIO_CAPTURE`` or to
+``V4L2_BUF_TYPE_AUDIO_OUTPUT``. Both drivers and applications must set the
+remainder of the :c:type:`v4l2_format` structure to 0.
+
+.. c:type:: v4l2_audio_format
+
+.. tabularcolumns:: |p{1.4cm}|p{2.4cm}|p{13.5cm}|
+
+.. flat-table:: struct v4l2_audio_format
+:header-rows:  0
+:stub-columns: 0
+:widths:   1 1 2
+
+* - __u32
+  - ``audioformat``
+  - The sample format, set by the application. see :ref:`pixfmt-audio`
+* - __u32
+  - ``channels``
+  - The channel number, set by the application. channel number range is
+[1, 32].
+* - __u32
+  - ``buffersize``
+  - Maximum buffer size in bytes required for data. The value is set by the
+driver.
diff --git 

[PATCH v15 07/16] media: uapi: Add V4L2_CAP_AUDIO_M2M capability flag

2024-03-19 Thread Shengjiu Wang
V4L2_CAP_AUDIO_M2M is similar to V4L2_CAP_VIDEO_M2M flag.

It is used for audio memory to memory case.

Signed-off-by: Shengjiu Wang 
---
 Documentation/userspace-api/media/v4l/vidioc-querycap.rst| 3 +++
 Documentation/userspace-api/media/videodev2.h.rst.exceptions | 1 +
 include/uapi/linux/videodev2.h   | 1 +
 3 files changed, 5 insertions(+)

diff --git a/Documentation/userspace-api/media/v4l/vidioc-querycap.rst 
b/Documentation/userspace-api/media/v4l/vidioc-querycap.rst
index 6c57b8428356..1c0d97bf192a 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-querycap.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-querycap.rst
@@ -173,6 +173,9 @@ specification the ioctl returns an ``EINVAL`` error code.
interface. A video overlay device typically stores captured images
directly in the video memory of a graphics card, with hardware
clipping and scaling.
+* - ``V4L2_CAP_AUDIO_M2M``
+  - 0x0008
+  - The device supports the audio Memory-To-Memory interface.
 * - ``V4L2_CAP_VBI_CAPTURE``
   - 0x0010
   - The device supports the :ref:`Raw VBI Capture `
diff --git a/Documentation/userspace-api/media/videodev2.h.rst.exceptions 
b/Documentation/userspace-api/media/videodev2.h.rst.exceptions
index 3e58aac4ef0b..da6d0b8e4c2c 100644
--- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions
+++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions
@@ -197,6 +197,7 @@ replace define V4L2_CAP_META_OUTPUT device-capabilities
 replace define V4L2_CAP_DEVICE_CAPS device-capabilities
 replace define V4L2_CAP_TOUCH device-capabilities
 replace define V4L2_CAP_IO_MC device-capabilities
+replace define V4L2_CAP_AUDIO_M2M device-capabilities
 
 # V4L2 pix flags
 replace define V4L2_PIX_FMT_PRIV_MAGIC :c:type:`v4l2_pix_format`
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index b8573e9ccde6..5cc2a978fd9c 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -473,6 +473,7 @@ struct v4l2_capability {
 #define V4L2_CAP_VIDEO_CAPTURE 0x0001  /* Is a video capture 
device */
 #define V4L2_CAP_VIDEO_OUTPUT  0x0002  /* Is a video output device 
*/
 #define V4L2_CAP_VIDEO_OVERLAY 0x0004  /* Can do video overlay */
+#define V4L2_CAP_AUDIO_M2M 0x0008  /* audio memory to memory */
 #define V4L2_CAP_VBI_CAPTURE   0x0010  /* Is a raw VBI capture 
device */
 #define V4L2_CAP_VBI_OUTPUT0x0020  /* Is a raw VBI output 
device */
 #define V4L2_CAP_SLICED_VBI_CAPTURE0x0040  /* Is a sliced VBI capture 
device */
-- 
2.34.1



[PATCH v15 06/16] ASoC: fsl_easrc: register m2m platform device

2024-03-19 Thread Shengjiu Wang
Register m2m platform device,that user can
use M2M feature.

Signed-off-by: Shengjiu Wang 
Acked-by: Mark Brown 
---
 sound/soc/fsl/fsl_easrc.c | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index cf7ad30a323b..ccbf45c7abf4 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -2075,6 +2075,7 @@ MODULE_DEVICE_TABLE(of, fsl_easrc_dt_ids);
 static int fsl_easrc_probe(struct platform_device *pdev)
 {
struct fsl_easrc_priv *easrc_priv;
+   struct fsl_asrc_m2m_pdata m2m_pdata;
struct device *dev = >dev;
struct fsl_asrc *easrc;
struct resource *res;
@@ -2190,6 +2191,19 @@ static int fsl_easrc_probe(struct platform_device *pdev)
goto err_pm_disable;
}
 
+   m2m_pdata.asrc = easrc;
+   m2m_pdata.fmt_in = FSL_EASRC_FORMATS;
+   m2m_pdata.fmt_out = FSL_EASRC_FORMATS | 
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
+   m2m_pdata.rate_min = 8000;
+   m2m_pdata.rate_max = 768000;
+   m2m_pdata.chan_min = 1;
+   m2m_pdata.chan_max = 32;
+   easrc->m2m_pdev = platform_device_register_data(>dev,
+   M2M_DRV_NAME,
+   PLATFORM_DEVID_AUTO,
+   _pdata,
+   sizeof(m2m_pdata));
+
return 0;
 
 err_pm_disable:
@@ -2199,6 +2213,11 @@ static int fsl_easrc_probe(struct platform_device *pdev)
 
 static void fsl_easrc_remove(struct platform_device *pdev)
 {
+   struct fsl_asrc *easrc = dev_get_drvdata(>dev);
+
+   if (easrc->m2m_pdev && !IS_ERR(easrc->m2m_pdev))
+   platform_device_unregister(easrc->m2m_pdev);
+
pm_runtime_disable(>dev);
 }
 
-- 
2.34.1



[PATCH v15 05/16] ASoC: fsl_asrc: register m2m platform device

2024-03-19 Thread Shengjiu Wang
Register m2m platform device, that user can
use M2M feature.

Defined platform data structure and platform
driver name.

Signed-off-by: Shengjiu Wang 
Acked-by: Mark Brown 
---
 include/sound/fsl_asrc_common.h | 23 +++
 sound/soc/fsl/fsl_asrc.c| 18 ++
 2 files changed, 41 insertions(+)

diff --git a/include/sound/fsl_asrc_common.h b/include/sound/fsl_asrc_common.h
index 3b53d366182f..c709b8906929 100644
--- a/include/sound/fsl_asrc_common.h
+++ b/include/sound/fsl_asrc_common.h
@@ -71,6 +71,7 @@ struct fsl_asrc_pair {
  * @dma_params_rx: DMA parameters for receive channel
  * @dma_params_tx: DMA parameters for transmit channel
  * @pdev: platform device pointer
+ * @m2m_pdev: m2m platform device pointer
  * @regmap: regmap handler
  * @paddr: physical address to the base address of registers
  * @mem_clk: clock source to access register
@@ -103,6 +104,7 @@ struct fsl_asrc {
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct platform_device *pdev;
+   struct platform_device *m2m_pdev;
struct regmap *regmap;
unsigned long paddr;
struct clk *mem_clk;
@@ -139,6 +141,27 @@ struct fsl_asrc {
void *private;
 };
 
+/**
+ * struct fsl_asrc_m2m_pdata - platform data
+ * @asrc: pointer to struct fsl_asrc
+ * @fmt_in: input sample format
+ * @fmt_out: output sample format
+ * @chan_min: minimum channel number
+ * @chan_max: maximum channel number
+ * @rate_min: minimum rate
+ * @rate_max: maximum rete
+ */
+struct fsl_asrc_m2m_pdata {
+   struct fsl_asrc *asrc;
+   u64 fmt_in;
+   u64 fmt_out;
+   int chan_min;
+   int chan_max;
+   int rate_min;
+   int rate_max;
+};
+
+#define M2M_DRV_NAME "fsl_asrc_m2m"
 #define DRV_NAME "fsl-asrc-dai"
 extern struct snd_soc_component_driver fsl_asrc_component;
 
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 7d8643ee0ba0..5ecb5d869607 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -1187,6 +1187,7 @@ static int fsl_asrc_runtime_suspend(struct device *dev);
 static int fsl_asrc_probe(struct platform_device *pdev)
 {
struct device_node *np = pdev->dev.of_node;
+   struct fsl_asrc_m2m_pdata m2m_pdata;
struct fsl_asrc_priv *asrc_priv;
struct fsl_asrc *asrc;
struct resource *res;
@@ -1368,6 +1369,18 @@ static int fsl_asrc_probe(struct platform_device *pdev)
goto err_pm_get_sync;
}
 
+   m2m_pdata.asrc = asrc;
+   m2m_pdata.fmt_in = FSL_ASRC_FORMATS;
+   m2m_pdata.fmt_out = FSL_ASRC_FORMATS | SNDRV_PCM_FMTBIT_S8;
+   m2m_pdata.rate_min = 5512;
+   m2m_pdata.rate_max = 192000;
+   m2m_pdata.chan_min = 1;
+   m2m_pdata.chan_max = 10;
+   asrc->m2m_pdev = platform_device_register_data(>dev,
+  M2M_DRV_NAME,
+  PLATFORM_DEVID_AUTO,
+  _pdata,
+  sizeof(m2m_pdata));
return 0;
 
 err_pm_get_sync:
@@ -1380,6 +1393,11 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 
 static void fsl_asrc_remove(struct platform_device *pdev)
 {
+   struct fsl_asrc *asrc = dev_get_drvdata(>dev);
+
+   if (asrc->m2m_pdev && !IS_ERR(asrc->m2m_pdev))
+   platform_device_unregister(asrc->m2m_pdev);
+
pm_runtime_disable(>dev);
if (!pm_runtime_status_suspended(>dev))
fsl_asrc_runtime_suspend(>dev);
-- 
2.34.1



[PATCH v15 04/16] ASoC: fsl_asrc: move fsl_asrc_common.h to include/sound

2024-03-19 Thread Shengjiu Wang
Move fsl_asrc_common.h to include/sound that it can be
included from other drivers.

Signed-off-by: Shengjiu Wang 
Acked-by: Mark Brown 
---
 {sound/soc/fsl => include/sound}/fsl_asrc_common.h | 0
 sound/soc/fsl/fsl_asrc.h   | 2 +-
 sound/soc/fsl/fsl_asrc_dma.c   | 2 +-
 sound/soc/fsl/fsl_easrc.h  | 2 +-
 4 files changed, 3 insertions(+), 3 deletions(-)
 rename {sound/soc/fsl => include/sound}/fsl_asrc_common.h (100%)

diff --git a/sound/soc/fsl/fsl_asrc_common.h b/include/sound/fsl_asrc_common.h
similarity index 100%
rename from sound/soc/fsl/fsl_asrc_common.h
rename to include/sound/fsl_asrc_common.h
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index 1c492eb237f5..66544624de7b 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -10,7 +10,7 @@
 #ifndef _FSL_ASRC_H
 #define _FSL_ASRC_H
 
-#include  "fsl_asrc_common.h"
+#include  
 
 #define ASRC_M2M_INPUTFIFO_WML 0x4
 #define ASRC_M2M_OUTPUTFIFO_WML0x2
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index f501f47242fb..f067bf1ecea7 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -12,7 +12,7 @@
 #include 
 #include 
 
-#include "fsl_asrc_common.h"
+#include 
 
 #define FSL_ASRC_DMABUF_SIZE   (256 * 1024)
 
diff --git a/sound/soc/fsl/fsl_easrc.h b/sound/soc/fsl/fsl_easrc.h
index c9f770862662..a24e540876a4 100644
--- a/sound/soc/fsl/fsl_easrc.h
+++ b/sound/soc/fsl/fsl_easrc.h
@@ -9,7 +9,7 @@
 #include 
 #include 
 
-#include "fsl_asrc_common.h"
+#include 
 
 /* EASRC Register Map */
 
-- 
2.34.1



[PATCH v15 03/16] ASoC: fsl_easrc: define functions for memory to memory usage

2024-03-19 Thread Shengjiu Wang
ASRC can be used on memory to memory case, define several
functions for m2m usage and export them as function pointer.

Signed-off-by: Shengjiu Wang 
Acked-by: Mark Brown 
---
 sound/soc/fsl/fsl_easrc.c | 214 ++
 sound/soc/fsl/fsl_easrc.h |   4 +
 2 files changed, 218 insertions(+)

diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index ec53bda46a46..cf7ad30a323b 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -1861,6 +1861,211 @@ static int fsl_easrc_get_fifo_addr(u8 dir, enum 
asrc_pair_index index)
return REG_EASRC_FIFO(dir, index);
 }
 
+/* Get sample numbers in FIFO */
+static unsigned int fsl_easrc_get_output_fifo_size(struct fsl_asrc_pair *pair)
+{
+   struct fsl_asrc *asrc = pair->asrc;
+   enum asrc_pair_index index = pair->index;
+   u32 val;
+
+   regmap_read(asrc->regmap, REG_EASRC_SFS(index), );
+   val &= EASRC_SFS_NSGO_MASK;
+
+   return val >> EASRC_SFS_NSGO_SHIFT;
+}
+
+static int fsl_easrc_m2m_prepare(struct fsl_asrc_pair *pair)
+{
+   struct fsl_easrc_ctx_priv *ctx_priv = pair->private;
+   struct fsl_asrc *asrc = pair->asrc;
+   struct device *dev = >pdev->dev;
+   int ret;
+
+   ctx_priv->in_params.sample_rate = pair->rate[IN];
+   ctx_priv->in_params.sample_format = pair->sample_format[IN];
+   ctx_priv->out_params.sample_rate = pair->rate[OUT];
+   ctx_priv->out_params.sample_format = pair->sample_format[OUT];
+
+   ctx_priv->in_params.fifo_wtmk = FSL_EASRC_INPUTFIFO_WML;
+   ctx_priv->out_params.fifo_wtmk = FSL_EASRC_OUTPUTFIFO_WML;
+   /* Fill the right half of the re-sampler with zeros */
+   ctx_priv->rs_init_mode = 0x2;
+   /* Zero fill the right half of the prefilter */
+   ctx_priv->pf_init_mode = 0x2;
+
+   ret = fsl_easrc_set_ctx_format(pair,
+  _priv->in_params.sample_format,
+  _priv->out_params.sample_format);
+   if (ret) {
+   dev_err(dev, "failed to set context format: %d\n", ret);
+   return ret;
+   }
+
+   ret = fsl_easrc_config_context(asrc, pair->index);
+   if (ret) {
+   dev_err(dev, "failed to config context %d\n", ret);
+   return ret;
+   }
+
+   ctx_priv->in_params.iterations = 1;
+   ctx_priv->in_params.group_len = pair->channels;
+   ctx_priv->in_params.access_len = pair->channels;
+   ctx_priv->out_params.iterations = 1;
+   ctx_priv->out_params.group_len = pair->channels;
+   ctx_priv->out_params.access_len = pair->channels;
+
+   ret = fsl_easrc_set_ctx_organziation(pair);
+   if (ret) {
+   dev_err(dev, "failed to set fifo organization\n");
+   return ret;
+   }
+
+   /* The context start flag */
+   pair->first_convert = 1;
+   return 0;
+}
+
+static int fsl_easrc_m2m_start(struct fsl_asrc_pair *pair)
+{
+   /* start context once */
+   if (pair->first_convert) {
+   fsl_easrc_start_context(pair);
+   pair->first_convert = 0;
+   }
+
+   return 0;
+}
+
+static int fsl_easrc_m2m_stop(struct fsl_asrc_pair *pair)
+{
+   /* Stop pair/context */
+   if (!pair->first_convert) {
+   fsl_easrc_stop_context(pair);
+   pair->first_convert = 1;
+   }
+
+   return 0;
+}
+
+/* calculate capture data length according to output data length and sample 
rate */
+static int fsl_easrc_m2m_calc_out_len(struct fsl_asrc_pair *pair, int 
input_buffer_length)
+{
+   struct fsl_asrc *easrc = pair->asrc;
+   struct fsl_easrc_priv *easrc_priv = easrc->private;
+   struct fsl_easrc_ctx_priv *ctx_priv = pair->private;
+   unsigned int in_rate = ctx_priv->in_params.norm_rate;
+   unsigned int out_rate = ctx_priv->out_params.norm_rate;
+   unsigned int channels = pair->channels;
+   unsigned int in_samples, out_samples;
+   unsigned int in_width, out_width;
+   unsigned int out_length;
+   unsigned int frac_bits;
+   u64 val1, val2;
+
+   switch (easrc_priv->rs_num_taps) {
+   case EASRC_RS_32_TAPS:
+   /* integer bits = 5; */
+   frac_bits = 39;
+   break;
+   case EASRC_RS_64_TAPS:
+   /* integer bits = 6; */
+   frac_bits = 38;
+   break;
+   case EASRC_RS_128_TAPS:
+   /* integer bits = 7; */
+   frac_bits = 37;
+   break;
+   default:
+   return -EINVAL;
+   }
+
+   val1 = (u64)in_rate << frac_bits;
+   do_div(val1, out_rate);
+   val1 += (s64)ctx_priv->ratio_mod << (frac_bits - 31);
+
+   in_width = 
snd_pcm_format_physical_width(ctx_priv->in_params.sample_format) / 8;
+   out_width = 
snd_pcm_format_physical_width(ctx_priv->out_params.sample_format) / 8;
+
+   ctx_priv->in_filled_len += input_buffer_length;
+   

[PATCH v15 02/16] ASoC: fsl_asrc: define functions for memory to memory usage

2024-03-19 Thread Shengjiu Wang
ASRC can be used on memory to memory case, define several
functions for m2m usage.

m2m_prepare: prepare for the start step
m2m_start: the start step
m2m_unprepare: unprepare for stop step, optional
m2m_stop: stop step
m2m_check_format: check format is supported or not
m2m_calc_out_len: calculate output length according to input length
m2m_get_maxburst: burst size for dma
m2m_pair_suspend: suspend function of pair, optional.
m2m_pair_resume: resume function of pair
get_output_fifo_size: get remaining data size in FIFO

Signed-off-by: Shengjiu Wang 
Acked-by: Mark Brown 
---
 sound/soc/fsl/fsl_asrc.c| 126 
 sound/soc/fsl/fsl_asrc.h|   2 +
 sound/soc/fsl/fsl_asrc_common.h |  37 ++
 3 files changed, 165 insertions(+)

diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index b793263291dc..7d8643ee0ba0 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -1063,6 +1063,124 @@ static int fsl_asrc_get_fifo_addr(u8 dir, enum 
asrc_pair_index index)
return REG_ASRDx(dir, index);
 }
 
+/* Get sample numbers in FIFO */
+static unsigned int fsl_asrc_get_output_fifo_size(struct fsl_asrc_pair *pair)
+{
+   struct fsl_asrc *asrc = pair->asrc;
+   enum asrc_pair_index index = pair->index;
+   u32 val;
+
+   regmap_read(asrc->regmap, REG_ASRFST(index), );
+
+   val &= ASRFSTi_OUTPUT_FIFO_MASK;
+
+   return val >> ASRFSTi_OUTPUT_FIFO_SHIFT;
+}
+
+static int fsl_asrc_m2m_prepare(struct fsl_asrc_pair *pair)
+{
+   struct fsl_asrc_pair_priv *pair_priv = pair->private;
+   struct fsl_asrc *asrc = pair->asrc;
+   struct device *dev = >pdev->dev;
+   struct asrc_config config;
+   int ret;
+
+   /* fill config */
+   config.pair = pair->index;
+   config.channel_num = pair->channels;
+   config.input_sample_rate = pair->rate[IN];
+   config.output_sample_rate = pair->rate[OUT];
+   config.input_format = pair->sample_format[IN];
+   config.output_format = pair->sample_format[OUT];
+   config.inclk = INCLK_NONE;
+   config.outclk = OUTCLK_ASRCK1_CLK;
+
+   pair_priv->config = 
+   ret = fsl_asrc_config_pair(pair, true);
+   if (ret) {
+   dev_err(dev, "failed to config pair: %d\n", ret);
+   return ret;
+   }
+
+   pair->first_convert = 1;
+
+   return 0;
+}
+
+static int fsl_asrc_m2m_start(struct fsl_asrc_pair *pair)
+{
+   if (pair->first_convert) {
+   fsl_asrc_start_pair(pair);
+   pair->first_convert = 0;
+   }
+   /*
+* Clear DMA request during the stall state of ASRC:
+* During STALL state, the remaining in input fifo would never be
+* smaller than the input threshold while the output fifo would not
+* be bigger than output one. Thus the DMA request would be cleared.
+*/
+   fsl_asrc_set_watermarks(pair, ASRC_FIFO_THRESHOLD_MIN,
+   ASRC_FIFO_THRESHOLD_MAX);
+
+   /* Update the real input threshold to raise DMA request */
+   fsl_asrc_set_watermarks(pair, ASRC_M2M_INPUTFIFO_WML,
+   ASRC_M2M_OUTPUTFIFO_WML);
+
+   return 0;
+}
+
+static int fsl_asrc_m2m_stop(struct fsl_asrc_pair *pair)
+{
+   if (!pair->first_convert) {
+   fsl_asrc_stop_pair(pair);
+   pair->first_convert = 1;
+   }
+
+   return 0;
+}
+
+/* calculate capture data length according to output data length and sample 
rate */
+static int fsl_asrc_m2m_calc_out_len(struct fsl_asrc_pair *pair, int 
input_buffer_length)
+{
+   unsigned int in_width, out_width;
+   unsigned int channels = pair->channels;
+   unsigned int in_samples, out_samples;
+   unsigned int out_length;
+
+   in_width = snd_pcm_format_physical_width(pair->sample_format[IN]) / 8;
+   out_width = snd_pcm_format_physical_width(pair->sample_format[OUT]) / 8;
+
+   in_samples = input_buffer_length / in_width / channels;
+   out_samples = pair->rate[OUT] * in_samples / pair->rate[IN];
+   out_length = (out_samples - ASRC_OUTPUT_LAST_SAMPLE) * out_width * 
channels;
+
+   return out_length;
+}
+
+static int fsl_asrc_m2m_get_maxburst(u8 dir, struct fsl_asrc_pair *pair)
+{
+   struct fsl_asrc *asrc = pair->asrc;
+   struct fsl_asrc_priv *asrc_priv = asrc->private;
+   int wml = (dir == IN) ? ASRC_M2M_INPUTFIFO_WML : 
ASRC_M2M_OUTPUTFIFO_WML;
+
+   if (!asrc_priv->soc->use_edma)
+   return wml * pair->channels;
+   else
+   return 1;
+}
+
+static int fsl_asrc_m2m_pair_resume(struct fsl_asrc_pair *pair)
+{
+   struct fsl_asrc *asrc = pair->asrc;
+   int i;
+
+   for (i = 0; i < pair->channels * 4; i++)
+   regmap_write(asrc->regmap, REG_ASRDI(pair->index), 0);
+
+   pair->first_convert = 1;
+   return 0;
+}
+
 static int fsl_asrc_runtime_resume(struct device *dev);
 static int 

[PATCH v15 01/16] media: v4l2-ctrls: add support for fraction_bits

2024-03-19 Thread Shengjiu Wang
From: Hans Verkuil 

This adds support for the fraction_bits field, used with integer controls.
This allows fixed point formats to be described.

The fraction_bits field is only exposed through VIDIOC_QUERY_EXT_CTRL.

For a given signed two's complement Qf fixed point value 'f' equals
fraction_bits.

Signed-off-by: Hans Verkuil 
---
 .../media/v4l/vidioc-queryctrl.rst| 11 ++-
 drivers/media/v4l2-core/v4l2-ctrls-api.c  |  1 +
 drivers/media/v4l2-core/v4l2-ctrls-core.c | 93 +++
 include/media/v4l2-ctrls.h|  7 +-
 include/uapi/linux/videodev2.h|  3 +-
 5 files changed, 95 insertions(+), 20 deletions(-)

diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst 
b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
index 4d38acafe8e1..e65c7e5d78ec 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
@@ -267,7 +267,16 @@ See also the examples in :ref:`control`.
   - The size of each dimension. The first ``nr_of_dims`` elements of
this array must be non-zero, all remaining elements must be zero.
 * - __u32
-  - ``reserved``\ [32]
+  - ``fraction_bits``
+  - The number of least significant bits of the control value that
+form the fraction of the fixed point value. This is 0 if the value
+   is a regular integer. This can be used with all integer control types
+   (``INTEGER``, ``INTEGER64``, ``U8``, ``U16`` and ``U32``).
+   For the signed types the signed two's complement representation is used.
+   This field applies to the control value as well as the ``minimum``,
+   ``maximum``, ``step`` and ``default_value`` fields.
+* - __u32
+  - ``reserved``\ [31]
   - Reserved for future extensions. Applications and drivers must set
the array to zero.
 
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c 
b/drivers/media/v4l2-core/v4l2-ctrls-api.c
index d9a422017bd9..ef16b00421ec 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-api.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c
@@ -1101,6 +1101,7 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, 
struct v4l2_query_ext_ctr
qc->elems = ctrl->elems;
qc->nr_of_dims = ctrl->nr_of_dims;
memcpy(qc->dims, ctrl->dims, qc->nr_of_dims * sizeof(qc->dims[0]));
+   qc->fraction_bits = ctrl->fraction_bits;
qc->minimum = ctrl->minimum;
qc->maximum = ctrl->maximum;
qc->default_value = ctrl->default_value;
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c 
b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index c4d995f32191..d83a37198bb5 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -252,12 +252,61 @@ void v4l2_ctrl_type_op_init(const struct v4l2_ctrl *ctrl, 
u32 from_idx,
 }
 EXPORT_SYMBOL(v4l2_ctrl_type_op_init);
 
+static void v4l2_ctrl_log_fp(s64 v, unsigned int fraction_bits)
+{
+   s64 i, f, mask;
+
+   if (!fraction_bits) {
+   pr_cont("%lld", v);
+   return;
+   }
+
+   mask = (1ULL << fraction_bits) - 1;
+
+   /*
+* Note: this function does not support fixed point u64 with
+* fraction_bits set to 64. At the moment there is no U64
+* control type, but if that is added, then this code will have
+* to add support for it.
+*/
+   if (fraction_bits >= 63)
+   i = v < 0 ? -1 : 0;
+   else
+   i = div64_s64(v, 1LL << fraction_bits);
+
+   f = v < 0 ? -((-v) & mask) : (v & mask);
+
+   if (!f) {
+   pr_cont("%lld", i);
+   } else if (fraction_bits < 20) {
+   u64 div = 1ULL << fraction_bits;
+
+   if (!i && f < 0)
+   pr_cont("-%lld/%llu", -f, div);
+   else if (!i)
+   pr_cont("%lld/%llu", f, div);
+   else if (i < 0 || f < 0)
+   pr_cont("-%lld-%llu/%llu", -i, -f, div);
+   else
+   pr_cont("%lld+%llu/%llu", i, f, div);
+   } else {
+   if (!i && f < 0)
+   pr_cont("-%lld/(2^%u)", -f, fraction_bits);
+   else if (!i)
+   pr_cont("%lld/(2^%u)", f, fraction_bits);
+   else if (i < 0 || f < 0)
+   pr_cont("-%lld-%llu/(2^%u)", -i, -f, fraction_bits);
+   else
+   pr_cont("%lld+%llu/(2^%u)", i, f, fraction_bits);
+   }
+}
+
 void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl)
 {
union v4l2_ctrl_ptr ptr = ctrl->p_cur;
 
if (ctrl->is_array) {
-   unsigned i;
+   unsigned int i;
 
for (i = 0; i < ctrl->nr_of_dims; i++)
pr_cont("[%u]", ctrl->dims[i]);
@@ -266,7 +315,7 @@ void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl)
 
 

[PATCH v15 00/16] Add audio support in v4l2 framework

2024-03-19 Thread Shengjiu Wang
Audio signal processing also has the requirement for memory to
memory similar as Video.

This asrc memory to memory (memory ->asrc->memory) case is a non
real time use case.

User fills the input buffer to the asrc module, after conversion, then asrc
sends back the output buffer to user. So it is not a traditional ALSA playback
and capture case.

It is a specific use case,  there is no reference in current kernel.
v4l2 memory to memory is the closed implementation,  v4l2 current
support video, image, radio, tuner, touch devices, so it is not
complicated to add support for this specific audio case.

Because we had implemented the "memory -> asrc ->i2s device-> codec"
use case in ALSA.  Now the "memory->asrc->memory" needs
to reuse the code in asrc driver, so the first 3 patches is for refining
the code to make it can be shared by the "memory->asrc->memory"
driver.

The main change is in the v4l2 side, A /dev/vl4-audioX will be created,
user applications only use the ioctl of v4l2 framework.

Other change is to add memory to memory support for two kinds of i.MX ASRC
module.

changes in v15:
- update MAINTAINERS for imx-asrc.c and vim2m-audio.c

changes in v14:
- document the reservation of 'AUXX' fourcc format.
- add v4l2_audfmt_to_fourcc() definition.

changes in v13
- change 'pixelformat' to 'audioformat' in dev-audio-mem2mem.rst
- add more description for clock drift in ext-ctrls-audio-m2m.rst
- Add "media: v4l2-ctrls: add support for fraction_bits" from Hans
  to avoid build issue for kernel test robot

changes in v12
- minor changes according to comments
- drop min_buffers_needed = 1 and V4L2_CTRL_FLAG_UPDATE flag
- drop bus_info

changes in v11
- add add-fixed-point-test-controls in vivid.
- add v4l2_ctrl_fp_compose() helper function for min and max

changes in v10
- remove FIXED_POINT type
- change code base on media: v4l2-ctrls: add support for fraction_bits
- fix issue reported by kernel test robot
- remove module_alias

changes in v9:
- add MEDIA_ENT_F_PROC_AUDIO_RESAMPLER.
- add MEDIA_INTF_T_V4L_AUDIO
- add media controller support
- refine the vim2m-audio to support 8k<->16k conversion.

changes in v8:
- refine V4L2_CAP_AUDIO_M2M to be 0x0008
- update doc for FIXED_POINT
- address comments for imx-asrc

changes in v7:
- add acked-by from Mark
- separate commit for fixed point, m2m audio class, audio rate controls
- use INTEGER_MENU for rate,  FIXED_POINT for rate offset
- remove used fmts
- address other comments for Hans

changes in v6:
- use m2m_prepare/m2m_unprepare/m2m_start/m2m_stop to replace
  m2m_start_part_one/m2m_stop_part_one, m2m_start_part_two/m2m_stop_part_two.
- change V4L2_CTRL_TYPE_ASRC_RATE to V4L2_CTRL_TYPE_FIXED_POINT
- fix warning by kernel test rebot
- remove some unused format V4L2_AUDIO_FMT_XX
- Get SNDRV_PCM_FORMAT from V4L2_AUDIO_FMT in driver.
- rename audm2m to viaudm2m.

changes in v5:
- remove V4L2_AUDIO_FMT_LPCM
- define audio pixel format like V4L2_AUDIO_FMT_S8...
- remove rate and format in struct v4l2_audio_format.
- Add V4L2_CID_ASRC_SOURCE_RATE and V4L2_CID_ASRC_DEST_RATE controls
- updata document accordingly.

changes in v4:
- update document style
- separate V4L2_AUDIO_FMT_LPCM and V4L2_CAP_AUDIO_M2M in separate commit

changes in v3:
- Modify documents for adding audio m2m support
- Add audio virtual m2m driver
- Defined V4L2_AUDIO_FMT_LPCM format type for audio.
- Defined V4L2_CAP_AUDIO_M2M capability type for audio m2m case.
- with modification in v4l-utils, pass v4l2-compliance test.

changes in v2:
- decouple the implementation in v4l2 and ALSA
- implement the memory to memory driver as a platfrom driver
  and move it to driver/media
- move fsl_asrc_common.h to include/sound folder

Hans Verkuil (1):
  media: v4l2-ctrls: add support for fraction_bits

Shengjiu Wang (15):
  ASoC: fsl_asrc: define functions for memory to memory usage
  ASoC: fsl_easrc: define functions for memory to memory usage
  ASoC: fsl_asrc: move fsl_asrc_common.h to include/sound
  ASoC: fsl_asrc: register m2m platform device
  ASoC: fsl_easrc: register m2m platform device
  media: uapi: Add V4L2_CAP_AUDIO_M2M capability flag
  media: v4l2: Add audio capture and output support
  media: uapi: Define audio sample format fourcc type
  media: uapi: Add V4L2_CTRL_CLASS_M2M_AUDIO
  media: uapi: Add audio rate controls support
  media: uapi: Declare interface types for Audio
  media: uapi: Add an entity type for audio resampler
  media: vivid: add fixed point test controls
  media: imx-asrc: Add memory to memory driver
  media: vim2m-audio: add virtual driver for audio memory to memory

 .../media/mediactl/media-types.rst|   11 +
 .../userspace-api/media/v4l/buffer.rst|6 +
 .../userspace-api/media/v4l/common.rst|1 +
 .../media/v4l/dev-audio-mem2mem.rst   |   71 +
 .../userspace-api/media/v4l/devices.rst   |1 +
 .../media/v4l/ext-ctrls-audio-m2m.rst |   59 +
 .../userspace-api/media/v4l/pixfmt-audio.rst  |  100 ++
 

[kvm-unit-tests PATCH v7 35/35] powerpc: gitlab CI update

2024-03-19 Thread Nicholas Piggin
This adds testing for the powernv machine, and adds a gitlab-ci test
group instead of specifying all tests in .gitlab-ci.yml.

Signed-off-by: Nicholas Piggin 
---
 .gitlab-ci.yml| 20 
 powerpc/unittests.cfg | 14 --
 2 files changed, 16 insertions(+), 18 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index bd34da04f..e3638b088 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -97,12 +97,10 @@ build-ppc64be:
  - cd build
  - ../configure --arch=ppc64 --endian=big --cross-prefix=powerpc64-linux-gnu-
  - make -j2
- - ACCEL=tcg ./run_tests.sh
- selftest-setup selftest-migration selftest-migration-skip spapr_hcall
- rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
- emulator
- | tee results.txt
- - if grep -q FAIL results.txt ; then exit 1 ; fi
+ - ACCEL=tcg MAX_SMP=8 ./run_tests.sh -g gitlab-ci | tee results.txt
+ - grep -q PASS results.txt && ! grep -q FAIL results.txt
+ - ACCEL=tcg MAX_SMP=8 MACHINE=powernv ./run_tests.sh -g gitlab-ci | tee 
results.txt
+ - grep -q PASS results.txt && ! grep -q FAIL results.txt
 
 build-ppc64le:
  extends: .intree_template
@@ -110,12 +108,10 @@ build-ppc64le:
  - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu nmap-ncat
  - ./configure --arch=ppc64 --endian=little --cross-prefix=powerpc64-linux-gnu-
  - make -j2
- - ACCEL=tcg ./run_tests.sh
- selftest-setup selftest-migration selftest-migration-skip spapr_hcall
- rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
- emulator
- | tee results.txt
- - if grep -q FAIL results.txt ; then exit 1 ; fi
+ - ACCEL=tcg MAX_SMP=8 ./run_tests.sh -g gitlab-ci | tee results.txt
+ - grep -q PASS results.txt && ! grep -q FAIL results.txt
+ - ACCEL=tcg MAX_SMP=8 MACHINE=powernv ./run_tests.sh -g gitlab-ci | tee 
results.txt
+ - grep -q PASS results.txt && ! grep -q FAIL results.txt
 
 # build-riscv32:
 # Fedora doesn't package a riscv32 compiler for QEMU. Oh, well.
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index 379aa166b..f6ddc4a7f 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -16,12 +16,12 @@
 file = selftest.elf
 smp = 2
 extra_params = -m 1g -append 'setup smp=2 mem=1024'
-groups = selftest
+groups = selftest gitlab-ci
 
 [selftest-migration]
 file = selftest-migration.elf
 machine = pseries
-groups = selftest migration
+groups = selftest migration gitlab-ci
 # TODO: Remove accel=kvm once the following TCG migration fix has been merged:
 # https://lore.kernel.org/qemu-devel/20240219061731.232570-1-npig...@gmail.com/
 accel = kvm
@@ -29,7 +29,7 @@ accel = kvm
 [selftest-migration-skip]
 file = selftest-migration.elf
 machine = pseries
-groups = selftest migration
+groups = selftest migration gitlab-ci
 extra_params = -append "skip"
 
 # This fails due to a QEMU TCG bug so KVM-only until QEMU is fixed upstream
@@ -42,6 +42,7 @@ groups = migration
 [spapr_hcall]
 file = spapr_hcall.elf
 machine = pseries
+groups = gitlab-ci
 
 [spapr_vpa]
 file = spapr_vpa.elf
@@ -52,24 +53,25 @@ file = rtas.elf
 machine = pseries
 timeout = 5
 extra_params = -append "get-time-of-day date=$(date +%s)"
-groups = rtas
+groups = rtas gitlab-ci
 
 [rtas-get-time-of-day-base]
 file = rtas.elf
 machine = pseries
 timeout = 5
 extra_params = -rtc base="2006-06-17" -append "get-time-of-day date=$(date 
--date="2006-06-17 UTC" +%s)"
-groups = rtas
+groups = rtas gitlab-ci
 
 [rtas-set-time-of-day]
 file = rtas.elf
 machine = pseries
 extra_params = -append "set-time-of-day"
 timeout = 5
-groups = rtas
+groups = rtas gitlab-ci
 
 [emulator]
 file = emulator.elf
+groups = gitlab-ci
 
 [interrupts]
 file = interrupts.elf
-- 
2.42.0



[kvm-unit-tests PATCH v7 34/35] powerpc: Remove remnants of ppc64 directory and build structure

2024-03-19 Thread Nicholas Piggin
This moves merges ppc64 directories and files into powerpc, and
merges the 3 makefiles into one.

The configure --arch=powerpc option is aliased to ppc64 for
good measure.

Signed-off-by: Nicholas Piggin 
---
 MAINTAINERS|   1 -
 configure  |   3 +-
 lib/{ppc64 => powerpc}/asm-offsets.c   |   0
 lib/{ppc64 => powerpc}/asm/asm-offsets.h   |   0
 lib/{ppc64 => powerpc}/asm/atomic.h|   0
 lib/{ppc64 => powerpc}/asm/barrier.h   |   4 +-
 lib/{ppc64 => powerpc}/asm/bitops.h|   4 +-
 lib/{ppc64 => powerpc}/asm/io.h|   4 +-
 lib/{ppc64 => powerpc}/asm/mmu.h   |   0
 lib/{ppc64 => powerpc}/asm/opal.h  |   4 +-
 lib/{ppc64 => powerpc}/asm/page.h  |   6 +-
 lib/{ppc64 => powerpc}/asm/pgtable-hwdef.h |   6 +-
 lib/{ppc64 => powerpc}/asm/pgtable.h   |   2 +-
 lib/{ppc64 => powerpc}/asm/ptrace.h|   6 +-
 lib/{ppc64 => powerpc}/asm/spinlock.h  |   6 +-
 lib/powerpc/asm/stack.h|   3 +
 lib/{ppc64 => powerpc}/asm/vpa.h   |   0
 lib/{ppc64 => powerpc}/mmu.c   |   0
 lib/{ppc64 => powerpc}/opal-calls.S|   0
 lib/{ppc64 => powerpc}/opal.c  |   0
 lib/{ppc64 => powerpc}/stack.c |   0
 lib/ppc64/.gitignore   |   1 -
 lib/ppc64/asm/handlers.h   |   1 -
 lib/ppc64/asm/hcall.h  |   1 -
 lib/ppc64/asm/memory_areas.h   |   6 --
 lib/ppc64/asm/ppc_asm.h|   1 -
 lib/ppc64/asm/processor.h  |   1 -
 lib/ppc64/asm/reg.h|   1 -
 lib/ppc64/asm/rtas.h   |   1 -
 lib/ppc64/asm/setup.h  |   1 -
 lib/ppc64/asm/smp.h|   1 -
 lib/ppc64/asm/stack.h  |  11 --
 powerpc/Makefile   | 111 -
 powerpc/Makefile.common|  95 --
 powerpc/Makefile.ppc64 |  31 --
 35 files changed, 136 insertions(+), 176 deletions(-)
 rename lib/{ppc64 => powerpc}/asm-offsets.c (100%)
 rename lib/{ppc64 => powerpc}/asm/asm-offsets.h (100%)
 rename lib/{ppc64 => powerpc}/asm/atomic.h (100%)
 rename lib/{ppc64 => powerpc}/asm/barrier.h (83%)
 rename lib/{ppc64 => powerpc}/asm/bitops.h (69%)
 rename lib/{ppc64 => powerpc}/asm/io.h (50%)
 rename lib/{ppc64 => powerpc}/asm/mmu.h (100%)
 rename lib/{ppc64 => powerpc}/asm/opal.h (90%)
 rename lib/{ppc64 => powerpc}/asm/page.h (94%)
 rename lib/{ppc64 => powerpc}/asm/pgtable-hwdef.h (93%)
 rename lib/{ppc64 => powerpc}/asm/pgtable.h (99%)
 rename lib/{ppc64 => powerpc}/asm/ptrace.h (89%)
 rename lib/{ppc64 => powerpc}/asm/spinlock.h (54%)
 rename lib/{ppc64 => powerpc}/asm/vpa.h (100%)
 rename lib/{ppc64 => powerpc}/mmu.c (100%)
 rename lib/{ppc64 => powerpc}/opal-calls.S (100%)
 rename lib/{ppc64 => powerpc}/opal.c (100%)
 rename lib/{ppc64 => powerpc}/stack.c (100%)
 delete mode 100644 lib/ppc64/.gitignore
 delete mode 100644 lib/ppc64/asm/handlers.h
 delete mode 100644 lib/ppc64/asm/hcall.h
 delete mode 100644 lib/ppc64/asm/memory_areas.h
 delete mode 100644 lib/ppc64/asm/ppc_asm.h
 delete mode 100644 lib/ppc64/asm/processor.h
 delete mode 100644 lib/ppc64/asm/reg.h
 delete mode 100644 lib/ppc64/asm/rtas.h
 delete mode 100644 lib/ppc64/asm/setup.h
 delete mode 100644 lib/ppc64/asm/smp.h
 delete mode 100644 lib/ppc64/asm/stack.h
 delete mode 100644 powerpc/Makefile.common
 delete mode 100644 powerpc/Makefile.ppc64

diff --git a/MAINTAINERS b/MAINTAINERS
index a2fa437da..1309863f2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -92,7 +92,6 @@ S: Maintained
 L: linuxppc-dev@lists.ozlabs.org
 F: powerpc/
 F: lib/powerpc/
-F: lib/ppc64/
 
 RISCV
 M: Andrew Jones 
diff --git a/configure b/configure
index a1308db8e..8508396af 100755
--- a/configure
+++ b/configure
@@ -215,6 +215,7 @@ fi
 
 arch_name=$arch
 [ "$arch" = "aarch64" ] && arch="arm64"
+[ "$arch" = "powerpc" ] && arch="ppc64"
 [ "$arch_name" = "arm64" ] && arch_name="aarch64"
 
 if [ "$arch" = "riscv" ]; then
@@ -337,7 +338,7 @@ elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
 fi
 elif [ "$arch" = "ppc64" ]; then
 testdir=powerpc
-arch_libdir=ppc64
+arch_libdir=powerpc
 firmware="$testdir/boot_rom.bin"
 if [ "$endian" != "little" ] && [ "$endian" != "big" ]; then
 echo "You must provide endianness (big or little)!"
diff --git a/lib/ppc64/asm-offsets.c b/lib/powerpc/asm-offsets.c
similarity index 100%
rename from lib/ppc64/asm-offsets.c
rename to lib/powerpc/asm-offsets.c
diff --git a/lib/ppc64/asm/asm-offsets.h b/lib/powerpc/asm/asm-offsets.h
similarity index 100%
rename from lib/ppc64/asm/asm-offsets.h
rename to lib/powerpc/asm/asm-offsets.h
diff --git a/lib/ppc64/asm/atomic.h b/lib/powerpc/asm/atomic.h
similarity index 100%
rename from lib/ppc64/asm/atomic.h
rename to lib/powerpc/asm/atomic.h
diff --git 

[kvm-unit-tests PATCH v7 33/35] configure: Make arch_libdir a first-class entity

2024-03-19 Thread Nicholas Piggin
arch_libdir was brought in to improve the heuristic determination of
the lib/ directory based on arch and testdir names, but it did not
entirely clean that mess up.

Remove the arch_libdir->arch->testdir heuristic and just require
everybody sets arch_libdir correctly. Fail if the lib/arch or
lib/arch/asm directories can not be found.

Cc: Alexandru Elisei 
Cc: Claudio Imbrenda 
Cc: David Hildenbrand 
Cc: Eric Auger 
Cc: Janosch Frank 
Cc: Laurent Vivier 
Cc: Nico Böhr 
Cc: Paolo Bonzini 
Cc: Thomas Huth 
Cc: k...@vger.kernel.org
Cc: linux-s...@vger.kernel.org
Cc: kvm...@lists.linux.dev
Cc: kvm-ri...@lists.infradead.org
Cc: linuxppc-dev@lists.ozlabs.org
Reviewed-by: Andrew Jones 
Signed-off-by: Nicholas Piggin 
---
 Makefile  |  2 +-
 configure | 18 +-
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index 4f35fffc6..4e0f54543 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ include config.mak
 VPATH = $(SRCDIR)
 
 libdirs-get = $(shell [ -d "lib/$(1)" ] && echo "lib/$(1) lib/$(1)/asm")
-ARCH_LIBDIRS := $(call libdirs-get,$(ARCH_LIBDIR)) $(call 
libdirs-get,$(TEST_DIR))
+ARCH_LIBDIRS := $(call libdirs-get,$(ARCH_LIBDIR))
 OBJDIRS := $(ARCH_LIBDIRS)
 
 DESTDIR := $(PREFIX)/share/kvm-unit-tests/
diff --git a/configure b/configure
index e19ba6f0c..a1308db8e 100755
--- a/configure
+++ b/configure
@@ -216,7 +216,6 @@ fi
 arch_name=$arch
 [ "$arch" = "aarch64" ] && arch="arm64"
 [ "$arch_name" = "arm64" ] && arch_name="aarch64"
-arch_libdir=$arch
 
 if [ "$arch" = "riscv" ]; then
 echo "riscv32 or riscv64 must be specified"
@@ -286,8 +285,10 @@ fi
 
 if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then
 testdir=x86
+arch_libdir=x86
 elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
 testdir=arm
+arch_libdir=$arch
 if [ "$target" = "qemu" ]; then
 arm_uart_early_addr=0x0900
 elif [ "$target" = "kvmtool" ]; then
@@ -336,6 +337,7 @@ elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
 fi
 elif [ "$arch" = "ppc64" ]; then
 testdir=powerpc
+arch_libdir=ppc64
 firmware="$testdir/boot_rom.bin"
 if [ "$endian" != "little" ] && [ "$endian" != "big" ]; then
 echo "You must provide endianness (big or little)!"
@@ -346,6 +348,7 @@ elif [ "$arch" = "riscv32" ] || [ "$arch" = "riscv64" ]; 
then
 arch_libdir=riscv
 elif [ "$arch" = "s390x" ]; then
 testdir=s390x
+arch_libdir=s390x
 else
 echo "arch $arch is not supported!"
 arch=
@@ -355,6 +358,10 @@ if [ ! -d "$srcdir/$testdir" ]; then
 echo "$srcdir/$testdir does not exist!"
 exit 1
 fi
+if [ ! -d "$srcdir/lib/$arch_libdir" ]; then
+echo "$srcdir/lib/$arch_libdir does not exist!"
+exit 1
+fi
 
 if [ "$efi" = "y" ] && [ -f "$srcdir/$testdir/efi/run" ]; then
 ln -fs "$srcdir/$testdir/efi/run" $testdir-run
@@ -417,10 +424,11 @@ fi
 # link lib/asm for the architecture
 rm -f lib/asm
 asm="asm-generic"
-if [ -d "$srcdir/lib/$arch/asm" ]; then
-   asm="$srcdir/lib/$arch/asm"
-elif [ -d "$srcdir/lib/$testdir/asm" ]; then
-   asm="$srcdir/lib/$testdir/asm"
+if [ -d "$srcdir/lib/$arch_libdir/asm" ]; then
+asm="$srcdir/lib/$arch_libdir/asm"
+else
+echo "$srcdir/lib/$arch_libdir/asm does not exist"
+exit 1
 fi
 mkdir -p lib
 ln -sf "$asm" lib/asm
-- 
2.42.0



[kvm-unit-tests PATCH v7 32/35] powerpc: add pmu tests

2024-03-19 Thread Nicholas Piggin
Add some initial PMU testing.

- PMC5/6 tests
- PMAE / PMI test
- BHRB basic tests

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h |   2 +
 lib/powerpc/asm/reg.h   |   9 +
 lib/powerpc/asm/setup.h |   1 +
 lib/powerpc/setup.c |  23 +++
 powerpc/Makefile.common |   3 +-
 powerpc/pmu.c   | 336 
 powerpc/unittests.cfg   |   3 +
 7 files changed, 376 insertions(+), 1 deletion(-)
 create mode 100644 powerpc/pmu.c

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index 749155696..28239c610 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -14,6 +14,8 @@ extern bool cpu_has_hv;
 extern bool cpu_has_power_mce;
 extern bool cpu_has_siar;
 extern bool cpu_has_heai;
+extern bool cpu_has_bhrb;
+extern bool cpu_has_p10_bhrb;
 extern bool cpu_has_radix;
 extern bool cpu_has_prefix;
 extern bool cpu_has_sc_lev;
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 69ef21adb..602fba1b6 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -40,10 +40,19 @@
 #define SPR_LPIDR  0x13f
 #define SPR_HEIR   0x153
 #define SPR_PTCR   0x1d0
+#define SPR_MMCRA  0x312
+#define   MMCRA_BHRBRD UL(0x0020)
+#define   MMCRA_IFM_MASK   UL(0xc000)
+#define SPR_PMC5   0x317
+#define SPR_PMC6   0x318
 #define SPR_MMCR0  0x31b
 #define   MMCR0_FC UL(0x8000)
+#define   MMCR0_FCPUL(0x2000)
 #define   MMCR0_PMAE   UL(0x0400)
+#define   MMCR0_BHRBA  UL(0x0020)
+#define   MMCR0_FCPC   UL(0x1000)
 #define   MMCR0_PMAO   UL(0x0080)
+#define   MMCR0_FC56   UL(0x0010)
 #define SPR_SIAR   0x31c
 
 /* Machine State Register definitions: */
diff --git a/lib/powerpc/asm/setup.h b/lib/powerpc/asm/setup.h
index 9ca318ce6..8f0b58ed0 100644
--- a/lib/powerpc/asm/setup.h
+++ b/lib/powerpc/asm/setup.h
@@ -10,6 +10,7 @@
 #define NR_CPUS8   /* arbitrarily set for now */
 
 extern uint64_t tb_hz;
+extern uint64_t cpu_hz;
 
 #define NR_MEM_REGIONS 8
 #define MR_F_PRIMARY   (1U << 0)
diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index 30b988a5c..42ba06ad1 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -32,6 +32,7 @@ u32 initrd_size;
 u32 cpu_to_hwid[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
 int nr_cpus_present;
 uint64_t tb_hz;
+uint64_t cpu_hz;
 
 struct mem_region mem_regions[NR_MEM_REGIONS];
 phys_addr_t __physical_start, __physical_end;
@@ -41,6 +42,7 @@ struct cpu_set_params {
unsigned icache_bytes;
unsigned dcache_bytes;
uint64_t tb_hz;
+   uint64_t cpu_hz;
 };
 
 static void cpu_set(int fdtnode, u64 regval, void *info)
@@ -94,6 +96,22 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
data = (u32 *)prop->data;
params->tb_hz = fdt32_to_cpu(*data);
 
+   prop = fdt_get_property(dt_fdt(), fdtnode,
+   "ibm,extended-clock-frequency", NULL);
+   if (prop) {
+   data = (u32 *)prop->data;
+   params->cpu_hz = fdt32_to_cpu(*data);
+   params->cpu_hz <<= 32;
+   data = (u32 *)prop->data + 1;
+   params->cpu_hz |= fdt32_to_cpu(*data);
+   } else {
+   prop = fdt_get_property(dt_fdt(), fdtnode,
+   "clock-frequency", NULL);
+   assert(prop != NULL);
+   data = (u32 *)prop->data;
+   params->cpu_hz = fdt32_to_cpu(*data);
+   }
+
read_common_info = true;
}
 }
@@ -102,6 +120,8 @@ bool cpu_has_hv;
 bool cpu_has_power_mce; /* POWER CPU machine checks */
 bool cpu_has_siar;
 bool cpu_has_heai;
+bool cpu_has_bhrb;
+bool cpu_has_p10_bhrb;
 bool cpu_has_radix;
 bool cpu_has_prefix;
 bool cpu_has_sc_lev; /* sc interrupt has LEV field in SRR1 */
@@ -118,12 +138,14 @@ static void cpu_init_params(void)
__icache_bytes = params.icache_bytes;
__dcache_bytes = params.dcache_bytes;
tb_hz = params.tb_hz;
+   cpu_hz = params.cpu_hz;
 
switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
case PVR_VER_POWER10:
cpu_has_prefix = true;
cpu_has_sc_lev = true;
cpu_has_pause_short = true;
+   cpu_has_p10_bhrb = true;
case PVR_VER_POWER9:
cpu_has_radix = true;
case PVR_VER_POWER8E:
@@ -132,6 +154,7 @@ static void cpu_init_params(void)
cpu_has_power_mce = true;
cpu_has_heai = true;
cpu_has_siar = true;
+   cpu_has_bhrb = true;
break;
default:
break;
diff --git a/powerpc/Makefile.common 

[kvm-unit-tests PATCH v7 31/35] powerpc: add usermode support

2024-03-19 Thread Nicholas Piggin
The biggest difficulty for user mode is MMU support. Otherwise it is
a simple matter of setting and clearing MSR[PR] with rfid and sc
respectively.

Some common harness operations will fail in usermode, so some workarounds
are reqiured (e.g., puts() can't be used directly).

A usermode privileged instruction interrupt test is added.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h |  9 +
 lib/powerpc/asm/reg.h   |  1 +
 lib/powerpc/asm/smp.h   |  1 +
 lib/powerpc/io.c|  7 +++
 lib/powerpc/processor.c | 38 +
 lib/powerpc/rtas.c  |  3 +++
 lib/powerpc/setup.c |  8 ++--
 lib/powerpc/spinlock.c  |  4 
 lib/ppc64/mmu.c |  2 ++
 powerpc/interrupts.c| 28 +++
 10 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index d348239c5..749155696 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -19,6 +19,8 @@ extern bool cpu_has_prefix;
 extern bool cpu_has_sc_lev;
 extern bool cpu_has_pause_short;
 
+bool in_usermode(void);
+
 static inline uint64_t mfspr(int nr)
 {
uint64_t ret;
@@ -51,6 +53,8 @@ static inline void local_irq_enable(void)
 {
unsigned long msr;
 
+   assert(!in_usermode());
+
asm volatile(
 "  mfmsr   %0  \n \
ori %0,%0,%1\n \
@@ -62,6 +66,8 @@ static inline void local_irq_disable(void)
 {
unsigned long msr;
 
+   assert(!in_usermode());
+
asm volatile(
 "  mfmsr   %0  \n \
andc%0,%0,%1\n \
@@ -90,4 +96,7 @@ static inline bool machine_is_pseries(void)
 void enable_mcheck(void);
 void disable_mcheck(void);
 
+void enter_usermode(void);
+void exit_usermode(void);
+
 #endif /* _ASMPOWERPC_PROCESSOR_H_ */
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index b2fab4313..69ef21adb 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -58,5 +58,6 @@
 #define MSR_SE UL(0x0400)  /* Single Step Enable */
 #define MSR_EE UL(0x8000)
 #define MSR_ME UL(0x1000)
+#define MSR_PR UL(0x4000)
 
 #endif
diff --git a/lib/powerpc/asm/smp.h b/lib/powerpc/asm/smp.h
index 820c05e9e..b96a55903 100644
--- a/lib/powerpc/asm/smp.h
+++ b/lib/powerpc/asm/smp.h
@@ -11,6 +11,7 @@ struct cpu {
unsigned long server_no;
unsigned long stack;
unsigned long exception_stack;
+   bool in_user;
secondary_entry_fn entry;
pgd_t *pgtable;
 } __attribute__((packed)); /* used by asm */
diff --git a/lib/powerpc/io.c b/lib/powerpc/io.c
index cb7f2f050..5c2810884 100644
--- a/lib/powerpc/io.c
+++ b/lib/powerpc/io.c
@@ -11,6 +11,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "io.h"
 
 static struct spinlock print_lock;
@@ -41,10 +42,16 @@ void io_init(void)
 
 void puts(const char *s)
 {
+   bool user = in_usermode();
+
+   if (user)
+   exit_usermode();
spin_lock(_lock);
while (*s)
putchar(*s++);
spin_unlock(_lock);
+   if (user)
+   enter_usermode();
 }
 
 /*
diff --git a/lib/powerpc/processor.c b/lib/powerpc/processor.c
index 09f6bb9d8..6c3000d5c 100644
--- a/lib/powerpc/processor.c
+++ b/lib/powerpc/processor.c
@@ -47,6 +47,8 @@ void do_handle_exception(struct pt_regs *regs)
unsigned char v;
 
__current_cpu = (struct cpu *)mfspr(SPR_SPRG0);
+   if (in_usermode())
+   current_cpu()->in_user = false;
 
/*
 * We run with AIL=0, so interrupts taken with MMU disabled.
@@ -60,6 +62,8 @@ void do_handle_exception(struct pt_regs *regs)
 
if (v < 128 && handlers[v].func) {
handlers[v].func(regs, handlers[v].data);
+   if (regs->msr & MSR_PR)
+   current_cpu()->in_user = true;
return;
}
 
@@ -169,3 +173,37 @@ void disable_mcheck(void)
 {
rfid_msr(mfmsr() & ~MSR_ME);
 }
+
+bool in_usermode(void)
+{
+   return current_cpu()->in_user;
+}
+
+static void usermode_sc_handler(struct pt_regs *regs, void *data)
+{
+   regs->msr &= ~(MSR_PR|MSR_EE);
+   /* Interrupt return handler will keep in_user clear */
+}
+
+void enter_usermode(void)
+{
+   assert_msg(!in_usermode(), "enter_usermode called with in_usermode");
+   /* mfmsr would fault in usermode anyway */
+   assert_msg(!(mfmsr() & MSR_PR), "enter_usermode called from user mode");
+   assert_msg(!(mfmsr() & MSR_EE), "enter_usermode called with interrupts 
enabled");
+   assert_msg((mfmsr() & (MSR_IR|MSR_DR)) == (MSR_IR|MSR_DR),
+   "enter_usermode called with virtual memory disabled");
+
+   handle_exception(0xc00, usermode_sc_handler, NULL);
+   rfid_msr(mfmsr() | (MSR_PR|MSR_IR|MSR_DR|MSR_EE));
+   current_cpu()->in_user = 

[kvm-unit-tests PATCH v7 30/35] powerpc: Add sieve.c common test

2024-03-19 Thread Nicholas Piggin
Now that sieve copes with lack of MMU support, it can be run by
powerpc.

Signed-off-by: Nicholas Piggin 
---
 powerpc/Makefile.common | 1 +
 powerpc/sieve.c | 1 +
 powerpc/unittests.cfg   | 3 +++
 3 files changed, 5 insertions(+)
 create mode 12 powerpc/sieve.c

diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index 5871da47a..410a675d9 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -8,6 +8,7 @@ tests-common = \
$(TEST_DIR)/selftest.elf \
$(TEST_DIR)/selftest-migration.elf \
$(TEST_DIR)/memory-verify.elf \
+   $(TEST_DIR)/sieve.elf \
$(TEST_DIR)/spapr_hcall.elf \
$(TEST_DIR)/rtas.elf \
$(TEST_DIR)/emulator.elf \
diff --git a/powerpc/sieve.c b/powerpc/sieve.c
new file mode 12
index 0..fe299f309
--- /dev/null
+++ b/powerpc/sieve.c
@@ -0,0 +1 @@
+../common/sieve.c
\ No newline at end of file
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index 0be787f67..351da46a6 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -121,3 +121,6 @@ file = sprs.elf
 machine = pseries
 extra_params = -append '-w'
 groups = migration
+
+[sieve]
+file = sieve.elf
-- 
2.42.0



[kvm-unit-tests PATCH v7 29/35] common/sieve: Support machines without MMU

2024-03-19 Thread Nicholas Piggin
Not all powerpc CPUs provide MMU support. Define vm_available() that is
true by default but archs can override it. Use this to run VM tests.

Cc: Paolo Bonzini 
Cc: Thomas Huth 
Cc: k...@vger.kernel.org
Reviewed-by: Andrew Jones 
Signed-off-by: Nicholas Piggin 
---
 common/sieve.c  | 14 --
 lib/ppc64/asm/mmu.h |  1 -
 lib/ppc64/mmu.c |  2 +-
 lib/vmalloc.c   |  7 +++
 lib/vmalloc.h   |  2 ++
 5 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/common/sieve.c b/common/sieve.c
index 8fe05ef13..db084691a 100644
--- a/common/sieve.c
+++ b/common/sieve.c
@@ -40,12 +40,14 @@ int main(void)
 
 printf("starting sieve\n");
 test_sieve("static", static_data, STATIC_SIZE);
-setup_vm();
-test_sieve("mapped", static_data, STATIC_SIZE);
-for (i = 0; i < 3; ++i) {
-   v = malloc(VSIZE);
-   test_sieve("virtual", v, VSIZE);
-   free(v);
+if (vm_available()) {
+   setup_vm();
+   test_sieve("mapped", static_data, STATIC_SIZE);
+   for (i = 0; i < 3; ++i) {
+   v = malloc(VSIZE);
+   test_sieve("virtual", v, VSIZE);
+   free(v);
+   }
 }
 
 return 0;
diff --git a/lib/ppc64/asm/mmu.h b/lib/ppc64/asm/mmu.h
index fadeee4bc..eaff0f1f7 100644
--- a/lib/ppc64/asm/mmu.h
+++ b/lib/ppc64/asm/mmu.h
@@ -3,7 +3,6 @@
 
 #include 
 
-bool vm_available(void);
 bool mmu_enabled(void);
 void mmu_enable(pgd_t *pgtable);
 void mmu_disable(void);
diff --git a/lib/ppc64/mmu.c b/lib/ppc64/mmu.c
index 7e445fdaf..ac9c0a285 100644
--- a/lib/ppc64/mmu.c
+++ b/lib/ppc64/mmu.c
@@ -23,7 +23,7 @@
 
 static pgd_t *identity_pgd;
 
-bool vm_available(void)
+bool vm_available(void) /* weak override */
 {
return cpu_has_radix;
 }
diff --git a/lib/vmalloc.c b/lib/vmalloc.c
index 572682576..cf2ef7a70 100644
--- a/lib/vmalloc.c
+++ b/lib/vmalloc.c
@@ -206,10 +206,17 @@ void init_alloc_vpage(void *top)
spin_unlock();
 }
 
+bool __attribute__((__weak__)) vm_available(void)
+{
+   return true;
+}
+
 void __setup_vm(void *opaque)
 {
phys_addr_t base, top;
 
+   assert_msg(vm_available(), "Virtual memory not available. Must check 
vm_available() before calling setup_vm()");
+
if (alloc_ops == _ops)
return;
 
diff --git a/lib/vmalloc.h b/lib/vmalloc.h
index 0269fdde9..e81be39f4 100644
--- a/lib/vmalloc.h
+++ b/lib/vmalloc.h
@@ -17,6 +17,8 @@ extern void setup_vm(void);
 /* As above, plus passes an opaque value to setup_mmu(). */
 extern void __setup_vm(void *opaque);
 
+/* common/ tests must check availability before calling setup_vm() */
+extern bool vm_available(void);
 /* Set up paging */
 extern void *setup_mmu(phys_addr_t top, void *opaque);
 /* Walk the page table and resolve the virtual address to a physical address */
-- 
2.42.0



[kvm-unit-tests PATCH v7 28/35] common/sieve: Use vmalloc.h for setup_mmu definition

2024-03-19 Thread Nicholas Piggin
There is no good reason to put setup_vm in libcflat.h when it's
defined in vmalloc.h.

Cc: Paolo Bonzini 
Cc: Thomas Huth 
Cc: Janosch Frank 
Cc: Claudio Imbrenda 
Cc: Nico Böhr 
Cc: David Hildenbrand 
Cc: k...@vger.kernel.org
Cc: linux-s...@vger.kernel.org
Acked-by: Andrew Jones 
Signed-off-by: Nicholas Piggin 
---
 common/sieve.c | 1 +
 lib/libcflat.h | 2 --
 lib/s390x/io.c | 1 +
 lib/s390x/uv.h | 1 +
 lib/x86/vm.h   | 1 +
 s390x/mvpg.c   | 1 +
 s390x/selftest.c   | 1 +
 x86/pmu.c  | 1 +
 x86/pmu_lbr.c  | 1 +
 x86/vmexit.c   | 1 +
 x86/vmware_backdoors.c | 1 +
 11 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/common/sieve.c b/common/sieve.c
index 8150f2d98..8fe05ef13 100644
--- a/common/sieve.c
+++ b/common/sieve.c
@@ -1,5 +1,6 @@
 #include "alloc.h"
 #include "libcflat.h"
+#include "vmalloc.h"
 
 static int sieve(char* data, int size)
 {
diff --git a/lib/libcflat.h b/lib/libcflat.h
index 700f43527..8c8dd0286 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -152,8 +152,6 @@ do {
\
 void binstr(unsigned long x, char out[BINSTR_SZ]);
 void print_binstr(unsigned long x);
 
-extern void setup_vm(void);
-
 #endif /* !__ASSEMBLY__ */
 
 #define SZ_256 (1 << 8)
diff --git a/lib/s390x/io.c b/lib/s390x/io.c
index fb7b7ddaa..2b28ccaa0 100644
--- a/lib/s390x/io.c
+++ b/lib/s390x/io.c
@@ -10,6 +10,7 @@
  */
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/lib/s390x/uv.h b/lib/s390x/uv.h
index 286933caa..00a370410 100644
--- a/lib/s390x/uv.h
+++ b/lib/s390x/uv.h
@@ -4,6 +4,7 @@
 
 #include 
 #include 
+#include 
 
 bool uv_os_is_guest(void);
 bool uv_os_is_host(void);
diff --git a/lib/x86/vm.h b/lib/x86/vm.h
index 4b714bad7..cf39787aa 100644
--- a/lib/x86/vm.h
+++ b/lib/x86/vm.h
@@ -2,6 +2,7 @@
 #define _X86_VM_H_
 
 #include "processor.h"
+#include "vmalloc.h"
 #include "asm/page.h"
 #include "asm/io.h"
 #include "asm/bitops.h"
diff --git a/s390x/mvpg.c b/s390x/mvpg.c
index 296338d4f..a0cfc575a 100644
--- a/s390x/mvpg.c
+++ b/s390x/mvpg.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/s390x/selftest.c b/s390x/selftest.c
index 92ed4e5d3..3eaae9b06 100644
--- a/s390x/selftest.c
+++ b/s390x/selftest.c
@@ -9,6 +9,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/x86/pmu.c b/x86/pmu.c
index 47a1a602a..7062c1ad9 100644
--- a/x86/pmu.c
+++ b/x86/pmu.c
@@ -6,6 +6,7 @@
 #include "x86/apic.h"
 #include "x86/desc.h"
 #include "x86/isr.h"
+#include "vmalloc.h"
 #include "alloc.h"
 
 #include "libcflat.h"
diff --git a/x86/pmu_lbr.c b/x86/pmu_lbr.c
index 40b63fa3d..c6f010847 100644
--- a/x86/pmu_lbr.c
+++ b/x86/pmu_lbr.c
@@ -2,6 +2,7 @@
 #include "x86/processor.h"
 #include "x86/pmu.h"
 #include "x86/desc.h"
+#include "vmalloc.h"
 
 #define N 100
 
diff --git a/x86/vmexit.c b/x86/vmexit.c
index eb5d3023a..48a38f60f 100644
--- a/x86/vmexit.c
+++ b/x86/vmexit.c
@@ -1,6 +1,7 @@
 #include "libcflat.h"
 #include "acpi.h"
 #include "smp.h"
+#include "vmalloc.h"
 #include "pci.h"
 #include "x86/vm.h"
 #include "x86/desc.h"
diff --git a/x86/vmware_backdoors.c b/x86/vmware_backdoors.c
index bc1002056..f8cf7ecb1 100644
--- a/x86/vmware_backdoors.c
+++ b/x86/vmware_backdoors.c
@@ -6,6 +6,7 @@
 #include "x86/desc.h"
 #include "x86/isr.h"
 #include "alloc.h"
+#include "vmalloc.h"
 #include "setjmp.h"
 #include "usermode.h"
 #include "fault_test.h"
-- 
2.42.0



[kvm-unit-tests PATCH v7 27/35] powerpc: Add MMU support

2024-03-19 Thread Nicholas Piggin
Add support for radix MMU, 4kB and 64kB pages.

This also adds MMU interrupt test cases, and runs the interrupts
test entirely with MMU enabled if it is available (aside from
machine check tests).

Acked-by: Andrew Jones  (configure changes)
Signed-off-by: Nicholas Piggin 
---
 configure |  39 +++--
 lib/powerpc/asm/hcall.h   |   6 +
 lib/powerpc/asm/processor.h   |   1 +
 lib/powerpc/asm/reg.h |   3 +
 lib/powerpc/asm/smp.h |   2 +
 lib/powerpc/processor.c   |   9 ++
 lib/powerpc/setup.c   |   4 +
 lib/ppc64/asm/mmu.h   |  11 ++
 lib/ppc64/asm/page.h  |  66 -
 lib/ppc64/asm/pgtable-hwdef.h |  66 +
 lib/ppc64/asm/pgtable.h   | 125 
 lib/ppc64/mmu.c   | 272 ++
 lib/ppc64/opal-calls.S|   4 +-
 powerpc/Makefile.common   |   2 +
 powerpc/Makefile.ppc64|   1 +
 powerpc/interrupts.c  |  96 ++--
 16 files changed, 680 insertions(+), 27 deletions(-)
 create mode 100644 lib/ppc64/asm/mmu.h
 create mode 100644 lib/ppc64/asm/pgtable-hwdef.h
 create mode 100644 lib/ppc64/asm/pgtable.h
 create mode 100644 lib/ppc64/mmu.c

diff --git a/configure b/configure
index 49f047cb2..e19ba6f0c 100755
--- a/configure
+++ b/configure
@@ -245,29 +245,35 @@ fi
 if [ -z "$page_size" ]; then
 if [ "$efi" = 'y' ] && [ "$arch" = "arm64" ]; then
 page_size="4096"
-elif [ "$arch" = "arm64" ]; then
+elif [ "$arch" = "arm64" ] || [ "$arch" = "ppc64" ]; then
 page_size="65536"
 elif [ "$arch" = "arm" ]; then
 page_size="4096"
 fi
 else
-if [ "$arch" != "arm64" ]; then
-echo "--page-size is not supported for $arch"
-usage
-fi
-
 if [ "${page_size: -1}" = "K" ] || [ "${page_size: -1}" = "k" ]; then
 page_size=$(( ${page_size%?} * 1024 ))
 fi
-if [ "$page_size" != "4096" ] && [ "$page_size" != "16384" ] &&
-   [ "$page_size" != "65536" ]; then
-echo "arm64 doesn't support page size of $page_size"
+
+if [ "$arch" = "arm64" ]; then
+if [ "$page_size" != "4096" ] && [ "$page_size" != "16384" ] &&
+   [ "$page_size" != "65536" ]; then
+echo "arm64 doesn't support page size of $page_size"
+usage
+fi
+if [ "$efi" = 'y' ] && [ "$page_size" != "4096" ]; then
+echo "efi must use 4K pages"
+exit 1
+fi
+elif [ "$arch" = "ppc64" ]; then
+if [ "$page_size" != "4096" ] && [ "$page_size" != "65536" ]; then
+echo "ppc64 doesn't support page size of $page_size"
+usage
+fi
+else
+echo "--page-size is not supported for $arch"
 usage
 fi
-if [ "$efi" = 'y' ] && [ "$page_size" != "4096" ]; then
-echo "efi must use 4K pages"
-exit 1
-fi
 fi
 
 [ -z "$processor" ] && processor="$arch"
@@ -472,6 +478,13 @@ cat <> lib/config.h
 
 #define CONFIG_UART_EARLY_BASE ${arm_uart_early_addr}
 #define CONFIG_ERRATA_FORCE ${errata_force}
+
+EOF
+fi
+
+if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ] || [ "$arch" = "ppc64" ]; then
+cat <> lib/config.h
+
 #define CONFIG_PAGE_SIZE _AC(${page_size}, UL)
 
 EOF
diff --git a/lib/powerpc/asm/hcall.h b/lib/powerpc/asm/hcall.h
index e0f5009e3..3b44dd204 100644
--- a/lib/powerpc/asm/hcall.h
+++ b/lib/powerpc/asm/hcall.h
@@ -24,6 +24,12 @@
 #define H_PUT_TERM_CHAR0x58
 #define H_RANDOM   0x300
 #define H_SET_MODE 0x31C
+#define H_REGISTER_PROCESS_TABLE   0x37C
+
+#define PTBL_NEW   0x18
+#define PTBL_UNREGISTER0x10
+#define PTBL_RADIX 0x04
+#define PTBL_GTSE  0x01
 
 #define KVMPPC_HCALL_BASE  0xf000
 #define KVMPPC_H_RTAS  (KVMPPC_HCALL_BASE + 0x0)
diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index a3859b5d4..d348239c5 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -14,6 +14,7 @@ extern bool cpu_has_hv;
 extern bool cpu_has_power_mce;
 extern bool cpu_has_siar;
 extern bool cpu_has_heai;
+extern bool cpu_has_radix;
 extern bool cpu_has_prefix;
 extern bool cpu_has_sc_lev;
 extern bool cpu_has_pause_short;
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 12f9e8ac6..b2fab4313 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -11,6 +11,7 @@
 #define SPR_SRR0   0x01a
 #define SPR_SRR1   0x01b
 #define   SRR1_PREFIX  UL(0x2000)
+#define SPR_PIDR   0x030
 #define SPR_FSCR   0x099
 #define   FSCR_PREFIX  UL(0x2000)
 #define SPR_HFSCR  0x0be
@@ -36,7 +37,9 @@
 #define SPR_LPCR   0x13e
 #define   LPCR_HDICE   UL(0x1)
 #define   LPCR_LD  UL(0x2)
+#define SPR_LPIDR  0x13f
 #define SPR_HEIR   0x153
+#define SPR_PTCR   0x1d0
 #define SPR_MMCR0  0x31b
 #define   MMCR0_FC UL(0x8000)
 #define   

[kvm-unit-tests PATCH v7 26/35] powerpc: Add timebase tests

2024-03-19 Thread Nicholas Piggin
This has a known failure on QEMU TCG machines where the decrementer
interrupt is not lowered when the DEC wraps from -ve to +ve.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/reg.h   |   1 +
 powerpc/Makefile.common |   1 +
 powerpc/timebase.c  | 329 
 powerpc/unittests.cfg   |   8 +
 4 files changed, 339 insertions(+)
 create mode 100644 powerpc/timebase.c

diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index d2ca964c4..12f9e8ac6 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -35,6 +35,7 @@
 #define SPR_HSRR1  0x13b
 #define SPR_LPCR   0x13e
 #define   LPCR_HDICE   UL(0x1)
+#define   LPCR_LD  UL(0x2)
 #define SPR_HEIR   0x153
 #define SPR_MMCR0  0x31b
 #define   MMCR0_FC UL(0x8000)
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index b6f9b3b85..1348f658b 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -15,6 +15,7 @@ tests-common = \
$(TEST_DIR)/tm.elf \
$(TEST_DIR)/smp.elf \
$(TEST_DIR)/sprs.elf \
+   $(TEST_DIR)/timebase.elf \
$(TEST_DIR)/interrupts.elf
 
 tests-all = $(tests-common) $(tests)
diff --git a/powerpc/timebase.c b/powerpc/timebase.c
new file mode 100644
index 0..1908ca838
--- /dev/null
+++ b/powerpc/timebase.c
@@ -0,0 +1,329 @@
+/* SPDX-License-Identifier: LGPL-2.0-only */
+/*
+ * Test Timebase
+ *
+ * Copyright 2024 Nicholas Piggin, IBM Corp.
+ *
+ * This contains tests of timebase facility, TB, DEC, etc.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static int dec_bits = 0;
+
+static void cpu_dec_bits(int fdtnode, u64 regval __unused, void *arg __unused)
+{
+   const struct fdt_property *prop;
+   int plen;
+
+   prop = fdt_get_property(dt_fdt(), fdtnode, "ibm,dec-bits", );
+   if (!prop) {
+   dec_bits = 32;
+   return;
+   }
+
+   /* Sanity check for the property layout (first two bytes are header) */
+   assert(plen == 4);
+
+   dec_bits = fdt32_to_cpu(*(uint32_t *)prop->data);
+}
+
+/* Check amount of CPUs nodes that have the TM flag */
+static int find_dec_bits(void)
+{
+   int ret;
+
+   ret = dt_for_each_cpu_node(cpu_dec_bits, NULL);
+   if (ret < 0)
+   return ret;
+
+   return dec_bits;
+}
+
+
+static bool do_migrate = false;
+static volatile bool got_interrupt;
+static volatile struct pt_regs recorded_regs;
+
+static uint64_t dec_max;
+static uint64_t dec_min;
+
+static void test_tb(int argc, char **argv)
+{
+   uint64_t tb;
+
+   tb = get_tb();
+   if (do_migrate)
+   migrate();
+   report(get_tb() >= tb, "timebase is incrementing");
+}
+
+static void dec_stop_handler(struct pt_regs *regs, void *data)
+{
+   mtspr(SPR_DEC, dec_max);
+}
+
+static void dec_handler(struct pt_regs *regs, void *data)
+{
+   got_interrupt = true;
+   memcpy((void *)_regs, regs, sizeof(struct pt_regs));
+   regs->msr &= ~MSR_EE;
+}
+
+static void test_dec(int argc, char **argv)
+{
+   uint64_t tb1, tb2, dec;
+   int i;
+
+   handle_exception(0x900, _handler, NULL);
+
+   for (i = 0; i < 100; i++) {
+   tb1 = get_tb();
+   mtspr(SPR_DEC, dec_max);
+   dec = mfspr(SPR_DEC);
+   tb2 = get_tb();
+   if (tb2 - tb1 < dec_max - dec)
+   break;
+   }
+   report(tb2 - tb1 >= dec_max - dec, "decrementer remains within TB after 
mtDEC");
+
+   tb1 = get_tb();
+   mtspr(SPR_DEC, dec_max);
+   mdelay(1000);
+   dec = mfspr(SPR_DEC);
+   tb2 = get_tb();
+   report(tb2 - tb1 >= dec_max - dec, "decrementer remains within TB after 
1s");
+
+   mtspr(SPR_DEC, dec_max);
+   local_irq_enable();
+   local_irq_disable();
+   if (mfspr(SPR_DEC) <= dec_max) {
+   report(!got_interrupt, "no interrupt on decrementer positive");
+   }
+   got_interrupt = false;
+
+   mtspr(SPR_DEC, 1);
+   mdelay(100); /* Give the timer a chance to run */
+   if (do_migrate)
+   migrate();
+   local_irq_enable();
+   local_irq_disable();
+   report(got_interrupt, "interrupt on decrementer underflow");
+   got_interrupt = false;
+
+   if (do_migrate)
+   migrate();
+   local_irq_enable();
+   local_irq_disable();
+   report(got_interrupt, "interrupt on decrementer still underflown");
+   got_interrupt = false;
+
+   mtspr(SPR_DEC, 0);
+   mdelay(100); /* Give the timer a chance to run */
+   if (do_migrate)
+   migrate();
+   local_irq_enable();
+   local_irq_disable();
+   report(got_interrupt, "DEC deal with set to 0");
+   got_interrupt = false;
+
+   /* Test for level-triggered decrementer */
+   mtspr(SPR_DEC, -1ULL);
+   if (do_migrate)
+

[kvm-unit-tests PATCH v7 25/35] powerpc: Add atomics tests

2024-03-19 Thread Nicholas Piggin
Signed-off-by: Nicholas Piggin 
---
 powerpc/Makefile.common |   1 +
 powerpc/atomics.c   | 374 
 powerpc/unittests.cfg   |   9 +
 3 files changed, 384 insertions(+)
 create mode 100644 powerpc/atomics.c

diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index 02af54b83..b6f9b3b85 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -11,6 +11,7 @@ tests-common = \
$(TEST_DIR)/spapr_hcall.elf \
$(TEST_DIR)/rtas.elf \
$(TEST_DIR)/emulator.elf \
+   $(TEST_DIR)/atomics.elf \
$(TEST_DIR)/tm.elf \
$(TEST_DIR)/smp.elf \
$(TEST_DIR)/sprs.elf \
diff --git a/powerpc/atomics.c b/powerpc/atomics.c
new file mode 100644
index 0..c3d1cef52
--- /dev/null
+++ b/powerpc/atomics.c
@@ -0,0 +1,374 @@
+/* SPDX-License-Identifier: LGPL-2.0-only */
+/*
+ * Test some powerpc instructions
+ *
+ * Copyright 2024 Nicholas Piggin, IBM Corp.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static bool do_migrate;
+static bool do_record;
+
+#define RSV_SIZE 128
+
+static uint8_t granule[RSV_SIZE] __attribute((__aligned__(RSV_SIZE)));
+
+static void spin_lock(unsigned int *lock)
+{
+   unsigned int old;
+
+   asm volatile ("1:"
+ "lwarx%0,0,%2;"
+ "cmpwi%0,0;"
+ "bne  1b;"
+ "stwcx.   %1,0,%2;"
+ "bne- 1b;"
+ "lwsync;"
+ : "="(old) : "r"(1), "r"(lock) : "cr0", "memory");
+}
+
+static void spin_unlock(unsigned int *lock)
+{
+   asm volatile("lwsync;"
+"stw   %1,%0;"
+: "+m"(*lock) : "r"(0) : "memory");
+}
+
+static volatile bool got_interrupt;
+static volatile struct pt_regs recorded_regs;
+
+static void interrupt_handler(struct pt_regs *regs, void *opaque)
+{
+   assert(!got_interrupt);
+   got_interrupt = true;
+   memcpy((void *)_regs, regs, sizeof(struct pt_regs));
+   regs_advance_insn(regs);
+}
+
+static void test_lwarx_stwcx(int argc, char *argv[])
+{
+   unsigned int *var = (unsigned int *)granule;
+   unsigned int old;
+   unsigned int result;
+
+   *var = 0;
+   asm volatile ("1:"
+ "lwarx%0,0,%2;"
+ "stwcx.   %1,0,%2;"
+ "bne- 1b;"
+ : "="(old) : "r"(1), "r"(var) : "cr0", "memory");
+   report(old == 0 && *var == 1, "simple update");
+
+   *var = 0;
+   asm volatile ("li   %0,0;"
+ "stwcx.   %1,0,%2;"
+ "stwcx.   %1,0,%2;"
+ "bne- 1f;"
+ "li   %0,1;"
+ "1:"
+ : "="(result)
+ : "r"(1), "r"(var) : "cr0", "memory");
+   report(result == 0 && *var == 0, "failed stwcx. (no reservation)");
+
+   *var = 0;
+   asm volatile ("li   %0,0;"
+ "lwarx%1,0,%4;"
+ "stw  %3,0(%4);"
+ "stwcx.   %2,0,%4;"
+ "bne- 1f;"
+ "li   %0,1;"
+ "1:"
+ : "="(result), "="(old)
+ : "r"(1), "r"(2), "r"(var) : "cr0", "memory");
+   /* This is implementation specific, so don't fail */
+   if (result == 0 && *var == 2)
+   report(true, "failed stwcx. (intervening store)");
+   else
+   report(true, "succeeded stwcx. (intervening store)");
+
+   handle_exception(0x600, interrupt_handler, NULL);
+   handle_exception(0x700, interrupt_handler, NULL);
+
+   /* Implementations may not necessarily invoke the alignment interrupt */
+   old = 10;
+   *var = 0;
+   asm volatile (
+ "lwarx%0,0,%1;"
+ : "+"(old) : "r"((char *)var + 1));
+   report(old == 10 && got_interrupt && recorded_regs.trap == 0x600, 
"unaligned lwarx causes fault");
+   got_interrupt = false;
+
+   /*
+* Unaligned stwcx. is more difficult to test, at least under QEMU,
+* the store does not proceed if there is no matching reservation, so
+* the alignment handler does not get invoked. This is okay according
+* to the Power ISA (unalignment does not necessarily invoke the
+* alignment interrupt). But POWER CPUs do cause alignment interrupt.
+*/
+   *var = 0;
+   asm volatile (
+ "lwarx%0,0,%2;"
+ "stwcx.   %1,0,%3;"
+ : "="(old) : "r"(1), "r"(var), "r"((char *)var+1) : 
"cr0", "memory");
+   report(old == 0 && *var == 0 && got_interrupt && recorded_regs.trap == 
0x600, "unaligned stwcx. causes fault");
+   got_interrupt = false;
+
+   handle_exception(0x600, NULL, NULL);
+
+}
+
+static void 

[kvm-unit-tests PATCH v7 24/35] powerpc: Avoid using larx/stcx. in spinlocks when only one CPU is running

2024-03-19 Thread Nicholas Piggin
The test harness uses spinlocks if they are implemented with larx/stcx.
it can prevent some test scenarios such as testing migration of a
reservation.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/smp.h|  1 +
 lib/powerpc/smp.c|  5 +
 lib/powerpc/spinlock.c   | 29 +
 lib/ppc64/asm/spinlock.h |  7 ++-
 powerpc/Makefile.common  |  1 +
 5 files changed, 42 insertions(+), 1 deletion(-)
 create mode 100644 lib/powerpc/spinlock.c

diff --git a/lib/powerpc/asm/smp.h b/lib/powerpc/asm/smp.h
index 4519e5436..6ef3ae521 100644
--- a/lib/powerpc/asm/smp.h
+++ b/lib/powerpc/asm/smp.h
@@ -15,6 +15,7 @@ struct cpu {
 
 extern int nr_cpus_present;
 extern int nr_cpus_online;
+extern bool multithreaded;
 extern struct cpu cpus[];
 
 register struct cpu *__current_cpu asm("r13");
diff --git a/lib/powerpc/smp.c b/lib/powerpc/smp.c
index a3bf85d44..f3b2a3faf 100644
--- a/lib/powerpc/smp.c
+++ b/lib/powerpc/smp.c
@@ -276,6 +276,8 @@ static void start_each_secondary(int fdtnode, u64 regval 
__unused, void *info)
start_core(fdtnode, datap->entry);
 }
 
+bool multithreaded = false;
+
 /*
  * Start all stopped cpus on the guest at entry with register 3 set to r3
  * We expect that we come in with only one thread currently started
@@ -290,6 +292,7 @@ bool start_all_cpus(secondary_entry_fn entry)
 
assert(nr_cpus_online == 1);
assert(nr_started == 1);
+   multithreaded = true;
ret = dt_for_each_cpu_node(start_each_secondary, );
assert(ret == 0);
assert(nr_started == nr_cpus_present);
@@ -308,8 +311,10 @@ bool start_all_cpus(secondary_entry_fn entry)
 
 void stop_all_cpus(void)
 {
+   assert(multithreaded);
while (nr_cpus_online > 1)
cpu_relax();
mb();
nr_started = 1;
+   multithreaded = false;
 }
diff --git a/lib/powerpc/spinlock.c b/lib/powerpc/spinlock.c
new file mode 100644
index 0..623a1f2c1
--- /dev/null
+++ b/lib/powerpc/spinlock.c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: LGPL-2.0 */
+#include 
+#include 
+
+/*
+ * Skip the atomic when single-threaded, which helps avoid larx/stcx. in
+ * the harness when testing tricky larx/stcx. sequences (e.g., migration
+ * vs reservation).
+ */
+void spin_lock(struct spinlock *lock)
+{
+   if (!multithreaded) {
+   assert(lock->v == 0);
+   lock->v = 1;
+   } else {
+   while (__sync_lock_test_and_set(>v, 1))
+   ;
+   }
+}
+
+void spin_unlock(struct spinlock *lock)
+{
+   assert(lock->v == 1);
+   if (!multithreaded) {
+   lock->v = 0;
+   } else {
+   __sync_lock_release(>v);
+   }
+}
diff --git a/lib/ppc64/asm/spinlock.h b/lib/ppc64/asm/spinlock.h
index f59eed191..b952386da 100644
--- a/lib/ppc64/asm/spinlock.h
+++ b/lib/ppc64/asm/spinlock.h
@@ -1,6 +1,11 @@
 #ifndef _ASMPPC64_SPINLOCK_H_
 #define _ASMPPC64_SPINLOCK_H_
 
-#include 
+struct spinlock {
+   unsigned int v;
+};
+
+void spin_lock(struct spinlock *lock);
+void spin_unlock(struct spinlock *lock);
 
 #endif /* _ASMPPC64_SPINLOCK_H_ */
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index 744dfc1f7..02af54b83 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -48,6 +48,7 @@ cflatobjs += lib/powerpc/rtas.o
 cflatobjs += lib/powerpc/processor.o
 cflatobjs += lib/powerpc/handlers.o
 cflatobjs += lib/powerpc/smp.o
+cflatobjs += lib/powerpc/spinlock.o
 
 OBJDIRS += lib/powerpc
 
-- 
2.42.0



[kvm-unit-tests PATCH v7 23/35] powerpc: Permit ACCEL=tcg,thread=single

2024-03-19 Thread Nicholas Piggin
Modify run script to permit single vs mttcg threading, add a
thread=single smp case to unittests.cfg.

Signed-off-by: Nicholas Piggin 
---
 powerpc/run   | 4 ++--
 powerpc/unittests.cfg | 6 ++
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/powerpc/run b/powerpc/run
index 172f32a46..27abf1ef6 100755
--- a/powerpc/run
+++ b/powerpc/run
@@ -36,8 +36,8 @@ if ! $qemu -machine '?' 2>&1 | grep $MACHINE > /dev/null; then
exit 2
 fi
 
+A="-accel $ACCEL$ACCEL_PROPS"
 M="-machine $MACHINE"
-M+=",accel=$ACCEL$ACCEL_PROPS"
 B=""
 D=""
 
@@ -54,7 +54,7 @@ if [[ "$MACHINE" == "powernv"* ]] ; then
D+="-device ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10"
 fi
 
-command="$qemu -nodefaults $M $B $D"
+command="$qemu -nodefaults $A $M $B $D"
 command+=" -display none -serial stdio -kernel"
 command="$(migration_cmd) $(timeout_cmd) $command"
 
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index ddce409a8..71bfc935d 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -82,6 +82,12 @@ smp = 2
 file = smp.elf
 smp = 8,threads=4
 
+# mttcg is the default most places, so add a thread=single test
+[smp-thread-single]
+file = smp.elf
+smp = 8,threads=4
+accel = tcg,thread=single
+
 [h_cede_tm]
 file = tm.elf
 machine = pseries
-- 
2.42.0



[kvm-unit-tests PATCH v7 22/35] powerpc: add SMP and IPI support

2024-03-19 Thread Nicholas Piggin
powerpc SMP support is very primitive and does not set up a first-class
runtime environment for secondary CPUs.

This reworks SMP support, and provides a complete C and harness
environment for the secondaries, including interrupt handling, as well
as IPI support.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h |  23 +++
 lib/powerpc/asm/reg.h   |   1 +
 lib/powerpc/asm/setup.h |   2 -
 lib/powerpc/asm/smp.h   |  46 +++--
 lib/powerpc/io.c|  15 +-
 lib/powerpc/processor.c |   7 +-
 lib/powerpc/setup.c |  90 +++---
 lib/powerpc/smp.c   | 282 +
 lib/ppc64/asm-offsets.c |   7 +
 lib/ppc64/asm/atomic.h  |   6 +
 lib/ppc64/asm/barrier.h |   3 +
 lib/ppc64/asm/opal.h|   7 +
 powerpc/Makefile.common |   1 +
 powerpc/cstart64.S  |  49 -
 powerpc/selftest.c  |   4 +-
 powerpc/smp.c   | 348 
 powerpc/tm.c|   4 +-
 powerpc/unittests.cfg   |   8 +
 18 files changed, 818 insertions(+), 85 deletions(-)
 create mode 100644 lib/ppc64/asm/atomic.h
 create mode 100644 powerpc/smp.c

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index eed37d1f4..a3859b5d4 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -16,6 +16,7 @@ extern bool cpu_has_siar;
 extern bool cpu_has_heai;
 extern bool cpu_has_prefix;
 extern bool cpu_has_sc_lev;
+extern bool cpu_has_pause_short;
 
 static inline uint64_t mfspr(int nr)
 {
@@ -45,6 +46,28 @@ static inline void mtmsr(uint64_t msr)
asm volatile ("mtmsrd %[msr]" :: [msr] "r" (msr) : "memory");
 }
 
+static inline void local_irq_enable(void)
+{
+   unsigned long msr;
+
+   asm volatile(
+"  mfmsr   %0  \n \
+   ori %0,%0,%1\n \
+   mtmsrd  %0,1"
+   : "=r"(msr) : "i"(MSR_EE): "memory");
+}
+
+static inline void local_irq_disable(void)
+{
+   unsigned long msr;
+
+   asm volatile(
+"  mfmsr   %0  \n \
+   andc%0,%0,%1\n \
+   mtmsrd  %0,1"
+   : "=r"(msr) : "r"(MSR_EE): "memory");
+}
+
 /*
  * This returns true on PowerNV / OPAL machines which run in hypervisor
  * mode. False on pseries / PAPR machines that run in guest mode.
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index d6097f48f..d2ca964c4 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -19,6 +19,7 @@
 #define SPR_SPRG1  0x111
 #define SPR_SPRG2  0x112
 #define SPR_SPRG3  0x113
+#define SPR_TBU40  0x11e
 #define SPR_PVR0x11f
 #define   PVR_VERSION_MASK UL(0x)
 #define   PVR_VER_970  UL(0x0039)
diff --git a/lib/powerpc/asm/setup.h b/lib/powerpc/asm/setup.h
index cc7cf5e25..9ca318ce6 100644
--- a/lib/powerpc/asm/setup.h
+++ b/lib/powerpc/asm/setup.h
@@ -8,8 +8,6 @@
 #include 
 
 #define NR_CPUS8   /* arbitrarily set for now */
-extern u32 cpus[NR_CPUS];
-extern int nr_cpus;
 
 extern uint64_t tb_hz;
 
diff --git a/lib/powerpc/asm/smp.h b/lib/powerpc/asm/smp.h
index 21940b4bc..4519e5436 100644
--- a/lib/powerpc/asm/smp.h
+++ b/lib/powerpc/asm/smp.h
@@ -2,21 +2,45 @@
 #define _ASMPOWERPC_SMP_H_
 
 #include 
+#include 
 
-extern int nr_threads;
+typedef void (*secondary_entry_fn)(int cpu_id);
 
-struct start_threads {
-   int nr_threads;
-   int nr_started;
-};
+struct cpu {
+   unsigned long server_no;
+   unsigned long stack;
+   unsigned long exception_stack;
+   secondary_entry_fn entry;
+} __attribute__((packed)); /* used by asm */
 
-typedef void (*secondary_entry_fn)(void);
+extern int nr_cpus_present;
+extern int nr_cpus_online;
+extern struct cpu cpus[];
 
-extern void halt(void);
+register struct cpu *__current_cpu asm("r13");
+static inline struct cpu *current_cpu(void)
+{
+   return __current_cpu;
+}
 
-extern int start_thread(int cpu_id, secondary_entry_fn entry, uint32_t r3);
-extern struct start_threads start_cpu(int cpu_node, secondary_entry_fn entry,
- uint32_t r3);
-extern bool start_all_cpus(secondary_entry_fn entry, uint32_t r3);
+static inline int smp_processor_id(void)
+{
+   return current_cpu()->server_no;
+}
+
+void cpu_init(struct cpu *cpu, int cpu_id);
+
+extern void halt(int cpu_id);
+
+extern bool start_all_cpus(secondary_entry_fn entry);
+extern void stop_all_cpus(void);
+
+struct pt_regs;
+void register_ipi(void (*fn)(struct pt_regs *, void *), void *data);
+void unregister_ipi(void);
+void cpu_init_ipis(void);
+void local_ipi_enable(void);
+void local_ipi_disable(void);
+void send_ipi(int cpu_id);
 
 #endif /* _ASMPOWERPC_SMP_H_ */
diff --git a/lib/powerpc/io.c b/lib/powerpc/io.c
index ab7bb843c..cb7f2f050 100644
--- a/lib/powerpc/io.c
+++ b/lib/powerpc/io.c
@@ -10,6 +10,7 @@
 #include 
 

[kvm-unit-tests PATCH v7 21/35] powerpc: Remove broken SMP exception stack setup

2024-03-19 Thread Nicholas Piggin
The exception stack setup does not work correctly for SMP, because
it is the boot processor that calls cpu_set() which sets SPRG2 to
the exception stack, not the target CPU itself. So secondaries
never got their SPRG2 set to a valid exception stack.

Remove the SMP code and just set an exception stack for the boot
processor. Make the stack 64kB while we're here, to match the
size of the regular stack.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/setup.c | 16 
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index 9b665f59c..496af40f8 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -42,10 +42,6 @@ struct cpu_set_params {
uint64_t tb_hz;
 };
 
-#define EXCEPTION_STACK_SIZE   (32*1024) /* 32kB */
-
-static char exception_stack[NR_CPUS][EXCEPTION_STACK_SIZE];
-
 static void cpu_set(int fdtnode, u64 regval, void *info)
 {
static bool read_common_info = false;
@@ -56,10 +52,6 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
 
cpus[cpu] = regval;
 
-   /* set exception stack address for this CPU (in SPGR0) */
-   asm volatile ("mtsprg0 %[addr]" ::
- [addr] "r" (exception_stack[cpu + 1]));
-
if (!read_common_info) {
const struct fdt_property *prop;
u32 *data;
@@ -180,6 +172,10 @@ static void mem_init(phys_addr_t freemem_start)
 ? __icache_bytes : __dcache_bytes);
 }
 
+#define EXCEPTION_STACK_SIZE   SZ_64K
+
+static char boot_exception_stack[EXCEPTION_STACK_SIZE];
+
 void setup(const void *fdt)
 {
void *freemem = 
@@ -189,6 +185,10 @@ void setup(const void *fdt)
 
cpu_has_hv = !!(mfmsr() & (1ULL << MSR_HV_BIT));
 
+   /* set exception stack address for this CPU (in SPGR0) */
+   asm volatile ("mtsprg0 %[addr]" ::
+ [addr] "r" (boot_exception_stack));
+
enable_mcheck();
 
/*
-- 
2.42.0



[kvm-unit-tests PATCH v7 20/35] powerpc: Add rtas stop-self support

2024-03-19 Thread Nicholas Piggin
In preparation for improved SMP support, add stop-self support to the
harness. This is non-trivial because it requires an unlocked rtas
call: a CPU can't be holding a spin lock when it goes offline or it
will deadlock other CPUs. rtas permits stop-self to be called without
serialising all other rtas operations.

Reviewed-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/rtas.h |  2 ++
 lib/powerpc/rtas.c | 78 +-
 2 files changed, 64 insertions(+), 16 deletions(-)

diff --git a/lib/powerpc/asm/rtas.h b/lib/powerpc/asm/rtas.h
index 6fb407a18..364bf9355 100644
--- a/lib/powerpc/asm/rtas.h
+++ b/lib/powerpc/asm/rtas.h
@@ -23,8 +23,10 @@ struct rtas_args {
 extern void rtas_init(void);
 extern int rtas_token(const char *service, uint32_t *token);
 extern int rtas_call(int token, int nargs, int nret, int *outputs, ...);
+extern int rtas_call_unlocked(struct rtas_args *args, int token, int nargs, 
int nret, int *outputs, ...);
 
 extern void rtas_power_off(void);
+extern void rtas_stop_self(void);
 #endif /* __ASSEMBLY__ */
 
 #define RTAS_MSR_MASK 0xfffe
diff --git a/lib/powerpc/rtas.c b/lib/powerpc/rtas.c
index 41c0a243e..b477a38e0 100644
--- a/lib/powerpc/rtas.c
+++ b/lib/powerpc/rtas.c
@@ -87,40 +87,86 @@ int rtas_token(const char *service, uint32_t *token)
return 0;
 }
 
-int rtas_call(int token, int nargs, int nret, int *outputs, ...)
+static void __rtas_call(struct rtas_args *args)
 {
-   va_list list;
-   int ret, i;
+   enter_rtas(__pa(args));
+}
 
-   spin_lock(_lock);
+static int rtas_call_unlocked_va(struct rtas_args *args,
+ int token, int nargs, int nret, int *outputs,
+ va_list list)
+{
+   int ret, i;
 
-   rtas_args.token = cpu_to_be32(token);
-   rtas_args.nargs = cpu_to_be32(nargs);
-   rtas_args.nret = cpu_to_be32(nret);
-   rtas_args.rets = _args.args[nargs];
+   args->token = cpu_to_be32(token);
+   args->nargs = cpu_to_be32(nargs);
+   args->nret = cpu_to_be32(nret);
+   args->rets = >args[nargs];
 
-   va_start(list, outputs);
for (i = 0; i < nargs; ++i)
-   rtas_args.args[i] = cpu_to_be32(va_arg(list, u32));
-   va_end(list);
+   args->args[i] = cpu_to_be32(va_arg(list, u32));
 
for (i = 0; i < nret; ++i)
-   rtas_args.rets[i] = 0;
+   args->rets[i] = 0;
 
-   enter_rtas(__pa(_args));
+   __rtas_call(args);
 
if (nret > 1 && outputs != NULL)
for (i = 0; i < nret - 1; ++i)
-   outputs[i] = be32_to_cpu(rtas_args.rets[i + 1]);
+   outputs[i] = be32_to_cpu(args->rets[i + 1]);
+
+   ret = nret > 0 ? be32_to_cpu(args->rets[0]) : 0;
+
+   return ret;
+}
+
+int rtas_call_unlocked(struct rtas_args *args, int token, int nargs, int nret, 
int *outputs, ...)
+{
+   va_list list;
+   int ret;
 
-   ret = nret > 0 ? be32_to_cpu(rtas_args.rets[0]) : 0;
+   va_start(list, outputs);
+   ret = rtas_call_unlocked_va(args, token, nargs, nret, outputs, list);
+   va_end(list);
+
+   return ret;
+}
+
+int rtas_call(int token, int nargs, int nret, int *outputs, ...)
+{
+   va_list list;
+   int ret;
+
+   spin_lock(_lock);
+
+   va_start(list, outputs);
+   ret = rtas_call_unlocked_va(_args, token, nargs, nret, outputs, 
list);
+   va_end(list);
 
spin_unlock(_lock);
+
return ret;
 }
 
+void rtas_stop_self(void)
+{
+   struct rtas_args args;
+   uint32_t token;
+   int ret;
+
+   ret = rtas_token("stop-self", );
+   if (ret) {
+   puts("RTAS stop-self not available\n");
+   return;
+   }
+
+   ret = rtas_call_unlocked(, token, 0, 1, NULL);
+   printf("RTAS stop-self returned %d\n", ret);
+}
+
 void rtas_power_off(void)
 {
+   struct rtas_args args;
uint32_t token;
int ret;
 
@@ -130,6 +176,6 @@ void rtas_power_off(void)
return;
}
 
-   ret = rtas_call(token, 2, 1, NULL, -1, -1);
+   ret = rtas_call_unlocked(, token, 2, 1, NULL, -1, -1);
printf("RTAS power-off returned %d\n", ret);
 }
-- 
2.42.0



[kvm-unit-tests PATCH v7 19/35] powerpc: general interrupt tests

2024-03-19 Thread Nicholas Piggin
Add basic testing of various kinds of interrupts, machine check,
page fault, illegal, decrementer, trace, syscall, etc.

This has a known failure on QEMU TCG pseries machines where MSR[ME]
can be incorrectly set to 0.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h |   4 +
 lib/powerpc/asm/reg.h   |  17 ++
 lib/powerpc/setup.c |  11 +
 lib/ppc64/asm/ptrace.h  |  16 ++
 powerpc/Makefile.common |   3 +-
 powerpc/interrupts.c| 414 
 powerpc/unittests.cfg   |   3 +
 7 files changed, 467 insertions(+), 1 deletion(-)
 create mode 100644 powerpc/interrupts.c

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index cf1b9d8ff..eed37d1f4 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -11,7 +11,11 @@ void do_handle_exception(struct pt_regs *regs);
 #endif /* __ASSEMBLY__ */
 
 extern bool cpu_has_hv;
+extern bool cpu_has_power_mce;
+extern bool cpu_has_siar;
 extern bool cpu_has_heai;
+extern bool cpu_has_prefix;
+extern bool cpu_has_sc_lev;
 
 static inline uint64_t mfspr(int nr)
 {
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 782e75527..d6097f48f 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -5,8 +5,15 @@
 
 #define UL(x) _AC(x, UL)
 
+#define SPR_DSISR  0x012
+#define SPR_DAR0x013
+#define SPR_DEC0x016
 #define SPR_SRR0   0x01a
 #define SPR_SRR1   0x01b
+#define   SRR1_PREFIX  UL(0x2000)
+#define SPR_FSCR   0x099
+#define   FSCR_PREFIX  UL(0x2000)
+#define SPR_HFSCR  0x0be
 #define SPR_TB 0x10c
 #define SPR_SPRG0  0x110
 #define SPR_SPRG1  0x111
@@ -22,12 +29,17 @@
 #define   PVR_VER_POWER8   UL(0x004d)
 #define   PVR_VER_POWER9   UL(0x004e)
 #define   PVR_VER_POWER10  UL(0x0080)
+#define SPR_HDEC   0x136
 #define SPR_HSRR0  0x13a
 #define SPR_HSRR1  0x13b
+#define SPR_LPCR   0x13e
+#define   LPCR_HDICE   UL(0x1)
+#define SPR_HEIR   0x153
 #define SPR_MMCR0  0x31b
 #define   MMCR0_FC UL(0x8000)
 #define   MMCR0_PMAE   UL(0x0400)
 #define   MMCR0_PMAO   UL(0x0080)
+#define SPR_SIAR   0x31c
 
 /* Machine State Register definitions: */
 #define MSR_LE_BIT 0
@@ -35,6 +47,11 @@
 #define MSR_HV_BIT 60  /* Hypervisor mode */
 #define MSR_SF_BIT 63  /* 64-bit mode */
 
+#define MSR_DR UL(0x0010)
+#define MSR_IR UL(0x0020)
+#define MSR_BE UL(0x0200)  /* Branch Trace Enable */
+#define MSR_SE UL(0x0400)  /* Single Step Enable */
+#define MSR_EE UL(0x8000)
 #define MSR_ME UL(0x1000)
 
 #endif
diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index 3c81aee9e..9b665f59c 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -87,7 +87,11 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
 }
 
 bool cpu_has_hv;
+bool cpu_has_power_mce; /* POWER CPU machine checks */
+bool cpu_has_siar;
 bool cpu_has_heai;
+bool cpu_has_prefix;
+bool cpu_has_sc_lev; /* sc interrupt has LEV field in SRR1 */
 
 static void cpu_init(void)
 {
@@ -112,15 +116,22 @@ static void cpu_init(void)
 
switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
case PVR_VER_POWER10:
+   cpu_has_prefix = true;
+   cpu_has_sc_lev = true;
case PVR_VER_POWER9:
case PVR_VER_POWER8E:
case PVR_VER_POWER8NVL:
case PVR_VER_POWER8:
+   cpu_has_power_mce = true;
cpu_has_heai = true;
+   cpu_has_siar = true;
break;
default:
break;
}
+
+   if (!cpu_has_hv) /* HEIR is HV register */
+   cpu_has_heai = false;
 }
 
 static void mem_init(phys_addr_t freemem_start)
diff --git a/lib/ppc64/asm/ptrace.h b/lib/ppc64/asm/ptrace.h
index 12de7499b..db263a59e 100644
--- a/lib/ppc64/asm/ptrace.h
+++ b/lib/ppc64/asm/ptrace.h
@@ -5,6 +5,9 @@
 #define STACK_FRAME_OVERHEAD112 /* size of minimum stack frame */
 
 #ifndef __ASSEMBLY__
+
+#include 
+
 struct pt_regs {
unsigned long gpr[32];
unsigned long nip;
@@ -17,6 +20,19 @@ struct pt_regs {
unsigned long _pad; /* stack must be 16-byte aligned */
 };
 
+static inline bool regs_is_prefix(volatile struct pt_regs *regs)
+{
+   return regs->msr & SRR1_PREFIX;
+}
+
+static inline void regs_advance_insn(struct pt_regs *regs)
+{
+   if (regs_is_prefix(regs))
+   regs->nip += 8;
+   else
+   regs->nip += 4;
+}
+
 #define STACK_INT_FRAME_SIZE(sizeof(struct pt_regs) + \
 STACK_FRAME_OVERHEAD + KERNEL_REDZONE_SIZE)
 
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index 1e181da69..68165fc25 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -12,7 +12,8 @@ 

[kvm-unit-tests PATCH v7 18/35] powerpc/sprs: Test hypervisor registers on powernv machine

2024-03-19 Thread Nicholas Piggin
This enables HV privilege registers to be tested with the powernv
machine.

Acked-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 powerpc/sprs.c | 33 +
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/powerpc/sprs.c b/powerpc/sprs.c
index cb1d6c980..0a82418d6 100644
--- a/powerpc/sprs.c
+++ b/powerpc/sprs.c
@@ -199,16 +199,16 @@ static const struct spr sprs_power_common[1024] = {
 [190] = { "HFSCR", 64, HV_RW, },
 [256] = { "VRSAVE",32, RW, },
 [259] = { "SPRG3", 64, RO, },
-[284] = { "TBL",   32, HV_WO, },
-[285] = { "TBU",   32, HV_WO, },
-[286] = { "TBU40", 64, HV_WO, },
+[284] = { "TBL",   32, HV_WO, }, /* Things can go a bit wonky with */
+[285] = { "TBU",   32, HV_WO, }, /* Timebase changing. Should save */
+[286] = { "TBU40", 64, HV_WO, }, /* and restore it. */
 [304] = { "HSPRG0",64, HV_RW, },
 [305] = { "HSPRG1",64, HV_RW, },
 [306] = { "HDSISR",32, HV_RW,  SPR_INT, },
 [307] = { "HDAR",  64, HV_RW,  SPR_INT, },
 [308] = { "SPURR", 64, HV_RW | OS_RO,  SPR_ASYNC, },
 [309] = { "PURR",  64, HV_RW | OS_RO,  SPR_ASYNC, },
-[313] = { "HRMOR", 64, HV_RW, },
+[313] = { "HRMOR", 64, HV_RW,  SPR_HARNESS, }, /* Harness 
can't cope with HRMOR changing */
 [314] = { "HSRR0", 64, HV_RW,  SPR_INT, },
 [315] = { "HSRR1", 64, HV_RW,  SPR_INT, },
 [318] = { "LPCR",  64, HV_RW, },
@@ -306,7 +306,7 @@ static const struct spr sprs_power9_10[1024] = {
 [921] = { "TSCR",  32, HV_RW, },
 [922] = { "TTR",   64, HV_RW, },
 [1006]= { "TRACE", 64, WO, },
-[1008]= { "HID",   64, HV_RW, },
+[1008]= { "HID",   64, HV_RW,  SPR_HARNESS, }, /* HILE would 
be unhelpful to change */
 };
 
 /* This covers POWER8 and POWER9 PMUs */
@@ -350,6 +350,22 @@ static const struct spr sprs_power10_pmu[1024] = {
 
 static struct spr sprs[1024];
 
+static bool spr_read_perms(int spr)
+{
+   if (cpu_has_hv)
+   return !!(sprs[spr].access & SPR_HV_READ);
+   else
+   return !!(sprs[spr].access & SPR_OS_READ);
+}
+
+static bool spr_write_perms(int spr)
+{
+   if (cpu_has_hv)
+   return !!(sprs[spr].access & SPR_HV_WRITE);
+   else
+   return !!(sprs[spr].access & SPR_OS_WRITE);
+}
+
 static void setup_sprs(void)
 {
int i;
@@ -461,7 +477,7 @@ static void get_sprs(uint64_t *v)
int i;
 
for (i = 0; i < 1024; i++) {
-   if (!(sprs[i].access & SPR_OS_READ))
+   if (!spr_read_perms(i))
continue;
v[i] = __mfspr(i);
}
@@ -472,8 +488,9 @@ static void set_sprs(uint64_t val)
int i;
 
for (i = 0; i < 1024; i++) {
-   if (!(sprs[i].access & SPR_OS_WRITE))
+   if (!spr_write_perms(i))
continue;
+
if (sprs[i].type & SPR_HARNESS)
continue;
__mtspr(i, val);
@@ -561,7 +578,7 @@ int main(int argc, char **argv)
for (i = 0; i < 1024; i++) {
bool pass = true;
 
-   if (!(sprs[i].access & SPR_OS_READ))
+   if (!spr_read_perms(i))
continue;
 
if (sprs[i].width == 32) {
-- 
2.42.0



[kvm-unit-tests PATCH v7 17/35] powerpc: Fix emulator illegal instruction test for powernv

2024-03-19 Thread Nicholas Piggin
Illegal instructions cause 0xe40 (HEAI) interrupts rather
than program interrupts.

Acked-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h |  1 +
 lib/powerpc/setup.c | 13 +
 powerpc/emulator.c  | 16 
 3 files changed, 30 insertions(+)

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index 9d8061962..cf1b9d8ff 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -11,6 +11,7 @@ void do_handle_exception(struct pt_regs *regs);
 #endif /* __ASSEMBLY__ */
 
 extern bool cpu_has_hv;
+extern bool cpu_has_heai;
 
 static inline uint64_t mfspr(int nr)
 {
diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index 89e5157f2..3c81aee9e 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -87,6 +87,7 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
 }
 
 bool cpu_has_hv;
+bool cpu_has_heai;
 
 static void cpu_init(void)
 {
@@ -108,6 +109,18 @@ static void cpu_init(void)
hcall(H_SET_MODE, 0, 4, 0, 0);
 #endif
}
+
+   switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
+   case PVR_VER_POWER10:
+   case PVR_VER_POWER9:
+   case PVR_VER_POWER8E:
+   case PVR_VER_POWER8NVL:
+   case PVR_VER_POWER8:
+   cpu_has_heai = true;
+   break;
+   default:
+   break;
+   }
 }
 
 static void mem_init(phys_addr_t freemem_start)
diff --git a/powerpc/emulator.c b/powerpc/emulator.c
index 39dd59645..af5174944 100644
--- a/powerpc/emulator.c
+++ b/powerpc/emulator.c
@@ -31,6 +31,20 @@ static void program_check_handler(struct pt_regs *regs, void 
*opaque)
regs->nip += 4;
 }
 
+static void heai_handler(struct pt_regs *regs, void *opaque)
+{
+   int *data = opaque;
+
+   if (verbose) {
+   printf("Detected invalid instruction %#018lx: %08x\n",
+  regs->nip, *(uint32_t*)regs->nip);
+   }
+
+   *data = 8; /* Illegal instruction */
+
+   regs->nip += 4;
+}
+
 static void alignment_handler(struct pt_regs *regs, void *opaque)
 {
int *data = opaque;
@@ -363,6 +377,8 @@ int main(int argc, char **argv)
int i;
 
handle_exception(0x700, program_check_handler, (void *)_invalid);
+   if (cpu_has_heai)
+   handle_exception(0xe40, heai_handler, (void *)_invalid);
handle_exception(0x600, alignment_handler, (void *));
 
for (i = 1; i < argc; i++) {
-- 
2.42.0



[kvm-unit-tests PATCH v7 16/35] powerpc: Support powernv machine with QEMU TCG

2024-03-19 Thread Nicholas Piggin
Add support for QEMU's powernv machine. This uses standard firmware
(skiboot) rather than a minimal firmware shim.

Reviewed-by: Cédric Le Goater 
Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h | 23 +++
 lib/powerpc/asm/reg.h   |  4 ++
 lib/powerpc/hcall.c |  4 +-
 lib/powerpc/io.c| 27 -
 lib/powerpc/io.h|  6 +++
 lib/powerpc/processor.c | 37 ++
 lib/powerpc/setup.c | 14 +--
 lib/ppc64/asm/opal.h| 15 
 lib/ppc64/opal-calls.S  | 50 
 lib/ppc64/opal.c| 76 +
 powerpc/Makefile.ppc64  |  2 +
 powerpc/cstart64.S  |  7 
 powerpc/run | 42 
 powerpc/unittests.cfg   | 10 -
 14 files changed, 301 insertions(+), 16 deletions(-)
 create mode 100644 lib/ppc64/asm/opal.h
 create mode 100644 lib/ppc64/opal-calls.S
 create mode 100644 lib/ppc64/opal.c

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index e415f9235..9d8061962 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -10,6 +10,8 @@ void handle_exception(int trap, void (*func)(struct pt_regs 
*, void *), void *);
 void do_handle_exception(struct pt_regs *regs);
 #endif /* __ASSEMBLY__ */
 
+extern bool cpu_has_hv;
+
 static inline uint64_t mfspr(int nr)
 {
uint64_t ret;
@@ -38,4 +40,25 @@ static inline void mtmsr(uint64_t msr)
asm volatile ("mtmsrd %[msr]" :: [msr] "r" (msr) : "memory");
 }
 
+/*
+ * This returns true on PowerNV / OPAL machines which run in hypervisor
+ * mode. False on pseries / PAPR machines that run in guest mode.
+ */
+static inline bool machine_is_powernv(void)
+{
+   return cpu_has_hv;
+}
+
+/*
+ * This returns true on pseries / PAPR / KVM machines which run under a
+ * hypervisor or QEMU pseries machine. False for PowerNV / OPAL.
+ */
+static inline bool machine_is_pseries(void)
+{
+   return !machine_is_powernv();
+}
+
+void enable_mcheck(void);
+void disable_mcheck(void);
+
 #endif /* _ASMPOWERPC_PROCESSOR_H_ */
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index c80b32059..782e75527 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -30,7 +30,11 @@
 #define   MMCR0_PMAO   UL(0x0080)
 
 /* Machine State Register definitions: */
+#define MSR_LE_BIT 0
 #define MSR_EE_BIT 15  /* External Interrupts Enable */
+#define MSR_HV_BIT 60  /* Hypervisor mode */
 #define MSR_SF_BIT 63  /* 64-bit mode */
 
+#define MSR_ME UL(0x1000)
+
 #endif
diff --git a/lib/powerpc/hcall.c b/lib/powerpc/hcall.c
index b4d39ac65..45f201315 100644
--- a/lib/powerpc/hcall.c
+++ b/lib/powerpc/hcall.c
@@ -25,7 +25,7 @@ int hcall_have_broken_sc1(void)
return r3 == (unsigned long)H_PRIVILEGE;
 }
 
-void putchar(int c)
+void papr_putchar(int c)
 {
unsigned long vty = 0;  /* 0 == default */
unsigned long nr_chars = 1;
@@ -34,7 +34,7 @@ void putchar(int c)
hcall(H_PUT_TERM_CHAR, vty, nr_chars, chars);
 }
 
-int __getchar(void)
+int __papr_getchar(void)
 {
register unsigned long r3 asm("r3") = H_GET_TERM_CHAR;
register unsigned long r4 asm("r4") = 0; /* 0 == default vty */
diff --git a/lib/powerpc/io.c b/lib/powerpc/io.c
index a381688bc..ab7bb843c 100644
--- a/lib/powerpc/io.c
+++ b/lib/powerpc/io.c
@@ -9,13 +9,33 @@
 #include 
 #include 
 #include 
+#include 
 #include "io.h"
 
 static struct spinlock print_lock;
 
+void putchar(int c)
+{
+   if (machine_is_powernv())
+   opal_putchar(c);
+   else
+   papr_putchar(c);
+}
+
+int __getchar(void)
+{
+   if (machine_is_powernv())
+   return __opal_getchar();
+   else
+   return __papr_getchar();
+}
+
 void io_init(void)
 {
-   rtas_init();
+   if (machine_is_powernv())
+   assert(!opal_init());
+   else
+   rtas_init();
 }
 
 void puts(const char *s)
@@ -38,7 +58,10 @@ void exit(int code)
 // FIXME: change this print-exit/rtas-poweroff to chr_testdev_exit(),
 //maybe by plugging chr-testdev into a spapr-vty.
printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1);
-   rtas_power_off();
+   if (machine_is_powernv())
+   opal_power_off();
+   else
+   rtas_power_off();
halt(code);
__builtin_unreachable();
 }
diff --git a/lib/powerpc/io.h b/lib/powerpc/io.h
index d4f21ba15..943bf142b 100644
--- a/lib/powerpc/io.h
+++ b/lib/powerpc/io.h
@@ -8,6 +8,12 @@
 #define _POWERPC_IO_H_
 
 extern void io_init(void);
+extern int opal_init(void);
+extern void opal_power_off(void);
 extern void putchar(int c);
+extern void opal_putchar(int c);
+extern void papr_putchar(int c);
+extern int __opal_getchar(void);
+extern int __papr_getchar(void);
 
 #endif
diff --git 

[kvm-unit-tests PATCH v7 15/35] scripts: Accommodate powerpc powernv machine differences

2024-03-19 Thread Nicholas Piggin
The QEMU powerpc powernv machine has minor differences that must be
accommodated for in output parsing:

- Summary parsing must search more lines of output for the summary
  line, to accommodate OPAL message on shutdown.
- Premature failure testing must tolerate case differences in kernel
  load error message.

Acked-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 powerpc/unittests.cfg | 1 +
 scripts/runtime.bash  | 6 --
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index 432c81d58..4929e71a1 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -4,6 +4,7 @@
 # powerpc specifics:
 #
 # file = .elf # powerpc uses .elf files
+# machine = pseries|powernv
 ##
 
 #
diff --git a/scripts/runtime.bash b/scripts/runtime.bash
index a66940ead..e4ad1962f 100644
--- a/scripts/runtime.bash
+++ b/scripts/runtime.bash
@@ -9,7 +9,7 @@ FAIL() { echo -ne "\e[31mFAIL\e[0m"; }
 extract_summary()
 {
 local cr=$'\r'
-tail -3 | grep '^SUMMARY: ' | sed 's/^SUMMARY: /(/;s/'"$cr"'\{0,1\}$/)/'
+tail -5 | grep '^SUMMARY: ' | sed 's/^SUMMARY: /(/;s/'"$cr"'\{0,1\}$/)/'
 }
 
 # We assume that QEMU is going to work if it tried to load the kernel
@@ -18,7 +18,9 @@ premature_failure()
 local log="$(eval "$(get_cmdline _NO_FILE_4Uhere_)" 2>&1)"
 
 echo "$log" | grep "_NO_FILE_4Uhere_" |
-grep -q -e "could not \(load\|open\) kernel" -e "error loading" -e 
"failed to load" &&
+grep -q -e "[Cc]ould not \(load\|open\) kernel" \
+-e "error loading" \
+-e "failed to load" &&
 return 1
 
 RUNTIME_log_stderr <<< "$log"
-- 
2.42.0



[kvm-unit-tests PATCH v7 14/35] scripts: allow machine option to be specified in unittests.cfg

2024-03-19 Thread Nicholas Piggin
This allows different machines with different requirements to be
supported by run_tests.sh, similarly to how different accelerators
are handled.

Acked-by: Thomas Huth 
Acked-by: Andrew Jones 
Signed-off-by: Nicholas Piggin 
---
 docs/unittests.txt   |  6 ++
 scripts/common.bash  |  8 ++--
 scripts/runtime.bash | 16 
 3 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/docs/unittests.txt b/docs/unittests.txt
index 53e02077c..5b184723c 100644
--- a/docs/unittests.txt
+++ b/docs/unittests.txt
@@ -42,6 +42,12 @@ For / directories that support multiple architectures, 
this restricts
 the test to the specified arch. By default, the test will run on any
 architecture.
 
+machine
+---
+For those architectures that support multiple machine types, this allows
+machine-specific tests to be created. By default, the test will run on
+any machine type.
+
 smp
 ---
 smp = 
diff --git a/scripts/common.bash b/scripts/common.bash
index b9413d683..ee1dd8659 100644
--- a/scripts/common.bash
+++ b/scripts/common.bash
@@ -10,6 +10,7 @@ function for_each_unittest()
local opts
local groups
local arch
+   local machine
local check
local accel
local timeout
@@ -21,7 +22,7 @@ function for_each_unittest()
if [[ "$line" =~ ^\[(.*)\]$ ]]; then
rematch=${BASH_REMATCH[1]}
if [ -n "${testname}" ]; then
-   $(arch_cmd) "$cmd" "$testname" "$groups" "$smp" 
"$kernel" "$opts" "$arch" "$check" "$accel" "$timeout"
+   $(arch_cmd) "$cmd" "$testname" "$groups" "$smp" 
"$kernel" "$opts" "$arch" "$machine" "$check" "$accel" "$timeout"
fi
testname=$rematch
smp=1
@@ -29,6 +30,7 @@ function for_each_unittest()
opts=""
groups=""
arch=""
+   machine=""
check=""
accel=""
timeout=""
@@ -58,6 +60,8 @@ function for_each_unittest()
groups=${BASH_REMATCH[1]}
elif [[ $line =~ ^arch\ *=\ *(.*)$ ]]; then
arch=${BASH_REMATCH[1]}
+   elif [[ $line =~ ^machine\ *=\ *(.*)$ ]]; then
+   machine=${BASH_REMATCH[1]}
elif [[ $line =~ ^check\ *=\ *(.*)$ ]]; then
check=${BASH_REMATCH[1]}
elif [[ $line =~ ^accel\ *=\ *(.*)$ ]]; then
@@ -67,7 +71,7 @@ function for_each_unittest()
fi
done
if [ -n "${testname}" ]; then
-   $(arch_cmd) "$cmd" "$testname" "$groups" "$smp" "$kernel" 
"$opts" "$arch" "$check" "$accel" "$timeout"
+   $(arch_cmd) "$cmd" "$testname" "$groups" "$smp" "$kernel" 
"$opts" "$arch" "$machine" "$check" "$accel" "$timeout"
fi
exec {fd}<&-
 }
diff --git a/scripts/runtime.bash b/scripts/runtime.bash
index 255e756f2..a66940ead 100644
--- a/scripts/runtime.bash
+++ b/scripts/runtime.bash
@@ -30,7 +30,7 @@ premature_failure()
 get_cmdline()
 {
 local kernel=$1
-echo "TESTNAME=$testname TIMEOUT=$timeout ACCEL=$accel $RUNTIME_arch_run 
$kernel -smp $smp $opts"
+echo "TESTNAME=$testname TIMEOUT=$timeout MACHINE=$machine ACCEL=$accel 
$RUNTIME_arch_run $kernel -smp $smp $opts"
 }
 
 skip_nodefault()
@@ -78,9 +78,10 @@ function run()
 local kernel="$4"
 local opts="$5"
 local arch="$6"
-local check="${CHECK:-$7}"
-local accel="$8"
-local timeout="${9:-$TIMEOUT}" # unittests.cfg overrides the default
+local machine="$7"
+local check="${CHECK:-$8}"
+local accel="$9"
+local timeout="${10:-$TIMEOUT}" # unittests.cfg overrides the default
 
 if [ "${CONFIG_EFI}" == "y" ]; then
 kernel=${kernel/%.flat/.efi}
@@ -114,6 +115,13 @@ function run()
 return 2
 fi
 
+if [ -n "$machine" ] && [ -n "$MACHINE" ] && [ "$machine" != "$MACHINE" ]; 
then
+print_result "SKIP" $testname "" "$machine only"
+return 2
+elif [ -n "$MACHINE" ]; then
+machine="$MACHINE"
+fi
+
 if [ -n "$accel" ] && [ -n "$ACCEL" ] && [ "$accel" != "$ACCEL" ]; then
 print_result "SKIP" $testname "" "$accel only, but ACCEL=$ACCEL"
 return 2
-- 
2.42.0



[kvm-unit-tests PATCH v7 13/35] doc: start documentation directory with unittests.cfg doc

2024-03-19 Thread Nicholas Piggin
Consolidate unittests.cfg documentation in one place.

Suggested-by: Andrew Jones 
Signed-off-by: Nicholas Piggin 
---
 arm/unittests.cfg | 26 ++---
 docs/unittests.txt| 89 +++
 powerpc/unittests.cfg | 25 ++--
 riscv/unittests.cfg   | 26 ++---
 s390x/unittests.cfg   | 18 ++---
 x86/unittests.cfg | 26 ++---
 6 files changed, 107 insertions(+), 103 deletions(-)
 create mode 100644 docs/unittests.txt

diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index fe601cbb1..54cedea28 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -1,28 +1,10 @@
 ##
 # unittest configuration
 #
-# [unittest_name]
-# file = .flat   # Name of the flat file to be used.
-# smp  =  # Number of processors the VM will use
-#  # during this test. Use $MAX_SMP to use
-#  # the maximum the host supports. Defaults
-#  # to one.
-# extra_params = -append# Additional parameters used.
-# arch = arm|arm64 # Select one if the test case is
-#  # specific to only one.
-# groups =   ... # Used to identify test cases
-#  # with run_tests -g ...
-#  # Specify group_name=nodefault
-#  # to have test not run by
-#  # default
-# accel = kvm|tcg  # Optionally specify if test must run with
-#  # kvm or tcg. If not specified, then kvm will
-#  # be used when available.
-# timeout =  # Optionally specify a timeout.
-# check = = # check a file for a particular value before running
-## a test. The check line can contain multiple files
-## to check separated by a space but each check
-## parameter needs to be of the form =
+# arm specifics:
+#
+# file = .flat# arm uses .flat files
+# arch = arm|arm64
 ##
 
 #
diff --git a/docs/unittests.txt b/docs/unittests.txt
new file mode 100644
index 0..53e02077c
--- /dev/null
+++ b/docs/unittests.txt
@@ -0,0 +1,89 @@
+unittests
+*
+
+run_tests.sh is driven by the /unittests.cfg file. That file defines
+test cases by specifying an executable (target image) under the /
+directory, and how to run it. This way, for example, a single file can
+provide multiple test cases by being run with different host configurations
+and/or different parameters passed to it.
+
+Detailed output from run_tests.sh unit tests are stored in files under
+the logs/ directory.
+
+unittests.cfg format
+
+
+# is the comment symbol, all following contents of the line is ignored.
+
+Each unit test is defined as with a [unit-test-name] line, followed by
+a set of parameters that control how the test case is run. The name is
+arbitrary and appears in the status reporting output.
+
+Parameters appear on their own lines under the test name, and have a
+param = value format.
+
+Available parameters
+
+Note! Some parameters like smp and extra_params modify how a test is run,
+while others like arch and accel restrict the configurations in which the
+test is run.
+
+file
+
+file = 
+
+This parameter is mandatory and specifies which binary under the /
+directory to run. Typically this is .flat or .elf, depending
+on the arch. The directory name is not included, only the file name.
+
+arch
+
+For / directories that support multiple architectures, this restricts
+the test to the specified arch. By default, the test will run on any
+architecture.
+
+smp
+---
+smp = 
+
+Optional, the number of processors created in the machine to run the test.
+Defaults to 1. $MAX_SMP can be used to specify the maximum supported.
+
+extra_params
+
+These are extra parameters supplied to the QEMU process. -append '...' can
+be used to pass arguments into the test case argv. Multiple parameters can
+be added, for example:
+
+extra_params = -m 256 -append 'smp=2'
+
+groups
+--
+groups =   ...
+
+Used to group the test cases for the `run_tests.sh -g ...` run group
+option. Adding a test to the nodefault group will cause it to not be
+run by default.
+
+accel
+-
+accel = kvm|tcg
+
+This restricts the test to the specified accelerator. By default, the
+test will run on either accelerator. (Note, the accelerator can be
+specified with ACCEL= environment variable, and defaults to KVM if
+available).
+
+timeout
+---
+timeout = 
+
+Optional timeout in seconds, after which the test will be killed and fail.
+
+check
+-
+check = =<
+
+Check a file for a 

[kvm-unit-tests PATCH v7 12/35] powerpc/sprs: Avoid taking PMU interrupts caused by register fuzzing

2024-03-19 Thread Nicholas Piggin
Storing certain values in MMCR0 can cause PMU interrupts when msleep
enables MSR[EE], and this crashes the test. Freeze the PMU counters
and clear any PMU exception before calling msleep.

Reviewed-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/reg.h |  4 
 powerpc/sprs.c| 17 +++--
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 1f991288e..c80b32059 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -24,6 +24,10 @@
 #define   PVR_VER_POWER10  UL(0x0080)
 #define SPR_HSRR0  0x13a
 #define SPR_HSRR1  0x13b
+#define SPR_MMCR0  0x31b
+#define   MMCR0_FC UL(0x8000)
+#define   MMCR0_PMAE   UL(0x0400)
+#define   MMCR0_PMAO   UL(0x0080)
 
 /* Machine State Register definitions: */
 #define MSR_EE_BIT 15  /* External Interrupts Enable */
diff --git a/powerpc/sprs.c b/powerpc/sprs.c
index 44edd0d7b..cb1d6c980 100644
--- a/powerpc/sprs.c
+++ b/powerpc/sprs.c
@@ -476,12 +476,7 @@ static void set_sprs(uint64_t val)
continue;
if (sprs[i].type & SPR_HARNESS)
continue;
-   if (!strcmp(sprs[i].name, "MMCR0")) {
-   /* XXX: could use a comment or better abstraction! */
-   __mtspr(i, (val & 0xfbab3fffULL) | 0xfa0b2070);
-   } else {
-   __mtspr(i, val);
-   }
+   __mtspr(i, val);
}
 }
 
@@ -538,6 +533,16 @@ int main(int argc, char **argv)
if (sprs[895].name)
before[895] = mfspr(895);
} else {
+   /*
+* msleep will enable MSR[EE] and take a decrementer
+* interrupt. Must account for changed registers and
+* prevent taking unhandled interrupts.
+*/
+   /* Prevent PMU interrupt */
+   mtspr(SPR_MMCR0, (mfspr(SPR_MMCR0) | MMCR0_FC) &
+   ~(MMCR0_PMAO | MMCR0_PMAE));
+   before[SPR_MMCR0] = mfspr(SPR_MMCR0);
+   before[779] = mfspr(SPR_MMCR0);
msleep(2000);
 
/* Reload regs changed by dec interrupt */
-- 
2.42.0



[kvm-unit-tests PATCH v7 11/35] powerpc/sprs: Specify SPRs with data rather than code

2024-03-19 Thread Nicholas Piggin
A significant rework that builds an array of 'struct spr', where each
element describes an SPR. This makes various metadata about the SPR
like name and access type easier to carry and use.

Hypervisor privileged registers are described despite not being used
at the moment for completeness, but also the code might one day be
reused for a hypervisor-privileged test.

Acked-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/reg.h |   2 +
 powerpc/sprs.c| 647 +-
 2 files changed, 457 insertions(+), 192 deletions(-)

diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 6810c1d82..1f991288e 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -5,6 +5,8 @@
 
 #define UL(x) _AC(x, UL)
 
+#define SPR_SRR0   0x01a
+#define SPR_SRR1   0x01b
 #define SPR_TB 0x10c
 #define SPR_SPRG0  0x110
 #define SPR_SPRG1  0x111
diff --git a/powerpc/sprs.c b/powerpc/sprs.c
index a19d80a1a..44edd0d7b 100644
--- a/powerpc/sprs.c
+++ b/powerpc/sprs.c
@@ -30,229 +30,458 @@
 #include 
 #include 
 
-uint64_t before[1024], after[1024];
-
-/* Common SPRs for all PowerPC CPUs */
-static void set_sprs_common(uint64_t val)
+/* "Indirect" mfspr/mtspr which accept a non-constant spr number */
+static uint64_t __mfspr(unsigned spr)
 {
-   mtspr(9, val);  /* CTR */
-   // mtspr(273, val); /* SPRG1 */  /* Used by our exception handler */
-   mtspr(274, val);/* SPRG2 */
-   mtspr(275, val);/* SPRG3 */
+   uint64_t tmp;
+   uint64_t ret;
+
+   asm volatile(
+"  bcl 20, 31, 1f  \n"
+"1:mflr%0  \n"
+"  addi%0, %0, (2f-1b) \n"
+"  add %0, %0, %2  \n"
+"  mtctr   %0  \n"
+"  bctr\n"
+"2:\n"
+".LSPR=0   \n"
+".rept 1024\n"
+"  mfspr   %1, .LSPR   \n"
+"  b   3f  \n"
+"  .LSPR=.LSPR+1   \n"
+".endr \n"
+"3:\n"
+   : "="(tmp),
+ "=r"(ret)
+   : "r"(spr*8) /* 8 bytes per 'mfspr ; b' block */
+   : "lr", "ctr");
+
+   return ret;
 }
 
-/* SPRs from PowerPC Operating Environment Architecture, Book III, Vers. 2.01 
*/
-static void set_sprs_book3s_201(uint64_t val)
+static void __mtspr(unsigned spr, uint64_t val)
 {
-   mtspr(18, val); /* DSISR */
-   mtspr(19, val); /* DAR */
-   mtspr(152, val);/* CTRL */
-   mtspr(256, val);/* VRSAVE */
-   mtspr(786, val);/* MMCRA */
-   mtspr(795, val);/* MMCR0 */
-   mtspr(798, val);/* MMCR1 */
+   uint64_t tmp;
+
+   asm volatile(
+"  bcl 20, 31, 1f  \n"
+"1:mflr%0  \n"
+"  addi%0, %0, (2f-1b) \n"
+"  add %0, %0, %2  \n"
+"  mtctr   %0  \n"
+"  bctr\n"
+"2:\n"
+".LSPR=0   \n"
+".rept 1024\n"
+"  mtspr   .LSPR, %1   \n"
+"  b   3f  \n"
+"  .LSPR=.LSPR+1   \n"
+".endr \n"
+"3:\n"
+   : "="(tmp)
+   : "r"(val),
+ "r"(spr*8) /* 8 bytes per 'mfspr ; b' block */
+   : "lr", "ctr", "xer");
 }
 
+static uint64_t before[1024], after[1024];
+
+#define SPR_PR_READ0x0001
+#define SPR_PR_WRITE   0x0002
+#define SPR_OS_READ0x0010
+#define SPR_OS_WRITE   0x0020
+#define SPR_HV_READ0x0100
+#define SPR_HV_WRITE   0x0200
+
+#define RW 0x333
+#define RO 0x111
+#define WO 0x222
+#define OS_RW  0x330
+#define OS_RO  0x110
+#define OS_WO  0x220
+#define HV_RW  0x300
+#define HV_RO  0x100
+#define HV_WO  0x200
+
+#define SPR_ASYNC  0x1000  /* May be updated asynchronously */
+#define SPR_INT0x2000  /* May be updated by synchronous 
interrupt */
+#define SPR_HARNESS0x4000  /* Test harness uses the register */
+
+struct spr {
+   const char  *name;
+   uint8_t width;
+   uint16_taccess;
+   uint16_ttype;
+};
+
+/* SPRs common denominator back to PowerPC Operating Environment Architecture 
*/
+static const struct spr sprs_common[1024] = {
+  [1] = { "XER",   64, RW, SPR_HARNESS, }, /* Used by 
compiler */
+  [8] = { "LR",64, RW, SPR_HARNESS, }, /* Compiler, 
mfspr/mtspr */
+  [9] = { "CTR",   64, RW, SPR_HARNESS, }, /* Compiler, 
mfspr/mtspr */
+ [18] = { "DSISR", 32, OS_RW,  SPR_INT, },
+ 

[kvm-unit-tests PATCH v7 10/35] powerpc: interrupt stack backtracing

2024-03-19 Thread Nicholas Piggin
Add support for backtracing across interrupt stacks, and add
interrupt frame backtrace for unhandled interrupts.

This requires a back-chain created from initial interrupt stack
frame to the r1 value of the interrupted context. A label is
added at the return location of the exception handler call, so
the unwinder can recognize the initial interrupt frame.

The additional cstart entry-frame is no longer required because
the unwinder now looks for frame == 0 as well as address == 0.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/processor.c |  4 +++-
 lib/ppc64/asm/stack.h   |  3 +++
 lib/ppc64/stack.c   | 53 +
 powerpc/Makefile.ppc64  |  1 +
 powerpc/cstart64.S  | 15 +++-
 5 files changed, 63 insertions(+), 13 deletions(-)
 create mode 100644 lib/ppc64/stack.c

diff --git a/lib/powerpc/processor.c b/lib/powerpc/processor.c
index ad0d95666..114584024 100644
--- a/lib/powerpc/processor.c
+++ b/lib/powerpc/processor.c
@@ -51,7 +51,9 @@ void do_handle_exception(struct pt_regs *regs)
return;
}
 
-   printf("unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", 
regs->trap, regs->nip, regs->msr);
+   printf("Unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n",
+   regs->trap, regs->nip, regs->msr);
+   dump_frame_stack((void *)regs->nip, (void *)regs->gpr[1]);
abort();
 }
 
diff --git a/lib/ppc64/asm/stack.h b/lib/ppc64/asm/stack.h
index 9734bbb8f..94fd1021c 100644
--- a/lib/ppc64/asm/stack.h
+++ b/lib/ppc64/asm/stack.h
@@ -5,4 +5,7 @@
 #error Do not directly include . Just use .
 #endif
 
+#define HAVE_ARCH_BACKTRACE
+#define HAVE_ARCH_BACKTRACE_FRAME
+
 #endif
diff --git a/lib/ppc64/stack.c b/lib/ppc64/stack.c
new file mode 100644
index 0..e6f259de7
--- /dev/null
+++ b/lib/ppc64/stack.c
@@ -0,0 +1,53 @@
+#include 
+#include 
+#include 
+
+extern char do_handle_exception_return[];
+
+int arch_backtrace_frame(const void *frame, const void **return_addrs,
+int max_depth, bool current_frame)
+{
+   static int walking;
+   int depth = 0;
+   const unsigned long *bp = (unsigned long *)frame;
+   void *return_addr;
+
+   asm volatile("" ::: "lr"); /* Force it to save LR */
+
+   if (walking) {
+   printf("RECURSIVE STACK WALK!!!\n");
+   return 0;
+   }
+   walking = 1;
+
+   if (current_frame)
+   bp = __builtin_frame_address(0);
+
+   bp = (unsigned long *)bp[0];
+   return_addr = (void *)bp[2];
+
+   for (depth = 0; bp && depth < max_depth; depth++) {
+   return_addrs[depth] = return_addr;
+   if (return_addrs[depth] == 0)
+   break;
+   if (return_addrs[depth] == do_handle_exception_return) {
+   struct pt_regs *regs;
+
+   regs = (void *)bp + STACK_FRAME_OVERHEAD;
+   bp = (unsigned long *)bp[0];
+   /* Represent interrupt frame with vector number */
+   return_addr = (void *)regs->trap;
+   if (depth + 1 < max_depth) {
+   depth++;
+   return_addrs[depth] = return_addr;
+   return_addr = (void *)regs->nip;
+   }
+   } else {
+   bp = (unsigned long *)bp[0];
+   return_addr = (void *)bp[2];
+   }
+   }
+
+   walking = 0;
+   return depth;
+}
diff --git a/powerpc/Makefile.ppc64 b/powerpc/Makefile.ppc64
index b0ed2b104..eb682c226 100644
--- a/powerpc/Makefile.ppc64
+++ b/powerpc/Makefile.ppc64
@@ -17,6 +17,7 @@ cstart.o = $(TEST_DIR)/cstart64.o
 reloc.o  = $(TEST_DIR)/reloc64.o
 
 OBJDIRS += lib/ppc64
+cflatobjs += lib/ppc64/stack.o
 
 # ppc64 specific tests
 tests = $(TEST_DIR)/spapr_vpa.elf
diff --git a/powerpc/cstart64.S b/powerpc/cstart64.S
index 80baabe8f..07d297f61 100644
--- a/powerpc/cstart64.S
+++ b/powerpc/cstart64.S
@@ -51,16 +51,6 @@ start:
std r0,0(r1)
std r0,16(r1)
 
-   /*
-* Create entry frame of 64-bytes, same as the initial frame. A callee
-* may use the caller frame to store LR, and backtrace() termination
-* looks for return address == NULL, so the initial stack frame can't
-* be used to call C or else it could overwrite the zeroed LR save slot
-* and break backtrace termination.  This frame would be unnecessary if
-* backtrace looked for a zeroed frame address.
-*/
-   stdur1,-64(r1)
-
/* save DTB pointer */
std r3, 56(r1)
 
@@ -195,6 +185,7 @@ call_handler:
.endr
mfsprg1 r0
std r0,GPR1(r1)
+   std r0,0(r1) /* Backchain from interrupt stack to regular stack */
 
/* lr, xer, ccr */
 
@@ -213,12 +204,12 @@ call_handler:
subir31, 

[kvm-unit-tests PATCH v7 09/35] powerpc: Fix stack backtrace termination

2024-03-19 Thread Nicholas Piggin
The backtrace handler terminates when it sees a NULL caller address,
but the powerpc stack setup does not keep such a NULL caller frame
at the start of the stack.

This happens to work on pseries because the memory at 0 is mapped and
it contains 0 at the location of the return address pointer if it
were a stack frame. But this is fragile, and does not work with powernv
where address 0 contains firmware instructions.

Use the existing dummy frame on stack as the NULL caller, and create a
new frame on stack for the entry code.

Signed-off-by: Nicholas Piggin 
---
 powerpc/cstart64.S | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/powerpc/cstart64.S b/powerpc/cstart64.S
index e18ae9a22..80baabe8f 100644
--- a/powerpc/cstart64.S
+++ b/powerpc/cstart64.S
@@ -46,6 +46,21 @@ start:
add r1, r1, r31
add r2, r2, r31
 
+   /* Zero backpointers in initial stack frame so backtrace() stops */
+   li  r0,0
+   std r0,0(r1)
+   std r0,16(r1)
+
+   /*
+* Create entry frame of 64-bytes, same as the initial frame. A callee
+* may use the caller frame to store LR, and backtrace() termination
+* looks for return address == NULL, so the initial stack frame can't
+* be used to call C or else it could overwrite the zeroed LR save slot
+* and break backtrace termination.  This frame would be unnecessary if
+* backtrace looked for a zeroed frame address.
+*/
+   stdur1,-64(r1)
+
/* save DTB pointer */
std r3, 56(r1)
 
-- 
2.42.0



[kvm-unit-tests PATCH v7 08/35] powerpc: Fix KVM caps on POWER9 hosts

2024-03-19 Thread Nicholas Piggin
KVM does not like to run on POWER9 hosts without cap-ccf-assist=off.

Reviewed-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 powerpc/run | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/powerpc/run b/powerpc/run
index e469f1eb3..5cdb94194 100755
--- a/powerpc/run
+++ b/powerpc/run
@@ -24,6 +24,8 @@ M+=",accel=$ACCEL$ACCEL_PROPS"
 
 if [[ "$ACCEL" == "tcg" ]] ; then
M+=",cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken,cap-ccf-assist=off"
+elif [[ "$ACCEL" == "kvm" ]] ; then
+   M+=",cap-ccf-assist=off"
 fi
 
 command="$qemu -nodefaults $M -bios $FIRMWARE"
-- 
2.42.0



[kvm-unit-tests PATCH v7 07/35] common: add memory dirtying vs migration test

2024-03-19 Thread Nicholas Piggin
This test stores to a bunch of pages and verifies previous stores,
while being continually migrated. Default runtime is 5 seconds.

Add this test to ppc64 and s390x builds. This can fail due to a QEMU
TCG physical memory dirty bitmap bug, so it is not enabled in unittests
for TCG yet.

The selftest-migration test time is reduced significantly because
this test

Signed-off-by: Nicholas Piggin 
---
 common/memory-verify.c  | 67 +
 common/selftest-migration.c |  8 ++---
 powerpc/Makefile.common |  1 +
 powerpc/memory-verify.c |  1 +
 powerpc/unittests.cfg   |  7 
 s390x/Makefile  |  1 +
 s390x/memory-verify.c   |  1 +
 s390x/unittests.cfg |  6 
 8 files changed, 88 insertions(+), 4 deletions(-)
 create mode 100644 common/memory-verify.c
 create mode 12 powerpc/memory-verify.c
 create mode 12 s390x/memory-verify.c

diff --git a/common/memory-verify.c b/common/memory-verify.c
new file mode 100644
index 0..e78fb4338
--- /dev/null
+++ b/common/memory-verify.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Simple memory verification test, used to exercise dirty memory migration.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define NR_PAGES 32
+
+static unsigned time_sec = 5;
+
+static void do_getopts(int argc, char **argv)
+{
+   int i;
+
+   for (i = 0; i < argc; ++i) {
+   if (strcmp(argv[i], "-t") == 0) {
+   i++;
+   if (i == argc)
+   break;
+   time_sec = atol(argv[i]);
+   }
+   }
+
+   printf("running for %d secs\n", time_sec);
+}
+
+int main(int argc, char **argv)
+{
+   void *mem = malloc(NR_PAGES*PAGE_SIZE);
+   bool success = true;
+   uint64_t ms;
+   long i;
+
+   do_getopts(argc, argv);
+
+   report_prefix_push("memory");
+
+   memset(mem, 0, NR_PAGES*PAGE_SIZE);
+
+   migrate_begin_continuous();
+   ms = get_clock_ms();
+   i = 0;
+   do {
+   int j;
+
+   for (j = 0; j < NR_PAGES*PAGE_SIZE; j += PAGE_SIZE) {
+   if (*(volatile long *)(mem + j) != i) {
+   success = false;
+   goto out;
+   }
+   *(volatile long *)(mem + j) = i + 1;
+   }
+   i++;
+   } while (get_clock_ms() - ms < time_sec * 1000);
+out:
+   migrate_end_continuous();
+
+   report(success, "memory verification stress test");
+
+   report_prefix_pop();
+
+   return report_summary();
+}
diff --git a/common/selftest-migration.c b/common/selftest-migration.c
index 9a9b61835..3693148aa 100644
--- a/common/selftest-migration.c
+++ b/common/selftest-migration.c
@@ -11,7 +11,7 @@
 #include 
 #include 
 
-#define NR_MIGRATIONS 15
+#define NR_MIGRATIONS 5
 
 int main(int argc, char **argv)
 {
@@ -28,11 +28,11 @@ int main(int argc, char **argv)
report(true, "cooperative migration");
 
migrate_begin_continuous();
-   mdelay(2000);
-   migrate_end_continuous();
mdelay(1000);
+   migrate_end_continuous();
+   mdelay(500);
migrate_begin_continuous();
-   mdelay(2000);
+   mdelay(1000);
migrate_end_continuous();
report(true, "continuous migration");
}
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index da4a7bbb8..1e181da69 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -7,6 +7,7 @@
 tests-common = \
$(TEST_DIR)/selftest.elf \
$(TEST_DIR)/selftest-migration.elf \
+   $(TEST_DIR)/memory-verify.elf \
$(TEST_DIR)/spapr_hcall.elf \
$(TEST_DIR)/rtas.elf \
$(TEST_DIR)/emulator.elf \
diff --git a/powerpc/memory-verify.c b/powerpc/memory-verify.c
new file mode 12
index 0..5985c730f
--- /dev/null
+++ b/powerpc/memory-verify.c
@@ -0,0 +1 @@
+../common/memory-verify.c
\ No newline at end of file
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index cae4949e8..e65217c18 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -49,6 +49,13 @@ machine = pseries
 groups = selftest migration
 extra_params = -append "skip"
 
+# This fails due to a QEMU TCG bug so KVM-only until QEMU is fixed upstream
+[migration-memory]
+file = memory-verify.elf
+accel = kvm
+machine = pseries
+groups = migration
+
 [spapr_hcall]
 file = spapr_hcall.elf
 
diff --git a/s390x/Makefile b/s390x/Makefile
index 344d46d68..ddc0969f3 100644
--- a/s390x/Makefile
+++ b/s390x/Makefile
@@ -1,5 +1,6 @@
 tests = $(TEST_DIR)/selftest.elf
 tests += $(TEST_DIR)/selftest-migration.elf
+tests += $(TEST_DIR)/memory-verify.elf
 tests += $(TEST_DIR)/intercept.elf
 tests += $(TEST_DIR)/emulator.elf
 tests += $(TEST_DIR)/sieve.elf

[kvm-unit-tests PATCH v7 06/35] gitlab-ci: Run migration selftest on s390x and powerpc

2024-03-19 Thread Nicholas Piggin
The migration harness is complicated and easy to break so CI will
be helpful.

Signed-off-by: Nicholas Piggin 
---
 .gitlab-ci.yml  | 18 +++---
 s390x/unittests.cfg |  8 
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ff34b1f50..bd34da04f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -92,26 +92,28 @@ build-arm:
 build-ppc64be:
  extends: .outoftree_template
  script:
- - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu
+ - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu nmap-ncat
  - mkdir build
  - cd build
  - ../configure --arch=ppc64 --endian=big --cross-prefix=powerpc64-linux-gnu-
  - make -j2
  - ACCEL=tcg ./run_tests.sh
- selftest-setup spapr_hcall rtas-get-time-of-day rtas-get-time-of-day-base
- rtas-set-time-of-day emulator
+ selftest-setup selftest-migration selftest-migration-skip spapr_hcall
+ rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
+ emulator
  | tee results.txt
  - if grep -q FAIL results.txt ; then exit 1 ; fi
 
 build-ppc64le:
  extends: .intree_template
  script:
- - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu
+ - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu nmap-ncat
  - ./configure --arch=ppc64 --endian=little --cross-prefix=powerpc64-linux-gnu-
  - make -j2
  - ACCEL=tcg ./run_tests.sh
- selftest-setup spapr_hcall rtas-get-time-of-day rtas-get-time-of-day-base
- rtas-set-time-of-day emulator
+ selftest-setup selftest-migration selftest-migration-skip spapr_hcall
+ rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
+ emulator
  | tee results.txt
  - if grep -q FAIL results.txt ; then exit 1 ; fi
 
@@ -135,7 +137,7 @@ build-riscv64:
 build-s390x:
  extends: .outoftree_template
  script:
- - dnf install -y qemu-system-s390x gcc-s390x-linux-gnu
+ - dnf install -y qemu-system-s390x gcc-s390x-linux-gnu nmap-ncat
  - mkdir build
  - cd build
  - ../configure --arch=s390x --cross-prefix=s390x-linux-gnu-
@@ -161,6 +163,8 @@ build-s390x:
   sclp-1g
   sclp-3g
   selftest-setup
+  selftest-migration-kvm
+  selftest-migration-skip
   sieve
   smp
   stsi
diff --git a/s390x/unittests.cfg b/s390x/unittests.cfg
index 49e3e4608..b79b99416 100644
--- a/s390x/unittests.cfg
+++ b/s390x/unittests.cfg
@@ -31,6 +31,14 @@ groups = selftest migration
 # https://lore.kernel.org/qemu-devel/20240219061731.232570-1-npig...@gmail.com/
 accel = kvm
 
+[selftest-migration-kvm]
+file = selftest-migration.elf
+groups = nodefault
+accel = kvm
+# This is a special test for gitlab-ci that can must not use TCG until the
+# TCG migration fix has made its way into CI environment's QEMU.
+# https://lore.kernel.org/qemu-devel/20240219061731.232570-1-npig...@gmail.com/
+
 [selftest-migration-skip]
 file = selftest-migration.elf
 groups = selftest migration
-- 
2.42.0



[kvm-unit-tests PATCH v7 04/35] (arm|s390): Use migrate_skip in test cases

2024-03-19 Thread Nicholas Piggin
Have tests use the new migrate_skip command in skip paths, rather than
calling migrate_once to prevent harness reporting an error.

s390x/migration.c adds a new command that looks like it was missing
previously.

Reviewed-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 arm/gic.c  | 21 -
 s390x/migration-cmm.c  |  8 
 s390x/migration-skey.c |  4 +++-
 s390x/migration.c  |  1 +
 4 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/arm/gic.c b/arm/gic.c
index c950b0d15..bbf828f17 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -782,13 +782,15 @@ static void test_its_migration(void)
struct its_device *dev2, *dev7;
cpumask_t mask;
 
-   if (its_setup1())
+   if (its_setup1()) {
+   migrate_skip();
return;
+   }
 
dev2 = its_get_device(2);
dev7 = its_get_device(7);
 
-   migrate_once();
+   migrate();
 
stats_reset();
cpumask_clear();
@@ -819,8 +821,10 @@ static void test_migrate_unmapped_collection(void)
int pe0 = 0;
u8 config;
 
-   if (its_setup1())
+   if (its_setup1()) {
+   migrate_skip();
return;
+   }
 
if (!errata(ERRATA_UNMAPPED_COLLECTIONS)) {
report_skip("Skipping test, as this test hangs without the fix. 
"
@@ -836,7 +840,7 @@ static void test_migrate_unmapped_collection(void)
its_send_mapti(dev2, 8192, 0, col);
gicv3_lpi_set_config(8192, LPI_PROP_DEFAULT);
 
-   migrate_once();
+   migrate();
 
/* on the destination, map the collection */
its_send_mapc(col, true);
@@ -875,8 +879,10 @@ static void test_its_pending_migration(void)
void *ptr;
int i;
 
-   if (its_prerequisites(4))
+   if (its_prerequisites(4)) {
+   migrate_skip();
return;
+   }
 
dev = its_create_device(2 /* dev id */, 8 /* nb_ites */);
its_send_mapd(dev, true);
@@ -923,7 +929,7 @@ static void test_its_pending_migration(void)
gicv3_lpi_rdist_enable(pe0);
gicv3_lpi_rdist_enable(pe1);
 
-   migrate_once();
+   migrate();
 
/* let's wait for the 256 LPIs to be handled */
mdelay(1000);
@@ -970,17 +976,14 @@ int main(int argc, char **argv)
} else if (!strcmp(argv[1], "its-migration")) {
report_prefix_push(argv[1]);
test_its_migration();
-   migrate_once();
report_prefix_pop();
} else if (!strcmp(argv[1], "its-pending-migration")) {
report_prefix_push(argv[1]);
test_its_pending_migration();
-   migrate_once();
report_prefix_pop();
} else if (!strcmp(argv[1], "its-migrate-unmapped-collection")) {
report_prefix_push(argv[1]);
test_migrate_unmapped_collection();
-   migrate_once();
report_prefix_pop();
} else if (strcmp(argv[1], "its-introspection") == 0) {
report_prefix_push(argv[1]);
diff --git a/s390x/migration-cmm.c b/s390x/migration-cmm.c
index 43673f18e..b4043a80e 100644
--- a/s390x/migration-cmm.c
+++ b/s390x/migration-cmm.c
@@ -55,12 +55,12 @@ int main(void)
 {
report_prefix_push("migration-cmm");
 
-   if (!check_essa_available())
+   if (!check_essa_available()) {
report_skip("ESSA is not available");
-   else
+   migrate_skip();
+   } else {
test_migration();
-
-   migrate_once();
+   }
 
report_prefix_pop();
return report_summary();
diff --git a/s390x/migration-skey.c b/s390x/migration-skey.c
index 8d6d8ecfe..1a196ae1e 100644
--- a/s390x/migration-skey.c
+++ b/s390x/migration-skey.c
@@ -169,6 +169,7 @@ static void test_skey_migration_parallel(void)
 
if (smp_query_num_cpus() == 1) {
report_skip("need at least 2 cpus for this test");
+   migrate_skip();
goto error;
}
 
@@ -233,6 +234,7 @@ int main(int argc, char **argv)
 
if (test_facility(169)) {
report_skip("storage key removal facility is active");
+   migrate_skip();
goto error;
}
 
@@ -247,11 +249,11 @@ int main(int argc, char **argv)
break;
default:
print_usage();
+   migrate_skip();
break;
}
 
 error:
-   migrate_once();
report_prefix_pop();
return report_summary();
 }
diff --git a/s390x/migration.c b/s390x/migration.c
index 269e272de..115afb731 100644
--- a/s390x/migration.c
+++ b/s390x/migration.c
@@ -164,6 +164,7 @@ int main(void)
 
if (smp_query_num_cpus() == 1) {
report_skip("need at least 2 cpus for this test");
+   migrate_skip();
goto done;
}
 
-- 
2.42.0



[kvm-unit-tests PATCH v7 05/35] arch-run: Add a "continuous" migration option for tests

2024-03-19 Thread Nicholas Piggin
The cooperative migration protocol is very good to control precise
pre and post conditions for a migration event. However in some cases
its intrusiveness to the test program, can mask problems and make
analysis more difficult.

For example to stress test migration vs concurrent complicated
memory access, including TLB refill, ram dirtying, etc., then the
tight spin at getchar() and resumption of the workload after
migration is unhelpful.

This adds a continuous migration mode that directs the harness to
perform migrations continually. This is added to the migration
selftests, which also sees cooperative migration iterations reduced
to avoid increasing test time too much.

Signed-off-by: Nicholas Piggin 
---
 common/selftest-migration.c | 16 +--
 lib/migrate.c   | 18 
 lib/migrate.h   |  3 ++
 scripts/arch-run.bash   | 55 -
 4 files changed, 82 insertions(+), 10 deletions(-)

diff --git a/common/selftest-migration.c b/common/selftest-migration.c
index 0afd8581c..9a9b61835 100644
--- a/common/selftest-migration.c
+++ b/common/selftest-migration.c
@@ -9,12 +9,13 @@
  */
 #include 
 #include 
+#include 
 
-#define NR_MIGRATIONS 30
+#define NR_MIGRATIONS 15
 
 int main(int argc, char **argv)
 {
-   report_prefix_push("migration");
+   report_prefix_push("migration harness");
 
if (argc > 1 && !strcmp(argv[1], "skip")) {
migrate_skip();
@@ -24,7 +25,16 @@ int main(int argc, char **argv)
 
for (i = 0; i < NR_MIGRATIONS; i++)
migrate_quiet();
-   report(true, "simple harness stress");
+   report(true, "cooperative migration");
+
+   migrate_begin_continuous();
+   mdelay(2000);
+   migrate_end_continuous();
+   mdelay(1000);
+   migrate_begin_continuous();
+   mdelay(2000);
+   migrate_end_continuous();
+   report(true, "continuous migration");
}
 
report_prefix_pop();
diff --git a/lib/migrate.c b/lib/migrate.c
index 1d22196b7..770f76d5c 100644
--- a/lib/migrate.c
+++ b/lib/migrate.c
@@ -60,3 +60,21 @@ void migrate_skip(void)
puts("Skipped VM migration (quiet)\n");
(void)getchar();
 }
+
+void migrate_begin_continuous(void)
+{
+   puts("Begin continuous migration\n");
+   (void)getchar();
+}
+
+void migrate_end_continuous(void)
+{
+   /*
+* Migration can split this output between source and dest QEMU
+* output files, print twice and match once to always cope with
+* a split.
+*/
+   puts("End continuous migration\n");
+   puts("End continuous migration (quiet)\n");
+   (void)getchar();
+}
diff --git a/lib/migrate.h b/lib/migrate.h
index db6e0c501..35b6703a2 100644
--- a/lib/migrate.h
+++ b/lib/migrate.h
@@ -11,3 +11,6 @@ void migrate_quiet(void);
 void migrate_once(void);
 
 void migrate_skip(void);
+
+void migrate_begin_continuous(void);
+void migrate_end_continuous(void);
diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
index 4a1aab48d..1901a929f 100644
--- a/scripts/arch-run.bash
+++ b/scripts/arch-run.bash
@@ -125,15 +125,17 @@ qmp_events ()
 filter_quiet_msgs ()
 {
grep -v "Now migrate the VM (quiet)" |
+   grep -v "Begin continuous migration (quiet)" |
+   grep -v "End continuous migration (quiet)" |
grep -v "Skipped VM migration (quiet)"
 }
 
 seen_migrate_msg ()
 {
if [ $skip_migration -eq 1 ]; then
-   grep -q -e "Now migrate the VM" < $1
+   grep -q -e "Now migrate the VM" -e "Begin continuous migration" 
< $1
else
-   grep -q -e "Now migrate the VM" -e "Skipped VM migration" < $1
+   grep -q -e "Now migrate the VM" -e "Begin continuous migration" 
-e "Skipped VM migration" < $1
fi
 }
 
@@ -161,6 +163,7 @@ run_migration ()
src_qmpout=/dev/null
dst_qmpout=/dev/null
skip_migration=0
+   continuous_migration=0
 
mkfifo ${src_outfifo}
mkfifo ${dst_outfifo}
@@ -186,9 +189,12 @@ run_migration ()
do_migration || return $?
 
while ps -p ${live_pid} > /dev/null ; do
-   # Wait for test exit or further migration messages.
-   if ! seen_migrate_msg ${src_out} ;  then
+   if [ ${continuous_migration} -eq 1 ] ; then
+   do_migration || return $?
+   elif ! seen_migrate_msg ${src_out} ;  then
sleep 0.1
+   elif grep -q "Begin continuous migration" < ${src_out} ; then
+   do_migration || return $?
elif grep -q "Now migrate the VM" < ${src_out} ; then
do_migration || return $?
elif [ $skip_migration -eq 0 ] && grep -q "Skipped VM 
migration" < ${src_out} ; then
@@ -218,7 +224,7 @@ do_migration ()
 
# The test must 

[kvm-unit-tests PATCH v7 03/35] migration: Add a migrate_skip command

2024-03-19 Thread Nicholas Piggin
Tests that are run with MIGRATION=yes but skip due to some requirement
not being met will show as a failure due to the harness requirement to
see one successful migration. The workaround for this is to migrate in
test's skip path. Add a new command that just tells the harness to not
expect a migration.

Reviewed-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 common/selftest-migration.c | 14 -
 lib/migrate.c   | 19 -
 lib/migrate.h   |  2 ++
 powerpc/unittests.cfg   |  6 ++
 s390x/unittests.cfg |  5 +
 scripts/arch-run.bash   | 41 +
 6 files changed, 73 insertions(+), 14 deletions(-)

diff --git a/common/selftest-migration.c b/common/selftest-migration.c
index 54b5d6b2d..0afd8581c 100644
--- a/common/selftest-migration.c
+++ b/common/selftest-migration.c
@@ -14,14 +14,18 @@
 
 int main(int argc, char **argv)
 {
-   int i = 0;
-
report_prefix_push("migration");
 
-   for (i = 0; i < NR_MIGRATIONS; i++)
-   migrate_quiet();
+   if (argc > 1 && !strcmp(argv[1], "skip")) {
+   migrate_skip();
+   report(true, "migration skipping");
+   } else {
+   int i;
 
-   report(true, "simple harness stress test");
+   for (i = 0; i < NR_MIGRATIONS; i++)
+   migrate_quiet();
+   report(true, "simple harness stress");
+   }
 
report_prefix_pop();
 
diff --git a/lib/migrate.c b/lib/migrate.c
index 92d1d957d..1d22196b7 100644
--- a/lib/migrate.c
+++ b/lib/migrate.c
@@ -39,7 +39,24 @@ void migrate_once(void)
 
if (migrated)
return;
-
migrated = true;
+
migrate();
 }
+
+/*
+ * When the test has been started in migration mode, but the test case is
+ * skipped and no migration point is reached, this can be used to tell the
+ * harness not to mark it as a failure to migrate.
+ */
+void migrate_skip(void)
+{
+   static bool did_migrate_skip;
+
+   if (did_migrate_skip)
+   return;
+   did_migrate_skip = true;
+
+   puts("Skipped VM migration (quiet)\n");
+   (void)getchar();
+}
diff --git a/lib/migrate.h b/lib/migrate.h
index 95b9102b0..db6e0c501 100644
--- a/lib/migrate.h
+++ b/lib/migrate.h
@@ -9,3 +9,5 @@
 void migrate(void);
 void migrate_quiet(void);
 void migrate_once(void);
+
+void migrate_skip(void);
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index 1559bee98..cae4949e8 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -43,6 +43,12 @@ groups = selftest migration
 # https://lore.kernel.org/qemu-devel/20240219061731.232570-1-npig...@gmail.com/
 accel = kvm
 
+[selftest-migration-skip]
+file = selftest-migration.elf
+machine = pseries
+groups = selftest migration
+extra_params = -append "skip"
+
 [spapr_hcall]
 file = spapr_hcall.elf
 
diff --git a/s390x/unittests.cfg b/s390x/unittests.cfg
index dac9e4db1..49e3e4608 100644
--- a/s390x/unittests.cfg
+++ b/s390x/unittests.cfg
@@ -31,6 +31,11 @@ groups = selftest migration
 # https://lore.kernel.org/qemu-devel/20240219061731.232570-1-npig...@gmail.com/
 accel = kvm
 
+[selftest-migration-skip]
+file = selftest-migration.elf
+groups = selftest migration
+extra_params = -append "skip"
+
 [intercept]
 file = intercept.elf
 
diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
index 39419d4e2..4a1aab48d 100644
--- a/scripts/arch-run.bash
+++ b/scripts/arch-run.bash
@@ -124,12 +124,17 @@ qmp_events ()
 
 filter_quiet_msgs ()
 {
-   grep -v "Now migrate the VM (quiet)"
+   grep -v "Now migrate the VM (quiet)" |
+   grep -v "Skipped VM migration (quiet)"
 }
 
 seen_migrate_msg ()
 {
-   grep -q -e "Now migrate the VM" < $1
+   if [ $skip_migration -eq 1 ]; then
+   grep -q -e "Now migrate the VM" < $1
+   else
+   grep -q -e "Now migrate the VM" -e "Skipped VM migration" < $1
+   fi
 }
 
 run_migration ()
@@ -142,7 +147,7 @@ run_migration ()
migcmdline=$@
 
trap 'trap - TERM ; kill 0 ; exit 2' INT TERM
-   trap 'rm -f ${src_out} ${dst_out} ${src_outfifo} ${dst_outfifo} 
${dst_incoming} ${src_qmp} ${dst_qmp} ${dst_infifo}' RETURN EXIT
+   trap 'rm -f ${src_out} ${dst_out} ${src_outfifo} ${dst_outfifo} 
${dst_incoming} ${src_qmp} ${dst_qmp} ${src_infifo} ${dst_infifo}' RETURN EXIT
 
dst_incoming=$(mktemp -u -t mig-helper-socket-incoming.XX)
src_out=$(mktemp -t mig-helper-stdout1.XX)
@@ -151,21 +156,26 @@ run_migration ()
dst_outfifo=$(mktemp -u -t mig-helper-fifo-stdout2.XX)
src_qmp=$(mktemp -u -t mig-helper-qmp1.XX)
dst_qmp=$(mktemp -u -t mig-helper-qmp2.XX)
-   dst_infifo=$(mktemp -u -t mig-helper-fifo-stdin.XX)
+   src_infifo=$(mktemp -u -t mig-helper-fifo-stdin1.XX)
+   dst_infifo=$(mktemp -u -t mig-helper-fifo-stdin2.XX)

[kvm-unit-tests PATCH v7 02/35] arch-run: Keep infifo open

2024-03-19 Thread Nicholas Piggin
The infifo fifo that is used to send characters to QEMU console is
only able to receive one character before the cat process exits.
Supporting interactions between test and harness involving multiple
characters requires the fifo to remain open.

The infifo is removed by the exit handler like other files and fifos
so it does not have to be removed explicitly.

With this we can let the cat out of the subshell, simplifying the
input pipeline.

Reviewed-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 scripts/arch-run.bash | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
index e34d784c0..39419d4e2 100644
--- a/scripts/arch-run.bash
+++ b/scripts/arch-run.bash
@@ -158,6 +158,11 @@ run_migration ()
mkfifo ${src_outfifo}
mkfifo ${dst_outfifo}
 
+   # Holding both ends of the input fifo open prevents opens from
+   # blocking and readers getting EOF when a writer closes it.
+   mkfifo ${dst_infifo}
+   exec {dst_infifo_fd}<>${dst_infifo}
+
eval "$migcmdline" \
-chardev socket,id=mon,path=${src_qmp},server=on,wait=off \
-mon chardev=mon,mode=control > ${src_outfifo} &
@@ -191,14 +196,10 @@ run_migration ()
 
 do_migration ()
 {
-   # We have to use cat to open the named FIFO, because named FIFO's,
-   # unlike pipes, will block on open() until the other end is also
-   # opened, and that totally breaks QEMU...
-   mkfifo ${dst_infifo}
eval "$migcmdline" \
-chardev socket,id=mon,path=${dst_qmp},server=on,wait=off \
-mon chardev=mon,mode=control -incoming unix:${dst_incoming} \
-   < <(cat ${dst_infifo}) > ${dst_outfifo} &
+   < ${dst_infifo} > ${dst_outfifo} &
incoming_pid=$!
cat ${dst_outfifo} | tee ${dst_out} | filter_quiet_msgs &
 
@@ -245,7 +246,6 @@ do_migration ()
 
# keypress to dst so getchar completes and test continues
echo > ${dst_infifo}
-   rm ${dst_infifo}
 
# Wait for the incoming socket being removed, ready for next destination
while [ -S ${dst_incoming} ] ; do sleep 0.1 ; done
-- 
2.42.0



[kvm-unit-tests PATCH v7 01/35] arch-run: Add functions to help handle migration directives from test

2024-03-19 Thread Nicholas Piggin
The migration harness will be expanded to deal with more commands
from the test, moving these checks into functions helps keep things
managable.

Signed-off-by: Nicholas Piggin 
---
 scripts/arch-run.bash | 20 +++-
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
index 413f3eda8..e34d784c0 100644
--- a/scripts/arch-run.bash
+++ b/scripts/arch-run.bash
@@ -122,6 +122,16 @@ qmp_events ()
jq -c 'select(has("event"))'
 }
 
+filter_quiet_msgs ()
+{
+   grep -v "Now migrate the VM (quiet)"
+}
+
+seen_migrate_msg ()
+{
+   grep -q -e "Now migrate the VM" < $1
+}
+
 run_migration ()
 {
if ! command -v ncat >/dev/null 2>&1; then
@@ -152,7 +162,7 @@ run_migration ()
-chardev socket,id=mon,path=${src_qmp},server=on,wait=off \
-mon chardev=mon,mode=control > ${src_outfifo} &
live_pid=$!
-   cat ${src_outfifo} | tee ${src_out} | grep -v "Now migrate the VM 
(quiet)" &
+   cat ${src_outfifo} | tee ${src_out} | filter_quiet_msgs &
 
# Start the first destination QEMU machine in advance of the test
# reaching the migration point, since we expect at least one migration.
@@ -162,7 +172,7 @@ run_migration ()
 
while ps -p ${live_pid} > /dev/null ; do
# Wait for test exit or further migration messages.
-   if ! grep -q -i "Now migrate the VM" < ${src_out} ; then
+   if ! seen_migrate_msg ${src_out} ;  then
sleep 0.1
else
do_migration || return $?
@@ -190,11 +200,11 @@ do_migration ()
-mon chardev=mon,mode=control -incoming unix:${dst_incoming} \
< <(cat ${dst_infifo}) > ${dst_outfifo} &
incoming_pid=$!
-   cat ${dst_outfifo} | tee ${dst_out} | grep -v "Now migrate the VM 
(quiet)" &
+   cat ${dst_outfifo} | tee ${dst_out} | filter_quiet_msgs &
 
# The test must prompt the user to migrate, so wait for the
-   # "Now migrate VM" console message.
-   while ! grep -q -i "Now migrate the VM" < ${src_out} ; do
+   # "Now migrate VM" or similar console message.
+   while ! seen_migrate_msg ${src_out} ; do
if ! ps -p ${live_pid} > /dev/null ; then
echo "ERROR: Test exit before migration point." >&2
echo > ${dst_infifo}
-- 
2.42.0



[kvm-unit-tests PATCH v7 00/35] migration, powerpc improvements

2024-03-19 Thread Nicholas Piggin
Tree here
https://gitlab.com/npiggin/kvm-unit-tests/-/tree/powerpc?ref_type=heads

Sorry I lost the v6 tag on the previous series. Since then,
I merged the series with the migration ones since they touch
the same things.

Addressed almost all comments since the last post, I think just
one case where a "elif kvm" branch was kept in the powerpc/run
script because I find it convenient to add KVM specific things
there if needed.

Main changes since v6 (thanks to reviewers):
- Rebased on new stack backtrace patches, and cherry picks
  from v6.
- Move new files to SPDX headers.
- Improve comments on and simplify interrupt stack frame and
  backtracing.
- Add a docs/ directory with unittests.cfg documentation
  deduplicated from arch code and moved there, and document
  new machine= option. Not exactly 1:1 move of comments, so
  suggestions and improvements welcome there.
- Made new shell script a bit more consistent with style. I
  do have shellcheck working and some patches started, btw.,
  will look at submitting that after this series.
- Fix up a few unittests and gitlab CI to avoid failing on the
  QEMU TCG migration bug. Reduced runtime of some of the new
  migration tests.

Thanks,
Nick

Nicholas Piggin (35):
  arch-run: Add functions to help handle migration directives from test
  arch-run: Keep infifo open
  migration: Add a migrate_skip command
  (arm|s390): Use migrate_skip in test cases
  arch-run: Add a "continuous" migration option for tests
  gitlab-ci: Run migration selftest on s390x and powerpc
  common: add memory dirtying vs migration test
  powerpc: Fix KVM caps on POWER9 hosts
  powerpc: Fix stack backtrace termination
  powerpc: interrupt stack backtracing
  powerpc/sprs: Specify SPRs with data rather than code
  powerpc/sprs: Avoid taking PMU interrupts caused by register fuzzing
  doc: start documentation directory with unittests.cfg doc
  scripts: allow machine option to be specified in unittests.cfg
  scripts: Accommodate powerpc powernv machine differences
  powerpc: Support powernv machine with QEMU TCG
  powerpc: Fix emulator illegal instruction test for powernv
  powerpc/sprs: Test hypervisor registers on powernv machine
  powerpc: general interrupt tests
  powerpc: Add rtas stop-self support
  powerpc: Remove broken SMP exception stack setup
  powerpc: add SMP and IPI support
  powerpc: Permit ACCEL=tcg,thread=single
  powerpc: Avoid using larx/stcx. in spinlocks when only one CPU is
running
  powerpc: Add atomics tests
  powerpc: Add timebase tests
  powerpc: Add MMU support
  common/sieve: Use vmalloc.h for setup_mmu definition
  common/sieve: Support machines without MMU
  powerpc: Add sieve.c common test
  powerpc: add usermode support
  powerpc: add pmu tests
  configure: Make arch_libdir a first-class entity
  powerpc: Remove remnants of ppc64 directory and build structure
  powerpc: gitlab CI update

 .gitlab-ci.yml   |  26 +-
 MAINTAINERS  |   1 -
 Makefile |   2 +-
 arm/gic.c|  21 +-
 arm/unittests.cfg|  26 +-
 common/memory-verify.c   |  67 +++
 common/selftest-migration.c  |  26 +-
 common/sieve.c   |  15 +-
 configure|  58 +-
 docs/unittests.txt   |  95 
 lib/libcflat.h   |   2 -
 lib/migrate.c|  37 +-
 lib/migrate.h|   5 +
 lib/{ppc64 => powerpc}/asm-offsets.c |   7 +
 lib/{ppc64 => powerpc}/asm/asm-offsets.h |   0
 lib/powerpc/asm/atomic.h |   6 +
 lib/powerpc/asm/barrier.h|  12 +
 lib/{ppc64 => powerpc}/asm/bitops.h  |   4 +-
 lib/powerpc/asm/hcall.h  |   6 +
 lib/{ppc64 => powerpc}/asm/io.h  |   4 +-
 lib/powerpc/asm/mmu.h|  10 +
 lib/powerpc/asm/opal.h   |  22 +
 lib/powerpc/asm/page.h   |  65 +++
 lib/powerpc/asm/pgtable-hwdef.h  |  66 +++
 lib/powerpc/asm/pgtable.h| 125 +
 lib/powerpc/asm/processor.h  |  63 +++
 lib/{ppc64 => powerpc}/asm/ptrace.h  |  22 +-
 lib/powerpc/asm/reg.h|  42 ++
 lib/powerpc/asm/rtas.h   |   2 +
 lib/powerpc/asm/setup.h  |   3 +-
 lib/powerpc/asm/smp.h|  50 +-
 lib/powerpc/asm/spinlock.h   |  11 +
 lib/powerpc/asm/stack.h  |   3 +
 lib/{ppc64 => powerpc}/asm/vpa.h |   0
 lib/powerpc/hcall.c  |   4 +-
 lib/powerpc/io.c |  41 +-
 lib/powerpc/io.h |   6 +
 lib/powerpc/mmu.c| 274 ++
 lib/powerpc/opal-calls.S |  50 ++
 lib/powerpc/opal.c   |  76 +++
 lib/powerpc/processor.c  |  91 +++-
 lib/powerpc/rtas.c 

Re: [PATCH v14 00/16] Add audio support in v4l2 framework

2024-03-19 Thread Hans Verkuil
On 19/03/2024 4:14 am, Shengjiu Wang wrote:
> On Tue, Mar 19, 2024 at 10:24 AM Shengjiu Wang  
> wrote:
>>
>> On Mon, Mar 18, 2024 at 11:56 PM Hans Verkuil  wrote:
>>>
>>> Hi Shengjiu,
>>>
>>> I was about to prepare a pull request for this when I realized that
>>> entries for the new drivers need to be added to the MAINTAINERS file.
>>>
>>> Can you post patches 'v14 17/16' and 'v14/18/16' adding entries for each
>>> new driver?
>>
>> Ok,  How about the change below?
>>
>> VIRTUAL MEM2MEM DRIVER FOR AUDIO
>> M:  Hans Verkuil 
>> M:  Shengjiu Wang 
>> L:  linux-me...@vger.kernel.org
>> S:  Maintained
>> W:  https://linuxtv.org
>> T:  git git://linuxtv.org/media_tree.git
>> F:  drivers/media/test-drivers/vim2m-audio.c
>>
>> NXP ASRC V4L2 MEM2MEM DRIVERS
>> M:  Shengjiu Wang 
>> L:  linux-me...@vger.kernel.org
>> S:  Maintained
>> W:  https://linuxtv.org
>> T:  git git://linuxtv.org/media_tree.git
>> F:  drivers/media/platform/nxp/imx-asrc.c
>>
> 
> BTW, should I merge this change to PATCH 15/16  and PATCH 16/16?
> That I will resend the whole patch series.  Seems this is a better way.

That's fine!

Regards,

Hans

> 
> Best regrads
> Shengjiu Wang
> 
>> best regards
>> wang shengjiu
>>
>>>
>>> Thank you,
>>>
>>> Hans
>>>
>>> On 11/03/2024 10:53 am, Shengjiu Wang wrote:
 Audio signal processing also has the requirement for memory to
 memory similar as Video.

 This asrc memory to memory (memory ->asrc->memory) case is a non
 real time use case.

 User fills the input buffer to the asrc module, after conversion, then asrc
 sends back the output buffer to user. So it is not a traditional ALSA 
 playback
 and capture case.

 It is a specific use case,  there is no reference in current kernel.
 v4l2 memory to memory is the closed implementation,  v4l2 current
 support video, image, radio, tuner, touch devices, so it is not
 complicated to add support for this specific audio case.

 Because we had implemented the "memory -> asrc ->i2s device-> codec"
 use case in ALSA.  Now the "memory->asrc->memory" needs
 to reuse the code in asrc driver, so the first 3 patches is for refining
 the code to make it can be shared by the "memory->asrc->memory"
 driver.

 The main change is in the v4l2 side, A /dev/vl4-audioX will be created,
 user applications only use the ioctl of v4l2 framework.

 Other change is to add memory to memory support for two kinds of i.MX ASRC
 module.

 changes in v14:
 - document the reservation of 'AUXX' fourcc format.
 - add v4l2_audfmt_to_fourcc() definition.

 changes in v13
 - change 'pixelformat' to 'audioformat' in dev-audio-mem2mem.rst
 - add more description for clock drift in ext-ctrls-audio-m2m.rst
 - Add "media: v4l2-ctrls: add support for fraction_bits" from Hans
   to avoid build issue for kernel test robot

 changes in v12
 - minor changes according to comments
 - drop min_buffers_needed = 1 and V4L2_CTRL_FLAG_UPDATE flag
 - drop bus_info

 changes in v11
 - add add-fixed-point-test-controls in vivid.
 - add v4l2_ctrl_fp_compose() helper function for min and max

 changes in v10
 - remove FIXED_POINT type
 - change code base on media: v4l2-ctrls: add support for fraction_bits
 - fix issue reported by kernel test robot
 - remove module_alias

 changes in v9:
 - add MEDIA_ENT_F_PROC_AUDIO_RESAMPLER.
 - add MEDIA_INTF_T_V4L_AUDIO
 - add media controller support
 - refine the vim2m-audio to support 8k<->16k conversion.

 changes in v8:
 - refine V4L2_CAP_AUDIO_M2M to be 0x0008
 - update doc for FIXED_POINT
 - address comments for imx-asrc

 changes in v7:
 - add acked-by from Mark
 - separate commit for fixed point, m2m audio class, audio rate controls
 - use INTEGER_MENU for rate,  FIXED_POINT for rate offset
 - remove used fmts
 - address other comments for Hans

 changes in v6:
 - use m2m_prepare/m2m_unprepare/m2m_start/m2m_stop to replace
   m2m_start_part_one/m2m_stop_part_one, 
 m2m_start_part_two/m2m_stop_part_two.
 - change V4L2_CTRL_TYPE_ASRC_RATE to V4L2_CTRL_TYPE_FIXED_POINT
 - fix warning by kernel test rebot
 - remove some unused format V4L2_AUDIO_FMT_XX
 - Get SNDRV_PCM_FORMAT from V4L2_AUDIO_FMT in driver.
 - rename audm2m to viaudm2m.

 changes in v5:
 - remove V4L2_AUDIO_FMT_LPCM
 - define audio pixel format like V4L2_AUDIO_FMT_S8...
 - remove rate and format in struct v4l2_audio_format.
 - Add V4L2_CID_ASRC_SOURCE_RATE and V4L2_CID_ASRC_DEST_RATE controls
 - updata document accordingly.

 changes in v4:
 - update document style
 - separate V4L2_AUDIO_FMT_LPCM and V4L2_CAP_AUDIO_M2M in separate commit

 changes in v3:
 - Modify 

[PATCH v2 25/25] scsi: ibmvscsi: Convert sprintf() family to sysfs_emit() family

2024-03-19 Thread Li Zhijian
Per filesystems/sysfs.rst, show() should only use sysfs_emit()
or sysfs_emit_at() when formatting the value to be returned to user space.

coccinelle complains that there are still a couple of functions that use
snprintf(). Convert them to sysfs_emit().

sprintf() and scnprintf() will be converted as well if they have.

Generally, this patch is generated by
make coccicheck M= MODE=patch \
COCCI=scripts/coccinelle/api/device_attr_show.cocci

No functional change intended

CC: Tyrel Datwyler 
CC: Michael Ellerman 
CC: Nicholas Piggin 
CC: Christophe Leroy 
CC: "Aneesh Kumar K.V" 
CC: "Naveen N. Rao" 
CC: "James E.J. Bottomley" 
CC: "Martin K. Petersen" 
CC: linux-s...@vger.kernel.org
CC: linuxppc-dev@lists.ozlabs.org
Signed-off-by: Li Zhijian 
---
This is a part of the work "Fix coccicheck device_attr_show warnings"[1]
Split them per subsystem so that the maintainer can review it easily
[1] https://lore.kernel.org/lkml/20240116041129.3937800-1-lizhij...@fujitsu.com/
---
 drivers/scsi/ibmvscsi/ibmvscsi.c | 38 +---
 1 file changed, 10 insertions(+), 28 deletions(-)

diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 71f3e9563520..d6f205d30dcd 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -1904,11 +1904,8 @@ static ssize_t show_host_vhost_loc(struct device *dev,
 {
struct Scsi_Host *shost = class_to_shost(dev);
struct ibmvscsi_host_data *hostdata = shost_priv(shost);
-   int len;
 
-   len = snprintf(buf, sizeof(hostdata->caps.loc), "%s\n",
-  hostdata->caps.loc);
-   return len;
+   return sysfs_emit(buf, "%s\n", hostdata->caps.loc);
 }
 
 static struct device_attribute ibmvscsi_host_vhost_loc = {
@@ -1924,11 +1921,8 @@ static ssize_t show_host_vhost_name(struct device *dev,
 {
struct Scsi_Host *shost = class_to_shost(dev);
struct ibmvscsi_host_data *hostdata = shost_priv(shost);
-   int len;
 
-   len = snprintf(buf, sizeof(hostdata->caps.name), "%s\n",
-  hostdata->caps.name);
-   return len;
+   return sysfs_emit(buf, "%s\n", hostdata->caps.name);
 }
 
 static struct device_attribute ibmvscsi_host_vhost_name = {
@@ -1944,11 +1938,8 @@ static ssize_t show_host_srp_version(struct device *dev,
 {
struct Scsi_Host *shost = class_to_shost(dev);
struct ibmvscsi_host_data *hostdata = shost_priv(shost);
-   int len;
 
-   len = snprintf(buf, PAGE_SIZE, "%s\n",
-  hostdata->madapter_info.srp_version);
-   return len;
+   return sysfs_emit(buf, "%s\n", hostdata->madapter_info.srp_version);
 }
 
 static struct device_attribute ibmvscsi_host_srp_version = {
@@ -1965,11 +1956,8 @@ static ssize_t show_host_partition_name(struct device 
*dev,
 {
struct Scsi_Host *shost = class_to_shost(dev);
struct ibmvscsi_host_data *hostdata = shost_priv(shost);
-   int len;
 
-   len = snprintf(buf, PAGE_SIZE, "%s\n",
-  hostdata->madapter_info.partition_name);
-   return len;
+   return sysfs_emit(buf, "%s\n", hostdata->madapter_info.partition_name);
 }
 
 static struct device_attribute ibmvscsi_host_partition_name = {
@@ -1986,11 +1974,9 @@ static ssize_t show_host_partition_number(struct device 
*dev,
 {
struct Scsi_Host *shost = class_to_shost(dev);
struct ibmvscsi_host_data *hostdata = shost_priv(shost);
-   int len;
 
-   len = snprintf(buf, PAGE_SIZE, "%d\n",
-  be32_to_cpu(hostdata->madapter_info.partition_number));
-   return len;
+   return sysfs_emit(buf, "%d\n",
+be32_to_cpu(hostdata->madapter_info.partition_number));
 }
 
 static struct device_attribute ibmvscsi_host_partition_number = {
@@ -2006,11 +1992,9 @@ static ssize_t show_host_mad_version(struct device *dev,
 {
struct Scsi_Host *shost = class_to_shost(dev);
struct ibmvscsi_host_data *hostdata = shost_priv(shost);
-   int len;
 
-   len = snprintf(buf, PAGE_SIZE, "%d\n",
-  be32_to_cpu(hostdata->madapter_info.mad_version));
-   return len;
+   return sysfs_emit(buf, "%d\n",
+be32_to_cpu(hostdata->madapter_info.mad_version));
 }
 
 static struct device_attribute ibmvscsi_host_mad_version = {
@@ -2026,11 +2010,9 @@ static ssize_t show_host_os_type(struct device *dev,
 {
struct Scsi_Host *shost = class_to_shost(dev);
struct ibmvscsi_host_data *hostdata = shost_priv(shost);
-   int len;
 
-   len = snprintf(buf, PAGE_SIZE, "%d\n",
-  be32_to_cpu(hostdata->madapter_info.os_type));
-   return len;
+   return sysfs_emit(buf, "%d\n",
+be32_to_cpu(hostdata->madapter_info.os_type));
 }
 
 static struct device_attribute ibmvscsi_host_os_type = {
-- 
2.29.2