Linux Documentation
 help / color / mirror / Atom feed
* Re: [PATCH v4 2/4] workflow: process/changes.rst: expand and cleanup list
From: Jonathan Corbet @ 2026-03-23 18:28 UTC (permalink / raw)
  To: Manuel Ebner, Collin Funk, Shuah Khan; +Cc: workflows, linux-doc, linux-kernel
In-Reply-To: <21f66cb8aa8e3ede1666bec65540824784041aa3.camel@airmail.cc>

Manuel Ebner <manuelebner@airmail.cc> writes:

> On Tue, 2026-03-17 at 09:04 -0600, Jonathan Corbet wrote:
>> Manuel Ebner <manuelebner@airmail.cc> writes:
>> > remove footnote for sphinx
>> >  in the paragraph before the list it says:
>> >  "Also, not all tools are necessary on all systems;
>> >  obviously, if you don't have any PC Card hardware, for example,
>> >  you probably needn't concern yourself with pcmciautils."
>
> i understand this paragraph like this:
> most or all tools can be optional, depending on the specific use case.
> e.g. quota-tools is optional for people compiling the kernel.
> that's why i removed the optional markings.
>
> and pcmciautils, the example in the the file, is not marked as optional in changes.rst:
>
> ====================== ===============  ========================================
>         Program        Minimal version       Command to check the version
> ====================== ===============  ========================================
> [...]
> pcmciautils            004              pccardctl -V

The markings can certainly be done in a more thoughtful way; I don't see
that as an argument for simply removing them, though.

>> > remove "(optional)" for the same reason as above
>> 
>> Here you have lost some information - now the document doesn't say
>> *which* tools are optional.  That is, I think, not ideal.
>
> that's true.
> my question is: what are the tools optional for?
> or what is the criteria for "optional"?

Well, that would be an awfully nice addition to the documentation, but I
wouldn't require that to get your current changes in :)

Thanks,

jon

^ permalink raw reply

* Re: [PATCH v11 04/16] mm/gup: drop secretmem optimization from gup_fast_folio_allowed
From: David Hildenbrand (Arm) @ 2026-03-23 18:31 UTC (permalink / raw)
  To: Kalyazin, Nikita, kvm@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
	linux-fsdevel@vger.kernel.org, linux-mm@kvack.org,
	bpf@vger.kernel.org, linux-kselftest@vger.kernel.org,
	kernel@xen0n.name, linux-riscv@lists.infradead.org,
	linux-s390@vger.kernel.org, loongarch@lists.linux.dev,
	linux-pm@vger.kernel.org
  Cc: pbonzini@redhat.com, corbet@lwn.net, maz@kernel.org,
	oupton@kernel.org, joey.gouly@arm.com, suzuki.poulose@arm.com,
	yuzenghui@huawei.com, catalin.marinas@arm.com, will@kernel.org,
	seanjc@google.com, tglx@kernel.org, mingo@redhat.com,
	bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
	hpa@zytor.com, luto@kernel.org, peterz@infradead.org,
	willy@infradead.org, akpm@linux-foundation.org,
	lorenzo.stoakes@oracle.com, vbabka@kernel.org, rppt@kernel.org,
	surenb@google.com, mhocko@suse.com, ast@kernel.org,
	daniel@iogearbox.net, andrii@kernel.org, martin.lau@linux.dev,
	eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev,
	john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me,
	haoluo@google.com, jolsa@kernel.org, jgg@ziepe.ca,
	jhubbard@nvidia.com, peterx@redhat.com, jannh@google.com,
	pfalcato@suse.de, skhan@linuxfoundation.org, riel@surriel.com,
	ryan.roberts@arm.com, jgross@suse.com, yu-cheng.yu@intel.com,
	kas@kernel.org, coxu@redhat.com, kevin.brodsky@arm.com,
	ackerleytng@google.com, yosry@kernel.org, ajones@ventanamicro.com,
	maobibo@loongson.cn, tabba@google.com, prsampat@amd.com,
	wu.fei9@sanechips.com.cn, mlevitsk@redhat.com,
	jmattson@google.com, jthoughton@google.com,
	agordeev@linux.ibm.com, alex@ghiti.fr, aou@eecs.berkeley.edu,
	borntraeger@linux.ibm.com, chenhuacai@kernel.org,
	dev.jain@arm.com, gor@linux.ibm.com, hca@linux.ibm.com,
	palmer@dabbelt.com, pjw@kernel.org, shijie@os.amperecomputing.com,
	svens@linux.ibm.com, thuth@redhat.com, wyihan@google.com,
	yang@os.amperecomputing.com, Jonathan.Cameron@huawei.com,
	Liam.Howlett@oracle.com, urezki@gmail.com,
	zhengqi.arch@bytedance.com, gerald.schaefer@linux.ibm.com,
	jiayuan.chen@shopee.com, lenb@kernel.org, osalvador@suse.de,
	pavel@kernel.org, rafael@kernel.org, vannapurve@google.com,
	jackmanb@google.com, aneesh.kumar@kernel.org,
	patrick.roy@linux.dev, Thomson, Jack, Itazuri, Takahiro,
	Manwaring, Derek, Vlastimil Babka, Dan Williams, Alistair Popple
In-Reply-To: <20260317141031.514-5-kalyazin@amazon.com>

On 3/17/26 15:11, Kalyazin, Nikita wrote:
> From: Patrick Roy <patrick.roy@linux.dev>
> 
> This drops an optimization in gup_fast_folio_allowed() where
> secretmem_mapping() was only called if CONFIG_SECRETMEM=y. secretmem is
> enabled by default since commit b758fe6df50d ("mm/secretmem: make it on
> by default"), so the secretmem check did not actually end up elided in
> most cases anymore anyway.
> 
> This is in preparation of the generalization of handling mappings where
> direct map entries of folios are set to not present.  Currently,
> mappings that match this description are secretmem mappings
> (memfd_secret()).  Later, some guest_memfd configurations will also fall
> into this category.
> 
> Signed-off-by: Patrick Roy <patrick.roy@linux.dev>
> Acked-by: Vlastimil Babka <vbabka@suse.cz>
> Acked-by: David Hildenbrand (Red Hat) <david@kernel.org>
> Signed-off-by: Nikita Kalyazin <kalyazin@amazon.com>
> ---
>  mm/gup.c | 11 +----------
>  1 file changed, 1 insertion(+), 10 deletions(-)
> 
> diff --git a/mm/gup.c b/mm/gup.c
> index 8e7dc2c6ee73..5856d35be385 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -2739,7 +2739,6 @@ static bool gup_fast_folio_allowed(struct folio *folio, unsigned int flags)
>  {
>  	bool reject_file_backed = false;
>  	struct address_space *mapping;
> -	bool check_secretmem = false;
>  	unsigned long mapping_flags;
>  
>  	/*
> @@ -2751,14 +2750,6 @@ static bool gup_fast_folio_allowed(struct folio *folio, unsigned int flags)
>  		reject_file_backed = true;
>  
>  	/* We hold a folio reference, so we can safely access folio fields. */
> -
> -	/* secretmem folios are always order-0 folios. */
> -	if (IS_ENABLED(CONFIG_SECRETMEM) && !folio_test_large(folio))
> -		check_secretmem = true;
> -
> -	if (!reject_file_backed && !check_secretmem)
> -		return true;
> -

The AI review says that this will force all small folios through the
mapping check (which we obviously need later :) ).

It brings up two cases where page->mapping is not set up:

1) ZONE_DEVICE pages (like Device DAX and PCI P2PDMA)

2) large shmem folios in the swap cache


2) doesn't make sense, because the folio cannot be mapped in user space
when that happens.

I am also skeptical about 1), especially as large folios are also
supported for device dax and would be problematic here.
__dev_dax_pte_fault() clearly sets folio->mapping through dax_set_mapping().


If 1) is ever a case we could allow them by checking for
folio_is_zone_device(). But I am not sure if that is really required.
Sounds weird.


-- 
Cheers,

David

^ permalink raw reply

* Re: [PATCH 0/2] kallsyms: show typed function parameters in oops/WARN dumps
From: Alexey Dobriyan @ 2026-03-23 18:43 UTC (permalink / raw)
  To: Sasha Levin
  Cc: Andrew Morton, Masahiro Yamada, Nathan Chancellor, Nicolas Schier,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H. Peter Anvin, Peter Zijlstra, Josh Poimboeuf, Petr Mladek,
	Alexei Starovoitov, Jonathan Corbet, David Gow, Kees Cook,
	Greg KH, Luis Chamberlain, Steven Rostedt, Helge Deller,
	Randy Dunlap, Geert Uytterhoeven, Juergen Gross, James Bottomley,
	Vlastimil Babka, Laurent Pinchart, Petr Pavlu, x86, linux-kernel,
	linux-kbuild, linux-doc, linux-modules, bpf
In-Reply-To: <20260323164858.1939248-1-sashal@kernel.org>

On Mon, Mar 23, 2026 at 12:48:55PM -0400, Sasha Levin wrote:
>  Function parameters (paraminfo_demo_crash):
>   uts      (struct new_utsname *) = 0xffffffffb8ca8d00
>    .sysname = "Linux"                        .nodename = "localhost"
>    .release = "7.0.0-rc2-00006-g3190..."     .version = "#45 SMP PRE"
>   file     (struct file *       ) = 0xffffa0a3c250acc0
>    .f_mode = (fmode_t)67993630               .f_op = (struct file_operations *)0xffffffffb7237620
>    .f_flags = (unsigned int)32769            .f_cred = (struct cred *)0xffffa0a3c2e06a80
>    .dentry = (struct dentry *)0xffffa0a3c0978cc0

Should this be in crash's format?

	struct dentry ffffffffffff0000

^ permalink raw reply

* Re: [PATCH v11 02/16] set_memory: add folio_{zap,restore}_direct_map helpers
From: Ackerley Tng @ 2026-03-23 18:43 UTC (permalink / raw)
  To: Kalyazin, Nikita, kvm@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
	linux-fsdevel@vger.kernel.org, linux-mm@kvack.org,
	bpf@vger.kernel.org, linux-kselftest@vger.kernel.org,
	kernel@xen0n.name, linux-riscv@lists.infradead.org,
	linux-s390@vger.kernel.org, loongarch@lists.linux.dev,
	linux-pm@vger.kernel.org
  Cc: pbonzini@redhat.com, corbet@lwn.net, maz@kernel.org,
	oupton@kernel.org, joey.gouly@arm.com, suzuki.poulose@arm.com,
	yuzenghui@huawei.com, catalin.marinas@arm.com, will@kernel.org,
	seanjc@google.com, tglx@kernel.org, mingo@redhat.com,
	bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
	hpa@zytor.com, luto@kernel.org, peterz@infradead.org,
	willy@infradead.org, akpm@linux-foundation.org, david@kernel.org,
	lorenzo.stoakes@oracle.com, vbabka@kernel.org, rppt@kernel.org,
	surenb@google.com, mhocko@suse.com, ast@kernel.org,
	daniel@iogearbox.net, andrii@kernel.org, martin.lau@linux.dev,
	eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev,
	john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me,
	haoluo@google.com, jolsa@kernel.org, jgg@ziepe.ca,
	jhubbard@nvidia.com, peterx@redhat.com, jannh@google.com,
	pfalcato@suse.de, skhan@linuxfoundation.org, riel@surriel.com,
	ryan.roberts@arm.com, jgross@suse.com, yu-cheng.yu@intel.com,
	kas@kernel.org, coxu@redhat.com, kevin.brodsky@arm.com,
	yosry@kernel.org, ajones@ventanamicro.com, maobibo@loongson.cn,
	tabba@google.com, prsampat@amd.com, wu.fei9@sanechips.com.cn,
	mlevitsk@redhat.com, jmattson@google.com, jthoughton@google.com,
	agordeev@linux.ibm.com, alex@ghiti.fr, aou@eecs.berkeley.edu,
	borntraeger@linux.ibm.com, chenhuacai@kernel.org,
	dev.jain@arm.com, gor@linux.ibm.com, hca@linux.ibm.com,
	palmer@dabbelt.com, pjw@kernel.org, shijie@os.amperecomputing.com,
	svens@linux.ibm.com, thuth@redhat.com, wyihan@google.com,
	yang@os.amperecomputing.com, Jonathan.Cameron@huawei.com,
	Liam.Howlett@oracle.com, urezki@gmail.com,
	zhengqi.arch@bytedance.com, gerald.schaefer@linux.ibm.com,
	jiayuan.chen@shopee.com, lenb@kernel.org, osalvador@suse.de,
	pavel@kernel.org, rafael@kernel.org, vannapurve@google.com,
	jackmanb@google.com, aneesh.kumar@kernel.org,
	patrick.roy@linux.dev, Thomson, Jack, Itazuri, Takahiro,
	Manwaring, Derek
In-Reply-To: <20260317141031.514-3-kalyazin@amazon.com>

"Kalyazin, Nikita" <kalyazin@amazon.co.uk> writes:

> From: Nikita Kalyazin <kalyazin@amazon.com>
>
> Let's provide folio_{zap,restore}_direct_map helpers as preparation for
> supporting removal of the direct map for guest_memfd folios.
> In folio_zap_direct_map(), flush TLB to make sure the data is not
> accessible.
>
> The new helpers need to be accessible to KVM on architectures that
> support guest_memfd (x86 and arm64).
>
> Direct map removal gives guest_memfd the same protection that
> memfd_secret does, such as hardening against Spectre-like attacks
> through in-kernel gadgets.
>
> Signed-off-by: Nikita Kalyazin <kalyazin@amazon.com>
> ---
>  include/linux/set_memory.h | 13 ++++++++++++
>  mm/memory.c                | 42 ++++++++++++++++++++++++++++++++++++++
>  2 files changed, 55 insertions(+)
>
> diff --git a/include/linux/set_memory.h b/include/linux/set_memory.h
> index 1a2563f525fc..24caea2931f9 100644
> --- a/include/linux/set_memory.h
> +++ b/include/linux/set_memory.h
> @@ -41,6 +41,15 @@ static inline int set_direct_map_valid_noflush(const void *addr,
>  	return 0;
>  }
>
> +static inline int folio_zap_direct_map(struct folio *folio)
> +{
> +	return 0;
> +}
> +
> +static inline void folio_restore_direct_map(struct folio *folio)
> +{
> +}
> +
>  static inline bool kernel_page_present(struct page *page)
>  {
>  	return true;
> @@ -57,6 +66,10 @@ static inline bool can_set_direct_map(void)
>  }
>  #define can_set_direct_map can_set_direct_map
>  #endif
> +
> +int folio_zap_direct_map(struct folio *folio);
> +void folio_restore_direct_map(struct folio *folio);
> +
>  #endif /* CONFIG_ARCH_HAS_SET_DIRECT_MAP */
>
>  #ifdef CONFIG_X86_64
> diff --git a/mm/memory.c b/mm/memory.c
> index 07778814b4a8..cab6bb237fc0 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -78,6 +78,7 @@
>  #include <linux/sched/sysctl.h>
>  #include <linux/pgalloc.h>
>  #include <linux/uaccess.h>
> +#include <linux/set_memory.h>
>
>  #include <trace/events/kmem.h>
>
> @@ -7478,3 +7479,44 @@ void vma_pgtable_walk_end(struct vm_area_struct *vma)
>  	if (is_vm_hugetlb_page(vma))
>  		hugetlb_vma_unlock_read(vma);
>  }
> +
> +#ifdef CONFIG_ARCH_HAS_SET_DIRECT_MAP
> +/**
> + * folio_zap_direct_map - remove a folio from the kernel direct map
> + * @folio: folio to remove from the direct map
> + *
> + * Removes the folio from the kernel direct map and flushes the TLB.  This may
> + * require splitting huge pages in the direct map, which can fail due to memory
> + * allocation.
> + *
> + * Return: 0 on success, or a negative error code on failure.
> + */
> +int folio_zap_direct_map(struct folio *folio)
> +{
> +	const void *addr = folio_address(folio);
> +	int ret;
> +
> +	ret = set_direct_map_valid_noflush(addr, folio_nr_pages(folio), false);
> +	flush_tlb_kernel_range((unsigned long)addr,
> +			       (unsigned long)addr + folio_size(folio));
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_FOR_MODULES(folio_zap_direct_map, "kvm");
> +
> +/**
> + * folio_restore_direct_map - restore the kernel direct map entry for a folio
> + * @folio: folio whose direct map entry is to be restored
> + *
> + * This may only be called after a prior successful folio_zap_direct_map() on
> + * the same folio.  Because the zap will have already split any huge pages in
> + * the direct map, restoration here only updates protection bits and cannot
> + * fail.
> + */
> +void folio_restore_direct_map(struct folio *folio)
> +{
> +	WARN_ON_ONCE(set_direct_map_valid_noflush(folio_address(folio),
> +						  folio_nr_pages(folio), true));
> +}
> +EXPORT_SYMBOL_FOR_MODULES(folio_restore_direct_map, "kvm");
> +#endif /* CONFIG_ARCH_HAS_SET_DIRECT_MAP */
> --
> 2.50.1

Reviewed-by: Ackerley Tng <ackerleytng@google.com>

I also took a look at Sashiko's [1] comments and I think that the
highmem folio issues should be the responsibility of the caller to
check.

[1] https://sashiko.dev/#/patchset/20260317141031.514-1-kalyazin%40amazon.com

^ permalink raw reply

* Re: [PATCH v11 03/16] mm/secretmem: make use of folio_{zap,restore}_direct_map
From: Ackerley Tng @ 2026-03-23 18:46 UTC (permalink / raw)
  To: Kalyazin, Nikita, kvm@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
	linux-fsdevel@vger.kernel.org, linux-mm@kvack.org,
	bpf@vger.kernel.org, linux-kselftest@vger.kernel.org,
	kernel@xen0n.name, linux-riscv@lists.infradead.org,
	linux-s390@vger.kernel.org, loongarch@lists.linux.dev,
	linux-pm@vger.kernel.org
  Cc: pbonzini@redhat.com, corbet@lwn.net, maz@kernel.org,
	oupton@kernel.org, joey.gouly@arm.com, suzuki.poulose@arm.com,
	yuzenghui@huawei.com, catalin.marinas@arm.com, will@kernel.org,
	seanjc@google.com, tglx@kernel.org, mingo@redhat.com,
	bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
	hpa@zytor.com, luto@kernel.org, peterz@infradead.org,
	willy@infradead.org, akpm@linux-foundation.org, david@kernel.org,
	lorenzo.stoakes@oracle.com, vbabka@kernel.org, rppt@kernel.org,
	surenb@google.com, mhocko@suse.com, ast@kernel.org,
	daniel@iogearbox.net, andrii@kernel.org, martin.lau@linux.dev,
	eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev,
	john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me,
	haoluo@google.com, jolsa@kernel.org, jgg@ziepe.ca,
	jhubbard@nvidia.com, peterx@redhat.com, jannh@google.com,
	pfalcato@suse.de, skhan@linuxfoundation.org, riel@surriel.com,
	ryan.roberts@arm.com, jgross@suse.com, yu-cheng.yu@intel.com,
	kas@kernel.org, coxu@redhat.com, kevin.brodsky@arm.com,
	yosry@kernel.org, ajones@ventanamicro.com, maobibo@loongson.cn,
	tabba@google.com, prsampat@amd.com, wu.fei9@sanechips.com.cn,
	mlevitsk@redhat.com, jmattson@google.com, jthoughton@google.com,
	agordeev@linux.ibm.com, alex@ghiti.fr, aou@eecs.berkeley.edu,
	borntraeger@linux.ibm.com, chenhuacai@kernel.org,
	dev.jain@arm.com, gor@linux.ibm.com, hca@linux.ibm.com,
	palmer@dabbelt.com, pjw@kernel.org, shijie@os.amperecomputing.com,
	svens@linux.ibm.com, thuth@redhat.com, wyihan@google.com,
	yang@os.amperecomputing.com, Jonathan.Cameron@huawei.com,
	Liam.Howlett@oracle.com, urezki@gmail.com,
	zhengqi.arch@bytedance.com, gerald.schaefer@linux.ibm.com,
	jiayuan.chen@shopee.com, lenb@kernel.org, osalvador@suse.de,
	pavel@kernel.org, rafael@kernel.org, vannapurve@google.com,
	jackmanb@google.com, aneesh.kumar@kernel.org,
	patrick.roy@linux.dev, Thomson, Jack, Itazuri, Takahiro,
	Manwaring, Derek
In-Reply-To: <20260317141031.514-4-kalyazin@amazon.com>

"Kalyazin, Nikita" <kalyazin@amazon.co.uk> writes:

> From: Nikita Kalyazin <kalyazin@amazon.com>
>
> Signed-off-by: Nikita Kalyazin <kalyazin@amazon.com>
> ---
>  mm/secretmem.c | 8 ++------
>  1 file changed, 2 insertions(+), 6 deletions(-)
>
> diff --git a/mm/secretmem.c b/mm/secretmem.c
> index fd29b33c6764..27b176af8fc4 100644
> --- a/mm/secretmem.c
> +++ b/mm/secretmem.c
> @@ -53,7 +53,6 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf)
>  	struct inode *inode = file_inode(vmf->vma->vm_file);
>  	pgoff_t offset = vmf->pgoff;
>  	gfp_t gfp = vmf->gfp_mask;
> -	unsigned long addr;
>  	struct folio *folio;
>  	vm_fault_t ret;
>  	int err;
> @@ -72,7 +71,7 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf)
>  			goto out;
>  		}
>
> -		err = set_direct_map_invalid_noflush(folio_address(folio));
> +		err = folio_zap_direct_map(folio);
>  		if (err) {
>  			folio_put(folio);
>  			ret = vmf_error(err);
> @@ -87,7 +86,7 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf)
>  			 * already happened when we marked the page invalid
>  			 * which guarantees that this call won't fail
>  			 */
> -			set_direct_map_default_noflush(folio_address(folio));
> +			folio_restore_direct_map(folio);
>  			folio_put(folio);
>  			if (err == -EEXIST)
>  				goto retry;
> @@ -95,9 +94,6 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf)
>  			ret = vmf_error(err);
>  			goto out;
>  		}
> -
> -		addr = (unsigned long)folio_address(folio);
> -		flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
>  	}
>
>  	vmf->page = folio_file_page(folio, vmf->pgoff);
> --
> 2.50.1

Reviewed-by: Ackerley Tng <ackerleytng@google.com>

^ permalink raw reply

* Re: [PATCH v4] landlock: Expand restrict flags example for ABI version 8
From: Mickaël Salaün @ 2026-03-23 18:56 UTC (permalink / raw)
  To: Panagiotis "Ivory" Vasilopoulos
  Cc: Günther Noack, Jonathan Corbet, Shuah Khan,
	linux-security-module, linux-doc, linux-kernel, Dan Cojocaru
In-Reply-To: <20260304-landlock-docs-add-tsync-example-v4-1-819a276f05c5@n0toose.net>

Thanks!  I pushed your patch in next with a minor fix.

Günther, does it look good to you?

On Wed, Mar 04, 2026 at 07:13:04PM +0100, Panagiotis "Ivory" Vasilopoulos wrote:
> Add LANDLOCK_RESTRICT_SELF_TSYNC to the backwards compatibility example
> for restrict flags. This introduces completeness, similar to that of
> the ruleset attributes example. However, as the new example can impact
> enforcement in certain cases, an appropriate warning is also included.
> 
> Additionally, I modified the two comments of the example to make them
> more consistent with the ruleset attributes example's.
> 
> Signed-off-by: Panagiotis 'Ivory' Vasilopoulos <git@n0toose.net>
> Co-developed-by: Dan Cojocaru <dan@dcdev.ro>
> Signed-off-by: Dan Cojocaru <dan@dcdev.ro>
> ---
> Changes in v4:
> - Make warning somewhat more terse, merge comments.
>   - Remove some sensationalization. ("Don't copy-paste this just yet!")
>   - Apply Günther's suggestion (v3 "recycled" some phrases, was long)
>     - ... but also retain some of the wording on ABI differences
> - Provide a brief overview that contextualizes the example further:
>   - Clarify the difference behind ABI < 8 & ABI v8, to avoid
>     misunderstandings on which option is the default.
>   - Make "linear reading" easier.
> - Based on Mickaël's feedback: Avoid cans of worms w.r.t. use cases
> - Link to v3: https://lore.kernel.org/r/20260228-landlock-docs-add-tsync-example-v3-1-140ab50f0524@n0toose.net
> 
> Changes in v3:
> - Add __attribute__((fallthrough)) like in earlier example.
> - Improve comment for LANDLOCK_RESTRICT_SELF_TSYNC (ABI < 8) example.
> - Add relevant warning for ABI < 8 example based on Günther's feedback.
> - Link to v2: https://lore.kernel.org/r/20260221-landlock-docs-add-tsync-example-v2-1-60990986bba5@n0toose.net
> 
> Changes in v2:
> - Fix formatting error.
> - Link to v1: https://lore.kernel.org/r/20260221-landlock-docs-add-tsync-example-v1-1-f89383809eb4@n0toose.net
> ---
>  Documentation/userspace-api/landlock.rst | 22 ++++++++++++++++++----
>  1 file changed, 18 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/userspace-api/landlock.rst b/Documentation/userspace-api/landlock.rst
> index 13134bccdd39d78ddce3daf454f32dda162ce91b..64c7138a788d74f99da0a71428da392b3d873bf8 100644
> --- a/Documentation/userspace-api/landlock.rst
> +++ b/Documentation/userspace-api/landlock.rst
> @@ -196,13 +196,27 @@ similar backwards compatibility check is needed for the restrict flags
>  (see sys_landlock_restrict_self() documentation for available flags):
>  
>  .. code-block:: c
> -
> -    __u32 restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON;
> -    if (abi < 7) {
> -        /* Clear logging flags unsupported before ABI 7. */
> +    __u32 restrict_flags =
> +        LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON |
> +        LANDLOCK_RESTRICT_SELF_TSYNC;
> +    switch (abi) {
> +    case 1 ... 6:
> +        /* Clear logging flags unsupported for ABI < 7 */
>          restrict_flags &= ~(LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF |
>                              LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON |
>                              LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF);
> +        __attribute__((fallthrough));
> +    case 7:
> +        /*
> +         * Removes multithreaded enforcement flag unsupported for ABI < 8
> +         *
> +         * WARNING: Without this flag, calling landlock_restrict_self(2) is
> +         * only equivalent if the calling process is single-threaded. Below
> +         * ABI v8 (and as of ABI v8, when not using this flag), a Landlock
> +         * policy would only be enforced for the calling thread and its
> +         * children (and not for all threads, including parents and siblings).
> +         */
> +        restrict_flags &= ~LANDLOCK_RESTRICT_SELF_TSYNC;
>      }
>  
>  The next step is to restrict the current thread from gaining more privileges
> 
> ---
> base-commit: ceb977bfe9e8715e6cd3a4785c7aab8ea5cd2b77
> change-id: 20260221-landlock-docs-add-tsync-example-e8fd5c64a366
> 
> Best regards,
> -- 
> Panagiotis "Ivory" Vasilopoulos <git@n0toose.net>
> 
> 

^ permalink raw reply

* Re: [Intel-wired-lan] [PATCH iwl-next v6 08/14] idpf: refactor idpf to use libie control queues
From: Paul Menzel @ 2026-03-23 18:58 UTC (permalink / raw)
  To: Larysa Zaremba
  Cc: intel-wired-lan, Tony Nguyen, aleksander.lobakin,
	sridhar.samudrala, Anjali Singhai, Michal Swiatkowski,
	Maciej Fijalkowski, Emil Tantilov, Madhu Chittim, Josh Hay,
	Jacob E Keller, jayaprakash.shanmugam, Jiri Pirko,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Richard Cochran, Przemek Kitszel,
	Andrew Lunn, netdev, linux-doc, linux-kernel
In-Reply-To: <20260323174052.5355-9-larysa.zaremba@intel.com>

Dear Larysa, dear Pavan,


Thank you for your patch.

Am 23.03.26 um 18:40 schrieb Larysa Zaremba:
> From: Pavan Kumar Linga <pavan.kumar.linga@intel.com>
> 
> Support to initialize and configure controlqs, and manage their
> transactions was introduced in libie. As part of it, most of the existing
> controlq structures are renamed and modified. Use those APIs in idpf and
> make all the necessary changes.
> 
> Previously for the send and receive virtchnl messages, there used to be a
> memcpy involved in controlq code to copy the buffer info passed by the send
> function into the controlq specific buffers. There was no restriction to
> use automatic memory in that case. The new implementation in libie removed
> copying of the send buffer info and introduced DMA mapping of the send
> buffer itself. To accommodate it, use dynamic memory for the larger send
> buffers. For smaller ones (<= 128 bytes) libie still can copy them into the
> pre-allocated message memory.
> 
> In case of receive, idpf receives a page pool buffer allocated by the libie
> and care should be taken to release it after use in the idpf.
> 
> The changes are fairly trivial and localized, with a notable exception
> being the consolidation of idpf_vc_xn_shutdown and idpf_deinit_dflt_mbx
> under the latter name. This has some additional consequences that are
> addressed in the following patches.
> 
> This refactoring introduces roughly additional 40KB of module storage used
> for systems that only run idpf, so idpf + libie_cp + libie_pci takes about
> 7% more storage than just idpf before refactoring.

Excuse my ignorance, but what is “module storage”? Size of the build module?

> We now pre-allocate small TX buffers, so that does increase the memory
> usage, but reduces the need to allocate. This results in additional 256 *
> 128B of memory permanently used, increasing the worst-case memory usage by
> 32KB but our ctlq RX buffers need to be of size 4096B anyway (not changed
> by the patchset), so this is hardly noticeable.

Thank you for adding this information.

> As for the timings, the fact that we are mostly limited by the HW response
> time which is far from instant, is not changed by this refactor.

It’d be great if you named a benchmark you used to test this.

> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Signed-off-by: Pavan Kumar Linga <pavan.kumar.linga@intel.com>
> Co-developed-by: Larysa Zaremba <larysa.zaremba@intel.com>
> Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
> ---
>   drivers/net/ethernet/intel/idpf/Makefile      |    2 -
>   drivers/net/ethernet/intel/idpf/idpf.h        |   28 +-
>   .../net/ethernet/intel/idpf/idpf_controlq.c   |  631 -------
>   .../net/ethernet/intel/idpf/idpf_controlq.h   |  142 --
>   .../ethernet/intel/idpf/idpf_controlq_api.h   |  177 --
>   .../ethernet/intel/idpf/idpf_controlq_setup.c |  169 --
>   drivers/net/ethernet/intel/idpf/idpf_dev.c    |   60 +-
>   .../net/ethernet/intel/idpf/idpf_ethtool.c    |   28 +-
>   drivers/net/ethernet/intel/idpf/idpf_lib.c    |   51 +-
>   drivers/net/ethernet/intel/idpf/idpf_main.c   |    5 -
>   drivers/net/ethernet/intel/idpf/idpf_mem.h    |   20 -
>   drivers/net/ethernet/intel/idpf/idpf_txrx.h   |    2 +-
>   drivers/net/ethernet/intel/idpf/idpf_vf_dev.c |   67 +-
>   .../net/ethernet/intel/idpf/idpf_virtchnl.c   | 1620 +++++++----------
>   .../net/ethernet/intel/idpf/idpf_virtchnl.h   |   93 +-
>   .../ethernet/intel/idpf/idpf_virtchnl_ptp.c   |  246 ++-
>   16 files changed, 820 insertions(+), 2521 deletions(-)

Great diffstat!

>   delete mode 100644 drivers/net/ethernet/intel/idpf/idpf_controlq.c
>   delete mode 100644 drivers/net/ethernet/intel/idpf/idpf_controlq.h
>   delete mode 100644 drivers/net/ethernet/intel/idpf/idpf_controlq_api.h
>   delete mode 100644 drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c
>   delete mode 100644 drivers/net/ethernet/intel/idpf/idpf_mem.h
> 
> diff --git a/drivers/net/ethernet/intel/idpf/Makefile b/drivers/net/ethernet/intel/idpf/Makefile
> index 651ddee942bd..4aaafa175ec3 100644
> --- a/drivers/net/ethernet/intel/idpf/Makefile
> +++ b/drivers/net/ethernet/intel/idpf/Makefile
> @@ -6,8 +6,6 @@
>   obj-$(CONFIG_IDPF) += idpf.o
>   
>   idpf-y := \
> -	idpf_controlq.o		\
> -	idpf_controlq_setup.o	\
>   	idpf_dev.o		\
>   	idpf_ethtool.o		\
>   	idpf_idc.o		\
> diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
> index 7866b8beb6fd..b06640925fb9 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf.h
> +++ b/drivers/net/ethernet/intel/idpf/idpf.h
> @@ -27,7 +27,6 @@ struct idpf_rss_data;
>   #include <linux/intel/virtchnl2.h>
>   
>   #include "idpf_txrx.h"
> -#include "idpf_controlq.h"
>   
>   #define GETMAXVAL(num_bits)		GENMASK((num_bits) - 1, 0)
>   
> @@ -37,11 +36,10 @@ struct idpf_rss_data;
>   #define IDPF_NUM_FILTERS_PER_MSG	20
>   #define IDPF_NUM_DFLT_MBX_Q		2	/* includes both TX and RX */
>   #define IDPF_DFLT_MBX_Q_LEN		64
> -#define IDPF_DFLT_MBX_ID		-1
>   /* maximum number of times to try before resetting mailbox */
>   #define IDPF_MB_MAX_ERR			20
>   #define IDPF_NUM_CHUNKS_PER_MSG(struct_sz, chunk_sz)	\
> -	((IDPF_CTLQ_MAX_BUF_LEN - (struct_sz)) / (chunk_sz))
> +	((LIBIE_CTLQ_MAX_BUF_LEN - (struct_sz)) / (chunk_sz))
>   
>   #define IDPF_WAIT_FOR_MARKER_TIMEO	500
>   #define IDPF_MAX_WAIT			500
> @@ -202,8 +200,8 @@ struct idpf_vport_max_q {
>    * @ptp_reg_init: PTP register initialization
>    */
>   struct idpf_reg_ops {
> -	void (*ctlq_reg_init)(struct idpf_adapter *adapter,
> -			      struct idpf_ctlq_create_info *cq);
> +	void (*ctlq_reg_init)(struct libie_mmio_info *mmio,
> +			      struct libie_ctlq_create_info *cctlq_info);
>   	int (*intr_reg_init)(struct idpf_vport *vport,
>   			     struct idpf_q_vec_rsrc *rsrc);
>   	void (*mb_intr_reg_init)(struct idpf_adapter *adapter);
> @@ -606,8 +604,6 @@ struct idpf_vport_config {
>   	DECLARE_BITMAP(flags, IDPF_VPORT_CONFIG_FLAGS_NBITS);
>   };
>   
> -struct idpf_vc_xn_manager;
> -
>   #define idpf_for_each_vport(adapter, iter) \
>   	for (struct idpf_vport **__##iter = &(adapter)->vports[0], \
>   	     *iter = (adapter)->max_vports ? *__##iter : NULL; \
> @@ -625,8 +621,10 @@ struct idpf_vc_xn_manager;
>    * @state: Init state machine
>    * @flags: See enum idpf_flags
>    * @reset_reg: See struct idpf_reset_reg
> - * @hw: Device access data
>    * @ctlq_ctx: controlq context
> + * @asq: Send control queue info
> + * @arq: Receive control queue info
> + * @xnm: Xn transaction manager
>    * @num_avail_msix: Available number of MSIX vectors
>    * @num_msix_entries: Number of entries in MSIX table
>    * @msix_entries: MSIX table
> @@ -659,7 +657,6 @@ struct idpf_vc_xn_manager;
>    * @stats_task: Periodic statistics retrieval task
>    * @stats_wq: Workqueue for statistics task
>    * @caps: Negotiated capabilities with device
> - * @vcxn_mngr: Virtchnl transaction manager
>    * @dev_ops: See idpf_dev_ops
>    * @cdev_info: IDC core device info pointer
>    * @num_vfs: Number of allocated VFs through sysfs. PF does not directly talk
> @@ -683,8 +680,10 @@ struct idpf_adapter {
>   	enum idpf_state state;
>   	DECLARE_BITMAP(flags, IDPF_FLAGS_NBITS);
>   	struct idpf_reset_reg reset_reg;
> -	struct idpf_hw hw;
>   	struct libie_ctlq_ctx ctlq_ctx;
> +	struct libie_ctlq_info *asq;
> +	struct libie_ctlq_info *arq;
> +	struct libie_ctlq_xn_manager *xnm;
>   	u16 num_avail_msix;
>   	u16 num_msix_entries;
>   	struct msix_entry *msix_entries;
> @@ -721,7 +720,6 @@ struct idpf_adapter {
>   	struct delayed_work stats_task;
>   	struct workqueue_struct *stats_wq;
>   	struct virtchnl2_get_capabilities caps;
> -	struct idpf_vc_xn_manager *vcxn_mngr;
>   
>   	struct idpf_dev_ops dev_ops;
>   	struct iidc_rdma_core_dev_info *cdev_info;
> @@ -881,12 +879,12 @@ static inline u8 idpf_get_min_tx_pkt_len(struct idpf_adapter *adapter)
>    */
>   static inline bool idpf_is_reset_detected(struct idpf_adapter *adapter)
>   {
> -	if (!adapter->hw.arq)
> +	struct libie_ctlq_info *arq = adapter->arq;
> +
> +	if (!arq)
>   		return true;
>   
> -	return !(readl(libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info,
> -					       adapter->hw.arq->reg.len)) &
> -		 adapter->hw.arq->reg.len_mask);
> +	return !(readl(arq->reg.len) & arq->reg.len_mask);
>   }
>   
>   /**
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq.c b/drivers/net/ethernet/intel/idpf/idpf_controlq.c
> deleted file mode 100644
> index 020b08367e18..000000000000
> --- a/drivers/net/ethernet/intel/idpf/idpf_controlq.c
> +++ /dev/null
> @@ -1,631 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-only
> -/* Copyright (C) 2023 Intel Corporation */
> -
> -#include "idpf.h"
> -
> -/**
> - * idpf_ctlq_setup_regs - initialize control queue registers
> - * @cq: pointer to the specific control queue
> - * @q_create_info: structs containing info for each queue to be initialized
> - */
> -static void idpf_ctlq_setup_regs(struct idpf_ctlq_info *cq,
> -				 struct idpf_ctlq_create_info *q_create_info)
> -{
> -	/* set control queue registers in our local struct */
> -	cq->reg.head = q_create_info->reg.head;
> -	cq->reg.tail = q_create_info->reg.tail;
> -	cq->reg.len = q_create_info->reg.len;
> -	cq->reg.bah = q_create_info->reg.bah;
> -	cq->reg.bal = q_create_info->reg.bal;
> -	cq->reg.len_mask = q_create_info->reg.len_mask;
> -	cq->reg.len_ena_mask = q_create_info->reg.len_ena_mask;
> -	cq->reg.head_mask = q_create_info->reg.head_mask;
> -}
> -
> -/**
> - * idpf_ctlq_init_regs - Initialize control queue registers
> - * @hw: pointer to hw struct
> - * @cq: pointer to the specific Control queue
> - * @is_rxq: true if receive control queue, false otherwise
> - *
> - * Initialize registers. The caller is expected to have already initialized the
> - * descriptor ring memory and buffer memory
> - */
> -static void idpf_ctlq_init_regs(struct idpf_hw *hw, struct idpf_ctlq_info *cq,
> -				bool is_rxq)
> -{
> -	struct libie_mmio_info *mmio = &hw->back->ctlq_ctx.mmio_info;
> -
> -	/* Update tail to post pre-allocated buffers for rx queues */
> -	if (is_rxq)
> -		writel((u32)(cq->ring_size - 1),
> -		       libie_pci_get_mmio_addr(mmio, cq->reg.tail));
> -
> -	/* For non-Mailbox control queues only TAIL need to be set */
> -	if (cq->q_id != -1)
> -		return;
> -
> -	/* Clear Head for both send or receive */
> -	writel(0, libie_pci_get_mmio_addr(mmio, cq->reg.head));
> -
> -	/* set starting point */
> -	writel(lower_32_bits(cq->desc_ring.pa),
> -	       libie_pci_get_mmio_addr(mmio, cq->reg.bal));
> -	writel(upper_32_bits(cq->desc_ring.pa),
> -	       libie_pci_get_mmio_addr(mmio, cq->reg.bah));
> -	writel((cq->ring_size | cq->reg.len_ena_mask),
> -	       libie_pci_get_mmio_addr(mmio, cq->reg.len));
> -}
> -
> -/**
> - * idpf_ctlq_init_rxq_bufs - populate receive queue descriptors with buf
> - * @cq: pointer to the specific Control queue
> - *
> - * Record the address of the receive queue DMA buffers in the descriptors.
> - * The buffers must have been previously allocated.
> - */
> -static void idpf_ctlq_init_rxq_bufs(struct idpf_ctlq_info *cq)
> -{
> -	int i;
> -
> -	for (i = 0; i < cq->ring_size; i++) {
> -		struct idpf_ctlq_desc *desc = IDPF_CTLQ_DESC(cq, i);
> -		struct idpf_dma_mem *bi = cq->bi.rx_buff[i];
> -
> -		/* No buffer to post to descriptor, continue */
> -		if (!bi)
> -			continue;
> -
> -		desc->flags =
> -			cpu_to_le16(IDPF_CTLQ_FLAG_BUF | IDPF_CTLQ_FLAG_RD);
> -		desc->opcode = 0;
> -		desc->datalen = cpu_to_le16(bi->size);
> -		desc->ret_val = 0;
> -		desc->v_opcode_dtype = 0;
> -		desc->v_retval = 0;
> -		desc->params.indirect.addr_high =
> -			cpu_to_le32(upper_32_bits(bi->pa));
> -		desc->params.indirect.addr_low =
> -			cpu_to_le32(lower_32_bits(bi->pa));
> -		desc->params.indirect.param0 = 0;
> -		desc->params.indirect.sw_cookie = 0;
> -		desc->params.indirect.v_flags = 0;
> -	}
> -}
> -
> -/**
> - * idpf_ctlq_shutdown - shutdown the CQ
> - * @hw: pointer to hw struct
> - * @cq: pointer to the specific Control queue
> - *
> - * The main shutdown routine for any controq queue
> - */
> -static void idpf_ctlq_shutdown(struct idpf_hw *hw, struct idpf_ctlq_info *cq)
> -{
> -	spin_lock(&cq->cq_lock);
> -
> -	/* free ring buffers and the ring itself */
> -	idpf_ctlq_dealloc_ring_res(hw, cq);
> -
> -	/* Set ring_size to 0 to indicate uninitialized queue */
> -	cq->ring_size = 0;
> -
> -	spin_unlock(&cq->cq_lock);
> -}
> -
> -/**
> - * idpf_ctlq_add - add one control queue
> - * @hw: pointer to hardware struct
> - * @qinfo: info for queue to be created
> - * @cq_out: (output) double pointer to control queue to be created
> - *
> - * Allocate and initialize a control queue and add it to the control queue list.
> - * The cq parameter will be allocated/initialized and passed back to the caller
> - * if no errors occur.
> - *
> - * Note: idpf_ctlq_init must be called prior to any calls to idpf_ctlq_add
> - */
> -int idpf_ctlq_add(struct idpf_hw *hw,
> -		  struct idpf_ctlq_create_info *qinfo,
> -		  struct idpf_ctlq_info **cq_out)
> -{
> -	struct idpf_ctlq_info *cq;
> -	bool is_rxq = false;
> -	int err;
> -
> -	cq = kzalloc_obj(*cq);
> -	if (!cq)
> -		return -ENOMEM;
> -
> -	cq->cq_type = qinfo->type;
> -	cq->q_id = qinfo->id;
> -	cq->buf_size = qinfo->buf_size;
> -	cq->ring_size = qinfo->len;
> -
> -	cq->next_to_use = 0;
> -	cq->next_to_clean = 0;
> -	cq->next_to_post = cq->ring_size - 1;
> -
> -	switch (qinfo->type) {
> -	case IDPF_CTLQ_TYPE_MAILBOX_RX:
> -		is_rxq = true;
> -		fallthrough;
> -	case IDPF_CTLQ_TYPE_MAILBOX_TX:
> -		err = idpf_ctlq_alloc_ring_res(hw, cq);
> -		break;
> -	default:
> -		err = -EBADR;
> -		break;
> -	}
> -
> -	if (err)
> -		goto init_free_q;
> -
> -	if (is_rxq) {
> -		idpf_ctlq_init_rxq_bufs(cq);
> -	} else {
> -		/* Allocate the array of msg pointers for TX queues */
> -		cq->bi.tx_msg = kzalloc_objs(struct idpf_ctlq_msg *, qinfo->len);
> -		if (!cq->bi.tx_msg) {
> -			err = -ENOMEM;
> -			goto init_dealloc_q_mem;
> -		}
> -	}
> -
> -	idpf_ctlq_setup_regs(cq, qinfo);
> -
> -	idpf_ctlq_init_regs(hw, cq, is_rxq);
> -
> -	spin_lock_init(&cq->cq_lock);
> -
> -	list_add(&cq->cq_list, &hw->cq_list_head);
> -
> -	*cq_out = cq;
> -
> -	return 0;
> -
> -init_dealloc_q_mem:
> -	/* free ring buffers and the ring itself */
> -	idpf_ctlq_dealloc_ring_res(hw, cq);
> -init_free_q:
> -	kfree(cq);
> -
> -	return err;
> -}
> -
> -/**
> - * idpf_ctlq_remove - deallocate and remove specified control queue
> - * @hw: pointer to hardware struct
> - * @cq: pointer to control queue to be removed
> - */
> -void idpf_ctlq_remove(struct idpf_hw *hw,
> -		      struct idpf_ctlq_info *cq)
> -{
> -	list_del(&cq->cq_list);
> -	idpf_ctlq_shutdown(hw, cq);
> -	kfree(cq);
> -}
> -
> -/**
> - * idpf_ctlq_init - main initialization routine for all control queues
> - * @hw: pointer to hardware struct
> - * @num_q: number of queues to initialize
> - * @q_info: array of structs containing info for each queue to be initialized
> - *
> - * This initializes any number and any type of control queues. This is an all
> - * or nothing routine; if one fails, all previously allocated queues will be
> - * destroyed. This must be called prior to using the individual add/remove
> - * APIs.
> - */
> -int idpf_ctlq_init(struct idpf_hw *hw, u8 num_q,
> -		   struct idpf_ctlq_create_info *q_info)
> -{
> -	struct idpf_ctlq_info *cq, *tmp;
> -	int err;
> -	int i;
> -
> -	INIT_LIST_HEAD(&hw->cq_list_head);
> -
> -	for (i = 0; i < num_q; i++) {
> -		struct idpf_ctlq_create_info *qinfo = q_info + i;
> -
> -		err = idpf_ctlq_add(hw, qinfo, &cq);
> -		if (err)
> -			goto init_destroy_qs;
> -	}
> -
> -	return 0;
> -
> -init_destroy_qs:
> -	list_for_each_entry_safe(cq, tmp, &hw->cq_list_head, cq_list)
> -		idpf_ctlq_remove(hw, cq);
> -
> -	return err;
> -}
> -
> -/**
> - * idpf_ctlq_deinit - destroy all control queues
> - * @hw: pointer to hw struct
> - */
> -void idpf_ctlq_deinit(struct idpf_hw *hw)
> -{
> -	struct idpf_ctlq_info *cq, *tmp;
> -
> -	list_for_each_entry_safe(cq, tmp, &hw->cq_list_head, cq_list)
> -		idpf_ctlq_remove(hw, cq);
> -}
> -
> -/**
> - * idpf_ctlq_send - send command to Control Queue (CTQ)
> - * @hw: pointer to hw struct
> - * @cq: handle to control queue struct to send on
> - * @num_q_msg: number of messages to send on control queue
> - * @q_msg: pointer to array of queue messages to be sent
> - *
> - * The caller is expected to allocate DMAable buffers and pass them to the
> - * send routine via the q_msg struct / control queue specific data struct.
> - * The control queue will hold a reference to each send message until
> - * the completion for that message has been cleaned.
> - */
> -int idpf_ctlq_send(struct idpf_hw *hw, struct idpf_ctlq_info *cq,
> -		   u16 num_q_msg, struct idpf_ctlq_msg q_msg[])
> -{
> -	struct idpf_ctlq_desc *desc;
> -	int num_desc_avail;
> -	int err = 0;
> -	int i;
> -
> -	spin_lock(&cq->cq_lock);
> -
> -	/* Ensure there are enough descriptors to send all messages */
> -	num_desc_avail = IDPF_CTLQ_DESC_UNUSED(cq);
> -	if (num_desc_avail == 0 || num_desc_avail < num_q_msg) {
> -		err = -ENOSPC;
> -		goto err_unlock;
> -	}
> -
> -	for (i = 0; i < num_q_msg; i++) {
> -		struct idpf_ctlq_msg *msg = &q_msg[i];
> -
> -		desc = IDPF_CTLQ_DESC(cq, cq->next_to_use);
> -
> -		desc->opcode = cpu_to_le16(msg->opcode);
> -		desc->pfid_vfid = cpu_to_le16(msg->func_id);
> -
> -		desc->v_opcode_dtype = cpu_to_le32(msg->cookie.mbx.chnl_opcode);
> -		desc->v_retval = cpu_to_le32(msg->cookie.mbx.chnl_retval);
> -
> -		desc->flags = cpu_to_le16((msg->host_id & IDPF_HOST_ID_MASK) <<
> -					  IDPF_CTLQ_FLAG_HOST_ID_S);
> -		if (msg->data_len) {
> -			struct idpf_dma_mem *buff = msg->ctx.indirect.payload;
> -
> -			desc->datalen |= cpu_to_le16(msg->data_len);
> -			desc->flags |= cpu_to_le16(IDPF_CTLQ_FLAG_BUF);
> -			desc->flags |= cpu_to_le16(IDPF_CTLQ_FLAG_RD);
> -
> -			/* Update the address values in the desc with the pa
> -			 * value for respective buffer
> -			 */
> -			desc->params.indirect.addr_high =
> -				cpu_to_le32(upper_32_bits(buff->pa));
> -			desc->params.indirect.addr_low =
> -				cpu_to_le32(lower_32_bits(buff->pa));
> -
> -			memcpy(&desc->params, msg->ctx.indirect.context,
> -			       IDPF_INDIRECT_CTX_SIZE);
> -		} else {
> -			memcpy(&desc->params, msg->ctx.direct,
> -			       IDPF_DIRECT_CTX_SIZE);
> -		}
> -
> -		/* Store buffer info */
> -		cq->bi.tx_msg[cq->next_to_use] = msg;
> -
> -		(cq->next_to_use)++;
> -		if (cq->next_to_use == cq->ring_size)
> -			cq->next_to_use = 0;
> -	}
> -
> -	/* Force memory write to complete before letting hardware
> -	 * know that there are new descriptors to fetch.
> -	 */
> -	dma_wmb();
> -
> -	writel(cq->next_to_use,
> -	       libie_pci_get_mmio_addr(&hw->back->ctlq_ctx.mmio_info,
> -				       cq->reg.tail));
> -
> -err_unlock:
> -	spin_unlock(&cq->cq_lock);
> -
> -	return err;
> -}
> -
> -/**
> - * idpf_ctlq_clean_sq - reclaim send descriptors on HW write back for the
> - * requested queue
> - * @cq: pointer to the specific Control queue
> - * @clean_count: (input|output) number of descriptors to clean as input, and
> - * number of descriptors actually cleaned as output
> - * @msg_status: (output) pointer to msg pointer array to be populated; needs
> - * to be allocated by caller
> - *
> - * Returns an array of message pointers associated with the cleaned
> - * descriptors. The pointers are to the original ctlq_msgs sent on the cleaned
> - * descriptors.  The status will be returned for each; any messages that failed
> - * to send will have a non-zero status. The caller is expected to free original
> - * ctlq_msgs and free or reuse the DMA buffers.
> - */
> -int idpf_ctlq_clean_sq(struct idpf_ctlq_info *cq, u16 *clean_count,
> -		       struct idpf_ctlq_msg *msg_status[])
> -{
> -	struct idpf_ctlq_desc *desc;
> -	u16 i, num_to_clean;
> -	u16 ntc, desc_err;
> -
> -	if (*clean_count == 0)
> -		return 0;
> -	if (*clean_count > cq->ring_size)
> -		return -EBADR;
> -
> -	spin_lock(&cq->cq_lock);
> -
> -	ntc = cq->next_to_clean;
> -
> -	num_to_clean = *clean_count;
> -
> -	for (i = 0; i < num_to_clean; i++) {
> -		/* Fetch next descriptor and check if marked as done */
> -		desc = IDPF_CTLQ_DESC(cq, ntc);
> -		if (!(le16_to_cpu(desc->flags) & IDPF_CTLQ_FLAG_DD))
> -			break;
> -
> -		/* Ensure no other fields are read until DD flag is checked */
> -		dma_rmb();
> -
> -		/* strip off FW internal code */
> -		desc_err = le16_to_cpu(desc->ret_val) & 0xff;
> -
> -		msg_status[i] = cq->bi.tx_msg[ntc];
> -		msg_status[i]->status = desc_err;
> -
> -		cq->bi.tx_msg[ntc] = NULL;
> -
> -		/* Zero out any stale data */
> -		memset(desc, 0, sizeof(*desc));
> -
> -		ntc++;
> -		if (ntc == cq->ring_size)
> -			ntc = 0;
> -	}
> -
> -	cq->next_to_clean = ntc;
> -
> -	spin_unlock(&cq->cq_lock);
> -
> -	/* Return number of descriptors actually cleaned */
> -	*clean_count = i;
> -
> -	return 0;
> -}
> -
> -/**
> - * idpf_ctlq_post_rx_buffs - post buffers to descriptor ring
> - * @hw: pointer to hw struct
> - * @cq: pointer to control queue handle
> - * @buff_count: (input|output) input is number of buffers caller is trying to
> - * return; output is number of buffers that were not posted
> - * @buffs: array of pointers to dma mem structs to be given to hardware
> - *
> - * Caller uses this function to return DMA buffers to the descriptor ring after
> - * consuming them; buff_count will be the number of buffers.
> - *
> - * Note: this function needs to be called after a receive call even
> - * if there are no DMA buffers to be returned, i.e. buff_count = 0,
> - * buffs = NULL to support direct commands
> - */
> -int idpf_ctlq_post_rx_buffs(struct idpf_hw *hw, struct idpf_ctlq_info *cq,
> -			    u16 *buff_count, struct idpf_dma_mem **buffs)
> -{
> -	struct idpf_ctlq_desc *desc;
> -	u16 ntp = cq->next_to_post;
> -	bool buffs_avail = false;
> -	u16 tbp = ntp + 1;
> -	int i = 0;
> -
> -	if (*buff_count > cq->ring_size)
> -		return -EBADR;
> -
> -	if (*buff_count > 0)
> -		buffs_avail = true;
> -
> -	spin_lock(&cq->cq_lock);
> -
> -	if (tbp >= cq->ring_size)
> -		tbp = 0;
> -
> -	if (tbp == cq->next_to_clean)
> -		/* Nothing to do */
> -		goto post_buffs_out;
> -
> -	/* Post buffers for as many as provided or up until the last one used */
> -	while (ntp != cq->next_to_clean) {
> -		desc = IDPF_CTLQ_DESC(cq, ntp);
> -
> -		if (cq->bi.rx_buff[ntp])
> -			goto fill_desc;
> -		if (!buffs_avail) {
> -			/* If the caller hasn't given us any buffers or
> -			 * there are none left, search the ring itself
> -			 * for an available buffer to move to this
> -			 * entry starting at the next entry in the ring
> -			 */
> -			tbp = ntp + 1;
> -
> -			/* Wrap ring if necessary */
> -			if (tbp >= cq->ring_size)
> -				tbp = 0;
> -
> -			while (tbp != cq->next_to_clean) {
> -				if (cq->bi.rx_buff[tbp]) {
> -					cq->bi.rx_buff[ntp] =
> -						cq->bi.rx_buff[tbp];
> -					cq->bi.rx_buff[tbp] = NULL;
> -
> -					/* Found a buffer, no need to
> -					 * search anymore
> -					 */
> -					break;
> -				}
> -
> -				/* Wrap ring if necessary */
> -				tbp++;
> -				if (tbp >= cq->ring_size)
> -					tbp = 0;
> -			}
> -
> -			if (tbp == cq->next_to_clean)
> -				goto post_buffs_out;
> -		} else {
> -			/* Give back pointer to DMA buffer */
> -			cq->bi.rx_buff[ntp] = buffs[i];
> -			i++;
> -
> -			if (i >= *buff_count)
> -				buffs_avail = false;
> -		}
> -
> -fill_desc:
> -		desc->flags =
> -			cpu_to_le16(IDPF_CTLQ_FLAG_BUF | IDPF_CTLQ_FLAG_RD);
> -
> -		/* Post buffers to descriptor */
> -		desc->datalen = cpu_to_le16(cq->bi.rx_buff[ntp]->size);
> -		desc->params.indirect.addr_high =
> -			cpu_to_le32(upper_32_bits(cq->bi.rx_buff[ntp]->pa));
> -		desc->params.indirect.addr_low =
> -			cpu_to_le32(lower_32_bits(cq->bi.rx_buff[ntp]->pa));
> -
> -		ntp++;
> -		if (ntp == cq->ring_size)
> -			ntp = 0;
> -	}
> -
> -post_buffs_out:
> -	/* Only update tail if buffers were actually posted */
> -	if (cq->next_to_post != ntp) {
> -		if (ntp)
> -			/* Update next_to_post to ntp - 1 since current ntp
> -			 * will not have a buffer
> -			 */
> -			cq->next_to_post = ntp - 1;
> -		else
> -			/* Wrap to end of end ring since current ntp is 0 */
> -			cq->next_to_post = cq->ring_size - 1;
> -
> -		dma_wmb();
> -
> -		writel(cq->next_to_post,
> -		       libie_pci_get_mmio_addr(&hw->back->ctlq_ctx.mmio_info,
> -					       cq->reg.tail));
> -	}
> -
> -	spin_unlock(&cq->cq_lock);
> -
> -	/* return the number of buffers that were not posted */
> -	*buff_count = *buff_count - i;
> -
> -	return 0;
> -}
> -
> -/**
> - * idpf_ctlq_recv - receive control queue message call back
> - * @cq: pointer to control queue handle to receive on
> - * @num_q_msg: (input|output) input number of messages that should be received;
> - * output number of messages actually received
> - * @q_msg: (output) array of received control queue messages on this q;
> - * needs to be pre-allocated by caller for as many messages as requested
> - *
> - * Called by interrupt handler or polling mechanism. Caller is expected
> - * to free buffers
> - */
> -int idpf_ctlq_recv(struct idpf_ctlq_info *cq, u16 *num_q_msg,
> -		   struct idpf_ctlq_msg *q_msg)
> -{
> -	u16 num_to_clean, ntc, flags;
> -	struct idpf_ctlq_desc *desc;
> -	int err = 0;
> -	u16 i;
> -
> -	/* take the lock before we start messing with the ring */
> -	spin_lock(&cq->cq_lock);
> -
> -	ntc = cq->next_to_clean;
> -
> -	num_to_clean = *num_q_msg;
> -
> -	for (i = 0; i < num_to_clean; i++) {
> -		/* Fetch next descriptor and check if marked as done */
> -		desc = IDPF_CTLQ_DESC(cq, ntc);
> -		flags = le16_to_cpu(desc->flags);
> -
> -		if (!(flags & IDPF_CTLQ_FLAG_DD))
> -			break;
> -
> -		/* Ensure no other fields are read until DD flag is checked */
> -		dma_rmb();
> -
> -		q_msg[i].vmvf_type = (flags &
> -				      (IDPF_CTLQ_FLAG_FTYPE_VM |
> -				       IDPF_CTLQ_FLAG_FTYPE_PF)) >>
> -				       IDPF_CTLQ_FLAG_FTYPE_S;
> -
> -		if (flags & IDPF_CTLQ_FLAG_ERR)
> -			err  = -EBADMSG;
> -
> -		q_msg[i].cookie.mbx.chnl_opcode =
> -				le32_to_cpu(desc->v_opcode_dtype);
> -		q_msg[i].cookie.mbx.chnl_retval =
> -				le32_to_cpu(desc->v_retval);
> -
> -		q_msg[i].opcode = le16_to_cpu(desc->opcode);
> -		q_msg[i].data_len = le16_to_cpu(desc->datalen);
> -		q_msg[i].status = le16_to_cpu(desc->ret_val);
> -
> -		if (desc->datalen) {
> -			memcpy(q_msg[i].ctx.indirect.context,
> -			       &desc->params.indirect, IDPF_INDIRECT_CTX_SIZE);
> -
> -			/* Assign pointer to dma buffer to ctlq_msg array
> -			 * to be given to upper layer
> -			 */
> -			q_msg[i].ctx.indirect.payload = cq->bi.rx_buff[ntc];
> -
> -			/* Zero out pointer to DMA buffer info;
> -			 * will be repopulated by post buffers API
> -			 */
> -			cq->bi.rx_buff[ntc] = NULL;
> -		} else {
> -			memcpy(q_msg[i].ctx.direct, desc->params.raw,
> -			       IDPF_DIRECT_CTX_SIZE);
> -		}
> -
> -		/* Zero out stale data in descriptor */
> -		memset(desc, 0, sizeof(struct idpf_ctlq_desc));
> -
> -		ntc++;
> -		if (ntc == cq->ring_size)
> -			ntc = 0;
> -	}
> -
> -	cq->next_to_clean = ntc;
> -
> -	spin_unlock(&cq->cq_lock);
> -
> -	*num_q_msg = i;
> -	if (*num_q_msg == 0)
> -		err = -ENOMSG;
> -
> -	return err;
> -}
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq.h b/drivers/net/ethernet/intel/idpf/idpf_controlq.h
> deleted file mode 100644
> index acf595e9265f..000000000000
> --- a/drivers/net/ethernet/intel/idpf/idpf_controlq.h
> +++ /dev/null
> @@ -1,142 +0,0 @@
> -/* SPDX-License-Identifier: GPL-2.0-only */
> -/* Copyright (C) 2023 Intel Corporation */
> -
> -#ifndef _IDPF_CONTROLQ_H_
> -#define _IDPF_CONTROLQ_H_
> -
> -#include <linux/slab.h>
> -
> -#include "idpf_controlq_api.h"
> -
> -/* Maximum buffer length for all control queue types */
> -#define IDPF_CTLQ_MAX_BUF_LEN	4096
> -
> -#define IDPF_CTLQ_DESC(R, i) \
> -	(&(((struct idpf_ctlq_desc *)((R)->desc_ring.va))[i]))
> -
> -#define IDPF_CTLQ_DESC_UNUSED(R) \
> -	((u16)((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->ring_size) + \
> -	       (R)->next_to_clean - (R)->next_to_use - 1))
> -
> -/* Control Queue default settings */
> -#define IDPF_CTRL_SQ_CMD_TIMEOUT	250  /* msecs */
> -
> -struct idpf_ctlq_desc {
> -	/* Control queue descriptor flags */
> -	__le16 flags;
> -	/* Control queue message opcode */
> -	__le16 opcode;
> -	__le16 datalen;		/* 0 for direct commands */
> -	union {
> -		__le16 ret_val;
> -		__le16 pfid_vfid;
> -#define IDPF_CTLQ_DESC_VF_ID_S	0
> -#define IDPF_CTLQ_DESC_VF_ID_M	(0x7FF << IDPF_CTLQ_DESC_VF_ID_S)
> -#define IDPF_CTLQ_DESC_PF_ID_S	11
> -#define IDPF_CTLQ_DESC_PF_ID_M	(0x1F << IDPF_CTLQ_DESC_PF_ID_S)
> -	};
> -
> -	/* Virtchnl message opcode and virtchnl descriptor type
> -	 * v_opcode=[27:0], v_dtype=[31:28]
> -	 */
> -	__le32 v_opcode_dtype;
> -	/* Virtchnl return value */
> -	__le32 v_retval;
> -	union {
> -		struct {
> -			__le32 param0;
> -			__le32 param1;
> -			__le32 param2;
> -			__le32 param3;
> -		} direct;
> -		struct {
> -			__le32 param0;
> -			__le16 sw_cookie;
> -			/* Virtchnl flags */
> -			__le16 v_flags;
> -			__le32 addr_high;
> -			__le32 addr_low;
> -		} indirect;
> -		u8 raw[16];
> -	} params;
> -};
> -
> -/* Flags sub-structure
> - * |0  |1  |2  |3  |4  |5  |6  |7  |8  |9  |10 |11 |12 |13 |14 |15 |
> - * |DD |CMP|ERR|  * RSV *  |FTYPE  | *RSV* |RD |VFC|BUF|  HOST_ID  |
> - */
> -/* command flags and offsets */
> -#define IDPF_CTLQ_FLAG_DD_S		0
> -#define IDPF_CTLQ_FLAG_CMP_S		1
> -#define IDPF_CTLQ_FLAG_ERR_S		2
> -#define IDPF_CTLQ_FLAG_FTYPE_S		6
> -#define IDPF_CTLQ_FLAG_RD_S		10
> -#define IDPF_CTLQ_FLAG_VFC_S		11
> -#define IDPF_CTLQ_FLAG_BUF_S		12
> -#define IDPF_CTLQ_FLAG_HOST_ID_S	13
> -
> -#define IDPF_CTLQ_FLAG_DD	BIT(IDPF_CTLQ_FLAG_DD_S)	/* 0x1	  */
> -#define IDPF_CTLQ_FLAG_CMP	BIT(IDPF_CTLQ_FLAG_CMP_S)	/* 0x2	  */
> -#define IDPF_CTLQ_FLAG_ERR	BIT(IDPF_CTLQ_FLAG_ERR_S)	/* 0x4	  */
> -#define IDPF_CTLQ_FLAG_FTYPE_VM	BIT(IDPF_CTLQ_FLAG_FTYPE_S)	/* 0x40	  */
> -#define IDPF_CTLQ_FLAG_FTYPE_PF	BIT(IDPF_CTLQ_FLAG_FTYPE_S + 1)	/* 0x80   */
> -#define IDPF_CTLQ_FLAG_RD	BIT(IDPF_CTLQ_FLAG_RD_S)	/* 0x400  */
> -#define IDPF_CTLQ_FLAG_VFC	BIT(IDPF_CTLQ_FLAG_VFC_S)	/* 0x800  */
> -#define IDPF_CTLQ_FLAG_BUF	BIT(IDPF_CTLQ_FLAG_BUF_S)	/* 0x1000 */
> -
> -/* Host ID is a special field that has 3b and not a 1b flag */
> -#define IDPF_CTLQ_FLAG_HOST_ID_M MAKE_MASK(0x7000UL, IDPF_CTLQ_FLAG_HOST_ID_S)
> -
> -struct idpf_mbxq_desc {
> -	u8 pad[8];		/* CTLQ flags/opcode/len/retval fields */
> -	u32 chnl_opcode;	/* avoid confusion with desc->opcode */
> -	u32 chnl_retval;	/* ditto for desc->retval */
> -	u32 pf_vf_id;		/* used by CP when sending to PF */
> -};
> -
> -/* Max number of MMIO regions not including the mailbox and rstat regions in
> - * the fallback case when the whole bar is mapped.
> - */
> -#define IDPF_MMIO_MAP_FALLBACK_MAX_REMAINING		3
> -
> -struct idpf_mmio_reg {
> -	void __iomem *vaddr;
> -	resource_size_t addr_start;
> -	resource_size_t addr_len;
> -};
> -
> -/* Define the driver hardware struct to replace other control structs as needed
> - * Align to ctlq_hw_info
> - */
> -struct idpf_hw {
> -	/* Array of remaining LAN BAR regions */
> -	int num_lan_regs;
> -	struct idpf_mmio_reg *lan_regs;
> -
> -	struct idpf_adapter *back;
> -
> -	/* control queue - send and receive */
> -	struct idpf_ctlq_info *asq;
> -	struct idpf_ctlq_info *arq;
> -
> -	/* pci info */
> -	u16 device_id;
> -	u16 vendor_id;
> -	u16 subsystem_device_id;
> -	u16 subsystem_vendor_id;
> -	u8 revision_id;
> -	bool adapter_stopped;
> -
> -	struct list_head cq_list_head;
> -};
> -
> -int idpf_ctlq_alloc_ring_res(struct idpf_hw *hw,
> -			     struct idpf_ctlq_info *cq);
> -
> -void idpf_ctlq_dealloc_ring_res(struct idpf_hw *hw, struct idpf_ctlq_info *cq);
> -
> -/* prototype for functions used for dynamic memory allocation */
> -void *idpf_alloc_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem,
> -			 u64 size);
> -void idpf_free_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem);
> -#endif /* _IDPF_CONTROLQ_H_ */
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h b/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h
> deleted file mode 100644
> index 3414c5f9a831..000000000000
> --- a/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h
> +++ /dev/null
> @@ -1,177 +0,0 @@
> -/* SPDX-License-Identifier: GPL-2.0-only */
> -/* Copyright (C) 2023 Intel Corporation */
> -
> -#ifndef _IDPF_CONTROLQ_API_H_
> -#define _IDPF_CONTROLQ_API_H_
> -
> -#include "idpf_mem.h"
> -
> -struct idpf_hw;
> -
> -/* Used for queue init, response and events */
> -enum idpf_ctlq_type {
> -	IDPF_CTLQ_TYPE_MAILBOX_TX	= 0,
> -	IDPF_CTLQ_TYPE_MAILBOX_RX	= 1,
> -	IDPF_CTLQ_TYPE_CONFIG_TX	= 2,
> -	IDPF_CTLQ_TYPE_CONFIG_RX	= 3,
> -	IDPF_CTLQ_TYPE_EVENT_RX		= 4,
> -	IDPF_CTLQ_TYPE_RDMA_TX		= 5,
> -	IDPF_CTLQ_TYPE_RDMA_RX		= 6,
> -	IDPF_CTLQ_TYPE_RDMA_COMPL	= 7
> -};
> -
> -/* Generic Control Queue Structures */
> -struct idpf_ctlq_reg {
> -	/* used for queue tracking */
> -	u32 head;
> -	u32 tail;
> -	/* Below applies only to default mb (if present) */
> -	u32 len;
> -	u32 bah;
> -	u32 bal;
> -	u32 len_mask;
> -	u32 len_ena_mask;
> -	u32 head_mask;
> -};
> -
> -/* Generic queue msg structure */
> -struct idpf_ctlq_msg {
> -	u8 vmvf_type; /* represents the source of the message on recv */
> -#define IDPF_VMVF_TYPE_VF 0
> -#define IDPF_VMVF_TYPE_VM 1
> -#define IDPF_VMVF_TYPE_PF 2
> -	u8 host_id;
> -	/* 3b field used only when sending a message to CP - to be used in
> -	 * combination with target func_id to route the message
> -	 */
> -#define IDPF_HOST_ID_MASK 0x7
> -
> -	u16 opcode;
> -	u16 data_len;	/* data_len = 0 when no payload is attached */
> -	union {
> -		u16 func_id;	/* when sending a message */
> -		u16 status;	/* when receiving a message */
> -	};
> -	union {
> -		struct {
> -			u32 chnl_opcode;
> -			u32 chnl_retval;
> -		} mbx;
> -	} cookie;
> -	union {
> -#define IDPF_DIRECT_CTX_SIZE	16
> -#define IDPF_INDIRECT_CTX_SIZE	8
> -		/* 16 bytes of context can be provided or 8 bytes of context
> -		 * plus the address of a DMA buffer
> -		 */
> -		u8 direct[IDPF_DIRECT_CTX_SIZE];
> -		struct {
> -			u8 context[IDPF_INDIRECT_CTX_SIZE];
> -			struct idpf_dma_mem *payload;
> -		} indirect;
> -		struct {
> -			u32 rsvd;
> -			u16 data;
> -			u16 flags;
> -		} sw_cookie;
> -	} ctx;
> -};
> -
> -/* Generic queue info structures */
> -/* MB, CONFIG and EVENT q do not have extended info */
> -struct idpf_ctlq_create_info {
> -	enum idpf_ctlq_type type;
> -	int id; /* absolute queue offset passed as input
> -		 * -1 for default mailbox if present
> -		 */
> -	u16 len; /* Queue length passed as input */
> -	u16 buf_size; /* buffer size passed as input */
> -	u64 base_address; /* output, HPA of the Queue start  */
> -	struct idpf_ctlq_reg reg; /* registers accessed by ctlqs */
> -
> -	int ext_info_size;
> -	void *ext_info; /* Specific to q type */
> -};
> -
> -/* Control Queue information */
> -struct idpf_ctlq_info {
> -	struct list_head cq_list;
> -
> -	enum idpf_ctlq_type cq_type;
> -	int q_id;
> -	spinlock_t cq_lock;		/* control queue lock */
> -	/* used for interrupt processing */
> -	u16 next_to_use;
> -	u16 next_to_clean;
> -	u16 next_to_post;		/* starting descriptor to post buffers
> -					 * to after recev
> -					 */
> -
> -	struct idpf_dma_mem desc_ring;	/* descriptor ring memory
> -					 * idpf_dma_mem is defined in OSdep.h
> -					 */
> -	union {
> -		struct idpf_dma_mem **rx_buff;
> -		struct idpf_ctlq_msg **tx_msg;
> -	} bi;
> -
> -	u16 buf_size;			/* queue buffer size */
> -	u16 ring_size;			/* Number of descriptors */
> -	struct idpf_ctlq_reg reg;	/* registers accessed by ctlqs */
> -};
> -
> -/**
> - * enum idpf_mbx_opc - PF/VF mailbox commands
> - * @idpf_mbq_opc_send_msg_to_cp: used by PF or VF to send a message to its CP
> - * @idpf_mbq_opc_send_msg_to_peer_drv: used by PF or VF to send a message to
> - *				       any peer driver
> - */
> -enum idpf_mbx_opc {
> -	idpf_mbq_opc_send_msg_to_cp		= 0x0801,
> -	idpf_mbq_opc_send_msg_to_peer_drv	= 0x0804,
> -};
> -
> -/* API supported for control queue management */
> -/* Will init all required q including default mb.  "q_info" is an array of
> - * create_info structs equal to the number of control queues to be created.
> - */
> -int idpf_ctlq_init(struct idpf_hw *hw, u8 num_q,
> -		   struct idpf_ctlq_create_info *q_info);
> -
> -/* Allocate and initialize a single control queue, which will be added to the
> - * control queue list; returns a handle to the created control queue
> - */
> -int idpf_ctlq_add(struct idpf_hw *hw,
> -		  struct idpf_ctlq_create_info *qinfo,
> -		  struct idpf_ctlq_info **cq);
> -
> -/* Deinitialize and deallocate a single control queue */
> -void idpf_ctlq_remove(struct idpf_hw *hw,
> -		      struct idpf_ctlq_info *cq);
> -
> -/* Sends messages to HW and will also free the buffer*/
> -int idpf_ctlq_send(struct idpf_hw *hw,
> -		   struct idpf_ctlq_info *cq,
> -		   u16 num_q_msg,
> -		   struct idpf_ctlq_msg q_msg[]);
> -
> -/* Receives messages and called by interrupt handler/polling
> - * initiated by app/process. Also caller is supposed to free the buffers
> - */
> -int idpf_ctlq_recv(struct idpf_ctlq_info *cq, u16 *num_q_msg,
> -		   struct idpf_ctlq_msg *q_msg);
> -
> -/* Reclaims send descriptors on HW write back */
> -int idpf_ctlq_clean_sq(struct idpf_ctlq_info *cq, u16 *clean_count,
> -		       struct idpf_ctlq_msg *msg_status[]);
> -
> -/* Indicate RX buffers are done being processed */
> -int idpf_ctlq_post_rx_buffs(struct idpf_hw *hw,
> -			    struct idpf_ctlq_info *cq,
> -			    u16 *buff_count,
> -			    struct idpf_dma_mem **buffs);
> -
> -/* Will destroy all q including the default mb */
> -void idpf_ctlq_deinit(struct idpf_hw *hw);
> -
> -#endif /* _IDPF_CONTROLQ_API_H_ */
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c b/drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c
> deleted file mode 100644
> index d4d488c7cfd6..000000000000
> --- a/drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c
> +++ /dev/null
> @@ -1,169 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-only
> -/* Copyright (C) 2023 Intel Corporation */
> -
> -#include "idpf_controlq.h"
> -
> -/**
> - * idpf_ctlq_alloc_desc_ring - Allocate Control Queue (CQ) rings
> - * @hw: pointer to hw struct
> - * @cq: pointer to the specific Control queue
> - */
> -static int idpf_ctlq_alloc_desc_ring(struct idpf_hw *hw,
> -				     struct idpf_ctlq_info *cq)
> -{
> -	size_t size = cq->ring_size * sizeof(struct idpf_ctlq_desc);
> -
> -	cq->desc_ring.va = idpf_alloc_dma_mem(hw, &cq->desc_ring, size);
> -	if (!cq->desc_ring.va)
> -		return -ENOMEM;
> -
> -	return 0;
> -}
> -
> -/**
> - * idpf_ctlq_alloc_bufs - Allocate Control Queue (CQ) buffers
> - * @hw: pointer to hw struct
> - * @cq: pointer to the specific Control queue
> - *
> - * Allocate the buffer head for all control queues, and if it's a receive
> - * queue, allocate DMA buffers
> - */
> -static int idpf_ctlq_alloc_bufs(struct idpf_hw *hw,
> -				struct idpf_ctlq_info *cq)
> -{
> -	int i;
> -
> -	/* Do not allocate DMA buffers for transmit queues */
> -	if (cq->cq_type == IDPF_CTLQ_TYPE_MAILBOX_TX)
> -		return 0;
> -
> -	/* We'll be allocating the buffer info memory first, then we can
> -	 * allocate the mapped buffers for the event processing
> -	 */
> -	cq->bi.rx_buff = kzalloc_objs(struct idpf_dma_mem *, cq->ring_size);
> -	if (!cq->bi.rx_buff)
> -		return -ENOMEM;
> -
> -	/* allocate the mapped buffers (except for the last one) */
> -	for (i = 0; i < cq->ring_size - 1; i++) {
> -		struct idpf_dma_mem *bi;
> -		int num = 1; /* number of idpf_dma_mem to be allocated */
> -
> -		cq->bi.rx_buff[i] = kzalloc_objs(struct idpf_dma_mem, num);
> -		if (!cq->bi.rx_buff[i])
> -			goto unwind_alloc_cq_bufs;
> -
> -		bi = cq->bi.rx_buff[i];
> -
> -		bi->va = idpf_alloc_dma_mem(hw, bi, cq->buf_size);
> -		if (!bi->va) {
> -			/* unwind will not free the failed entry */
> -			kfree(cq->bi.rx_buff[i]);
> -			goto unwind_alloc_cq_bufs;
> -		}
> -	}
> -
> -	return 0;
> -
> -unwind_alloc_cq_bufs:
> -	/* don't try to free the one that failed... */
> -	i--;
> -	for (; i >= 0; i--) {
> -		idpf_free_dma_mem(hw, cq->bi.rx_buff[i]);
> -		kfree(cq->bi.rx_buff[i]);
> -	}
> -	kfree(cq->bi.rx_buff);
> -
> -	return -ENOMEM;
> -}
> -
> -/**
> - * idpf_ctlq_free_desc_ring - Free Control Queue (CQ) rings
> - * @hw: pointer to hw struct
> - * @cq: pointer to the specific Control queue
> - *
> - * This assumes the posted send buffers have already been cleaned
> - * and de-allocated
> - */
> -static void idpf_ctlq_free_desc_ring(struct idpf_hw *hw,
> -				     struct idpf_ctlq_info *cq)
> -{
> -	idpf_free_dma_mem(hw, &cq->desc_ring);
> -}
> -
> -/**
> - * idpf_ctlq_free_bufs - Free CQ buffer info elements
> - * @hw: pointer to hw struct
> - * @cq: pointer to the specific Control queue
> - *
> - * Free the DMA buffers for RX queues, and DMA buffer header for both RX and TX
> - * queues.  The upper layers are expected to manage freeing of TX DMA buffers
> - */
> -static void idpf_ctlq_free_bufs(struct idpf_hw *hw, struct idpf_ctlq_info *cq)
> -{
> -	void *bi;
> -
> -	if (cq->cq_type == IDPF_CTLQ_TYPE_MAILBOX_RX) {
> -		int i;
> -
> -		/* free DMA buffers for rx queues*/
> -		for (i = 0; i < cq->ring_size; i++) {
> -			if (cq->bi.rx_buff[i]) {
> -				idpf_free_dma_mem(hw, cq->bi.rx_buff[i]);
> -				kfree(cq->bi.rx_buff[i]);
> -			}
> -		}
> -
> -		bi = (void *)cq->bi.rx_buff;
> -	} else {
> -		bi = (void *)cq->bi.tx_msg;
> -	}
> -
> -	/* free the buffer header */
> -	kfree(bi);
> -}
> -
> -/**
> - * idpf_ctlq_dealloc_ring_res - Free memory allocated for control queue
> - * @hw: pointer to hw struct
> - * @cq: pointer to the specific Control queue
> - *
> - * Free the memory used by the ring, buffers and other related structures
> - */
> -void idpf_ctlq_dealloc_ring_res(struct idpf_hw *hw, struct idpf_ctlq_info *cq)
> -{
> -	/* free ring buffers and the ring itself */
> -	idpf_ctlq_free_bufs(hw, cq);
> -	idpf_ctlq_free_desc_ring(hw, cq);
> -}
> -
> -/**
> - * idpf_ctlq_alloc_ring_res - allocate memory for descriptor ring and bufs
> - * @hw: pointer to hw struct
> - * @cq: pointer to control queue struct
> - *
> - * Do *NOT* hold cq_lock when calling this as the memory allocation routines
> - * called are not going to be atomic context safe
> - */
> -int idpf_ctlq_alloc_ring_res(struct idpf_hw *hw, struct idpf_ctlq_info *cq)
> -{
> -	int err;
> -
> -	/* allocate the ring memory */
> -	err = idpf_ctlq_alloc_desc_ring(hw, cq);
> -	if (err)
> -		return err;
> -
> -	/* allocate buffers in the rings */
> -	err = idpf_ctlq_alloc_bufs(hw, cq);
> -	if (err)
> -		goto idpf_init_cq_free_ring;
> -
> -	/* success! */
> -	return 0;
> -
> -idpf_init_cq_free_ring:
> -	idpf_free_dma_mem(hw, &cq->desc_ring);
> -
> -	return err;
> -}
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c
> index a9e170eb24b7..92e707ff2b9c 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_dev.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c
> @@ -10,44 +10,32 @@
>   
>   /**
>    * idpf_ctlq_reg_init - initialize default mailbox registers
> - * @adapter: adapter structure
> - * @cq: pointer to the array of create control queues
> + * @mmio: struct that contains MMIO region info
> + * @cci: struct where the register offset pointer to be copied to
>    */
> -static void idpf_ctlq_reg_init(struct idpf_adapter *adapter,
> -			       struct idpf_ctlq_create_info *cq)
> +static void idpf_ctlq_reg_init(struct libie_mmio_info *mmio,
> +			       struct libie_ctlq_create_info *cci)
>   {
> -	int i;
> -
> -	for (i = 0; i < IDPF_NUM_DFLT_MBX_Q; i++) {
> -		struct idpf_ctlq_create_info *ccq = cq + i;
> -
> -		switch (ccq->type) {
> -		case IDPF_CTLQ_TYPE_MAILBOX_TX:
> -			/* set head and tail registers in our local struct */
> -			ccq->reg.head = PF_FW_ATQH;
> -			ccq->reg.tail = PF_FW_ATQT;
> -			ccq->reg.len = PF_FW_ATQLEN;
> -			ccq->reg.bah = PF_FW_ATQBAH;
> -			ccq->reg.bal = PF_FW_ATQBAL;
> -			ccq->reg.len_mask = PF_FW_ATQLEN_ATQLEN_M;
> -			ccq->reg.len_ena_mask = PF_FW_ATQLEN_ATQENABLE_M;
> -			ccq->reg.head_mask = PF_FW_ATQH_ATQH_M;
> -			break;
> -		case IDPF_CTLQ_TYPE_MAILBOX_RX:
> -			/* set head and tail registers in our local struct */
> -			ccq->reg.head = PF_FW_ARQH;
> -			ccq->reg.tail = PF_FW_ARQT;
> -			ccq->reg.len = PF_FW_ARQLEN;
> -			ccq->reg.bah = PF_FW_ARQBAH;
> -			ccq->reg.bal = PF_FW_ARQBAL;
> -			ccq->reg.len_mask = PF_FW_ARQLEN_ARQLEN_M;
> -			ccq->reg.len_ena_mask = PF_FW_ARQLEN_ARQENABLE_M;
> -			ccq->reg.head_mask = PF_FW_ARQH_ARQH_M;
> -			break;
> -		default:
> -			break;
> -		}
> -	}
> +	struct libie_ctlq_reg *tx_reg = &cci[LIBIE_CTLQ_TYPE_TX].reg;
> +	struct libie_ctlq_reg *rx_reg = &cci[LIBIE_CTLQ_TYPE_RX].reg;
> +
> +	tx_reg->head		= libie_pci_get_mmio_addr(mmio, PF_FW_ATQH);
> +	tx_reg->tail		= libie_pci_get_mmio_addr(mmio, PF_FW_ATQT);
> +	tx_reg->len		= libie_pci_get_mmio_addr(mmio, PF_FW_ATQLEN);
> +	tx_reg->addr_high	= libie_pci_get_mmio_addr(mmio, PF_FW_ATQBAH);
> +	tx_reg->addr_low	= libie_pci_get_mmio_addr(mmio, PF_FW_ATQBAL);
> +	tx_reg->len_mask	= PF_FW_ATQLEN_ATQLEN_M;
> +	tx_reg->len_ena_mask	= PF_FW_ATQLEN_ATQENABLE_M;
> +	tx_reg->head_mask	= PF_FW_ATQH_ATQH_M;
> +
> +	rx_reg->head		= libie_pci_get_mmio_addr(mmio, PF_FW_ARQH);
> +	rx_reg->tail		= libie_pci_get_mmio_addr(mmio, PF_FW_ARQT);
> +	rx_reg->len		= libie_pci_get_mmio_addr(mmio, PF_FW_ARQLEN);
> +	rx_reg->addr_high	= libie_pci_get_mmio_addr(mmio, PF_FW_ARQBAH);
> +	rx_reg->addr_low	= libie_pci_get_mmio_addr(mmio, PF_FW_ARQBAL);
> +	rx_reg->len_mask	= PF_FW_ARQLEN_ARQLEN_M;
> +	rx_reg->len_ena_mask	= PF_FW_ARQLEN_ARQENABLE_M;
> +	rx_reg->head_mask	= PF_FW_ARQH_ARQH_M;
>   }
>   
>   /**
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
> index bb99d9e7c65d..95c45f12b0f9 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
> @@ -225,7 +225,7 @@ static int idpf_add_flow_steer(struct net_device *netdev,
>   	spin_unlock_bh(&vport_config->flow_steer_list_lock);
>   
>   	if (err)
> -		goto out;
> +		goto out_free_fltr;
>   
>   	rule->vport_id = cpu_to_le32(vport->vport_id);
>   	rule->count = cpu_to_le32(1);
> @@ -252,17 +252,15 @@ static int idpf_add_flow_steer(struct net_device *netdev,
>   		break;
>   	default:
>   		err = -EINVAL;
> -		goto out;
> +		goto out_free_fltr;
>   	}
>   
>   	err = idpf_add_del_fsteer_filters(vport->adapter, rule,
>   					  VIRTCHNL2_OP_ADD_FLOW_RULE);
> -	if (err)
> -		goto out;
> -
> -	if (info->status != cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS)) {
> -		err = -EIO;
> -		goto out;
> +	if (err) {
> +		/* virtchnl2 rule is already consumed */
> +		kfree(fltr);
> +		return err;
>   	}
>   
>   	/* Save a copy of the user's flow spec so ethtool can later retrieve it */
> @@ -274,9 +272,10 @@ static int idpf_add_flow_steer(struct net_device *netdev,
>   
>   	user_config->num_fsteer_fltrs++;
>   	spin_unlock_bh(&vport_config->flow_steer_list_lock);
> -	goto out_free_rule;
>   
> -out:
> +	return 0;
> +
> +out_free_fltr:
>   	kfree(fltr);
>   out_free_rule:
>   	kfree(rule);
> @@ -319,12 +318,7 @@ static int idpf_del_flow_steer(struct net_device *netdev,
>   	err = idpf_add_del_fsteer_filters(vport->adapter, rule,
>   					  VIRTCHNL2_OP_DEL_FLOW_RULE);
>   	if (err)
> -		goto out;
> -
> -	if (info->status != cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS)) {
> -		err = -EIO;
> -		goto out;
> -	}
> +		return err;
>   
>   	spin_lock_bh(&vport_config->flow_steer_list_lock);
>   	list_for_each_entry_safe(f, iter,
> @@ -340,8 +334,6 @@ static int idpf_del_flow_steer(struct net_device *netdev,
>   
>   out_unlock:
>   	spin_unlock_bh(&vport_config->flow_steer_list_lock);
> -out:
> -	kfree(rule);
>   	return err;
>   }
>   
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
> index 875472ae77fd..0d131bf0993e 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
> @@ -1371,6 +1371,7 @@ void idpf_statistics_task(struct work_struct *work)
>    */
>   void idpf_mbx_task(struct work_struct *work)
>   {
> +	struct libie_ctlq_xn_recv_params xn_params;
>   	struct idpf_adapter *adapter;
>   
>   	adapter = container_of(work, struct idpf_adapter, mbx_task.work);
> @@ -1381,7 +1382,14 @@ void idpf_mbx_task(struct work_struct *work)
>   		queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task,
>   				   usecs_to_jiffies(300));
>   
> -	idpf_recv_mb_msg(adapter, adapter->hw.arq);
> +	xn_params = (struct libie_ctlq_xn_recv_params) {
> +		.xnm = adapter->xnm,
> +		.ctlq = adapter->arq,
> +		.ctlq_msg_handler = idpf_recv_event_msg,
> +		.budget = LIBIE_CTLQ_MAX_XN_ENTRIES,
> +	};
> +
> +	libie_ctlq_xn_recv(&xn_params);
>   }
>   
>   /**
> @@ -1909,7 +1917,6 @@ static void idpf_init_hard_reset(struct idpf_adapter *adapter)
>   		idpf_vc_core_deinit(adapter);
>   		if (!is_reset)
>   			reg_ops->trigger_reset(adapter, IDPF_HR_FUNC_RESET);
> -		idpf_deinit_dflt_mbx(adapter);
>   	} else {
>   		dev_err(dev, "Unhandled hard reset cause\n");
>   		err = -EBADRQC;
> @@ -1984,7 +1991,7 @@ void idpf_vc_event_task(struct work_struct *work)
>   	return;
>   
>   func_reset:
> -	idpf_vc_xn_shutdown(adapter->vcxn_mngr);
> +	libie_ctlq_xn_shutdown(adapter->xnm);
>   drv_load:
>   	set_bit(IDPF_HR_RESET_IN_PROG, adapter->flags);
>   	idpf_init_hard_reset(adapter);
> @@ -2567,44 +2574,6 @@ static int idpf_set_mac(struct net_device *netdev, void *p)
>   	return err;
>   }
>   
> -/**
> - * idpf_alloc_dma_mem - Allocate dma memory
> - * @hw: pointer to hw struct
> - * @mem: pointer to dma_mem struct
> - * @size: size of the memory to allocate
> - */
> -void *idpf_alloc_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem, u64 size)
> -{
> -	struct idpf_adapter *adapter = hw->back;
> -	size_t sz = ALIGN(size, 4096);
> -
> -	/* The control queue resources are freed under a spinlock, contiguous
> -	 * pages will avoid IOMMU remapping and the use vmap (and vunmap in
> -	 * dma_free_*() path.
> -	 */
> -	mem->va = dma_alloc_attrs(&adapter->pdev->dev, sz, &mem->pa,
> -				  GFP_KERNEL, DMA_ATTR_FORCE_CONTIGUOUS);
> -	mem->size = sz;
> -
> -	return mem->va;
> -}
> -
> -/**
> - * idpf_free_dma_mem - Free the allocated dma memory
> - * @hw: pointer to hw struct
> - * @mem: pointer to dma_mem struct
> - */
> -void idpf_free_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem)
> -{
> -	struct idpf_adapter *adapter = hw->back;
> -
> -	dma_free_attrs(&adapter->pdev->dev, mem->size,
> -		       mem->va, mem->pa, DMA_ATTR_FORCE_CONTIGUOUS);
> -	mem->size = 0;
> -	mem->va = NULL;
> -	mem->pa = 0;
> -}
> -
>   static int idpf_hwtstamp_set(struct net_device *netdev,
>   			     struct kernel_hwtstamp_config *config,
>   			     struct netlink_ext_ack *extack)
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c
> index d8e19d5f1647..d99f759c55e1 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_main.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_main.c
> @@ -133,7 +133,6 @@ static void idpf_remove(struct pci_dev *pdev)
>   
>   	/* Be a good citizen and leave the device clean on exit */
>   	adapter->dev_ops.reg_ops.trigger_reset(adapter, IDPF_HR_FUNC_RESET);
> -	idpf_deinit_dflt_mbx(adapter);
>   
>   	if (!adapter->netdevs)
>   		goto destroy_wqs;
> @@ -170,8 +169,6 @@ static void idpf_remove(struct pci_dev *pdev)
>   	adapter->vport_config = NULL;
>   	kfree(adapter->netdevs);
>   	adapter->netdevs = NULL;
> -	kfree(adapter->vcxn_mngr);
> -	adapter->vcxn_mngr = NULL;
>   
>   	mutex_destroy(&adapter->vport_ctrl_lock);
>   	mutex_destroy(&adapter->vector_lock);
> @@ -194,7 +191,6 @@ static void idpf_shutdown(struct pci_dev *pdev)
>   	cancel_delayed_work_sync(&adapter->serv_task);
>   	cancel_delayed_work_sync(&adapter->vc_event_task);
>   	idpf_vc_core_deinit(adapter);
> -	idpf_deinit_dflt_mbx(adapter);
>   
>   	if (system_state == SYSTEM_POWER_OFF)
>   		pci_set_power_state(pdev, PCI_D3hot);
> @@ -239,7 +235,6 @@ static int idpf_cfg_device(struct idpf_adapter *adapter)
>   		pci_dbg(pdev, "PCIe PTM is not supported by PCIe bus/controller\n");
>   
>   	pci_set_drvdata(pdev, adapter);
> -	adapter->hw.back = adapter;
>   
>   	return 0;
>   }
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_mem.h b/drivers/net/ethernet/intel/idpf/idpf_mem.h
> deleted file mode 100644
> index 2aaabdc02dd2..000000000000
> --- a/drivers/net/ethernet/intel/idpf/idpf_mem.h
> +++ /dev/null
> @@ -1,20 +0,0 @@
> -/* SPDX-License-Identifier: GPL-2.0-only */
> -/* Copyright (C) 2023 Intel Corporation */
> -
> -#ifndef _IDPF_MEM_H_
> -#define _IDPF_MEM_H_
> -
> -#include <linux/io.h>
> -
> -struct idpf_dma_mem {
> -	void *va;
> -	dma_addr_t pa;
> -	size_t size;
> -};
> -
> -#define idpf_mbx_wr32(a, reg, value)	writel((value), ((a)->mbx.vaddr + (reg)))
> -#define idpf_mbx_rd32(a, reg)		readl((a)->mbx.vaddr + (reg))
> -#define idpf_mbx_wr64(a, reg, value)	writeq((value), ((a)->mbx.vaddr + (reg)))
> -#define idpf_mbx_rd64(a, reg)		readq((a)->mbx.vaddr + (reg))
> -
> -#endif /* _IDPF_MEM_H_ */
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
> index e101ffb20ae0..a82794c8db3b 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
> +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
> @@ -236,7 +236,7 @@ enum idpf_tx_ctx_desc_eipt_offload {
>   				 (sizeof(u16) * IDPF_RX_MAX_PTYPE_PROTO_IDS))
>   #define IDPF_RX_PTYPE_HDR_SZ	sizeof(struct virtchnl2_get_ptype_info)
>   #define IDPF_RX_MAX_PTYPES_PER_BUF	\
> -	DIV_ROUND_DOWN_ULL((IDPF_CTLQ_MAX_BUF_LEN - IDPF_RX_PTYPE_HDR_SZ), \
> +	DIV_ROUND_DOWN_ULL(LIBIE_CTLQ_MAX_BUF_LEN - IDPF_RX_PTYPE_HDR_SZ, \
>   			   IDPF_RX_MAX_PTYPE_SZ)
>   
>   #define IDPF_GET_PTYPE_SIZE(p) struct_size((p), proto_id, (p)->proto_id_count)
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
> index a6127bac10a8..54535cd8dfaa 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
> @@ -9,45 +9,32 @@
>   
>   /**
>    * idpf_vf_ctlq_reg_init - initialize default mailbox registers
> - * @adapter: adapter structure
> - * @cq: pointer to the array of create control queues
> + * @mmio: struct that contains MMIO region info
> + * @cci: struct where the register offset pointer to be copied to
>    */
> -static void idpf_vf_ctlq_reg_init(struct idpf_adapter *adapter,
> -				  struct idpf_ctlq_create_info *cq)
> +static void idpf_vf_ctlq_reg_init(struct libie_mmio_info *mmio,
> +				  struct libie_ctlq_create_info *cci)
>   {
> -	resource_size_t mbx_start = adapter->dev_ops.static_reg_info[0].start;
> -	int i;
> -
> -	for (i = 0; i < IDPF_NUM_DFLT_MBX_Q; i++) {
> -		struct idpf_ctlq_create_info *ccq = cq + i;
> -
> -		switch (ccq->type) {
> -		case IDPF_CTLQ_TYPE_MAILBOX_TX:
> -			/* set head and tail registers in our local struct */
> -			ccq->reg.head = VF_ATQH - mbx_start;
> -			ccq->reg.tail = VF_ATQT - mbx_start;
> -			ccq->reg.len = VF_ATQLEN - mbx_start;
> -			ccq->reg.bah = VF_ATQBAH - mbx_start;
> -			ccq->reg.bal = VF_ATQBAL - mbx_start;
> -			ccq->reg.len_mask = VF_ATQLEN_ATQLEN_M;
> -			ccq->reg.len_ena_mask = VF_ATQLEN_ATQENABLE_M;
> -			ccq->reg.head_mask = VF_ATQH_ATQH_M;
> -			break;
> -		case IDPF_CTLQ_TYPE_MAILBOX_RX:
> -			/* set head and tail registers in our local struct */
> -			ccq->reg.head = VF_ARQH - mbx_start;
> -			ccq->reg.tail = VF_ARQT - mbx_start;
> -			ccq->reg.len = VF_ARQLEN - mbx_start;
> -			ccq->reg.bah = VF_ARQBAH - mbx_start;
> -			ccq->reg.bal = VF_ARQBAL - mbx_start;
> -			ccq->reg.len_mask = VF_ARQLEN_ARQLEN_M;
> -			ccq->reg.len_ena_mask = VF_ARQLEN_ARQENABLE_M;
> -			ccq->reg.head_mask = VF_ARQH_ARQH_M;
> -			break;
> -		default:
> -			break;
> -		}
> -	}
> +	struct libie_ctlq_reg *tx_reg = &cci[LIBIE_CTLQ_TYPE_TX].reg;
> +	struct libie_ctlq_reg *rx_reg = &cci[LIBIE_CTLQ_TYPE_RX].reg;
> +
> +	tx_reg->head		= libie_pci_get_mmio_addr(mmio, VF_ATQH);
> +	tx_reg->tail		= libie_pci_get_mmio_addr(mmio, VF_ATQT);
> +	tx_reg->len		= libie_pci_get_mmio_addr(mmio, VF_ATQLEN);
> +	tx_reg->addr_high	= libie_pci_get_mmio_addr(mmio, VF_ATQBAH);
> +	tx_reg->addr_low	= libie_pci_get_mmio_addr(mmio, VF_ATQBAL);
> +	tx_reg->len_mask	= VF_ATQLEN_ATQLEN_M;
> +	tx_reg->len_ena_mask	= VF_ATQLEN_ATQENABLE_M;
> +	tx_reg->head_mask	= VF_ATQH_ATQH_M;
> +
> +	rx_reg->head		= libie_pci_get_mmio_addr(mmio, VF_ARQH);
> +	rx_reg->tail		= libie_pci_get_mmio_addr(mmio, VF_ARQT);
> +	rx_reg->len		= libie_pci_get_mmio_addr(mmio, VF_ARQLEN);
> +	rx_reg->addr_high	= libie_pci_get_mmio_addr(mmio, VF_ARQBAH);
> +	rx_reg->addr_low	= libie_pci_get_mmio_addr(mmio, VF_ARQBAL);
> +	rx_reg->len_mask	= VF_ARQLEN_ARQLEN_M;
> +	rx_reg->len_ena_mask	= VF_ARQLEN_ARQENABLE_M;
> +	rx_reg->head_mask	= VF_ARQH_ARQH_M;
>   }
>   
>   /**
> @@ -160,11 +147,13 @@ static void idpf_vf_reset_reg_init(struct idpf_adapter *adapter)
>   static void idpf_vf_trigger_reset(struct idpf_adapter *adapter,
>   				  enum idpf_flags trig_cause)
>   {
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.chnl_opcode	= VIRTCHNL2_OP_RESET_VF,
> +	};
>   	/* Do not send VIRTCHNL2_OP_RESET_VF message on driver unload */
>   	if (trig_cause == IDPF_HR_FUNC_RESET &&
>   	    !test_bit(IDPF_REMOVE_IN_PROG, adapter->flags))
> -		idpf_send_mb_msg(adapter, adapter->hw.asq,
> -				 VIRTCHNL2_OP_RESET_VF, 0, NULL, 0);
> +		idpf_send_mb_msg(adapter, &xn_params, NULL, 0);
>   }
>   
>   /**
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
> index 7023aecc2ed5..6d847aea00e4 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
> @@ -9,20 +9,6 @@
>   #include "idpf_virtchnl.h"
>   #include "idpf_ptp.h"
>   
> -/**
> - * struct idpf_vc_xn_manager - Manager for tracking transactions
> - * @ring: backing and lookup for transactions
> - * @free_xn_bm: bitmap for free transactions
> - * @xn_bm_lock: make bitmap access synchronous where necessary
> - * @salt: used to make cookie unique every message
> - */
> -struct idpf_vc_xn_manager {
> -	struct idpf_vc_xn ring[IDPF_VC_XN_RING_LEN];
> -	DECLARE_BITMAP(free_xn_bm, IDPF_VC_XN_RING_LEN);
> -	spinlock_t xn_bm_lock;
> -	u8 salt;
> -};
> -
>   /**
>    * idpf_vid_to_vport - Translate vport id to vport pointer
>    * @adapter: private data struct
> @@ -83,79 +69,65 @@ static void idpf_handle_event_link(struct idpf_adapter *adapter,
>   
>   /**
>    * idpf_recv_event_msg - Receive virtchnl event message
> - * @adapter: Driver specific private structure
> + * @ctx: control queue context
>    * @ctlq_msg: message to copy from
>    *
>    * Receive virtchnl event message
>    */
> -static void idpf_recv_event_msg(struct idpf_adapter *adapter,
> -				struct idpf_ctlq_msg *ctlq_msg)
> +void idpf_recv_event_msg(struct libie_ctlq_ctx *ctx,
> +			 struct libie_ctlq_msg *ctlq_msg)
>   {
> -	int payload_size = ctlq_msg->ctx.indirect.payload->size;
> +	struct kvec *buff = &ctlq_msg->recv_mem;
> +	int payload_size = buff->iov_len;
> +	struct idpf_adapter *adapter;
>   	struct virtchnl2_event *v2e;
>   	u32 event;
>   
> +	adapter = container_of(ctx, struct idpf_adapter, ctlq_ctx);
>   	if (payload_size < sizeof(*v2e)) {
>   		dev_err_ratelimited(&adapter->pdev->dev, "Failed to receive valid payload for event msg (op %d len %d)\n",
> -				    ctlq_msg->cookie.mbx.chnl_opcode,
> +				    ctlq_msg->chnl_opcode,
>   				    payload_size);
> -		return;
> +		goto free_rx_buf;
>   	}
>   
> -	v2e = (struct virtchnl2_event *)ctlq_msg->ctx.indirect.payload->va;
> +	v2e = (struct virtchnl2_event *)buff->iov_base;
>   	event = le32_to_cpu(v2e->event);
>   
>   	switch (event) {
>   	case VIRTCHNL2_EVENT_LINK_CHANGE:
>   		idpf_handle_event_link(adapter, v2e);
> -		return;
> +		break;
>   	default:
>   		dev_err(&adapter->pdev->dev,
>   			"Unknown event %d from PF\n", event);
>   		break;
>   	}
> +
> +free_rx_buf:
> +	libie_ctlq_release_rx_buf(buff);
>   }
>   
>   /**
>    * idpf_mb_clean - Reclaim the send mailbox queue entries
>    * @adapter: driver specific private structure
>    * @asq: send control queue info
> + * @deinit: release all buffers before destroying the queue
>    *
> - * Reclaim the send mailbox queue entries to be used to send further messages
> - *
> - * Return: 0 on success, negative on failure
> + * This is a helper function to clean the send mailbox queue entries.
>    */
> -static int idpf_mb_clean(struct idpf_adapter *adapter,
> -			 struct idpf_ctlq_info *asq)
> +static void idpf_mb_clean(struct idpf_adapter *adapter,
> +			  struct libie_ctlq_info *asq, bool deinit)
>   {
> -	u16 i, num_q_msg = IDPF_DFLT_MBX_Q_LEN;
> -	struct idpf_ctlq_msg **q_msg;
> -	struct idpf_dma_mem *dma_mem;
> -	int err;
> -
> -	q_msg = kzalloc_objs(struct idpf_ctlq_msg *, num_q_msg, GFP_ATOMIC);
> -	if (!q_msg)
> -		return -ENOMEM;
> -
> -	err = idpf_ctlq_clean_sq(asq, &num_q_msg, q_msg);
> -	if (err)
> -		goto err_kfree;
> -
> -	for (i = 0; i < num_q_msg; i++) {
> -		if (!q_msg[i])
> -			continue;
> -		dma_mem = q_msg[i]->ctx.indirect.payload;
> -		if (dma_mem)
> -			dma_free_coherent(&adapter->pdev->dev, dma_mem->size,
> -					  dma_mem->va, dma_mem->pa);
> -		kfree(q_msg[i]);
> -		kfree(dma_mem);
> -	}
> -
> -err_kfree:
> -	kfree(q_msg);
> +	struct libie_ctlq_xn_clean_params clean_params = {
> +		.ctx		= &adapter->ctlq_ctx,
> +		.ctlq		= asq,
> +		.rel_tx_buf	= kfree,
> +		.num_msgs	= IDPF_DFLT_MBX_Q_LEN,
> +		.force		= deinit,
> +	};
>   
> -	return err;
> +	libie_ctlq_xn_send_clean(&clean_params);
>   }
>   
>   #if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
> @@ -189,7 +161,7 @@ static bool idpf_ptp_is_mb_msg(u32 op)
>    * @ctlq_msg: Corresponding control queue message
>    */
>   static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,
> -				    struct idpf_ctlq_msg *ctlq_msg)
> +				    struct libie_ctlq_msg *ctlq_msg)
>   {
>   	/* If the message is PTP-related and the secondary mailbox is available,
>   	 * send the message through the secondary mailbox.
> @@ -197,526 +169,83 @@ static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,
>   	if (!idpf_ptp_is_mb_msg(op) || !adapter->ptp->secondary_mbx.valid)
>   		return;
>   
> -	ctlq_msg->opcode = idpf_mbq_opc_send_msg_to_peer_drv;
> +	ctlq_msg->opcode = LIBIE_CTLQ_SEND_MSG_TO_PEER;
>   	ctlq_msg->func_id = adapter->ptp->secondary_mbx.peer_mbx_q_id;
> -	ctlq_msg->host_id = adapter->ptp->secondary_mbx.peer_id;
> +	ctlq_msg->flags = FIELD_PREP(LIBIE_CTLQ_DESC_FLAG_HOST_ID,
> +				     adapter->ptp->secondary_mbx.peer_id);
>   }
>   #else /* !CONFIG_PTP_1588_CLOCK */
>   static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,
> -				    struct idpf_ctlq_msg *ctlq_msg)
> +				    struct libie_ctlq_msg *ctlq_msg)
>   { }
>   #endif /* CONFIG_PTP_1588_CLOCK */
>   
>   /**
> - * idpf_send_mb_msg - Send message over mailbox
> + * idpf_send_mb_msg - send mailbox message to the device control plane
>    * @adapter: driver specific private structure
> - * @asq: control queue to send message to
> - * @op: virtchnl opcode
> - * @msg_size: size of the payload
> - * @msg: pointer to buffer holding the payload
> - * @cookie: unique SW generated cookie per message
> + * @xn_params: Xn send parameters to fill
> + * @send_buf: buffer to send
> + * @send_buf_size: size of the send buffer
>    *
> - * Will prepare the control queue message and initiates the send api
> + * Fill the Xn parameters with the required info to send a virtchnl message.
> + * The send buffer is DMA mapped in the libie to avoid memcpy.
>    *
> - * Return: 0 on success, negative on failure
> - */
> -int idpf_send_mb_msg(struct idpf_adapter *adapter, struct idpf_ctlq_info *asq,
> -		     u32 op, u16 msg_size, u8 *msg, u16 cookie)
> -{
> -	struct idpf_ctlq_msg *ctlq_msg;
> -	struct idpf_dma_mem *dma_mem;
> -	int err;
> -
> -	/* If we are here and a reset is detected nothing much can be
> -	 * done. This thread should silently abort and expected to
> -	 * be corrected with a new run either by user or driver
> -	 * flows after reset
> -	 */
> -	if (idpf_is_reset_detected(adapter))
> -		return 0;
> -
> -	err = idpf_mb_clean(adapter, asq);
> -	if (err)
> -		return err;
> -
> -	ctlq_msg = kzalloc_obj(*ctlq_msg, GFP_ATOMIC);
> -	if (!ctlq_msg)
> -		return -ENOMEM;
> -
> -	dma_mem = kzalloc_obj(*dma_mem, GFP_ATOMIC);
> -	if (!dma_mem) {
> -		err = -ENOMEM;
> -		goto dma_mem_error;
> -	}
> -
> -	ctlq_msg->opcode = idpf_mbq_opc_send_msg_to_cp;
> -	ctlq_msg->func_id = 0;
> -
> -	idpf_prepare_ptp_mb_msg(adapter, op, ctlq_msg);
> -
> -	ctlq_msg->data_len = msg_size;
> -	ctlq_msg->cookie.mbx.chnl_opcode = op;
> -	ctlq_msg->cookie.mbx.chnl_retval = 0;
> -	dma_mem->size = IDPF_CTLQ_MAX_BUF_LEN;
> -	dma_mem->va = dma_alloc_coherent(&adapter->pdev->dev, dma_mem->size,
> -					 &dma_mem->pa, GFP_ATOMIC);
> -	if (!dma_mem->va) {
> -		err = -ENOMEM;
> -		goto dma_alloc_error;
> -	}
> -
> -	/* It's possible we're just sending an opcode but no buffer */
> -	if (msg && msg_size)
> -		memcpy(dma_mem->va, msg, msg_size);
> -	ctlq_msg->ctx.indirect.payload = dma_mem;
> -	ctlq_msg->ctx.sw_cookie.data = cookie;
> -
> -	err = idpf_ctlq_send(&adapter->hw, asq, 1, ctlq_msg);
> -	if (err)
> -		goto send_error;
> -
> -	return 0;
> -
> -send_error:
> -	dma_free_coherent(&adapter->pdev->dev, dma_mem->size, dma_mem->va,
> -			  dma_mem->pa);
> -dma_alloc_error:
> -	kfree(dma_mem);
> -dma_mem_error:
> -	kfree(ctlq_msg);
> -
> -	return err;
> -}
> -
> -/* API for virtchnl "transaction" support ("xn" for short).
> - *
> - * We are reusing the completion lock to serialize the accesses to the
> - * transaction state for simplicity, but it could be its own separate synchro
> - * as well. For now, this API is only used from within a workqueue context;
> - * raw_spin_lock() is enough.
> - */
> -/**
> - * idpf_vc_xn_lock - Request exclusive access to vc transaction
> - * @xn: struct idpf_vc_xn* to access
> - */
> -#define idpf_vc_xn_lock(xn)			\
> -	raw_spin_lock(&(xn)->completed.wait.lock)
> -
> -/**
> - * idpf_vc_xn_unlock - Release exclusive access to vc transaction
> - * @xn: struct idpf_vc_xn* to access
> - */
> -#define idpf_vc_xn_unlock(xn)		\
> -	raw_spin_unlock(&(xn)->completed.wait.lock)
> -
> -/**
> - * idpf_vc_xn_release_bufs - Release reference to reply buffer(s) and
> - * reset the transaction state.
> - * @xn: struct idpf_vc_xn to update
> - */
> -static void idpf_vc_xn_release_bufs(struct idpf_vc_xn *xn)
> -{
> -	xn->reply.iov_base = NULL;
> -	xn->reply.iov_len = 0;
> -
> -	if (xn->state != IDPF_VC_XN_SHUTDOWN)
> -		xn->state = IDPF_VC_XN_IDLE;
> -}
> -
> -/**
> - * idpf_vc_xn_init - Initialize virtchnl transaction object
> - * @vcxn_mngr: pointer to vc transaction manager struct
> - */
> -static void idpf_vc_xn_init(struct idpf_vc_xn_manager *vcxn_mngr)
> -{
> -	int i;
> -
> -	spin_lock_init(&vcxn_mngr->xn_bm_lock);
> -
> -	for (i = 0; i < ARRAY_SIZE(vcxn_mngr->ring); i++) {
> -		struct idpf_vc_xn *xn = &vcxn_mngr->ring[i];
> -
> -		xn->state = IDPF_VC_XN_IDLE;
> -		xn->idx = i;
> -		idpf_vc_xn_release_bufs(xn);
> -		init_completion(&xn->completed);
> -	}
> -
> -	bitmap_fill(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN);
> -}
> -
> -/**
> - * idpf_vc_xn_shutdown - Uninitialize virtchnl transaction object
> - * @vcxn_mngr: pointer to vc transaction manager struct
> + * Cleanup the mailbox queue entries of the previously sent message to
> + * unmap and release the buffer.
>    *
> - * All waiting threads will be woken-up and their transaction aborted. Further
> - * operations on that object will fail.
> + * Return: 0 if sending was successful or reset in detected,
> + *	   negative error code on failure.
>    */
> -void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr)
> +int idpf_send_mb_msg(struct idpf_adapter *adapter,
> +		     struct libie_ctlq_xn_send_params *xn_params,
> +		     void *send_buf, size_t send_buf_size)
>   {
> -	int i;
> +	struct libie_ctlq_msg ctlq_msg = {};
>   
> -	spin_lock_bh(&vcxn_mngr->xn_bm_lock);
> -	bitmap_zero(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN);
> -	spin_unlock_bh(&vcxn_mngr->xn_bm_lock);
> +	if (idpf_is_reset_detected(adapter)) {
> +		if (!libie_cp_can_send_onstack(send_buf_size))
> +			kfree(send_buf);
>   
> -	for (i = 0; i < ARRAY_SIZE(vcxn_mngr->ring); i++) {
> -		struct idpf_vc_xn *xn = &vcxn_mngr->ring[i];
> -
> -		idpf_vc_xn_lock(xn);
> -		xn->state = IDPF_VC_XN_SHUTDOWN;
> -		idpf_vc_xn_release_bufs(xn);
> -		idpf_vc_xn_unlock(xn);
> -		complete_all(&xn->completed);
> +		return -EBUSY;
>   	}
> -}
>   
> -/**
> - * idpf_vc_xn_pop_free - Pop a free transaction from free list
> - * @vcxn_mngr: transaction manager to pop from
> - *
> - * Returns NULL if no free transactions
> - */
> -static
> -struct idpf_vc_xn *idpf_vc_xn_pop_free(struct idpf_vc_xn_manager *vcxn_mngr)
> -{
> -	struct idpf_vc_xn *xn = NULL;
> -	unsigned long free_idx;
> +	idpf_prepare_ptp_mb_msg(adapter, xn_params->chnl_opcode, &ctlq_msg);
> +	xn_params->ctlq_msg = ctlq_msg.opcode ? &ctlq_msg : NULL;
>   
> -	spin_lock_bh(&vcxn_mngr->xn_bm_lock);
> -	free_idx = find_first_bit(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN);
> -	if (free_idx == IDPF_VC_XN_RING_LEN)
> -		goto do_unlock;
> +	xn_params->send_buf.iov_base = send_buf;
> +	xn_params->send_buf.iov_len = send_buf_size;
> +	xn_params->xnm = adapter->xnm;
> +	xn_params->ctlq = xn_params->ctlq ? xn_params->ctlq : adapter->asq;
> +	xn_params->rel_tx_buf = kfree;
>   
> -	clear_bit(free_idx, vcxn_mngr->free_xn_bm);
> -	xn = &vcxn_mngr->ring[free_idx];
> -	xn->salt = vcxn_mngr->salt++;
> -
> -do_unlock:
> -	spin_unlock_bh(&vcxn_mngr->xn_bm_lock);
> -
> -	return xn;
> -}
> +	idpf_mb_clean(adapter, xn_params->ctlq, false);
>   
> -/**
> - * idpf_vc_xn_push_free - Push a free transaction to free list
> - * @vcxn_mngr: transaction manager to push to
> - * @xn: transaction to push
> - */
> -static void idpf_vc_xn_push_free(struct idpf_vc_xn_manager *vcxn_mngr,
> -				 struct idpf_vc_xn *xn)
> -{
> -	idpf_vc_xn_release_bufs(xn);
> -	set_bit(xn->idx, vcxn_mngr->free_xn_bm);
> +	return libie_ctlq_xn_send(xn_params);
>   }
>   
>   /**
> - * idpf_vc_xn_exec - Perform a send/recv virtchnl transaction
> - * @adapter: driver specific private structure with vcxn_mngr
> - * @params: parameters for this particular transaction including
> - *   -vc_op: virtchannel operation to send
> - *   -send_buf: kvec iov for send buf and len
> - *   -recv_buf: kvec iov for recv buf and len (ignored if NULL)
> - *   -timeout_ms: timeout waiting for a reply (milliseconds)
> - *   -async: don't wait for message reply, will lose caller context
> - *   -async_handler: callback to handle async replies
> - *
> - * @returns >= 0 for success, the size of the initial reply (may or may not be
> - * >= @recv_buf.iov_len, but we never overflow @@recv_buf_iov_base). < 0 for
> - * error.
> - */
> -ssize_t idpf_vc_xn_exec(struct idpf_adapter *adapter,
> -			const struct idpf_vc_xn_params *params)
> -{
> -	const struct kvec *send_buf = &params->send_buf;
> -	struct idpf_vc_xn *xn;
> -	ssize_t retval;
> -	u16 cookie;
> -
> -	xn = idpf_vc_xn_pop_free(adapter->vcxn_mngr);
> -	/* no free transactions available */
> -	if (!xn)
> -		return -ENOSPC;
> -
> -	idpf_vc_xn_lock(xn);
> -	if (xn->state == IDPF_VC_XN_SHUTDOWN) {
> -		retval = -ENXIO;
> -		goto only_unlock;
> -	} else if (xn->state != IDPF_VC_XN_IDLE) {
> -		/* We're just going to clobber this transaction even though
> -		 * it's not IDLE. If we don't reuse it we could theoretically
> -		 * eventually leak all the free transactions and not be able to
> -		 * send any messages. At least this way we make an attempt to
> -		 * remain functional even though something really bad is
> -		 * happening that's corrupting what was supposed to be free
> -		 * transactions.
> -		 */
> -		WARN_ONCE(1, "There should only be idle transactions in free list (idx %d op %d)\n",
> -			  xn->idx, xn->vc_op);
> -	}
> -
> -	xn->reply = params->recv_buf;
> -	xn->reply_sz = 0;
> -	xn->state = params->async ? IDPF_VC_XN_ASYNC : IDPF_VC_XN_WAITING;
> -	xn->vc_op = params->vc_op;
> -	xn->async_handler = params->async_handler;
> -	idpf_vc_xn_unlock(xn);
> -
> -	if (!params->async)
> -		reinit_completion(&xn->completed);
> -	cookie = FIELD_PREP(IDPF_VC_XN_SALT_M, xn->salt) |
> -		 FIELD_PREP(IDPF_VC_XN_IDX_M, xn->idx);
> -
> -	retval = idpf_send_mb_msg(adapter, adapter->hw.asq, params->vc_op,
> -				  send_buf->iov_len, send_buf->iov_base,
> -				  cookie);
> -	if (retval) {
> -		idpf_vc_xn_lock(xn);
> -		goto release_and_unlock;
> -	}
> -
> -	if (params->async)
> -		return 0;
> -
> -	wait_for_completion_timeout(&xn->completed,
> -				    msecs_to_jiffies(params->timeout_ms));
> -
> -	/* No need to check the return value; we check the final state of the
> -	 * transaction below. It's possible the transaction actually gets more
> -	 * timeout than specified if we get preempted here but after
> -	 * wait_for_completion_timeout returns. This should be non-issue
> -	 * however.
> -	 */
> -	idpf_vc_xn_lock(xn);
> -	switch (xn->state) {
> -	case IDPF_VC_XN_SHUTDOWN:
> -		retval = -ENXIO;
> -		goto only_unlock;
> -	case IDPF_VC_XN_WAITING:
> -		dev_notice_ratelimited(&adapter->pdev->dev,
> -				       "Transaction timed-out (op:%d cookie:%04x vc_op:%d salt:%02x timeout:%dms)\n",
> -				       params->vc_op, cookie, xn->vc_op,
> -				       xn->salt, params->timeout_ms);
> -		retval = -ETIME;
> -		break;
> -	case IDPF_VC_XN_COMPLETED_SUCCESS:
> -		retval = xn->reply_sz;
> -		break;
> -	case IDPF_VC_XN_COMPLETED_FAILED:
> -		dev_notice_ratelimited(&adapter->pdev->dev, "Transaction failed (op %d)\n",
> -				       params->vc_op);
> -		retval = -EIO;
> -		break;
> -	default:
> -		/* Invalid state. */
> -		WARN_ON_ONCE(1);
> -		retval = -EIO;
> -		break;
> -	}
> -
> -release_and_unlock:
> -	idpf_vc_xn_push_free(adapter->vcxn_mngr, xn);
> -	/* If we receive a VC reply after here, it will be dropped. */
> -only_unlock:
> -	idpf_vc_xn_unlock(xn);
> -
> -	return retval;
> -}
> -
> -/**
> - * idpf_vc_xn_forward_async - Handle async reply receives
> - * @adapter: private data struct
> - * @xn: transaction to handle
> - * @ctlq_msg: corresponding ctlq_msg
> - *
> - * For async sends we're going to lose the caller's context so, if an
> - * async_handler was provided, it can deal with the reply, otherwise we'll just
> - * check and report if there is an error.
> - */
> -static int
> -idpf_vc_xn_forward_async(struct idpf_adapter *adapter, struct idpf_vc_xn *xn,
> -			 const struct idpf_ctlq_msg *ctlq_msg)
> -{
> -	int err = 0;
> -
> -	if (ctlq_msg->cookie.mbx.chnl_opcode != xn->vc_op) {
> -		dev_err_ratelimited(&adapter->pdev->dev, "Async message opcode does not match transaction opcode (msg: %d) (xn: %d)\n",
> -				    ctlq_msg->cookie.mbx.chnl_opcode, xn->vc_op);
> -		xn->reply_sz = 0;
> -		err = -EINVAL;
> -		goto release_bufs;
> -	}
> -
> -	if (xn->async_handler) {
> -		err = xn->async_handler(adapter, xn, ctlq_msg);
> -		goto release_bufs;
> -	}
> -
> -	if (ctlq_msg->cookie.mbx.chnl_retval) {
> -		xn->reply_sz = 0;
> -		dev_err_ratelimited(&adapter->pdev->dev, "Async message failure (op %d)\n",
> -				    ctlq_msg->cookie.mbx.chnl_opcode);
> -		err = -EINVAL;
> -	}
> -
> -release_bufs:
> -	idpf_vc_xn_push_free(adapter->vcxn_mngr, xn);
> -
> -	return err;
> -}
> -
> -/**
> - * idpf_vc_xn_forward_reply - copy a reply back to receiving thread
> - * @adapter: driver specific private structure with vcxn_mngr
> - * @ctlq_msg: controlq message to send back to receiving thread
> - */
> -static int
> -idpf_vc_xn_forward_reply(struct idpf_adapter *adapter,
> -			 const struct idpf_ctlq_msg *ctlq_msg)
> -{
> -	const void *payload = NULL;
> -	size_t payload_size = 0;
> -	struct idpf_vc_xn *xn;
> -	u16 msg_info;
> -	int err = 0;
> -	u16 xn_idx;
> -	u16 salt;
> -
> -	msg_info = ctlq_msg->ctx.sw_cookie.data;
> -	xn_idx = FIELD_GET(IDPF_VC_XN_IDX_M, msg_info);
> -	if (xn_idx >= ARRAY_SIZE(adapter->vcxn_mngr->ring)) {
> -		dev_err_ratelimited(&adapter->pdev->dev, "Out of bounds cookie received: %02x\n",
> -				    xn_idx);
> -		return -EINVAL;
> -	}
> -	xn = &adapter->vcxn_mngr->ring[xn_idx];
> -	idpf_vc_xn_lock(xn);
> -	salt = FIELD_GET(IDPF_VC_XN_SALT_M, msg_info);
> -	if (xn->salt != salt) {
> -		dev_err_ratelimited(&adapter->pdev->dev, "Transaction salt does not match (exp:%d@%02x(%d) != got:%d@%02x)\n",
> -				    xn->vc_op, xn->salt, xn->state,
> -				    ctlq_msg->cookie.mbx.chnl_opcode, salt);
> -		idpf_vc_xn_unlock(xn);
> -		return -EINVAL;
> -	}
> -
> -	switch (xn->state) {
> -	case IDPF_VC_XN_WAITING:
> -		/* success */
> -		break;
> -	case IDPF_VC_XN_IDLE:
> -		dev_err_ratelimited(&adapter->pdev->dev, "Unexpected or belated VC reply (op %d)\n",
> -				    ctlq_msg->cookie.mbx.chnl_opcode);
> -		err = -EINVAL;
> -		goto out_unlock;
> -	case IDPF_VC_XN_SHUTDOWN:
> -		/* ENXIO is a bit special here as the recv msg loop uses that
> -		 * know if it should stop trying to clean the ring if we lost
> -		 * the virtchnl. We need to stop playing with registers and
> -		 * yield.
> -		 */
> -		err = -ENXIO;
> -		goto out_unlock;
> -	case IDPF_VC_XN_ASYNC:
> -		err = idpf_vc_xn_forward_async(adapter, xn, ctlq_msg);
> -		idpf_vc_xn_unlock(xn);
> -		return err;
> -	default:
> -		dev_err_ratelimited(&adapter->pdev->dev, "Overwriting VC reply (op %d)\n",
> -				    ctlq_msg->cookie.mbx.chnl_opcode);
> -		err = -EBUSY;
> -		goto out_unlock;
> -	}
> -
> -	if (ctlq_msg->cookie.mbx.chnl_opcode != xn->vc_op) {
> -		dev_err_ratelimited(&adapter->pdev->dev, "Message opcode does not match transaction opcode (msg: %d) (xn: %d)\n",
> -				    ctlq_msg->cookie.mbx.chnl_opcode, xn->vc_op);
> -		xn->reply_sz = 0;
> -		xn->state = IDPF_VC_XN_COMPLETED_FAILED;
> -		err = -EINVAL;
> -		goto out_unlock;
> -	}
> -
> -	if (ctlq_msg->cookie.mbx.chnl_retval) {
> -		xn->reply_sz = 0;
> -		xn->state = IDPF_VC_XN_COMPLETED_FAILED;
> -		err = -EINVAL;
> -		goto out_unlock;
> -	}
> -
> -	if (ctlq_msg->data_len) {
> -		payload = ctlq_msg->ctx.indirect.payload->va;
> -		payload_size = ctlq_msg->data_len;
> -	}
> -
> -	xn->reply_sz = payload_size;
> -	xn->state = IDPF_VC_XN_COMPLETED_SUCCESS;
> -
> -	if (xn->reply.iov_base && xn->reply.iov_len && payload_size)
> -		memcpy(xn->reply.iov_base, payload,
> -		       min_t(size_t, xn->reply.iov_len, payload_size));
> -
> -out_unlock:
> -	idpf_vc_xn_unlock(xn);
> -	/* we _cannot_ hold lock while calling complete */
> -	complete(&xn->completed);
> -
> -	return err;
> -}
> -
> -/**
> - * idpf_recv_mb_msg - Receive message over mailbox
> + * idpf_send_mb_msg_kfree - send mailbox message and free the send buffer
>    * @adapter: driver specific private structure
> - * @arq: control queue to receive message from
> + * @xn_params: Xn send parameters to fill
> + * @send_buf: buffer to send, can be released with kfree()
> + * @send_buf_size: size of the send buffer
>    *
> - * Will receive control queue message and posts the receive buffer.
> + * libie_cp functions consume only buffers above certain size,
> + * smaller buffers are assumed to be on the stack. However, for some
> + * commands with variable message size it makes sense to always use kzalloc(),
> + * which means we have to free smaller buffers ourselves.
>    *
> - * Return: 0 on success and negative on failure.
> + * Return: 0 if no unexpected errors were encountered,
> + *	   negative error code otherwise.
>    */
> -int idpf_recv_mb_msg(struct idpf_adapter *adapter, struct idpf_ctlq_info *arq)
> +int idpf_send_mb_msg_kfree(struct idpf_adapter *adapter,
> +			   struct libie_ctlq_xn_send_params *xn_params,
> +			   void *send_buf, size_t send_buf_size)
>   {
> -	struct idpf_ctlq_msg ctlq_msg;
> -	struct idpf_dma_mem *dma_mem;
> -	int post_err, err;
> -	u16 num_recv;
> -
> -	while (1) {
> -		/* This will get <= num_recv messages and output how many
> -		 * actually received on num_recv.
> -		 */
> -		num_recv = 1;
> -		err = idpf_ctlq_recv(arq, &num_recv, &ctlq_msg);
> -		if (err || !num_recv)
> -			break;
> -
> -		if (ctlq_msg.data_len) {
> -			dma_mem = ctlq_msg.ctx.indirect.payload;
> -		} else {
> -			dma_mem = NULL;
> -			num_recv = 0;
> -		}
> +	int err = idpf_send_mb_msg(adapter, xn_params, send_buf, send_buf_size);
>   
> -		if (ctlq_msg.cookie.mbx.chnl_opcode == VIRTCHNL2_OP_EVENT)
> -			idpf_recv_event_msg(adapter, &ctlq_msg);
> -		else
> -			err = idpf_vc_xn_forward_reply(adapter, &ctlq_msg);
> -
> -		post_err = idpf_ctlq_post_rx_buffs(&adapter->hw, arq,
> -						   &num_recv, &dma_mem);
> -
> -		/* If post failed clear the only buffer we supplied */
> -		if (post_err) {
> -			if (dma_mem)
> -				dma_free_coherent(&adapter->pdev->dev,
> -						  dma_mem->size, dma_mem->va,
> -						  dma_mem->pa);
> -			break;
> -		}
> -
> -		/* virtchnl trying to shutdown, stop cleaning */
> -		if (err == -ENXIO)
> -			break;
> -	}
> +	if (libie_cp_can_send_onstack(send_buf_size))
> +		kfree(send_buf);
>   
>   	return err;
>   }
> @@ -766,45 +295,43 @@ struct idpf_queue_set *idpf_alloc_queue_set(struct idpf_adapter *adapter,
>   static int idpf_send_chunked_msg(struct idpf_adapter *adapter,
>   				 const struct idpf_chunked_msg_params *params)
>   {
> -	struct idpf_vc_xn_params xn_params = {
> -		.vc_op		= params->vc_op,
> +	struct libie_ctlq_xn_send_params xn_params = {
>   		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= params->vc_op,
>   	};
>   	const void *pos = params->chunks;
> -	u32 num_chunks, num_msgs, buf_sz;
> -	void *buf __free(kfree) = NULL;
>   	u32 totqs = params->num_chunks;
>   	u32 vid = params->vport_id;
> +	u32 num_chunks, num_msgs;
>   
> -	num_chunks = min(IDPF_NUM_CHUNKS_PER_MSG(params->config_sz,
> -						 params->chunk_sz), totqs);
> +	num_chunks = IDPF_NUM_CHUNKS_PER_MSG(params->config_sz,
> +					     params->chunk_sz);
>   	num_msgs = DIV_ROUND_UP(totqs, num_chunks);
>   
> -	buf_sz = params->config_sz + num_chunks * params->chunk_sz;
> -	buf = kzalloc(buf_sz, GFP_KERNEL);
> -	if (!buf)
> -		return -ENOMEM;
> -
> -	xn_params.send_buf.iov_base = buf;
> -
>   	for (u32 i = 0; i < num_msgs; i++) {
> -		ssize_t reply_sz;
> +		u32 buf_sz;
> +		void *buf;
> +		int err;
>   
> -		memset(buf, 0, buf_sz);
> -		xn_params.send_buf.iov_len = buf_sz;
> +		num_chunks = min(num_chunks, totqs);
> +		buf_sz = params->config_sz + num_chunks * params->chunk_sz;
> +		buf = kzalloc(buf_sz, GFP_KERNEL);
> +		if (!buf)
> +			return -ENOMEM;
>   
> -		if (params->prepare_msg(vid, buf, pos, num_chunks) != buf_sz)
> +		if (params->prepare_msg(vid, buf, pos, num_chunks) != buf_sz) {
> +			kfree(buf);
>   			return -EINVAL;
> +		}
>   
> -		reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -		if (reply_sz < 0)
> -			return reply_sz;
> +		err = idpf_send_mb_msg_kfree(adapter, &xn_params, buf, buf_sz);
> +		if (err)
> +			return err;
>   
> +		libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +		xn_params.recv_mem = (struct kvec) {};
>   		pos += num_chunks * params->chunk_sz;
>   		totqs -= num_chunks;
> -
> -		num_chunks = min(num_chunks, totqs);
> -		buf_sz = params->config_sz + num_chunks * params->chunk_sz;
>   	}
>   
>   	return 0;
> @@ -879,11 +406,14 @@ static int idpf_wait_for_marker_event(struct idpf_vport *vport)
>    */
>   static int idpf_send_ver_msg(struct idpf_adapter *adapter)
>   {
> -	struct idpf_vc_xn_params xn_params = {};
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_VERSION,
> +	};
> +	struct virtchnl2_version_info *vvi_recv;
>   	struct virtchnl2_version_info vvi;
> -	ssize_t reply_sz;
>   	u32 major, minor;
> -	int err = 0;
> +	int err;
>   
>   	if (adapter->virt_ver_maj) {
>   		vvi.major = cpu_to_le32(adapter->virt_ver_maj);
> @@ -893,24 +423,23 @@ static int idpf_send_ver_msg(struct idpf_adapter *adapter)
>   		vvi.minor = cpu_to_le32(IDPF_VIRTCHNL_VERSION_MINOR);
>   	}
>   
> -	xn_params.vc_op = VIRTCHNL2_OP_VERSION;
> -	xn_params.send_buf.iov_base = &vvi;
> -	xn_params.send_buf.iov_len = sizeof(vvi);
> -	xn_params.recv_buf = xn_params.send_buf;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> +	err = idpf_send_mb_msg(adapter, &xn_params, &vvi, sizeof(vvi));
> +	if (err)
> +		return err;
>   
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> -	if (reply_sz < sizeof(vvi))
> -		return -EIO;
> +	if (xn_params.recv_mem.iov_len < sizeof(*vvi_recv)) {
> +		err = -EIO;
> +		goto free_rx_buf;
> +	}
>   
> -	major = le32_to_cpu(vvi.major);
> -	minor = le32_to_cpu(vvi.minor);
> +	vvi_recv = xn_params.recv_mem.iov_base;
> +	major = le32_to_cpu(vvi_recv->major);
> +	minor = le32_to_cpu(vvi_recv->minor);
>   
>   	if (major > IDPF_VIRTCHNL_VERSION_MAJOR) {
>   		dev_warn(&adapter->pdev->dev, "Virtchnl major version greater than supported\n");
> -		return -EINVAL;
> +		err = -EINVAL;
> +		goto free_rx_buf;
>   	}
>   
>   	if (major == IDPF_VIRTCHNL_VERSION_MAJOR &&
> @@ -928,6 +457,9 @@ static int idpf_send_ver_msg(struct idpf_adapter *adapter)
>   	adapter->virt_ver_maj = major;
>   	adapter->virt_ver_min = minor;
>   
> +free_rx_buf:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +
>   	return err;
>   }
>   
> @@ -940,9 +472,12 @@ static int idpf_send_ver_msg(struct idpf_adapter *adapter)
>    */
>   static int idpf_send_get_caps_msg(struct idpf_adapter *adapter)
>   {
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_GET_CAPS,
> +	};
>   	struct virtchnl2_get_capabilities caps = {};
> -	struct idpf_vc_xn_params xn_params = {};
> -	ssize_t reply_sz;
> +	int err;
>   
>   	caps.csum_caps =
>   		cpu_to_le32(VIRTCHNL2_CAP_TX_CSUM_L3_IPV4	|
> @@ -1002,20 +537,22 @@ static int idpf_send_get_caps_msg(struct idpf_adapter *adapter)
>   			    VIRTCHNL2_CAP_LOOPBACK		|
>   			    VIRTCHNL2_CAP_PTP);
>   
> -	xn_params.vc_op = VIRTCHNL2_OP_GET_CAPS;
> -	xn_params.send_buf.iov_base = &caps;
> -	xn_params.send_buf.iov_len = sizeof(caps);
> -	xn_params.recv_buf.iov_base = &adapter->caps;
> -	xn_params.recv_buf.iov_len = sizeof(adapter->caps);
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> +	err = idpf_send_mb_msg(adapter, &xn_params, &caps, sizeof(caps));
> +	if (err)
> +		return err;
>   
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> -	if (reply_sz < sizeof(adapter->caps))
> -		return -EIO;
> +	if (xn_params.recv_mem.iov_len < sizeof(adapter->caps)) {
> +		err = -EIO;
> +		goto free_rx_buf;
> +	}
>   
> -	return 0;
> +	memcpy(&adapter->caps, xn_params.recv_mem.iov_base,
> +	       sizeof(adapter->caps));
> +
> +free_rx_buf:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +
> +	return err;
>   }
>   
>   /**
> @@ -1060,37 +597,39 @@ static void idpf_decfg_lan_memory_regions(struct idpf_adapter *adapter)
>    */
>   static int idpf_cfg_lan_memory_regions(struct idpf_adapter *adapter)
>   {
> -	struct virtchnl2_get_lan_memory_regions *rcvd_regions __free(kfree);
> -	struct idpf_vc_xn_params xn_params = {
> -		.vc_op = VIRTCHNL2_OP_GET_LAN_MEMORY_REGIONS,
> -		.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN,
> -		.send_buf.iov_len =
> -			sizeof(struct virtchnl2_get_lan_memory_regions) +
> -			sizeof(struct virtchnl2_mem_region),
> +	struct virtchnl2_get_lan_memory_regions *send_regions, *rcvd_regions;
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.chnl_opcode = VIRTCHNL2_OP_GET_LAN_MEMORY_REGIONS,
>   		.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
>   	};
> -	int num_regions, size;
> -	ssize_t reply_sz;
> +	size_t send_sz, reply_sz, size;
> +	int num_regions;
>   	int err = 0;
>   
> -	rcvd_regions = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
> -	if (!rcvd_regions)
> +	send_sz = sizeof(struct virtchnl2_get_lan_memory_regions) +
> +		  sizeof(struct virtchnl2_mem_region);
> +	send_regions = kzalloc(send_sz, GFP_KERNEL);
> +	if (!send_regions)
>   		return -ENOMEM;
>   
> -	xn_params.recv_buf.iov_base = rcvd_regions;
> -	rcvd_regions->num_memory_regions = cpu_to_le16(1);
> -	xn_params.send_buf.iov_base = rcvd_regions;
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> +	send_regions->num_memory_regions = cpu_to_le16(1);
> +	err = idpf_send_mb_msg_kfree(adapter, &xn_params, send_regions,
> +				     send_sz);
> +	if (err)
> +		return err;
>   
> +	rcvd_regions = xn_params.recv_mem.iov_base;
> +	reply_sz = xn_params.recv_mem.iov_len;
> +	if (reply_sz < sizeof(*rcvd_regions)) {
> +		err = -EIO;
> +		goto rel_rx_buf;
> +	}
>   	num_regions = le16_to_cpu(rcvd_regions->num_memory_regions);
>   	size = struct_size(rcvd_regions, mem_reg, num_regions);
> -	if (reply_sz < size)
> -		return -EIO;
> -
> -	if (size > IDPF_CTLQ_MAX_BUF_LEN)
> -		return -EINVAL;
> +	if (reply_sz < size) {
> +		err = -EIO;
> +		goto rel_rx_buf;
> +	}
>   
>   	for (int i = 0; i < num_regions; i++) {
>   		struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
> @@ -1100,10 +639,14 @@ static int idpf_cfg_lan_memory_regions(struct idpf_adapter *adapter)
>   		len = le64_to_cpu(rcvd_regions->mem_reg[i].size);
>   		if (!libie_pci_map_mmio_region(mmio, offset, len)) {
>   			idpf_decfg_lan_memory_regions(adapter);
> -			return -EIO;
> +			err = -EIO;
> +			goto rel_rx_buf;
>   		}
>   	}
>   
> +rel_rx_buf:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +
>   	return err;
>   }
>   
> @@ -1162,24 +705,43 @@ int idpf_add_del_fsteer_filters(struct idpf_adapter *adapter,
>   				struct virtchnl2_flow_rule_add_del *rule,
>   				enum virtchnl2_op opcode)
>   {
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.chnl_opcode = opcode,
> +		.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +	};
> +	struct virtchnl2_flow_rule_add_del *rx_rule;
>   	int rule_count = le32_to_cpu(rule->count);
> -	struct idpf_vc_xn_params xn_params = {};
> -	ssize_t reply_sz;
> +	size_t send_sz;
> +	int err;
>   
>   	if (opcode != VIRTCHNL2_OP_ADD_FLOW_RULE &&
> -	    opcode != VIRTCHNL2_OP_DEL_FLOW_RULE)
> +	    opcode != VIRTCHNL2_OP_DEL_FLOW_RULE) {
> +		kfree(rule);
>   		return -EINVAL;
> +	}
> +
> +	send_sz = struct_size(rule, rule_info, rule_count);
> +	err = idpf_send_mb_msg(adapter, &xn_params, rule, send_sz);
> +	if (err)
> +		return err;
> +
> +	if (xn_params.recv_mem.iov_len < send_sz) {
> +		err = -EIO;
> +		goto rel_rx;
> +	}
>   
> -	xn_params.vc_op = opcode;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	xn_params.async = false;
> -	xn_params.send_buf.iov_base = rule;
> -	xn_params.send_buf.iov_len = struct_size(rule, rule_info, rule_count);
> -	xn_params.recv_buf.iov_base = rule;
> -	xn_params.recv_buf.iov_len = struct_size(rule, rule_info, rule_count);
> +	rx_rule = xn_params.recv_mem.iov_base;
> +	for (int i = 0; i < rule_count; i++) {
> +		if (rx_rule->rule_info[i].status !=
> +		    cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS)) {
> +			err = -EIO;
> +			goto rel_rx;
> +		}
> +	}
>   
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	return reply_sz < 0 ? reply_sz : 0;
> +rel_rx:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +	return err;
>   }
>   
>   /**
> @@ -1553,11 +1115,13 @@ int idpf_queue_reg_init(struct idpf_vport *vport,
>   int idpf_send_create_vport_msg(struct idpf_adapter *adapter,
>   			       struct idpf_vport_max_q *max_q)
>   {
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_CREATE_VPORT,
> +	};
>   	struct virtchnl2_create_vport *vport_msg;
> -	struct idpf_vc_xn_params xn_params = {};
>   	u16 idx = adapter->next_vport;
>   	int err, buf_size;
> -	ssize_t reply_sz;
>   
>   	buf_size = sizeof(struct virtchnl2_create_vport);
>   	vport_msg = kzalloc(buf_size, GFP_KERNEL);
> @@ -1584,33 +1148,29 @@ int idpf_send_create_vport_msg(struct idpf_adapter *adapter,
>   	}
>   
>   	if (!adapter->vport_params_recvd[idx]) {
> -		adapter->vport_params_recvd[idx] = kzalloc(IDPF_CTLQ_MAX_BUF_LEN,
> -							   GFP_KERNEL);
> +		adapter->vport_params_recvd[idx] =
> +			kzalloc(LIBIE_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
>   		if (!adapter->vport_params_recvd[idx]) {
>   			err = -ENOMEM;
>   			goto rel_buf;
>   		}
>   	}
>   
> -	xn_params.vc_op = VIRTCHNL2_OP_CREATE_VPORT;
> -	xn_params.send_buf.iov_base = vport_msg;
> -	xn_params.send_buf.iov_len = buf_size;
> -	xn_params.recv_buf.iov_base = adapter->vport_params_recvd[idx];
> -	xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0) {
> -		err = reply_sz;
> -		goto free_vport_params;
> +	err = idpf_send_mb_msg_kfree(adapter, &xn_params, vport_msg,
> +				     sizeof(*vport_msg));
> +	if (err) {
> +		kfree(adapter->vport_params_recvd[idx]);
> +		adapter->vport_params_recvd[idx] = NULL;
> +		return err;
>   	}
>   
> -	kfree(vport_msg);
> +	memcpy(adapter->vport_params_recvd[idx], xn_params.recv_mem.iov_base,
> +	       xn_params.recv_mem.iov_len);
> +
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
>   	return 0;
>   
> -free_vport_params:
> -	kfree(adapter->vport_params_recvd[idx]);
> -	adapter->vport_params_recvd[idx] = NULL;
>   rel_buf:
>   	kfree(vport_msg);
>   
> @@ -1672,19 +1232,22 @@ int idpf_check_supported_desc_ids(struct idpf_vport *vport)
>    */
>   int idpf_send_destroy_vport_msg(struct idpf_adapter *adapter, u32 vport_id)
>   {
> -	struct idpf_vc_xn_params xn_params = {};
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_DESTROY_VPORT,
> +	};
>   	struct virtchnl2_vport v_id;
> -	ssize_t reply_sz;
> +	int err;
>   
>   	v_id.vport_id = cpu_to_le32(vport_id);
>   
> -	xn_params.vc_op = VIRTCHNL2_OP_DESTROY_VPORT;
> -	xn_params.send_buf.iov_base = &v_id;
> -	xn_params.send_buf.iov_len = sizeof(v_id);
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> +	err = idpf_send_mb_msg(adapter, &xn_params, &v_id, sizeof(v_id));
> +	if (err)
> +		return err;
> +
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
> -	return reply_sz < 0 ? reply_sz : 0;
> +	return 0;
>   }
>   
>   /**
> @@ -1696,19 +1259,22 @@ int idpf_send_destroy_vport_msg(struct idpf_adapter *adapter, u32 vport_id)
>    */
>   int idpf_send_enable_vport_msg(struct idpf_adapter *adapter, u32 vport_id)
>   {
> -	struct idpf_vc_xn_params xn_params = {};
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_ENABLE_VPORT,
> +	};
>   	struct virtchnl2_vport v_id;
> -	ssize_t reply_sz;
> +	int err;
>   
>   	v_id.vport_id = cpu_to_le32(vport_id);
>   
> -	xn_params.vc_op = VIRTCHNL2_OP_ENABLE_VPORT;
> -	xn_params.send_buf.iov_base = &v_id;
> -	xn_params.send_buf.iov_len = sizeof(v_id);
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> +	err = idpf_send_mb_msg(adapter, &xn_params, &v_id, sizeof(v_id));
> +	if (err)
> +		return err;
> +
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
> -	return reply_sz < 0 ? reply_sz : 0;
> +	return 0;
>   }
>   
>   /**
> @@ -1720,19 +1286,22 @@ int idpf_send_enable_vport_msg(struct idpf_adapter *adapter, u32 vport_id)
>    */
>   int idpf_send_disable_vport_msg(struct idpf_adapter *adapter, u32 vport_id)
>   {
> -	struct idpf_vc_xn_params xn_params = {};
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_DISABLE_VPORT,
> +	};
>   	struct virtchnl2_vport v_id;
> -	ssize_t reply_sz;
> +	int err;
>   
>   	v_id.vport_id = cpu_to_le32(vport_id);
>   
> -	xn_params.vc_op = VIRTCHNL2_OP_DISABLE_VPORT;
> -	xn_params.send_buf.iov_base = &v_id;
> -	xn_params.send_buf.iov_len = sizeof(v_id);
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> +	err = idpf_send_mb_msg(adapter, &xn_params, &v_id, sizeof(v_id));
> +	if (err)
> +		return err;
> +
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
> -	return reply_sz < 0 ? reply_sz : 0;
> +	return 0;
>   }
>   
>   /**
> @@ -2571,11 +2140,14 @@ int idpf_send_delete_queues_msg(struct idpf_adapter *adapter,
>   				struct idpf_queue_id_reg_info *chunks,
>   				u32 vport_id)
>   {
> -	struct virtchnl2_del_ena_dis_queues *eq __free(kfree) = NULL;
> -	struct idpf_vc_xn_params xn_params = {};
> -	ssize_t reply_sz;
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_DEL_QUEUES,
> +	};
> +	struct virtchnl2_del_ena_dis_queues *eq;
> +	ssize_t buf_size;
>   	u16 num_chunks;
> -	int buf_size;
> +	int err;
>   
>   	num_chunks = chunks->num_chunks;
>   	buf_size = struct_size(eq, chunks.chunks, num_chunks);
> @@ -2590,13 +2162,13 @@ int idpf_send_delete_queues_msg(struct idpf_adapter *adapter,
>   	idpf_convert_reg_to_queue_chunks(eq->chunks.chunks, chunks->queue_chunks,
>   					 num_chunks);
>   
> -	xn_params.vc_op = VIRTCHNL2_OP_DEL_QUEUES;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	xn_params.send_buf.iov_base = eq;
> -	xn_params.send_buf.iov_len = buf_size;
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> +	err = idpf_send_mb_msg_kfree(adapter, &xn_params, eq, buf_size);
> +	if (err)
> +		return err;
> +
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
> -	return reply_sz < 0 ? reply_sz : 0;
> +	return 0;
>   }
>   
>   /**
> @@ -2634,15 +2206,14 @@ int idpf_send_add_queues_msg(struct idpf_adapter *adapter,
>   			     struct idpf_q_vec_rsrc *rsrc,
>   			     u32 vport_id)
>   {
> -	struct virtchnl2_add_queues *vc_msg __free(kfree) = NULL;
> -	struct idpf_vc_xn_params xn_params = {};
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_ADD_QUEUES,
> +	};
> +	struct virtchnl2_add_queues *vc_msg;
>   	struct virtchnl2_add_queues aq = {};
> -	ssize_t reply_sz;
> -	int size;
> -
> -	vc_msg = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
> -	if (!vc_msg)
> -		return -ENOMEM;
> +	size_t size;
> +	int err;
>   
>   	aq.vport_id = cpu_to_le32(vport_id);
>   	aq.num_tx_q = cpu_to_le16(rsrc->num_txq);
> @@ -2650,29 +2221,38 @@ int idpf_send_add_queues_msg(struct idpf_adapter *adapter,
>   	aq.num_rx_q = cpu_to_le16(rsrc->num_rxq);
>   	aq.num_rx_bufq = cpu_to_le16(rsrc->num_bufq);
>   
> -	xn_params.vc_op = VIRTCHNL2_OP_ADD_QUEUES;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	xn_params.send_buf.iov_base = &aq;
> -	xn_params.send_buf.iov_len = sizeof(aq);
> -	xn_params.recv_buf.iov_base = vc_msg;
> -	xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> +	err = idpf_send_mb_msg(adapter, &xn_params, &aq, sizeof(aq));
> +	if (err)
> +		return err;
> +
> +	vc_msg = xn_params.recv_mem.iov_base;
> +	if (xn_params.recv_mem.iov_len < sizeof(*vc_msg)) {
> +		err = -EIO;
> +		goto free_rx_buf;
> +	}
>   
>   	/* compare vc_msg num queues with vport num queues */
>   	if (le16_to_cpu(vc_msg->num_tx_q) != rsrc->num_txq ||
>   	    le16_to_cpu(vc_msg->num_rx_q) != rsrc->num_rxq ||
>   	    le16_to_cpu(vc_msg->num_tx_complq) != rsrc->num_complq ||
> -	    le16_to_cpu(vc_msg->num_rx_bufq) != rsrc->num_bufq)
> -		return -EINVAL;
> +	    le16_to_cpu(vc_msg->num_rx_bufq) != rsrc->num_bufq) {
> +		err = -EINVAL;
> +		goto free_rx_buf;
> +	}
>   
>   	size = struct_size(vc_msg, chunks.chunks,
>   			   le16_to_cpu(vc_msg->chunks.num_chunks));
> -	if (reply_sz < size)
> -		return -EIO;
> +	if (xn_params.recv_mem.iov_len < size) {
> +		err = -EIO;
> +		goto free_rx_buf;
> +	}
> +
> +	err = idpf_vport_init_queue_reg_chunks(vport_config, &vc_msg->chunks);
>   
> -	return idpf_vport_init_queue_reg_chunks(vport_config, &vc_msg->chunks);
> +free_rx_buf:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +
> +	return err;
>   }
>   
>   /**
> @@ -2684,49 +2264,47 @@ int idpf_send_add_queues_msg(struct idpf_adapter *adapter,
>    */
>   int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors)
>   {
> -	struct virtchnl2_alloc_vectors *rcvd_vec __free(kfree) = NULL;
> -	struct idpf_vc_xn_params xn_params = {};
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_ALLOC_VECTORS,
> +	};
> +	struct virtchnl2_alloc_vectors *rcvd_vec;
>   	struct virtchnl2_alloc_vectors ac = {};
> -	ssize_t reply_sz;
>   	u16 num_vchunks;
> -	int size;
> +	int size, err;
>   
>   	ac.num_vectors = cpu_to_le16(num_vectors);
>   
> -	rcvd_vec = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
> -	if (!rcvd_vec)
> -		return -ENOMEM;
> +	err = idpf_send_mb_msg(adapter, &xn_params, &ac, sizeof(ac));
> +	if (err)
> +		return err;
>   
> -	xn_params.vc_op = VIRTCHNL2_OP_ALLOC_VECTORS;
> -	xn_params.send_buf.iov_base = &ac;
> -	xn_params.send_buf.iov_len = sizeof(ac);
> -	xn_params.recv_buf.iov_base = rcvd_vec;
> -	xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> +	rcvd_vec = xn_params.recv_mem.iov_base;
>   
>   	num_vchunks = le16_to_cpu(rcvd_vec->vchunks.num_vchunks);
>   	size = struct_size(rcvd_vec, vchunks.vchunks, num_vchunks);
> -	if (reply_sz < size)
> -		return -EIO;
> -
> -	if (size > IDPF_CTLQ_MAX_BUF_LEN)
> -		return -EINVAL;
> +	if (xn_params.recv_mem.iov_len < size) {
> +		err = -EIO;
> +		goto free_rx_buf;
> +	}
>   
>   	kfree(adapter->req_vec_chunks);
>   	adapter->req_vec_chunks = kmemdup(rcvd_vec, size, GFP_KERNEL);
> -	if (!adapter->req_vec_chunks)
> -		return -ENOMEM;
> +	if (!adapter->req_vec_chunks) {
> +		err = -ENOMEM;
> +		goto free_rx_buf;
> +	}
>   
>   	if (le16_to_cpu(adapter->req_vec_chunks->num_vectors) < num_vectors) {
>   		kfree(adapter->req_vec_chunks);
>   		adapter->req_vec_chunks = NULL;
> -		return -EINVAL;
> +		err = -EINVAL;
>   	}
>   
> -	return 0;
> +free_rx_buf:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +
> +	return err;
>   }
>   
>   /**
> @@ -2738,24 +2316,28 @@ int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors)
>   int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter)
>   {
>   	struct virtchnl2_alloc_vectors *ac = adapter->req_vec_chunks;
> -	struct virtchnl2_vector_chunks *vcs = &ac->vchunks;
> -	struct idpf_vc_xn_params xn_params = {};
> -	ssize_t reply_sz;
> -	int buf_size;
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_DEALLOC_VECTORS,
> +	};
> +	struct virtchnl2_vector_chunks *vcs;
> +	int buf_size, err;
>   
> -	buf_size = struct_size(vcs, vchunks, le16_to_cpu(vcs->num_vchunks));
> +	buf_size = struct_size(&ac->vchunks, vchunks,
> +			       le16_to_cpu(ac->vchunks.num_vchunks));
> +	vcs = kmemdup(&ac->vchunks, buf_size, GFP_KERNEL);
> +	if (!vcs)
> +		return -ENOMEM;
>   
> -	xn_params.vc_op = VIRTCHNL2_OP_DEALLOC_VECTORS;
> -	xn_params.send_buf.iov_base = vcs;
> -	xn_params.send_buf.iov_len = buf_size;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> +	err = idpf_send_mb_msg_kfree(adapter, &xn_params, vcs, buf_size);
> +	if (err)
> +		return err;
>   
>   	kfree(adapter->req_vec_chunks);
>   	adapter->req_vec_chunks = NULL;
>   
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +
>   	return 0;
>   }
>   
> @@ -2779,18 +2361,22 @@ static int idpf_get_max_vfs(struct idpf_adapter *adapter)
>    */
>   int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs)
>   {
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_SET_SRIOV_VFS,
> +	};
>   	struct virtchnl2_sriov_vfs_info svi = {};
> -	struct idpf_vc_xn_params xn_params = {};
> -	ssize_t reply_sz;
> +	int err;
>   
>   	svi.num_vfs = cpu_to_le16(num_vfs);
> -	xn_params.vc_op = VIRTCHNL2_OP_SET_SRIOV_VFS;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	xn_params.send_buf.iov_base = &svi;
> -	xn_params.send_buf.iov_len = sizeof(svi);
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
>   
> -	return reply_sz < 0 ? reply_sz : 0;
> +	err = idpf_send_mb_msg(adapter, &xn_params, &svi, sizeof(svi));
> +	if (err)
> +		return err;
> +
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +
> +	return 0;
>   }
>   
>   /**
> @@ -2803,10 +2389,14 @@ int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs)
>   int idpf_send_get_stats_msg(struct idpf_netdev_priv *np,
>   			    struct idpf_port_stats *port_stats)
>   {
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_GET_STATS,
> +	};
>   	struct rtnl_link_stats64 *netstats = &np->netstats;
> +	struct virtchnl2_vport_stats *stats_recv;
>   	struct virtchnl2_vport_stats stats_msg = {};
> -	struct idpf_vc_xn_params xn_params = {};
> -	ssize_t reply_sz;
> +	int err;
>   
>   
>   	/* Don't send get_stats message if the link is down */
> @@ -2815,38 +2405,41 @@ int idpf_send_get_stats_msg(struct idpf_netdev_priv *np,
>   
>   	stats_msg.vport_id = cpu_to_le32(np->vport_id);
>   
> -	xn_params.vc_op = VIRTCHNL2_OP_GET_STATS;
> -	xn_params.send_buf.iov_base = &stats_msg;
> -	xn_params.send_buf.iov_len = sizeof(stats_msg);
> -	xn_params.recv_buf = xn_params.send_buf;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> +	err = idpf_send_mb_msg(np->adapter, &xn_params, &stats_msg,
> +			       sizeof(stats_msg));
> +	if (err)
> +		return err;
>   
> -	reply_sz = idpf_vc_xn_exec(np->adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> -	if (reply_sz < sizeof(stats_msg))
> -		return -EIO;
> +	if (xn_params.recv_mem.iov_len < sizeof(*stats_recv)) {
> +		err = -EIO;
> +		goto free_rx_buf;
> +	}
> +
> +	stats_recv = xn_params.recv_mem.iov_base;
>   
>   	spin_lock_bh(&np->stats_lock);
>   
> -	netstats->rx_packets = le64_to_cpu(stats_msg.rx_unicast) +
> -			       le64_to_cpu(stats_msg.rx_multicast) +
> -			       le64_to_cpu(stats_msg.rx_broadcast);
> -	netstats->tx_packets = le64_to_cpu(stats_msg.tx_unicast) +
> -			       le64_to_cpu(stats_msg.tx_multicast) +
> -			       le64_to_cpu(stats_msg.tx_broadcast);
> -	netstats->rx_bytes = le64_to_cpu(stats_msg.rx_bytes);
> -	netstats->tx_bytes = le64_to_cpu(stats_msg.tx_bytes);
> -	netstats->rx_errors = le64_to_cpu(stats_msg.rx_errors);
> -	netstats->tx_errors = le64_to_cpu(stats_msg.tx_errors);
> -	netstats->rx_dropped = le64_to_cpu(stats_msg.rx_discards);
> -	netstats->tx_dropped = le64_to_cpu(stats_msg.tx_discards);
> -
> -	port_stats->vport_stats = stats_msg;
> +	netstats->rx_packets = le64_to_cpu(stats_recv->rx_unicast) +
> +			       le64_to_cpu(stats_recv->rx_multicast) +
> +			       le64_to_cpu(stats_recv->rx_broadcast);
> +	netstats->tx_packets = le64_to_cpu(stats_recv->tx_unicast) +
> +			       le64_to_cpu(stats_recv->tx_multicast) +
> +			       le64_to_cpu(stats_recv->tx_broadcast);
> +	netstats->rx_bytes = le64_to_cpu(stats_recv->rx_bytes);
> +	netstats->tx_bytes = le64_to_cpu(stats_recv->tx_bytes);
> +	netstats->rx_errors = le64_to_cpu(stats_recv->rx_errors);
> +	netstats->tx_errors = le64_to_cpu(stats_recv->tx_errors);
> +	netstats->rx_dropped = le64_to_cpu(stats_recv->rx_discards);
> +	netstats->tx_dropped = le64_to_cpu(stats_recv->tx_discards);
> +
> +	port_stats->vport_stats = *stats_recv;
>   
>   	spin_unlock_bh(&np->stats_lock);
>   
> -	return 0;
> +free_rx_buf:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +
> +	return err;
>   }
>   
>   /**
> @@ -2866,14 +2459,16 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_adapter *adapter,
>   				  struct idpf_rss_data *rss_data,
>   				  u32 vport_id, bool get)
>   {
> -	struct virtchnl2_rss_lut *recv_rl __free(kfree) = NULL;
> -	struct virtchnl2_rss_lut *rl __free(kfree) = NULL;
> -	struct idpf_vc_xn_params xn_params = {};
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= get ? VIRTCHNL2_OP_GET_RSS_LUT :
> +					VIRTCHNL2_OP_SET_RSS_LUT,
> +	};
> +	struct virtchnl2_rss_lut *rl, *recv_rl;
>   	int buf_size, lut_buf_size;
>   	struct idpf_vport *vport;
> -	ssize_t reply_sz;
>   	bool rxhash_ena;
> -	int i;
> +	int i, err;
>   
>   	vport = idpf_vid_to_vport(adapter, vport_id);
>   	if (!vport)
> @@ -2887,37 +2482,31 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_adapter *adapter,
>   		return -ENOMEM;
>   
>   	rl->vport_id = cpu_to_le32(vport_id);
> -
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	xn_params.send_buf.iov_base = rl;
> -	xn_params.send_buf.iov_len = buf_size;
> -
> -	if (get) {
> -		recv_rl = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
> -		if (!recv_rl)
> -			return -ENOMEM;
> -		xn_params.vc_op = VIRTCHNL2_OP_GET_RSS_LUT;
> -		xn_params.recv_buf.iov_base = recv_rl;
> -		xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
> -	} else {
> +	if (!get) {
>   		rl->lut_entries = cpu_to_le16(rss_data->rss_lut_size);
>   		for (i = 0; i < rss_data->rss_lut_size; i++)
>   			rl->lut[i] = rxhash_ena ?
>   				cpu_to_le32(rss_data->rss_lut[i]) : 0;
> -
> -		xn_params.vc_op = VIRTCHNL2_OP_SET_RSS_LUT;
>   	}
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> +
> +	err = idpf_send_mb_msg_kfree(adapter, &xn_params, rl, buf_size);
> +	if (err)
> +		return err;
> +
>   	if (!get)
> -		return 0;
> -	if (reply_sz < sizeof(struct virtchnl2_rss_lut))
> -		return -EIO;
> +		goto free_rx_buf;
> +	if (xn_params.recv_mem.iov_len < sizeof(struct virtchnl2_rss_lut)) {
> +		err = -EIO;
> +		goto free_rx_buf;
> +	}
> +
> +	recv_rl = xn_params.recv_mem.iov_base;
>   
>   	lut_buf_size = le16_to_cpu(recv_rl->lut_entries) * sizeof(u32);
> -	if (reply_sz < lut_buf_size)
> -		return -EIO;
> +	if (xn_params.recv_mem.iov_len < lut_buf_size) {
> +		err = -EIO;
> +		goto free_rx_buf;
> +	}
>   
>   	/* size didn't change, we can reuse existing lut buf */
>   	if (rss_data->rss_lut_size == le16_to_cpu(recv_rl->lut_entries))
> @@ -2929,13 +2518,16 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_adapter *adapter,
>   	rss_data->rss_lut = kzalloc(lut_buf_size, GFP_KERNEL);
>   	if (!rss_data->rss_lut) {
>   		rss_data->rss_lut_size = 0;
> -		return -ENOMEM;
> +		err = -ENOMEM;
> +		goto free_rx_buf;
>   	}
>   
>   do_memcpy:
>   	memcpy(rss_data->rss_lut, recv_rl->lut, rss_data->rss_lut_size);
> +free_rx_buf:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
> -	return 0;
> +	return err;
>   }
>   
>   /**
> @@ -2951,12 +2543,14 @@ int idpf_send_get_set_rss_key_msg(struct idpf_adapter *adapter,
>   				  struct idpf_rss_data *rss_data,
>   				  u32 vport_id, bool get)
>   {
> -	struct virtchnl2_rss_key *recv_rk __free(kfree) = NULL;
> -	struct virtchnl2_rss_key *rk __free(kfree) = NULL;
> -	struct idpf_vc_xn_params xn_params = {};
> -	ssize_t reply_sz;
> -	int i, buf_size;
> -	u16 key_size;
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= get ? VIRTCHNL2_OP_GET_RSS_KEY :
> +					VIRTCHNL2_OP_SET_RSS_KEY,
> +	};
> +	struct virtchnl2_rss_key *rk, *recv_rk;
> +	u16 key_size, recv_len;
> +	int i, buf_size, err;
>   
>   	buf_size = struct_size(rk, key_flex, rss_data->rss_key_size);
>   	rk = kzalloc(buf_size, GFP_KERNEL);
> @@ -2964,37 +2558,32 @@ int idpf_send_get_set_rss_key_msg(struct idpf_adapter *adapter,
>   		return -ENOMEM;
>   
>   	rk->vport_id = cpu_to_le32(vport_id);
> -	xn_params.send_buf.iov_base = rk;
> -	xn_params.send_buf.iov_len = buf_size;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	if (get) {
> -		recv_rk = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
> -		if (!recv_rk)
> -			return -ENOMEM;
> -
> -		xn_params.vc_op = VIRTCHNL2_OP_GET_RSS_KEY;
> -		xn_params.recv_buf.iov_base = recv_rk;
> -		xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
> -	} else {
> +	if (!get) {
>   		rk->key_len = cpu_to_le16(rss_data->rss_key_size);
>   		for (i = 0; i < rss_data->rss_key_size; i++)
>   			rk->key_flex[i] = rss_data->rss_key[i];
> -
> -		xn_params.vc_op = VIRTCHNL2_OP_SET_RSS_KEY;
>   	}
>   
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> +	err = idpf_send_mb_msg_kfree(adapter, &xn_params, rk, buf_size);
> +	if (err)
> +		return err;
> +
>   	if (!get)
> -		return 0;
> -	if (reply_sz < sizeof(struct virtchnl2_rss_key))
> -		return -EIO;
> +		goto free_rx_buf;
>   
> +	recv_len = xn_params.recv_mem.iov_len;
> +	if (recv_len < sizeof(struct virtchnl2_rss_key)) {
> +		err = -EIO;
> +		goto free_rx_buf;
> +	}
> +
> +	recv_rk = xn_params.recv_mem.iov_base;
>   	key_size = min_t(u16, NETDEV_RSS_KEY_LEN,
>   			 le16_to_cpu(recv_rk->key_len));
> -	if (reply_sz < key_size)
> -		return -EIO;
> +	if (recv_len < key_size) {
> +		err = -EIO;
> +		goto free_rx_buf;
> +	}
>   
>   	/* key len didn't change, reuse existing buf */
>   	if (rss_data->rss_key_size == key_size)
> @@ -3005,13 +2594,16 @@ int idpf_send_get_set_rss_key_msg(struct idpf_adapter *adapter,
>   	rss_data->rss_key = kzalloc(key_size, GFP_KERNEL);
>   	if (!rss_data->rss_key) {
>   		rss_data->rss_key_size = 0;
> -		return -ENOMEM;
> +		err = -ENOMEM;
> +		goto free_rx_buf;
>   	}
>   
>   do_memcpy:
>   	memcpy(rss_data->rss_key, recv_rk->key_flex, rss_data->rss_key_size);
> +free_rx_buf:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
> -	return 0;
> +	return err;
>   }
>   
>   /**
> @@ -3188,15 +2780,18 @@ static void idpf_parse_protocol_ids(struct virtchnl2_ptype *ptype,
>    */
>   static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)
>   {
> -	struct virtchnl2_get_ptype_info *get_ptype_info __free(kfree) = NULL;
> -	struct virtchnl2_get_ptype_info *ptype_info __free(kfree) = NULL;
>   	struct libeth_rx_pt *singleq_pt_lkup __free(kfree) = NULL;
>   	struct libeth_rx_pt *splitq_pt_lkup __free(kfree) = NULL;
> -	struct idpf_vc_xn_params xn_params = {};
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_GET_PTYPE_INFO,
> +	};
> +	struct virtchnl2_get_ptype_info *get_ptype_info;
> +	struct virtchnl2_get_ptype_info *ptype_info;
> +	int err = 0, max_ptype = IDPF_RX_MAX_PTYPE;
> +	int buf_size = sizeof(*get_ptype_info);
>   	int ptypes_recvd = 0, ptype_offset;
> -	u32 max_ptype = IDPF_RX_MAX_PTYPE;
>   	u16 next_ptype_id = 0;
> -	ssize_t reply_sz;
>   
>   	singleq_pt_lkup = kzalloc_objs(*singleq_pt_lkup, IDPF_RX_MAX_BASE_PTYPE);
>   	if (!singleq_pt_lkup)
> @@ -3206,42 +2801,34 @@ static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)
>   	if (!splitq_pt_lkup)
>   		return -ENOMEM;
>   
> -	get_ptype_info = kzalloc_obj(*get_ptype_info);
> -	if (!get_ptype_info)
> -		return -ENOMEM;
> -
> -	ptype_info = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
> -	if (!ptype_info)
> -		return -ENOMEM;
> +	while (next_ptype_id < max_ptype) {
> +		u16 num_ptypes;
>   
> -	xn_params.vc_op = VIRTCHNL2_OP_GET_PTYPE_INFO;
> -	xn_params.send_buf.iov_base = get_ptype_info;
> -	xn_params.send_buf.iov_len = sizeof(*get_ptype_info);
> -	xn_params.recv_buf.iov_base = ptype_info;
> -	xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> +		get_ptype_info = kzalloc(buf_size, GFP_KERNEL);
> +		if (!get_ptype_info)
> +			return -ENOMEM;
>   
> -	while (next_ptype_id < max_ptype) {
>   		get_ptype_info->start_ptype_id = cpu_to_le16(next_ptype_id);
>   
>   		if ((next_ptype_id + IDPF_RX_MAX_PTYPES_PER_BUF) > max_ptype)
> -			get_ptype_info->num_ptypes =
> -				cpu_to_le16(max_ptype - next_ptype_id);
> +			num_ptypes = max_ptype - next_ptype_id;
>   		else
> -			get_ptype_info->num_ptypes =
> -				cpu_to_le16(IDPF_RX_MAX_PTYPES_PER_BUF);
> +			num_ptypes = IDPF_RX_MAX_PTYPES_PER_BUF;
>   
> -		reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -		if (reply_sz < 0)
> -			return reply_sz;
> +		get_ptype_info->num_ptypes = cpu_to_le16(num_ptypes);
> +		err = idpf_send_mb_msg_kfree(adapter, &xn_params,
> +					     get_ptype_info, buf_size);
> +		if (err)
> +			return err;
>   
> +		ptype_info = xn_params.recv_mem.iov_base;
>   		ptypes_recvd += le16_to_cpu(ptype_info->num_ptypes);
> -		if (ptypes_recvd > max_ptype)
> -			return -EINVAL;
> -
> -		next_ptype_id = le16_to_cpu(get_ptype_info->start_ptype_id) +
> -				le16_to_cpu(get_ptype_info->num_ptypes);
> +		if (ptypes_recvd > max_ptype) {
> +			err = -EINVAL;
> +			goto free_rx_buf;
> +		}
>   
> +		next_ptype_id = next_ptype_id + num_ptypes;
>   		ptype_offset = IDPF_RX_PTYPE_HDR_SZ;
>   
>   		for (u16 i = 0; i < le16_to_cpu(ptype_info->num_ptypes); i++) {
> @@ -3256,14 +2843,18 @@ static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)
>   			pt_8 = ptype->ptype_id_8;
>   
>   			ptype_offset += IDPF_GET_PTYPE_SIZE(ptype);
> -			if (ptype_offset > IDPF_CTLQ_MAX_BUF_LEN)
> -				return -EINVAL;
> +			if (ptype_offset > LIBIE_CTLQ_MAX_BUF_LEN) {
> +				err = -EINVAL;
> +				goto free_rx_buf;
> +			}
>   
>   			/* 0xFFFF indicates end of ptypes */
>   			if (pt_10 == IDPF_INVALID_PTYPE_ID)
>   				goto out;
> -			if (pt_10 >= max_ptype)
> -				return -EINVAL;
> +			if (pt_10 >= max_ptype) {
> +				err = -EINVAL;
> +				goto free_rx_buf;
> +			}
>   
>   			idpf_parse_protocol_ids(ptype, &rx_pt);
>   			idpf_finalize_ptype_lookup(&rx_pt);
> @@ -3277,13 +2868,18 @@ static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)
>   			if (!singleq_pt_lkup[pt_8].outer_ip)
>   				singleq_pt_lkup[pt_8] = rx_pt;
>   		}
> +
> +		libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +		xn_params.recv_mem = (struct kvec) {};
>   	}
>   
>   out:
>   	adapter->splitq_pt_lkup = no_free_ptr(splitq_pt_lkup);
>   	adapter->singleq_pt_lkup = no_free_ptr(singleq_pt_lkup);
> +free_rx_buf:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
> -	return 0;
> +	return err;
>   }
>   
>   /**
> @@ -3311,40 +2907,24 @@ static void idpf_rel_rx_pt_lkup(struct idpf_adapter *adapter)
>   int idpf_send_ena_dis_loopback_msg(struct idpf_adapter *adapter, u32 vport_id,
>   				   bool loopback_ena)
>   {
> -	struct idpf_vc_xn_params xn_params = {};
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_LOOPBACK,
> +	};
>   	struct virtchnl2_loopback loopback;
> -	ssize_t reply_sz;
> +	int err;
>   
>   	loopback.vport_id = cpu_to_le32(vport_id);
>   	loopback.enable = loopback_ena;
>   
> -	xn_params.vc_op = VIRTCHNL2_OP_LOOPBACK;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	xn_params.send_buf.iov_base = &loopback;
> -	xn_params.send_buf.iov_len = sizeof(loopback);
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -
> -	return reply_sz < 0 ? reply_sz : 0;
> -}
> -
> -/**
> - * idpf_find_ctlq - Given a type and id, find ctlq info
> - * @hw: hardware struct
> - * @type: type of ctrlq to find
> - * @id: ctlq id to find
> - *
> - * Returns pointer to found ctlq info struct, NULL otherwise.
> - */
> -static struct idpf_ctlq_info *idpf_find_ctlq(struct idpf_hw *hw,
> -					     enum idpf_ctlq_type type, int id)
> -{
> -	struct idpf_ctlq_info *cq, *tmp;
> +	err = idpf_send_mb_msg(adapter, &xn_params, &loopback,
> +			       sizeof(loopback));
> +	if (err)
> +		return err;
>   
> -	list_for_each_entry_safe(cq, tmp, &hw->cq_list_head, cq_list)
> -		if (cq->q_id == id && cq->cq_type == type)
> -			return cq;
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
> -	return NULL;
> +	return 0;
>   }
>   
>   /**
> @@ -3355,40 +2935,43 @@ static struct idpf_ctlq_info *idpf_find_ctlq(struct idpf_hw *hw,
>    */
>   int idpf_init_dflt_mbx(struct idpf_adapter *adapter)
>   {
> -	struct idpf_ctlq_create_info ctlq_info[] = {
> +	struct libie_ctlq_ctx *ctx = &adapter->ctlq_ctx;
> +	struct libie_ctlq_create_info ctlq_info[] = {
>   		{
> -			.type = IDPF_CTLQ_TYPE_MAILBOX_TX,
> -			.id = IDPF_DFLT_MBX_ID,
> +			.type = LIBIE_CTLQ_TYPE_TX,
> +			.id = LIBIE_CTLQ_MBX_ID,
>   			.len = IDPF_DFLT_MBX_Q_LEN,
> -			.buf_size = IDPF_CTLQ_MAX_BUF_LEN
>   		},
>   		{
> -			.type = IDPF_CTLQ_TYPE_MAILBOX_RX,
> -			.id = IDPF_DFLT_MBX_ID,
> +			.type = LIBIE_CTLQ_TYPE_RX,
> +			.id = LIBIE_CTLQ_MBX_ID,
>   			.len = IDPF_DFLT_MBX_Q_LEN,
> -			.buf_size = IDPF_CTLQ_MAX_BUF_LEN
>   		}
>   	};
> -	struct idpf_hw *hw = &adapter->hw;
> +	struct libie_ctlq_xn_init_params params = {
> +		.num_qs = IDPF_NUM_DFLT_MBX_Q,
> +		.cctlq_info = ctlq_info,
> +		.ctx = ctx,
> +	};
>   	int err;
>   
> -	adapter->dev_ops.reg_ops.ctlq_reg_init(adapter, ctlq_info);
> +	adapter->dev_ops.reg_ops.ctlq_reg_init(&ctx->mmio_info,
> +					       params.cctlq_info);
>   
> -	err = idpf_ctlq_init(hw, IDPF_NUM_DFLT_MBX_Q, ctlq_info);
> +	err = libie_ctlq_xn_init(&params);
>   	if (err)
>   		return err;
>   
> -	hw->asq = idpf_find_ctlq(hw, IDPF_CTLQ_TYPE_MAILBOX_TX,
> -				 IDPF_DFLT_MBX_ID);
> -	hw->arq = idpf_find_ctlq(hw, IDPF_CTLQ_TYPE_MAILBOX_RX,
> -				 IDPF_DFLT_MBX_ID);
> -
> -	if (!hw->asq || !hw->arq) {
> -		idpf_ctlq_deinit(hw);
> -
> +	adapter->asq = libie_find_ctlq(ctx, LIBIE_CTLQ_TYPE_TX,
> +				       LIBIE_CTLQ_MBX_ID);
> +	adapter->arq = libie_find_ctlq(ctx, LIBIE_CTLQ_TYPE_RX,
> +				       LIBIE_CTLQ_MBX_ID);
> +	if (!adapter->asq || !adapter->arq) {
> +		libie_ctlq_xn_deinit(params.xnm, ctx);
>   		return -ENOENT;
>   	}
>   
> +	adapter->xnm = params.xnm;
>   	adapter->state = __IDPF_VER_CHECK;
>   
>   	return 0;
> @@ -3400,12 +2983,13 @@ int idpf_init_dflt_mbx(struct idpf_adapter *adapter)
>    */
>   void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter)
>   {
> -	if (adapter->hw.arq && adapter->hw.asq) {
> -		idpf_mb_clean(adapter, adapter->hw.asq);
> -		idpf_ctlq_deinit(&adapter->hw);
> +	if (adapter->arq && adapter->asq) {
> +		idpf_mb_clean(adapter, adapter->asq, true);
> +		libie_ctlq_xn_deinit(adapter->xnm, &adapter->ctlq_ctx);
>   	}
> -	adapter->hw.arq = NULL;
> -	adapter->hw.asq = NULL;
> +
> +	adapter->arq = NULL;
> +	adapter->asq = NULL;
>   }
>   
>   /**
> @@ -3476,15 +3060,6 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
>   	u16 num_max_vports;
>   	int err = 0;
>   
> -	if (!adapter->vcxn_mngr) {
> -		adapter->vcxn_mngr = kzalloc_obj(*adapter->vcxn_mngr);
> -		if (!adapter->vcxn_mngr) {
> -			err = -ENOMEM;
> -			goto init_failed;
> -		}
> -	}
> -	idpf_vc_xn_init(adapter->vcxn_mngr);
> -
>   	while (adapter->state != __IDPF_INIT_SW) {
>   		switch (adapter->state) {
>   		case __IDPF_VER_CHECK:
> @@ -3627,8 +3202,7 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
>   	 * the mailbox again
>   	 */
>   	adapter->state = __IDPF_VER_CHECK;
> -	if (adapter->vcxn_mngr)
> -		idpf_vc_xn_shutdown(adapter->vcxn_mngr);
> +	idpf_deinit_dflt_mbx(adapter);
>   	set_bit(IDPF_HR_DRV_LOAD, adapter->flags);
>   	queue_delayed_work(adapter->vc_event_wq, &adapter->vc_event_task,
>   			   msecs_to_jiffies(task_delay));
> @@ -3651,7 +3225,7 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)
>   	/* Avoid transaction timeouts when called during reset */
>   	remove_in_prog = test_bit(IDPF_REMOVE_IN_PROG, adapter->flags);
>   	if (!remove_in_prog)
> -		idpf_vc_xn_shutdown(adapter->vcxn_mngr);
> +		idpf_deinit_dflt_mbx(adapter);
>   
>   	idpf_ptp_release(adapter);
>   	idpf_deinit_task(adapter);
> @@ -3660,7 +3234,7 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)
>   	idpf_intr_rel(adapter);
>   
>   	if (remove_in_prog)
> -		idpf_vc_xn_shutdown(adapter->vcxn_mngr);
> +		idpf_deinit_dflt_mbx(adapter);
>   
>   	cancel_delayed_work_sync(&adapter->serv_task);
>   	cancel_delayed_work_sync(&adapter->mbx_task);
> @@ -4197,9 +3771,9 @@ static void idpf_set_mac_type(const u8 *default_mac_addr,
>   
>   /**
>    * idpf_mac_filter_async_handler - Async callback for mac filters
> - * @adapter: private data struct
> - * @xn: transaction for message
> - * @ctlq_msg: received message
> + * @ctx: controlq context structure
> + * @buff: response buffer pointer and size
> + * @status: async call return value
>    *
>    * In some scenarios driver can't sleep and wait for a reply (e.g.: stack is
>    * holding rtnl_lock) when adding a new mac filter. It puts us in a difficult
> @@ -4207,13 +3781,14 @@ static void idpf_set_mac_type(const u8 *default_mac_addr,
>    * ultimately do is remove it from our list of mac filters and report the
>    * error.
>    */
> -static int idpf_mac_filter_async_handler(struct idpf_adapter *adapter,
> -					 struct idpf_vc_xn *xn,
> -					 const struct idpf_ctlq_msg *ctlq_msg)
> +static void idpf_mac_filter_async_handler(void *ctx,
> +					  struct kvec *buff,
> +					  int status)
>   {
>   	struct virtchnl2_mac_addr_list *ma_list;
>   	struct idpf_vport_config *vport_config;
>   	struct virtchnl2_mac_addr *mac_addr;
> +	struct idpf_adapter *adapter = ctx;
>   	struct idpf_mac_filter *f, *tmp;
>   	struct list_head *ma_list_head;
>   	struct idpf_vport *vport;
> @@ -4221,18 +3796,18 @@ static int idpf_mac_filter_async_handler(struct idpf_adapter *adapter,
>   	int i;
>   
>   	/* if success we're done, we're only here if something bad happened */
> -	if (!ctlq_msg->cookie.mbx.chnl_retval)
> -		return 0;
> +	if (!status || status == -ETIMEDOUT)
> +		return;
>   
> +	ma_list = buff->iov_base;
>   	/* make sure at least struct is there */
> -	if (xn->reply_sz < sizeof(*ma_list))
> +	if (buff->iov_len < sizeof(*ma_list))
>   		goto invalid_payload;
>   
> -	ma_list = ctlq_msg->ctx.indirect.payload->va;
>   	mac_addr = ma_list->mac_addr_list;
>   	num_entries = le16_to_cpu(ma_list->num_mac_addr);
>   	/* we should have received a buffer at least this big */
> -	if (xn->reply_sz < struct_size(ma_list, mac_addr_list, num_entries))
> +	if (buff->iov_len < struct_size(ma_list, mac_addr_list, num_entries))
>   		goto invalid_payload;
>   
>   	vport = idpf_vid_to_vport(adapter, le32_to_cpu(ma_list->vport_id));
> @@ -4252,16 +3827,13 @@ static int idpf_mac_filter_async_handler(struct idpf_adapter *adapter,
>   			if (ether_addr_equal(mac_addr[i].addr, f->macaddr))
>   				list_del(&f->list);
>   	spin_unlock_bh(&vport_config->mac_filter_list_lock);
> -	dev_err_ratelimited(&adapter->pdev->dev, "Received error sending MAC filter request (op %d)\n",
> -			    xn->vc_op);
> -
> -	return 0;
> +	dev_err_ratelimited(&adapter->pdev->dev, "Received error %d on sending MAC filter request\n",
> +			    status);
> +	return;
>   
>   invalid_payload:
> -	dev_err_ratelimited(&adapter->pdev->dev, "Received invalid MAC filter payload (op %d) (len %zd)\n",
> -			    xn->vc_op, xn->reply_sz);
> -
> -	return -EINVAL;
> +	dev_err_ratelimited(&adapter->pdev->dev, "Received invalid MAC filter payload (len %zd)\n",
> +			    buff->iov_len);
>   }
>   
>   /**
> @@ -4280,19 +3852,21 @@ int idpf_add_del_mac_filters(struct idpf_adapter *adapter,
>   			     const u8 *default_mac_addr, u32 vport_id,
>   			     bool add, bool async)
>   {
> -	struct virtchnl2_mac_addr_list *ma_list __free(kfree) = NULL;
>   	struct virtchnl2_mac_addr *mac_addr __free(kfree) = NULL;
> -	struct idpf_vc_xn_params xn_params = {};
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= add ? VIRTCHNL2_OP_ADD_MAC_ADDR :
> +					VIRTCHNL2_OP_DEL_MAC_ADDR,
> +	};
> +	struct virtchnl2_mac_addr_list *ma_list;
>   	u32 num_msgs, total_filters = 0;
>   	struct idpf_mac_filter *f;
> -	ssize_t reply_sz;
> -	int i = 0, k;
> +	int i = 0;
>   
> -	xn_params.vc_op = add ? VIRTCHNL2_OP_ADD_MAC_ADDR :
> -				VIRTCHNL2_OP_DEL_MAC_ADDR;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	xn_params.async = async;
> -	xn_params.async_handler = idpf_mac_filter_async_handler;
> +	if (async) {
> +		xn_params.resp_cb = idpf_mac_filter_async_handler;
> +		xn_params.send_ctx = adapter;
> +	}
>   
>   	spin_lock_bh(&vport_config->mac_filter_list_lock);
>   
> @@ -4347,32 +3921,31 @@ int idpf_add_del_mac_filters(struct idpf_adapter *adapter,
>   	 */
>   	num_msgs = DIV_ROUND_UP(total_filters, IDPF_NUM_FILTERS_PER_MSG);
>   
> -	for (i = 0, k = 0; i < num_msgs; i++) {
> -		u32 entries_size, buf_size, num_entries;
> +	for (u32 i = 0, k = 0; i < num_msgs; i++) {
> +		u32 entries_size, num_entries;
> +		size_t buf_size;
> +		int err;
>   
>   		num_entries = min_t(u32, total_filters,
>   				    IDPF_NUM_FILTERS_PER_MSG);
>   		entries_size = sizeof(struct virtchnl2_mac_addr) * num_entries;
>   		buf_size = struct_size(ma_list, mac_addr_list, num_entries);
>   
> -		if (!ma_list || num_entries != IDPF_NUM_FILTERS_PER_MSG) {
> -			kfree(ma_list);
> -			ma_list = kzalloc(buf_size, GFP_ATOMIC);
> -			if (!ma_list)
> -				return -ENOMEM;
> -		} else {
> -			memset(ma_list, 0, buf_size);
> -		}
> +		ma_list = kzalloc(buf_size, GFP_ATOMIC);
> +		if (!ma_list)
> +			return -ENOMEM;
>   
>   		ma_list->vport_id = cpu_to_le32(vport_id);
>   		ma_list->num_mac_addr = cpu_to_le16(num_entries);
>   		memcpy(ma_list->mac_addr_list, &mac_addr[k], entries_size);
>   
> -		xn_params.send_buf.iov_base = ma_list;
> -		xn_params.send_buf.iov_len = buf_size;
> -		reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -		if (reply_sz < 0)
> -			return reply_sz;
> +		err = idpf_send_mb_msg_kfree(adapter, &xn_params, ma_list,
> +					     buf_size);
> +		if (err)
> +			return err;
> +
> +		if (!async)
> +			libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
>   		k += num_entries;
>   		total_filters -= num_entries;
> @@ -4381,6 +3954,26 @@ int idpf_add_del_mac_filters(struct idpf_adapter *adapter,
>   	return 0;
>   }
>   
> +/**
> + * idpf_promiscuous_async_handler - async callback for promiscuous mode
> + * @ctx: controlq context structure
> + * @buff: response buffer pointer and size
> + * @status: async call return value
> + *
> + * Nobody is waiting for the promiscuous virtchnl message response. Print
> + * an error message if something went wrong and return.
> + */
> +static void idpf_promiscuous_async_handler(void *ctx,
> +					   struct kvec *buff,
> +					   int status)
> +{
> +	struct idpf_adapter *adapter = ctx;
> +
> +	if (status)
> +		dev_err_ratelimited(&adapter->pdev->dev, "Failed to set promiscuous mode: %d\n",
> +				    status);
> +}
> +
>   /**
>    * idpf_set_promiscuous - set promiscuous and send message to mailbox
>    * @adapter: Driver specific private structure
> @@ -4395,9 +3988,13 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter,
>   			 struct idpf_vport_user_config_data *config_data,
>   			 u32 vport_id)
>   {
> -	struct idpf_vc_xn_params xn_params = {};
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +		.chnl_opcode	= VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE,
> +		.resp_cb	= idpf_promiscuous_async_handler,
> +		.send_ctx	= adapter,
> +	};
>   	struct virtchnl2_promisc_info vpi;
> -	ssize_t reply_sz;
>   	u16 flags = 0;
>   
>   	if (test_bit(__IDPF_PROMISC_UC, config_data->user_flags))
> @@ -4408,15 +4005,7 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter,
>   	vpi.vport_id = cpu_to_le32(vport_id);
>   	vpi.flags = cpu_to_le16(flags);
>   
> -	xn_params.vc_op = VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	xn_params.send_buf.iov_base = &vpi;
> -	xn_params.send_buf.iov_len = sizeof(vpi);
> -	/* setting promiscuous is only ever done asynchronously */
> -	xn_params.async = true;
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -
> -	return reply_sz < 0 ? reply_sz : 0;
> +	return idpf_send_mb_msg(adapter, &xn_params, &vpi, sizeof(vpi));
>   }
>   
>   /**
> @@ -4434,26 +4023,39 @@ int idpf_idc_rdma_vc_send_sync(struct iidc_rdma_core_dev_info *cdev_info,
>   			       u8 *recv_msg, u16 *recv_len)
>   {
>   	struct idpf_adapter *adapter = pci_get_drvdata(cdev_info->pdev);
> -	struct idpf_vc_xn_params xn_params = { };
> -	ssize_t reply_sz;
> -	u16 recv_size;
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.chnl_opcode = VIRTCHNL2_OP_RDMA,
> +		.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> +	};
> +	u8 on_stack_buf[LIBIE_CP_TX_COPYBREAK];
> +	void *send_buf;
> +	int err;
>   
> -	if (!recv_msg || !recv_len || msg_size > IDPF_CTLQ_MAX_BUF_LEN)
> +	if (!recv_msg || !recv_len || msg_size > LIBIE_CTLQ_MAX_BUF_LEN)
>   		return -EINVAL;
>   
> -	recv_size = min_t(u16, *recv_len, IDPF_CTLQ_MAX_BUF_LEN);
> -	*recv_len = 0;
> -	xn_params.vc_op = VIRTCHNL2_OP_RDMA;
> -	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
> -	xn_params.send_buf.iov_base = send_msg;
> -	xn_params.send_buf.iov_len = msg_size;
> -	xn_params.recv_buf.iov_base = recv_msg;
> -	xn_params.recv_buf.iov_len = recv_size;
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> -	*recv_len = reply_sz;
> +	if (!libie_cp_can_send_onstack(msg_size)) {
> +		send_buf = kzalloc(msg_size, GFP_KERNEL);
> +		if (!send_buf)
> +			return -ENOMEM;
> +	} else {
> +		send_buf = on_stack_buf;
> +	}
>   
> -	return 0;
> +	memcpy(send_buf, send_msg, msg_size);
> +	err = idpf_send_mb_msg(adapter, &xn_params, send_buf, msg_size);
> +	if (err)
> +		return err;
> +
> +	if (xn_params.recv_mem.iov_len > *recv_len) {
> +		err = -EINVAL;
> +		goto rel_buf;
> +	}
> +
> +	*recv_len = xn_params.recv_mem.iov_len;
> +	memcpy(recv_msg, xn_params.recv_mem.iov_base, *recv_len);
> +rel_buf:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +	return err;
>   }
>   EXPORT_SYMBOL_GPL(idpf_idc_rdma_vc_send_sync);
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
> index 762b477e019c..86a44b6e1488 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
> +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
> @@ -7,85 +7,6 @@
>   #include <linux/intel/virtchnl2.h>
>   
>   #define IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC	(60 * 1000)
> -#define IDPF_VC_XN_IDX_M		GENMASK(7, 0)
> -#define IDPF_VC_XN_SALT_M		GENMASK(15, 8)
> -#define IDPF_VC_XN_RING_LEN		U8_MAX
> -
> -/**
> - * enum idpf_vc_xn_state - Virtchnl transaction status
> - * @IDPF_VC_XN_IDLE: not expecting a reply, ready to be used
> - * @IDPF_VC_XN_WAITING: expecting a reply, not yet received
> - * @IDPF_VC_XN_COMPLETED_SUCCESS: a reply was expected and received, buffer
> - *				  updated
> - * @IDPF_VC_XN_COMPLETED_FAILED: a reply was expected and received, but there
> - *				 was an error, buffer not updated
> - * @IDPF_VC_XN_SHUTDOWN: transaction object cannot be used, VC torn down
> - * @IDPF_VC_XN_ASYNC: transaction sent asynchronously and doesn't have the
> - *		      return context; a callback may be provided to handle
> - *		      return
> - */
> -enum idpf_vc_xn_state {
> -	IDPF_VC_XN_IDLE = 1,
> -	IDPF_VC_XN_WAITING,
> -	IDPF_VC_XN_COMPLETED_SUCCESS,
> -	IDPF_VC_XN_COMPLETED_FAILED,
> -	IDPF_VC_XN_SHUTDOWN,
> -	IDPF_VC_XN_ASYNC,
> -};
> -
> -struct idpf_vc_xn;
> -/* Callback for asynchronous messages */
> -typedef int (*async_vc_cb) (struct idpf_adapter *, struct idpf_vc_xn *,
> -			    const struct idpf_ctlq_msg *);
> -
> -/**
> - * struct idpf_vc_xn - Data structure representing virtchnl transactions
> - * @completed: virtchnl event loop uses that to signal when a reply is
> - *	       available, uses kernel completion API
> - * @state: virtchnl event loop stores the data below, protected by the
> - *	   completion's lock.
> - * @reply_sz: Original size of reply, may be > reply_buf.iov_len; it will be
> - *	      truncated on its way to the receiver thread according to
> - *	      reply_buf.iov_len.
> - * @reply: Reference to the buffer(s) where the reply data should be written
> - *	   to. May be 0-length (then NULL address permitted) if the reply data
> - *	   should be ignored.
> - * @async_handler: if sent asynchronously, a callback can be provided to handle
> - *		   the reply when it's received
> - * @vc_op: corresponding opcode sent with this transaction
> - * @idx: index used as retrieval on reply receive, used for cookie
> - * @salt: changed every message to make unique, used for cookie
> - */
> -struct idpf_vc_xn {
> -	struct completion completed;
> -	enum idpf_vc_xn_state state;
> -	size_t reply_sz;
> -	struct kvec reply;
> -	async_vc_cb async_handler;
> -	u32 vc_op;
> -	u8 idx;
> -	u8 salt;
> -};
> -
> -/**
> - * struct idpf_vc_xn_params - Parameters for executing transaction
> - * @send_buf: kvec for send buffer
> - * @recv_buf: kvec for recv buffer, may be NULL, must then have zero length
> - * @timeout_ms: timeout to wait for reply
> - * @async: send message asynchronously, will not wait on completion
> - * @async_handler: If sent asynchronously, optional callback handler. The user
> - *		   must be careful when using async handlers as the memory for
> - *		   the recv_buf _cannot_ be on stack if this is async.
> - * @vc_op: virtchnl op to send
> - */
> -struct idpf_vc_xn_params {
> -	struct kvec send_buf;
> -	struct kvec recv_buf;
> -	int timeout_ms;
> -	bool async;
> -	async_vc_cb async_handler;
> -	u32 vc_op;
> -};
>   
>   struct idpf_adapter;
>   struct idpf_netdev_priv;
> @@ -95,8 +16,6 @@ struct idpf_vport_max_q;
>   struct idpf_vport_config;
>   struct idpf_vport_user_config_data;
>   
> -ssize_t idpf_vc_xn_exec(struct idpf_adapter *adapter,
> -			const struct idpf_vc_xn_params *params);
>   int idpf_init_dflt_mbx(struct idpf_adapter *adapter);
>   void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter);
>   int idpf_vc_core_init(struct idpf_adapter *adapter);
> @@ -123,9 +42,14 @@ bool idpf_sideband_action_ena(struct idpf_vport *vport,
>   			      struct ethtool_rx_flow_spec *fsp);
>   unsigned int idpf_fsteer_max_rules(struct idpf_vport *vport);
>   
> -int idpf_recv_mb_msg(struct idpf_adapter *adapter, struct idpf_ctlq_info *arq);
> -int idpf_send_mb_msg(struct idpf_adapter *adapter, struct idpf_ctlq_info *asq,
> -		     u32 op, u16 msg_size, u8 *msg, u16 cookie);
> +void idpf_recv_event_msg(struct libie_ctlq_ctx *ctx,
> +			 struct libie_ctlq_msg *ctlq_msg);
> +int idpf_send_mb_msg(struct idpf_adapter *adapter,
> +		     struct libie_ctlq_xn_send_params *xn_params,
> +		     void *send_buf, size_t send_buf_size);
> +int idpf_send_mb_msg_kfree(struct idpf_adapter *adapter,
> +			   struct libie_ctlq_xn_send_params *xn_params,
> +			   void *send_buf, size_t send_buf_size);
>   
>   struct idpf_queue_ptr {
>   	enum virtchnl2_queue_type	type;
> @@ -213,7 +137,6 @@ int idpf_send_get_set_rss_key_msg(struct idpf_adapter *adapter,
>   int idpf_send_get_set_rss_lut_msg(struct idpf_adapter *adapter,
>   				  struct idpf_rss_data *rss_data,
>   				  u32 vport_id, bool get);
> -void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr);
>   int idpf_idc_rdma_vc_send_sync(struct iidc_rdma_core_dev_info *cdev_info,
>   			       u8 *send_msg, u16 msg_size,
>   			       u8 *recv_msg, u16 *recv_len);
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c
> index 8d8fb498e092..6a90dd7d052e 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c
> @@ -15,7 +15,6 @@
>    */
>   int idpf_ptp_get_caps(struct idpf_adapter *adapter)
>   {
> -	struct virtchnl2_ptp_get_caps *recv_ptp_caps_msg __free(kfree) = NULL;
>   	struct virtchnl2_ptp_get_caps send_ptp_caps_msg = {
>   		.caps = cpu_to_le32(VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME |
>   				    VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME_MB |
> @@ -24,34 +23,34 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)
>   				    VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK_MB |
>   				    VIRTCHNL2_CAP_PTP_TX_TSTAMPS_MB)
>   	};
> -	struct idpf_vc_xn_params xn_params = {
> -		.vc_op = VIRTCHNL2_OP_PTP_GET_CAPS,
> -		.send_buf.iov_base = &send_ptp_caps_msg,
> -		.send_buf.iov_len = sizeof(send_ptp_caps_msg),
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.chnl_opcode = VIRTCHNL2_OP_PTP_GET_CAPS,
>   		.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
>   	};
>   	struct virtchnl2_ptp_cross_time_reg_offsets cross_tstamp_offsets;
>   	struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
>   	struct virtchnl2_ptp_clk_adj_reg_offsets clk_adj_offsets;
>   	struct virtchnl2_ptp_clk_reg_offsets clock_offsets;
> +	struct virtchnl2_ptp_get_caps *recv_ptp_caps_msg;
>   	struct idpf_ptp_secondary_mbx *scnd_mbx;
>   	struct idpf_ptp *ptp = adapter->ptp;
>   	enum idpf_ptp_access access_type;
>   	u32 temp_offset;
> -	int reply_sz;
> +	size_t reply_sz;
> +	int err;
>   
> -	recv_ptp_caps_msg = kzalloc_obj(struct virtchnl2_ptp_get_caps);
> -	if (!recv_ptp_caps_msg)
> -		return -ENOMEM;
> +	err = idpf_send_mb_msg(adapter, &xn_params, &send_ptp_caps_msg,
> +			       sizeof(send_ptp_caps_msg));
> +	if (err)
> +		return err;
>   
> -	xn_params.recv_buf.iov_base = recv_ptp_caps_msg;
> -	xn_params.recv_buf.iov_len = sizeof(*recv_ptp_caps_msg);
> +	reply_sz = xn_params.recv_mem.iov_len;
> +	if (reply_sz != sizeof(*recv_ptp_caps_msg)) {
> +		err = -EIO;
> +		goto free_resp;
> +	}
>   
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> -	else if (reply_sz != sizeof(*recv_ptp_caps_msg))
> -		return -EIO;
> +	recv_ptp_caps_msg = xn_params.recv_mem.iov_base;
>   
>   	ptp->caps = le32_to_cpu(recv_ptp_caps_msg->caps);
>   	ptp->base_incval = le64_to_cpu(recv_ptp_caps_msg->base_incval);
> @@ -112,7 +111,7 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)
>   discipline_clock:
>   	access_type = ptp->adj_dev_clk_time_access;
>   	if (access_type != IDPF_PTP_DIRECT)
> -		return 0;
> +		goto free_resp;
>   
>   	clk_adj_offsets = recv_ptp_caps_msg->clk_adj_offsets;
>   
> @@ -145,7 +144,9 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)
>   	ptp->dev_clk_regs.phy_shadj_h =
>   		libie_pci_get_mmio_addr(mmio, temp_offset);
>   
> -	return 0;
> +free_resp:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +	return err;
>   }
>   
>   /**
> @@ -160,28 +161,34 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)
>   int idpf_ptp_get_dev_clk_time(struct idpf_adapter *adapter,
>   			      struct idpf_ptp_dev_timers *dev_clk_time)
>   {
> +	struct virtchnl2_ptp_get_dev_clk_time *get_dev_clk_time_resp;
>   	struct virtchnl2_ptp_get_dev_clk_time get_dev_clk_time_msg;
> -	struct idpf_vc_xn_params xn_params = {
> -		.vc_op = VIRTCHNL2_OP_PTP_GET_DEV_CLK_TIME,
> -		.send_buf.iov_base = &get_dev_clk_time_msg,
> -		.send_buf.iov_len = sizeof(get_dev_clk_time_msg),
> -		.recv_buf.iov_base = &get_dev_clk_time_msg,
> -		.recv_buf.iov_len = sizeof(get_dev_clk_time_msg),
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.chnl_opcode = VIRTCHNL2_OP_PTP_GET_DEV_CLK_TIME,
>   		.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
>   	};
> -	int reply_sz;
> +	size_t reply_sz;
>   	u64 dev_time;
> +	int err;
>   
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> -	if (reply_sz != sizeof(get_dev_clk_time_msg))
> -		return -EIO;
> +	err = idpf_send_mb_msg(adapter, &xn_params, &get_dev_clk_time_msg,
> +			       sizeof(get_dev_clk_time_msg));
> +	if (err)
> +		return err;
>   
> -	dev_time = le64_to_cpu(get_dev_clk_time_msg.dev_time_ns);
> +	reply_sz = xn_params.recv_mem.iov_len;
> +	if (reply_sz != sizeof(*get_dev_clk_time_resp)) {
> +		err = -EIO;
> +		goto free_resp;
> +	}
> +
> +	get_dev_clk_time_resp = xn_params.recv_mem.iov_base;
> +	dev_time = le64_to_cpu(get_dev_clk_time_resp->dev_time_ns);
>   	dev_clk_time->dev_clk_time_ns = dev_time;
>   
> -	return 0;
> +free_resp:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +	return err;
>   }
>   
>   /**
> @@ -197,27 +204,30 @@ int idpf_ptp_get_dev_clk_time(struct idpf_adapter *adapter,
>   int idpf_ptp_get_cross_time(struct idpf_adapter *adapter,
>   			    struct idpf_ptp_dev_timers *cross_time)
>   {
> -	struct virtchnl2_ptp_get_cross_time cross_time_msg;
> -	struct idpf_vc_xn_params xn_params = {
> -		.vc_op = VIRTCHNL2_OP_PTP_GET_CROSS_TIME,
> -		.send_buf.iov_base = &cross_time_msg,
> -		.send_buf.iov_len = sizeof(cross_time_msg),
> -		.recv_buf.iov_base = &cross_time_msg,
> -		.recv_buf.iov_len = sizeof(cross_time_msg),
> +	struct virtchnl2_ptp_get_cross_time cross_time_send, *cross_time_recv;
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.chnl_opcode = VIRTCHNL2_OP_PTP_GET_CROSS_TIME,
>   		.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
>   	};
> -	int reply_sz;
> +	int err = 0;
>   
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> -	if (reply_sz != sizeof(cross_time_msg))
> -		return -EIO;
> +	err = idpf_send_mb_msg(adapter, &xn_params, &cross_time_send,
> +			       sizeof(cross_time_send));
> +	if (err)
> +		return err;
>   
> -	cross_time->dev_clk_time_ns = le64_to_cpu(cross_time_msg.dev_time_ns);
> -	cross_time->sys_time_ns = le64_to_cpu(cross_time_msg.sys_time_ns);
> +	if (xn_params.recv_mem.iov_len != sizeof(*cross_time_recv)) {
> +		err = -EIO;
> +		goto free_resp;
> +	}
>   
> -	return 0;
> +	cross_time_recv = xn_params.recv_mem.iov_base;
> +	cross_time->dev_clk_time_ns = le64_to_cpu(cross_time_recv->dev_time_ns);
> +	cross_time->sys_time_ns = le64_to_cpu(cross_time_recv->sys_time_ns);
> +
> +free_resp:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +	return err;
>   }
>   
>   /**
> @@ -234,23 +244,18 @@ int idpf_ptp_set_dev_clk_time(struct idpf_adapter *adapter, u64 time)
>   	struct virtchnl2_ptp_set_dev_clk_time set_dev_clk_time_msg = {
>   		.dev_time_ns = cpu_to_le64(time),
>   	};
> -	struct idpf_vc_xn_params xn_params = {
> -		.vc_op = VIRTCHNL2_OP_PTP_SET_DEV_CLK_TIME,
> -		.send_buf.iov_base = &set_dev_clk_time_msg,
> -		.send_buf.iov_len = sizeof(set_dev_clk_time_msg),
> -		.recv_buf.iov_base = &set_dev_clk_time_msg,
> -		.recv_buf.iov_len = sizeof(set_dev_clk_time_msg),
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.chnl_opcode = VIRTCHNL2_OP_PTP_SET_DEV_CLK_TIME,
>   		.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
>   	};
> -	int reply_sz;
> +	int err;
>   
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> -	if (reply_sz != sizeof(set_dev_clk_time_msg))
> -		return -EIO;
> +	err = idpf_send_mb_msg(adapter, &xn_params, &set_dev_clk_time_msg,
> +			       sizeof(set_dev_clk_time_msg));
> +	if (!err)
> +		libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
> -	return 0;
> +	return err;
>   }
>   
>   /**
> @@ -267,23 +272,18 @@ int idpf_ptp_adj_dev_clk_time(struct idpf_adapter *adapter, s64 delta)
>   	struct virtchnl2_ptp_adj_dev_clk_time adj_dev_clk_time_msg = {
>   		.delta = cpu_to_le64(delta),
>   	};
> -	struct idpf_vc_xn_params xn_params = {
> -		.vc_op = VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_TIME,
> -		.send_buf.iov_base = &adj_dev_clk_time_msg,
> -		.send_buf.iov_len = sizeof(adj_dev_clk_time_msg),
> -		.recv_buf.iov_base = &adj_dev_clk_time_msg,
> -		.recv_buf.iov_len = sizeof(adj_dev_clk_time_msg),
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.chnl_opcode = VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_TIME,
>   		.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
>   	};
> -	int reply_sz;
> +	int err;
>   
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> -	if (reply_sz != sizeof(adj_dev_clk_time_msg))
> -		return -EIO;
> +	err = idpf_send_mb_msg(adapter, &xn_params, &adj_dev_clk_time_msg,
> +			       sizeof(adj_dev_clk_time_msg));
> +	if (!err)
> +		libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
> -	return 0;
> +	return err;
>   }
>   
>   /**
> @@ -301,23 +301,18 @@ int idpf_ptp_adj_dev_clk_fine(struct idpf_adapter *adapter, u64 incval)
>   	struct virtchnl2_ptp_adj_dev_clk_fine adj_dev_clk_fine_msg = {
>   		.incval = cpu_to_le64(incval),
>   	};
> -	struct idpf_vc_xn_params xn_params = {
> -		.vc_op = VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_FINE,
> -		.send_buf.iov_base = &adj_dev_clk_fine_msg,
> -		.send_buf.iov_len = sizeof(adj_dev_clk_fine_msg),
> -		.recv_buf.iov_base = &adj_dev_clk_fine_msg,
> -		.recv_buf.iov_len = sizeof(adj_dev_clk_fine_msg),
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.chnl_opcode = VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_FINE,
>   		.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
>   	};
> -	int reply_sz;
> +	int err;
>   
> -	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
> -	if (reply_sz < 0)
> -		return reply_sz;
> -	if (reply_sz != sizeof(adj_dev_clk_fine_msg))
> -		return -EIO;
> +	err = idpf_send_mb_msg(adapter, &xn_params, &adj_dev_clk_fine_msg,
> +			       sizeof(adj_dev_clk_fine_msg));
> +	if (!err)
> +		libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
> -	return 0;
> +	return err;
>   }
>   
>   /**
> @@ -336,18 +331,16 @@ int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport)
>   	struct virtchnl2_ptp_tx_tstamp_latch_caps tx_tstamp_latch_caps;
>   	struct idpf_ptp_vport_tx_tstamp_caps *tstamp_caps;
>   	struct idpf_ptp_tx_tstamp *ptp_tx_tstamp, *tmp;
> -	struct idpf_vc_xn_params xn_params = {
> -		.vc_op = VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP_CAPS,
> -		.send_buf.iov_base = &send_tx_tstamp_caps,
> -		.send_buf.iov_len = sizeof(send_tx_tstamp_caps),
> -		.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN,
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.chnl_opcode = VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP_CAPS,
>   		.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
>   	};
>   	enum idpf_ptp_access tstamp_access, get_dev_clk_access;
>   	struct idpf_ptp *ptp = vport->adapter->ptp;
>   	struct list_head *head;
> -	int err = 0, reply_sz;
> +	size_t reply_sz;
>   	u16 num_latches;
> +	int err = 0;
>   	u32 size;
>   
>   	if (!ptp)
> @@ -359,19 +352,15 @@ int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport)
>   	    get_dev_clk_access == IDPF_PTP_NONE)
>   		return -EOPNOTSUPP;
>   
> -	rcv_tx_tstamp_caps = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
> -	if (!rcv_tx_tstamp_caps)
> -		return -ENOMEM;
> -
>   	send_tx_tstamp_caps.vport_id = cpu_to_le32(vport->vport_id);
> -	xn_params.recv_buf.iov_base = rcv_tx_tstamp_caps;
>   
> -	reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
> -	if (reply_sz < 0) {
> -		err = reply_sz;
> -		goto get_tstamp_caps_out;
> -	}
> +	err = idpf_send_mb_msg(vport->adapter, &xn_params, &send_tx_tstamp_caps,
> +			       sizeof(send_tx_tstamp_caps));
> +	if (err)
> +		return err;
>   
> +	rcv_tx_tstamp_caps = xn_params.recv_mem.iov_base;
> +	reply_sz = xn_params.recv_mem.iov_len;
>   	num_latches = le16_to_cpu(rcv_tx_tstamp_caps->num_latches);
>   	size = struct_size(rcv_tx_tstamp_caps, tstamp_latches, num_latches);
>   	if (reply_sz != size) {
> @@ -426,7 +415,7 @@ int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport)
>   	}
>   
>   	vport->tx_tstamp_caps = tstamp_caps;
> -	kfree(rcv_tx_tstamp_caps);
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
>   	return 0;
>   
> @@ -439,7 +428,7 @@ int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport)
>   
>   	kfree(tstamp_caps);
>   get_tstamp_caps_out:
> -	kfree(rcv_tx_tstamp_caps);
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>   
>   	return err;
>   }
> @@ -536,9 +525,9 @@ idpf_ptp_get_tstamp_value(struct idpf_vport *vport,
>   
>   /**
>    * idpf_ptp_get_tx_tstamp_async_handler - Async callback for getting Tx tstamps
> - * @adapter: Driver specific private structure
> - * @xn: transaction for message
> - * @ctlq_msg: received message
> + * @ctx: adapter pointer
> + * @mem: address and size of the response
> + * @status: return value of the request
>    *
>    * Read the tstamps Tx tstamp values from a received message and put them
>    * directly to the skb. The number of timestamps to read is specified by
> @@ -546,22 +535,23 @@ idpf_ptp_get_tstamp_value(struct idpf_vport *vport,
>    *
>    * Return: 0 on success, -errno otherwise.
>    */
> -static int
> -idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,
> -				     struct idpf_vc_xn *xn,
> -				     const struct idpf_ctlq_msg *ctlq_msg)
> +static void
> +idpf_ptp_get_tx_tstamp_async_handler(void *ctx, struct kvec *mem, int status)
>   {
>   	struct virtchnl2_ptp_get_vport_tx_tstamp_latches *recv_tx_tstamp_msg;
>   	struct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps;
>   	struct virtchnl2_ptp_tx_tstamp_latch tstamp_latch;
>   	struct idpf_ptp_tx_tstamp *tx_tstamp, *tmp;
>   	struct idpf_vport *tstamp_vport = NULL;
> +	struct idpf_adapter *adapter = ctx;
>   	struct list_head *head;
>   	u16 num_latches;
>   	u32 vport_id;
> -	int err = 0;
>   
> -	recv_tx_tstamp_msg = ctlq_msg->ctx.indirect.payload->va;
> +	if (status)
> +		return;
> +
> +	recv_tx_tstamp_msg = mem->iov_base;
>   	vport_id = le32_to_cpu(recv_tx_tstamp_msg->vport_id);
>   
>   	idpf_for_each_vport(adapter, vport) {
> @@ -575,7 +565,7 @@ idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,
>   	}
>   
>   	if (!tstamp_vport || !tstamp_vport->tx_tstamp_caps)
> -		return -EINVAL;
> +		return;
>   
>   	tx_tstamp_caps = tstamp_vport->tx_tstamp_caps;
>   	num_latches = le16_to_cpu(recv_tx_tstamp_msg->num_latches);
> @@ -589,13 +579,13 @@ idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,
>   		if (!tstamp_latch.valid)
>   			continue;
>   
> -		if (list_empty(head)) {
> -			err = -ENOBUFS;
> +		if (list_empty(head))
>   			goto unlock;
> -		}
>   
>   		list_for_each_entry_safe(tx_tstamp, tmp, head, list_member) {
>   			if (tstamp_latch.index == tx_tstamp->idx) {
> +				int err;
> +
>   				list_del(&tx_tstamp->list_member);
>   				err = idpf_ptp_get_tstamp_value(tstamp_vport,
>   								&tstamp_latch,
> @@ -610,8 +600,6 @@ idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,
>   
>   unlock:
>   	spin_unlock_bh(&tx_tstamp_caps->latches_lock);
> -
> -	return err;
>   }
>   
>   /**
> @@ -627,15 +615,15 @@ int idpf_ptp_get_tx_tstamp(struct idpf_vport *vport)
>   {
>   	struct virtchnl2_ptp_get_vport_tx_tstamp_latches *send_tx_tstamp_msg;
>   	struct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps;
> -	struct idpf_vc_xn_params xn_params = {
> -		.vc_op = VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP,
> +	struct libie_ctlq_xn_send_params xn_params = {
> +		.chnl_opcode = VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP,
>   		.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
> -		.async = true,
> -		.async_handler = idpf_ptp_get_tx_tstamp_async_handler,
> +		.resp_cb = idpf_ptp_get_tx_tstamp_async_handler,
> +		.send_ctx = vport->adapter,
>   	};
>   	struct idpf_ptp_tx_tstamp *ptp_tx_tstamp;
> -	int reply_sz, size, msg_size;
>   	struct list_head *head;
> +	int size, msg_size;

Use size_t for `msg_size` to match the signature of 
`idpf_send_mb_msg_kfree()`?

>   	bool state_upd;
>   	u16 id = 0;
>   
> @@ -668,11 +656,7 @@ int idpf_ptp_get_tx_tstamp(struct idpf_vport *vport)
>   	msg_size = struct_size(send_tx_tstamp_msg, tstamp_latches, id);
>   	send_tx_tstamp_msg->vport_id = cpu_to_le32(vport->vport_id);
>   	send_tx_tstamp_msg->num_latches = cpu_to_le16(id);
> -	xn_params.send_buf.iov_base = send_tx_tstamp_msg;
> -	xn_params.send_buf.iov_len = msg_size;
> -
> -	reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
> -	kfree(send_tx_tstamp_msg);
>   
> -	return min(reply_sz, 0);
> +	return idpf_send_mb_msg_kfree(vport->adapter, &xn_params,
> +				      send_tx_tstamp_msg, msg_size);
>   }


Kind regards,

Paul

^ permalink raw reply

* Re: [PATCH] docs: set canonical base URL for HTML output
From: Rito Rhymes @ 2026-03-23 19:09 UTC (permalink / raw)
  To: Jonathan Corbet, Rito Rhymes, linux-doc; +Cc: Shuah Khan, linux-kernel
In-Reply-To: <87y0ji9zbz.fsf@trenco.lwn.net>

To be clear:

canonical URL + local build = useless

canonical URL set by env var + official published build = source
authority support

hardcoded canonical URL in the source tree + mirror deployments =

1. Benign mirror benefit
    Mirrors inherit a source-authority-supporting default without
    needing to think about it or configure anything themselves.

2. Adversarial / careless mirror mitigation
    Anyone who does not want to preserve that signal must take an
    extra step to remove or override it, adding at least some
    friction to careless or hostile reuse. 

Hardcoding it is simpler, safer and more effective because it makes
preservation of the preferred source the path of least resistance,
requires any departure from it to be explicit, and costs local builds
very little without side effects.

Rito

^ permalink raw reply

* Re: [RFC PATCH v4 0/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics
From: Ravi Jonnalagadda @ 2026-03-23 19:23 UTC (permalink / raw)
  To: SeongJae Park
  Cc: damon, linux-mm, linux-kernel, linux-doc, akpm, corbet, bijan311,
	ajayjoshi, honggyu.kim, yunjeong.mun
In-Reply-To: <20260321165746.84394-1-sj@kernel.org>

On Sat, Mar 21, 2026 at 9:57 AM SeongJae Park <sj@kernel.org> wrote:
>
> Hello Ravi,
>
>
> Thank you for this patch!  TL; DR: Other than trivial things I commented below
> and to the patch, I believe it is time to drop the RFC tag, and work on merging
> this.
>

Thanks, SJ, for the prompt and detailed feedback!

> On Fri, 20 Mar 2026 12:04:52 -0700 Ravi Jonnalagadda <ravis.opensrc@gmail.com> wrote:
>
> > This patch introduces two new DAMON quota goal metrics for controlling
>
> s/DAMON/DAMOS/ ?
>

Will fix it.

> > memory distribution in heterogeneous memory systems (e.g., DRAM and CXL
> > memory tiering) using physical address (PA) mode monitoring.
> >
> > v3: https://lore.kernel.org/linux-mm/20260223123232.12851-1-ravis.opensrc@gmail.com/
>
> The above link would better to be put on 'Chage since v3' section below.
>

Got it. Will take care of it next time.

> >
> > Changes since v3:
> > =================
> >
> > - The first two patches from v3 (goal_tuner initialization fix and
> >   esz=0 quota bypass fix) are now in damon/next. This submission
>
> It is not also in mm-unstable :)

Good to know. Will mention this in the next version.

>
> >   contains only the core metrics patch, rebased on top of those fixes.
> >
> > - Simplified implementation: removed per-node eligible_bytes array, now
> >   iterates scheme-eligible regions directly for each goal evaluation.
> >
> > - Handle regions crossing node boundaries: uses damon_get_folio() to
> >   determine actual NUMA node placement of each folio rather than
> >   assuming uniform node placement within a region.
> >
> > - Pass scheme pointer directly to metric calculation functions, avoiding
> >   container_of() derivation from quota pointer.
> >
> > - Fixed 80-column wrapping issues.
>
> Thank you for addressing all my comments!
>
> >
> > Background and Motivation
> > =========================
> >
> > In heterogeneous memory systems, controlling memory distribution across
> > NUMA nodes is essential for performance optimization. This patch enables
> > system-wide page distribution with target-state goals like "maintain 30%
> > of scheme-eligible memory on CXL" using PA-mode DAMON schemes.
> >
> > What These Metrics Measure
> > ==========================
> >
> > node_eligible_mem_bp:
> >     scheme_eligible_bytes_on_node / total_scheme_eligible_bytes * 10000
> >
> > node_ineligible_mem_bp:
> >     (total - scheme_eligible_bytes_on_node) / total * 10000
> >
> > The metrics are complementary: eligible_bp + ineligible_bp = 10000 bp.
> >
> > Two-Scheme Setup for Hot Page Distribution
> > ==========================================
> >
> > For maintaining 30% of hot memory on CXL (node 1):
>
> I think it could help easy reading if the above sentence also explains
> node 0 is DRAM.  For example,
>
> For maintaining hot memory on DRAM (node 0) and CXL (node 1) in 7:3 ratio:

Good suggestion, will clarify the node mapping.

>
> >
> >     PUSH scheme: migrate_hot from node 0 -> node 1
> >       goal: node_ineligible_mem_bp, nid=0, target=3000
> >       "Push hot pages out until 30% of hot memory is NOT on DRAM"
>
> Seems the sentence assumes the actor is in DRAM.  It was not very clear to me.
> How about making it clear?  E.g.,
>
> "Move hot pages from DRAM to CXL, if more than 70% of hot data is in DRAM"

Got it. Will use your suggested wording.

>
> >
> >     PULL scheme: migrate_hot from node 1 -> node 0
> >       goal: node_eligible_mem_bp, nid=0, target=7000
> >       "Pull hot pages back until 70% of hot memory IS on DRAM"
>
> If the above example is good for you, to be consistent with it, how about
> rewording like below?
>
> "Move hot pages from CXL to DRAM, if less than 70% of hot data is in DRAM"

Agreed. Will reword this too.

>
> >
> > The complementary goals create a feedback loop that converges to the
> > target distribution.
> >
> > Dependencies
> > ============
> >
> > This patch is based on SJ's damon/next branch which includes the
> > TEMPORAL goal tuner required for these metrics.
>
> Your test might be depend on the feature.  But this patch series itself is not,
> as users could also use it with CONSIST tuner?
>

Correct, the metrics work with both tuners. Will reword to clarify that
testing used TEMPORAL but the patch itself does not depend on it.

> Also, as I mentioned above, the feature is now also in mm-unstable tree.
>
> >
> > Testing Results
> > ===============
> >
> > Functionally tested on a two-node heterogeneous memory system with DRAM
> > (node 0) and CXL memory (node 1). Used PUSH+PULL scheme configuration
> > with migrate_hot action to maintain a target hot memory ratio between
> > the two tiers.
> >
> > With the TEMPORAL goal tuner, the system converges quickly to the target
> > distribution. The tuner drives esz to maximum when under goal and to
> > zero once the goal is met, forming a simple on/off feedback loop that
> > stabilizes at the desired ratio.
> >
> > With the CONSIST tuner, the scheme still converges but more slowly, as
> > it migrates and then throttles itself based on quota feedback. The time
> > to reach the goal varies depending on workload intensity.
>
> Sounds reasonable!
>
> Do you plan to further evaluate some performance metrics?  I'd not strongly
> request that, but it would be very nice if we can have that.
>

Yes, I am planning to run additional tests. I will send v5 addressing
all the review comments and dropping the RFC tag. Results will follow
as the testing progresses.

> Regardless of your answer to the above question, I think the current code and
> the test is good enough to consider merging this.  I suggest dropping the RFC
> tag from the next spin.
>
> Thank you for doing this, Ravi!
>

Thank you! Will drop the RFC tag for v5.

>
> Thanks,
> SJ
>

Best Regards,
Ravi.

> [...]

^ permalink raw reply

* Re: [PATCH v4 0/4] kallsyms: embed source file:line info in kernel stack traces
From: Andrew Morton @ 2026-03-23 19:25 UTC (permalink / raw)
  To: Sasha Levin
  Cc: Masahiro Yamada, Luis Chamberlain, Linus Torvalds,
	Richard Weinberger, Juergen Gross, Geert Uytterhoeven,
	James Bottomley, Jonathan Corbet, Nathan Chancellor,
	Nicolas Schier, Petr Pavlu, Daniel Gomez, Greg KH, Petr Mladek,
	Steven Rostedt, Kees Cook, Peter Zijlstra, Thorsten Leemhuis,
	Vlastimil Babka, Helge Deller, Randy Dunlap, Laurent Pinchart,
	Vivian Wang, linux-kernel, linux-kbuild, linux-modules, linux-doc
In-Reply-To: <20260322131543.971079-1-sashal@kernel.org>

On Sun, 22 Mar 2026 09:15:39 -0400 Sasha Levin <sashal@kernel.org> wrote:

> This series adds CONFIG_KALLSYMS_LINEINFO, which embeds source file:line
> information directly in the kernel image so that stack traces annotate
> every frame with the originating source location - no external tools, no
> debug symbols at runtime, and safe to use in NMI/panic context.

Thanks, I've updated mm.git's mm-nonmm-unstable branch to this version.

> Changes since v3
> =================
> 
> - Remove redundant gen_lineinfo entry in scripts/Makefile for
>   CONFIG_KALLSYMS_LINEINFO_MODULES (depends on CONFIG_KALLSYMS_LINEINFO
>   which already builds it). (Reported by Petr Pavlu)
> 
> - Use R_* constants from <elf.h> instead of hardcoded relocation type
>   values in r_type_abs32(). (Reported by Petr Pavlu)
> 
> - Simplify duplicated-path detection in make_relative(): replace loop
>   over every '/' with a direct midpoint check, since true path
>   duplication always splits at len/2. (Suggested by Petr Pavlu)
> 
> - Fix comment in process_dwarf(): sections in ET_REL objects have
>   sh_addr == 0 and therefore overlapping address ranges; this is
>   expected behavior, not a "may" situation. (Reported by Petr Pavlu)
> 
> - Use U32_MAX instead of UINT_MAX for the module raw_offset bounds
>   check, matching the u32 type of the addrs array.
>   (Reported by Petr Pavlu)
> 
> - Document the assumption that .text is at the start of the MOD_TEXT
>   segment in module_lookup_lineinfo(). A proper fix using ELF
>   relocations is planned for a future series.
>   (Reported by Petr Pavlu)
> 
> - Wrap -fno-inline-functions-called-once in $(call cc-option,...) for
>   clang compatibility. Clang does not support this GCC-specific flag;
>   the noinline attribute is sufficient.

Here's how v3 altered mm.git:


 kernel/module/kallsyms.c |    8 +++++--
 lib/tests/Makefile       |    2 -
 scripts/Makefile         |    1 
 scripts/gen_lineinfo.c   |   40 +++++++++++++++++--------------------
 4 files changed, 26 insertions(+), 25 deletions(-)

--- a/kernel/module/kallsyms.c~b
+++ a/kernel/module/kallsyms.c
@@ -547,13 +547,17 @@ bool module_lookup_lineinfo(struct modul
 	if (hdr->files_size < hdr->num_files * sizeof(u32))
 		return false;
 
-	/* Compute offset from module .text base */
+	/*
+	 * Compute offset from module .text base.
+	 * NOTE: This assumes .text is at the start of the MOD_TEXT segment.
+	 * A proper fix would use ELF relocations to reference .text directly.
+	 */
 	text_base = (unsigned long)mod->mem[MOD_TEXT].base;
 	if (addr < text_base)
 		return false;
 
 	raw_offset = addr - text_base;
-	if (raw_offset > UINT_MAX)
+	if (raw_offset > U32_MAX)
 		return false;
 
 	tbl.blk_addrs	= base + hdr->blocks_offset;
--- a/lib/tests/Makefile~b
+++ a/lib/tests/Makefile
@@ -36,7 +36,7 @@ obj-$(CONFIG_LIVEUPDATE_TEST) += liveupd
 CFLAGS_longest_symbol_kunit.o += $(call cc-disable-warning, missing-prototypes)
 obj-$(CONFIG_LONGEST_SYM_KUNIT_TEST) += longest_symbol_kunit.o
 
-CFLAGS_lineinfo_kunit.o += -fno-inline-functions-called-once
+CFLAGS_lineinfo_kunit.o += $(call cc-option,-fno-inline-functions-called-once)
 obj-$(CONFIG_LINEINFO_KUNIT_TEST) += lineinfo_kunit.o
 
 obj-$(CONFIG_MEMCPY_KUNIT_TEST) += memcpy_kunit.o
--- a/scripts/gen_lineinfo.c~b
+++ a/scripts/gen_lineinfo.c
@@ -206,14 +206,11 @@ static const char *make_relative(const c
 	 */
 	{
 		size_t len = strlen(path);
+		size_t mid = len / 2;
 
-		for (p = path; (p = strchr(p, '/')) != NULL; p++) {
-			size_t prefix = p - path;
-			size_t rest = len - prefix - 1;
-
-			if (rest == prefix && !memcmp(path, p + 1, prefix))
-				return p + 1;
-		}
+		if (len > 1 && path[mid] == '/' &&
+		    !memcmp(path, path + mid + 1, mid))
+			return path + mid + 1;
 	}
 
 	/*
@@ -340,17 +337,17 @@ static void find_text_section_range(Elf
 static unsigned int r_type_abs32(unsigned int e_machine)
 {
 	switch (e_machine) {
-	case EM_X86_64:		return 10;	/* R_X86_64_32 */
-	case EM_386:		return 1;	/* R_386_32 */
-	case EM_AARCH64:	return 258;	/* R_AARCH64_ABS32 */
-	case EM_ARM:		return 2;	/* R_ARM_ABS32 */
-	case EM_RISCV:		return 1;	/* R_RISCV_32 */
-	case EM_S390:		return 4;	/* R_390_32 */
-	case EM_MIPS:		return 2;	/* R_MIPS_32 */
-	case EM_PPC64:		return 1;	/* R_PPC64_ADDR32 */
-	case EM_PPC:		return 1;	/* R_PPC_ADDR32 */
-	case EM_LOONGARCH:	return 1;	/* R_LARCH_32 */
-	case EM_PARISC:		return 1;	/* R_PARISC_DIR32 */
+	case EM_X86_64:		return R_X86_64_32;
+	case EM_386:		return R_386_32;
+	case EM_AARCH64:	return R_AARCH64_ABS32;
+	case EM_ARM:		return R_ARM_ABS32;
+	case EM_RISCV:		return R_RISCV_32;
+	case EM_S390:		return R_390_32;
+	case EM_MIPS:		return R_MIPS_32;
+	case EM_PPC64:		return R_PPC64_ADDR32;
+	case EM_PPC:		return R_PPC_ADDR32;
+	case EM_LOONGARCH:	return R_LARCH_32;
+	case EM_PARISC:		return R_PARISC_DIR32;
 	default:		return 0;
 	}
 }
@@ -492,9 +489,10 @@ static void process_dwarf(Dwarf *dwarf,
 
 			/*
 			 * In module mode, keep only .text addresses.
-			 * In ET_REL .ko files, .init.text/.exit.text may
-			 * overlap with .text address ranges, so we must
-			 * explicitly check against the .text bounds.
+			 * In ET_REL .ko files, .text, .init.text and
+			 * .exit.text all have sh_addr == 0 and therefore
+			 * overlapping address ranges.  Explicitly check
+			 * against the .text bounds.
 			 */
 			if (module_mode && text_section_end > text_section_start &&
 			    (addr < text_section_start || addr >= text_section_end))
--- a/scripts/Makefile~b
+++ a/scripts/Makefile
@@ -5,7 +5,6 @@
 
 hostprogs-always-$(CONFIG_KALLSYMS)			+= kallsyms
 hostprogs-always-$(CONFIG_KALLSYMS_LINEINFO)		+= gen_lineinfo
-hostprogs-always-$(CONFIG_KALLSYMS_LINEINFO_MODULES)	+= gen_lineinfo
 hostprogs-always-$(BUILD_C_RECORDMCOUNT)		+= recordmcount
 hostprogs-always-$(CONFIG_BUILDTIME_TABLE_SORT)		+= sorttable
 hostprogs-always-$(CONFIG_ASN1)				+= asn1_compiler
_


^ permalink raw reply

* Re: [PATCH 1/3] dt-bindings: hwmon: Add support for NXP P3T1084UK temperature sensor
From: Conor Dooley @ 2026-03-23 19:33 UTC (permalink / raw)
  To: Anshika Gupta
  Cc: linux, corbet, skhan, linux-hwmon, linux-doc, linux-kernel, robh,
	krzk+dt, conor+dt, devicetree, lakshaypiplani77
In-Reply-To: <20260323162252.15508-1-guptaanshika.ag@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 2503 bytes --]

On Mon, Mar 23, 2026 at 09:52:50PM +0530, Anshika Gupta wrote:
> The P3T1084UK is an NXP digital temperature sensor compatible with the
> Texas Instruments TMP108 register and protocol specification. This patch

Then why is tmp108 not used as a fallback compatible? Looks from the
driver patch like it would be suitable.

> extends the existing DT binding for "ti,tmp108" to document the
> compatible string for P3T1084UK so that the hwmon TMP108 driver can
> bind to this device.
> 
> Signed-off-by: Lakshay Piplani <lakshaypiplani77@gmail.com>

What did Lakshay do? You're author and submitter, but their sign-off is
here. Are you missing a co-developed-by?

> Signed-off-by: Anshika Gupta <guptaanshika.ag@gmail.com>
> ---
>  Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml b/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml
> index 9f6c9f6fa561..47714df5aaff 100644
> --- a/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml
> +++ b/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml
> @@ -4,20 +4,21 @@
>  $id: http://devicetree.org/schemas/hwmon/ti,tmp108.yaml#
>  $schema: http://devicetree.org/meta-schemas/core.yaml#
>  
> -title: TMP108/P3T1035/P3T1085/P3T2030 temperature sensor
> +title: TMP108/P3T1035/P3T1084/P3T1085/P3T2030 temperature sensor
>  
>  maintainers:
>    - Krzysztof Kozlowski <krzk@kernel.org>
>  
>  description: |
> -  The TMP108 or NXP P3T Family (P3T1035, P3T1085 and P3T2030) is a digital-
> +  The TMP108 or NXP P3T Family (P3T1035, P3T1084, P3T1085 and P3T2030) is a digital-
>    output temperature sensor with a dynamically-programmable limit window,
>    and under- and over-temperature alert functions.
>  
> -  NXP P3T Family (P3T1035, P3T1085 and P3T2030) supports I3C.
> +  NXP P3T Family (P3T1035, P3T1084, P3T1085 and P3T2030) supports I3C.
>  
>    Datasheets:
>      https://www.ti.com/product/TMP108
> +    https://www.nxp.com/docs/en/data-sheet/P3T1084UK.pdf
>      https://www.nxp.com/docs/en/data-sheet/P3T1085UK.pdf
>      https://www.nxp.com/docs/en/data-sheet/P3T1035XUK_P3T2030XUK.pdf
>  
> @@ -28,6 +29,7 @@ properties:
>            - const: nxp,p3t2030
>            - const: nxp,p3t1035
>        - const: nxp,p3t1035
> +      - const: nxp,p3t1084
>        - const: nxp,p3t1085
>        - const: ti,tmp108
>  
> -- 
> 2.34.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [RFC PATCH v4 1/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics
From: Ravi Jonnalagadda @ 2026-03-23 19:41 UTC (permalink / raw)
  To: SeongJae Park
  Cc: damon, linux-mm, linux-kernel, linux-doc, akpm, corbet, bijan311,
	ajayjoshi, honggyu.kim, yunjeong.mun
In-Reply-To: <20260321165425.84273-1-sj@kernel.org>

On Sat, Mar 21, 2026 at 9:54 AM SeongJae Park <sj@kernel.org> wrote:
>
> On Fri, 20 Mar 2026 12:04:53 -0700 Ravi Jonnalagadda <ravis.opensrc@gmail.com> wrote:
>
> > Add new quota goal metrics for memory tiering that track scheme-eligible
> > memory distribution across NUMA nodes:
> >
> > - DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP: ratio of eligible memory on a node
> > - DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP: ratio of eligible memory NOT on
> >   a node
>
> The description for the second metric should be "ratio of ineligible memory on
> a node".
>

Got it. Will fix the commit message.

> >
> > These complementary metrics enable push-pull migration schemes that
> > maintain a target memory distribution across different NUMA nodes
> > representing different memory tiers, based on access patterns defined
> > by each scheme.
> >
> > The metrics iterate scheme-eligible regions and use damon_get_folio()
> > to determine NUMA node placement of each folio, calculating the ratio
> > of eligible memory on the specified node versus total eligible memory.
> >
> > Suggested-by: SeongJae Park <sj@kernel.org>
> > Signed-off-by: Ravi Jonnalagadda <ravis.opensrc@gmail.com>
> > ---
> >  include/linux/damon.h    |   6 ++
> >  mm/damon/core.c          | 158 ++++++++++++++++++++++++++++++++++++---
> >  mm/damon/sysfs-schemes.c |  12 +++
> >  3 files changed, 164 insertions(+), 12 deletions(-)
> >
> > diff --git a/include/linux/damon.h b/include/linux/damon.h
> > index b1d8fd88a0fc..490918804f85 100644
> > --- a/include/linux/damon.h
> > +++ b/include/linux/damon.h
> > @@ -193,6 +193,10 @@ enum damos_action {
> >   * @DAMOS_QUOTA_NODE_MEMCG_FREE_BP:  MemFree ratio of a node for a cgroup.
> >   * @DAMOS_QUOTA_ACTIVE_MEM_BP:               Active to total LRU memory ratio.
> >   * @DAMOS_QUOTA_INACTIVE_MEM_BP:     Inactive to total LRU memory ratio.
> > + * @DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP:        Scheme-eligible memory ratio of a
> > + *                                   node.
> > + * @DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP:      Scheme-ineligible memory ratio of a
> > + *                                   node.
> >   * @NR_DAMOS_QUOTA_GOAL_METRICS:     Number of DAMOS quota goal metrics.
> >   *
> >   * Metrics equal to larger than @NR_DAMOS_QUOTA_GOAL_METRICS are unsupported.
> > @@ -206,6 +210,8 @@ enum damos_quota_goal_metric {
> >       DAMOS_QUOTA_NODE_MEMCG_FREE_BP,
> >       DAMOS_QUOTA_ACTIVE_MEM_BP,
> >       DAMOS_QUOTA_INACTIVE_MEM_BP,
> > +     DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP,
> > +     DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP,
> >       NR_DAMOS_QUOTA_GOAL_METRICS,
> >  };
> >
> > diff --git a/mm/damon/core.c b/mm/damon/core.c
> > index b9e12865622c..3e0ac65e34a0 100644
> > --- a/mm/damon/core.c
> > +++ b/mm/damon/core.c
> > @@ -17,6 +17,8 @@
> >  #include <linux/string.h>
> >  #include <linux/string_choices.h>
> >
> > +#include "ops-common.h"
> > +
>
> I don't find a reason to include this, and I'd like to avoid including that in
> core.c unless it is really necessary.  Could you please remove this?
>

The include was added because the implementation uses damon_get_folio() to
determine NUMA node placement of folios when iterating eligible regions.
Would you prefer that I move the damon_get_folio() declaration to
include/linux/damon.h, or would you suggest a different approach such as
adding an ops callback for the node calculation?

> Below looks all good for RFC level code to move on to the next stage (dropping
> RFC tag). :)
>

Thank you, SJ! Will send v5 with fixes once I hear back on the above.

Best Regards,
Ravi.

>
> Thanks,
> SJ
>
> [...]

^ permalink raw reply

* Re: [PATCH v5 00/21] Virtual Swap Space
From: Nhat Pham @ 2026-03-23 20:05 UTC (permalink / raw)
  To: Kairui Song
  Cc: Liam.Howlett, akpm, apopple, axelrasmussen, baohua, baolin.wang,
	bhe, byungchul, cgroups, chengming.zhou, chrisl, corbet, david,
	dev.jain, gourry, hannes, hughd, jannh, joshua.hahnjy, lance.yang,
	lenb, linux-doc, linux-kernel, linux-mm, linux-pm,
	lorenzo.stoakes, matthew.brost, mhocko, muchun.song, npache,
	pavel, peterx, peterz, pfalcato, rafael, rakie.kim,
	roman.gushchin, rppt, ryan.roberts, shakeel.butt, shikemeng,
	surenb, tglx, vbabka, weixugc, ying.huang, yosry.ahmed, yuanchu,
	zhengqi.arch, ziy, kernel-team, riel
In-Reply-To: <CAMgjq7AzySv801qDxfc8mEkEsFDv4P=_qw0rNOTe0n+qy7Fz6A@mail.gmail.com>

On Mon, Mar 23, 2026 at 12:41 PM Kairui Song <ryncsn@gmail.com> wrote:
>
> On Mon, Mar 23, 2026 at 11:33 PM Nhat Pham <nphamcs@gmail.com> wrote:
> >
> > On Mon, Mar 23, 2026 at 6:09 AM Kairui Song <ryncsn@gmail.com> wrote:
> > >
> > > On Sat, Mar 21, 2026 at 3:29 AM Nhat Pham <nphamcs@gmail.com> wrote:
> > > > This patch series is based on 6.19. There are a couple more
> > > > swap-related changes in mainline that I would need to coordinate
> > > > with, but I still want to send this out as an update for the
> > > > regressions reported by Kairui Song in [15]. It's probably easier
> > > > to just build this thing rather than dig through that series of
> > > > emails to get the fix patch :)
> > > >
> > > > Changelog:
> > > > * v4 -> v5:
> > > >     * Fix a deadlock in memcg1_swapout (reported by syzbot [16]).
> > > >     * Replace VM_WARN_ON(!spin_is_locked()) with lockdep_assert_held(),
> > > >       and use guard(rcu) in vswap_cpu_dead
> > > >       (reported by Peter Zijlstra [17]).
> > > > * v3 -> v4:
> > > >     * Fix poor swap free batching behavior to alleviate a regression
> > > >       (reported by Kairui Song).
> > >
> >
> > Hi Kairui! Thanks a lot for the testing big boss :) I will focus on
> > the regression in this patch series - we can talk more about
> > directions in another thread :)
>
> Hi Nhat,
>
> > Interesting. Normally "lots of zero-filled page" is a very beneficial
> > case for vswap. You don't need a swapfile, or any zram/zswap metadata
> > overhead - it's a native swap backend. If production workload has this
> > many zero-filled pages, I think the numbers of vswap would be much
> > less alarming - perhaps even matching memory overhead because you
> > don't need to maintain a zram entry metadata (it's at least 2 words
> > per zram entry right?), while there's no reverse map overhead induced
> > (so it's 24 bytes on both side), and no need to do zram-side locking
> > :)
> >
> > So I was surprised to see that it's not working out very well here. I
> > checked the implementation of memhog - let me know if this is wrong
> > place to look:
> >
> > https://man7.org/linux/man-pages/man8/memhog.8.html
> > https://github.com/numactl/numactl/blob/master/memhog.c#L52
> >
> > I think this is what happened here: memhog was populating the memory
> > 0xff, which triggers the full overhead of a swapfile-backed swap entry
> > because even though it's "same-filled" it's not zero-filled! I was
> > following Usama's observation - "less than 1% of the same-filled pages
> > were non-zero" - and so I only handled the zero-filled case here:
> >
> > https://lore.kernel.org/all/20240530102126.357438-1-usamaarif642@gmail.com/
> >
> > This sounds a bit artificial IMHO - as Usama pointed out above, I
> > think most samefilled pages are zero pages, in real production
> > workloads. However, if you think there are real use cases with a lot
>
> I vaguely remember some workloads like Java or some JS engine
> initialize their heap with fixed value, same fill might not be that
> common but not a rare thing, it strongly depends on the workload.

To a non-zero value? ISTR it was initialized to zero, but if I was
wrong then yeah it should just be a small simple patch.

>
> > of non-zero samefilled pages, please let me know I can fix this real
> > quick. We can support this in vswap with zero extra metadata overhead
> > - change the VSWAP_ZERO swap entry type to VSWAP_SAME_FILLED, then use
> > the backend field to store that value. I can send you a patch if
> > you're interested.
>
> Actually I don't think that's the main problem. For example, I just
> wrote a few lines C bench program to zerofill ~50G of memory
> and swapout sequentially:
>
> Before:
> Swapout: 4415467us
> Swapin: 49573297us
>
> After:
> Swapout: 4955874us
> Swapin: 56223658us
>
> And vmstat:
> cat /proc/vmstat | grep zero
> thp_zero_page_alloc 0
> thp_zero_page_alloc_failed 0
> swpin_zero 12239329
> swpout_zero 21516634
>
> There are all zero filled pages, but still slower. And what's more, a
> more critical issue, I just found the cgroup and global swap usage
> accounting are both somehow broken for zero page swap,
> maybe because you skipped some allocation? Users can
> no longer see how many pages are swapped out. I don't think you can
> break that, that's one major reason why we use a zero entry instead of
> mapping to a zero readonly page. If that is acceptable, we can have
> a very nice optimization right away with current swap.

No, that was intentional :) I probably should have documented this
better - but we're only charging towards swap usage (cgroup and system
wide) on memory. There was a whole patch that did that in the series
:)

I can add new counters to differentiate these cases, but it makes no
sense to me to charge towards swap usage for non-swapfile backend
(namely, zswap and zero swap pages). You are not actually occupying
the limited swapfile slots, but instead occupy a dynamic, vast virtual
swap space only (and memory in the case of zswap - this is actually an
argument against zram which does not do any cgroup accounting, but
that's another story for another day). I don't see a point in swap
charging here. It's the whole point of decoupling the backends - these
are not the same resource domains.

And if you follow Usama's work above, we actually were trying to
figure out a way to map it to a zero readonly page. That was Usama's
v2 of the patch series IIRC - but there was a bug. I think it was a
potential race between the reclaimer's rmap walk to unmap the page
from PTEs pointing to the page, and concurrent modifiers to the page?
We couldn't fix the race in a way that does not induce more overhead
than it's worth. But had that work we would also not do any swap
charging :)

BTW, if you can figure that part out, please let us know. We actually
quite like that idea - we just never managed to make it work (and we
have a bunch more urgent tasks).

>
> That's still just an example. bypassing the accounting and still
> slower is not a good sign. We should focus on the generic
> performance and design.

I will dig into the remaining regression :) Thanks for the report.

>
> Yet this is just another new found issue, there are many other parts
> like the folio swap allocation may still occur even if a lower device
> can no longer accept more whole folios, which I'm currently
> unsure how it will affect swap.



>
> > 1. Regarding pmem backend - I'm not sure if I can get my hands on one
> > of these, but if you think SSD has the same characteristics maybe I
> > can give that a try? The problem with SSD is for some reason variance
> > tends to be pretty high, between iterations yes, but especially across
> > reboots. Or maybe zram?
>
> Yeah, ZRAM has a very similar number for some cases, but storage is
> getting faster and faster and swap occurs through high speed networks
> too. We definitely shouldn't ignore that.

I can also simulate it using tmpfs as a swap backend (although it
might not work for certain benchmarks, like your usemem benchmark in
which we allocate more memory than the host physical memory).

>
> > 2. What about the other numbers below? Are they also on pmem? FTR I
> > was running most of my benchmarks on zswap, except for one kernel
> > build benchmark on SSD.
> >
> > 3. Any other backends and setup you're interested in?
> >
> > BTW, sounds like you have a great benchmark suite - is it open source
> > somewhere? If not, can you share it with us :) Vswap aside, I think
> > this would be a good suite to run all swap related changes for every
> > swap contributor.
>
> I can try to post that somewhere, really nothing fancy just some
> wrapper to make use of systemd for reboot and auto test. But all test
> steps I mentioned before are already posted and publically available.

Okay, thanks, Kairui!

^ permalink raw reply

* Re: [PATCH v11 05/16] mm/gup: drop local variable in gup_fast_folio_allowed
From: Ackerley Tng @ 2026-03-23 20:22 UTC (permalink / raw)
  To: David Hildenbrand (Arm), Kalyazin, Nikita, kvm@vger.kernel.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
	linux-fsdevel@vger.kernel.org, linux-mm@kvack.org,
	bpf@vger.kernel.org, linux-kselftest@vger.kernel.org,
	kernel@xen0n.name, linux-riscv@lists.infradead.org,
	linux-s390@vger.kernel.org, loongarch@lists.linux.dev,
	linux-pm@vger.kernel.org
  Cc: pbonzini@redhat.com, corbet@lwn.net, maz@kernel.org,
	oupton@kernel.org, joey.gouly@arm.com, suzuki.poulose@arm.com,
	yuzenghui@huawei.com, catalin.marinas@arm.com, will@kernel.org,
	seanjc@google.com, tglx@kernel.org, mingo@redhat.com,
	bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
	hpa@zytor.com, luto@kernel.org, peterz@infradead.org,
	willy@infradead.org, akpm@linux-foundation.org,
	lorenzo.stoakes@oracle.com, vbabka@kernel.org, rppt@kernel.org,
	surenb@google.com, mhocko@suse.com, ast@kernel.org,
	daniel@iogearbox.net, andrii@kernel.org, martin.lau@linux.dev,
	eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev,
	john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me,
	haoluo@google.com, jolsa@kernel.org, jgg@ziepe.ca,
	jhubbard@nvidia.com, peterx@redhat.com, jannh@google.com,
	pfalcato@suse.de, skhan@linuxfoundation.org, riel@surriel.com,
	ryan.roberts@arm.com, jgross@suse.com, yu-cheng.yu@intel.com,
	kas@kernel.org, coxu@redhat.com, kevin.brodsky@arm.com,
	yosry@kernel.org, ajones@ventanamicro.com, maobibo@loongson.cn,
	tabba@google.com, prsampat@amd.com, wu.fei9@sanechips.com.cn,
	mlevitsk@redhat.com, jmattson@google.com, jthoughton@google.com,
	agordeev@linux.ibm.com, alex@ghiti.fr, aou@eecs.berkeley.edu,
	borntraeger@linux.ibm.com, chenhuacai@kernel.org,
	dev.jain@arm.com, gor@linux.ibm.com, hca@linux.ibm.com,
	palmer@dabbelt.com, pjw@kernel.org, shijie@os.amperecomputing.com,
	svens@linux.ibm.com, thuth@redhat.com, wyihan@google.com,
	yang@os.amperecomputing.com, Jonathan.Cameron@huawei.com,
	Liam.Howlett@oracle.com, urezki@gmail.com,
	zhengqi.arch@bytedance.com, gerald.schaefer@linux.ibm.com,
	jiayuan.chen@shopee.com, lenb@kernel.org, osalvador@suse.de,
	pavel@kernel.org, rafael@kernel.org, vannapurve@google.com,
	jackmanb@google.com, aneesh.kumar@kernel.org,
	patrick.roy@linux.dev, Thomson, Jack, Itazuri, Takahiro,
	Manwaring, Derek
In-Reply-To: <0a14c10d-0dab-4b9c-85ec-e0ee25cd0db8@kernel.org>

"David Hildenbrand (Arm)" <david@kernel.org> writes:

> On 3/17/26 15:11, Kalyazin, Nikita wrote:
>> From: Nikita Kalyazin <kalyazin@amazon.com>
>>
>> Move the check for pinning closer to where the result is used.
>> No functional changes.
>>
>> Signed-off-by: Nikita Kalyazin <kalyazin@amazon.com>
>> ---
>>  mm/gup.c | 23 ++++++++++++-----------
>>  1 file changed, 12 insertions(+), 11 deletions(-)
>>
>> diff --git a/mm/gup.c b/mm/gup.c
>> index 5856d35be385..869d79c8daa4 100644
>> --- a/mm/gup.c
>> +++ b/mm/gup.c
>> @@ -2737,18 +2737,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
>>   */
>>  static bool gup_fast_folio_allowed(struct folio *folio, unsigned int flags)
>>  {
>> -	bool reject_file_backed = false;
>>  	struct address_space *mapping;
>>  	unsigned long mapping_flags;
>>
>> -	/*
>> -	 * If we aren't pinning then no problematic write can occur. A long term
>> -	 * pin is the most egregious case so this is the one we disallow.
>> -	 */
>> -	if ((flags & (FOLL_PIN | FOLL_LONGTERM | FOLL_WRITE)) ==
>> -	    (FOLL_PIN | FOLL_LONGTERM | FOLL_WRITE))
>> -		reject_file_backed = true;
>> -
>>  	/* We hold a folio reference, so we can safely access folio fields. */
>>  	if (WARN_ON_ONCE(folio_test_slab(folio)))
>>  		return false;
>> @@ -2793,8 +2784,18 @@ static bool gup_fast_folio_allowed(struct folio *folio, unsigned int flags)
>>  	 */
>>  	if (secretmem_mapping(mapping))
>>  		return false;
>> -	/* The only remaining allowed file system is shmem. */
>> -	return !reject_file_backed || shmem_mapping(mapping);
>> +
>> +	/*
>> +	 * If we aren't pinning then no problematic write can occur. A writable
>> +	 * long term pin is the most egregious case, so this is the one we
>> +	 * allow only for ...
>> +	 */
>> +	if ((flags & (FOLL_PIN | FOLL_LONGTERM | FOLL_WRITE)) !=
>> +	    (FOLL_PIN | FOLL_LONGTERM | FOLL_WRITE))
>> +		return true;
>> +
>> +	/* ... hugetlb (which we allowed above already) and shared memory. */
>> +	return shmem_mapping(mapping);
>
> Acked-by: David Hildenbrand (Arm) <david@kernel.org>
>
> I'm wondering if it would be a good idea to check for a hugetlb mapping
> here instead of having the folio_test_hugetlb() check above.
>

I think it's nice that hugetlb folios are determined immediately to be
eligible for GUP-fast regardless of whether the folio is file-backed or
not.

> Something to ponder about :)
>
> --
> Cheers,
>
> David

^ permalink raw reply

* Re: [PATCH v11 10/16] KVM: guest_memfd: Add flag to remove from direct map
From: Ackerley Tng @ 2026-03-23 20:47 UTC (permalink / raw)
  To: David Hildenbrand (Arm), Kalyazin, Nikita, kvm@vger.kernel.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
	linux-fsdevel@vger.kernel.org, linux-mm@kvack.org,
	bpf@vger.kernel.org, linux-kselftest@vger.kernel.org,
	kernel@xen0n.name, linux-riscv@lists.infradead.org,
	linux-s390@vger.kernel.org, loongarch@lists.linux.dev,
	linux-pm@vger.kernel.org
  Cc: pbonzini@redhat.com, corbet@lwn.net, maz@kernel.org,
	oupton@kernel.org, joey.gouly@arm.com, suzuki.poulose@arm.com,
	yuzenghui@huawei.com, catalin.marinas@arm.com, will@kernel.org,
	seanjc@google.com, tglx@kernel.org, mingo@redhat.com,
	bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
	hpa@zytor.com, luto@kernel.org, peterz@infradead.org,
	willy@infradead.org, akpm@linux-foundation.org,
	lorenzo.stoakes@oracle.com, vbabka@kernel.org, rppt@kernel.org,
	surenb@google.com, mhocko@suse.com, ast@kernel.org,
	daniel@iogearbox.net, andrii@kernel.org, martin.lau@linux.dev,
	eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev,
	john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me,
	haoluo@google.com, jolsa@kernel.org, jgg@ziepe.ca,
	jhubbard@nvidia.com, peterx@redhat.com, jannh@google.com,
	pfalcato@suse.de, skhan@linuxfoundation.org, riel@surriel.com,
	ryan.roberts@arm.com, jgross@suse.com, yu-cheng.yu@intel.com,
	kas@kernel.org, coxu@redhat.com, kevin.brodsky@arm.com,
	yosry@kernel.org, ajones@ventanamicro.com, maobibo@loongson.cn,
	tabba@google.com, prsampat@amd.com, wu.fei9@sanechips.com.cn,
	mlevitsk@redhat.com, jmattson@google.com, jthoughton@google.com,
	agordeev@linux.ibm.com, alex@ghiti.fr, aou@eecs.berkeley.edu,
	borntraeger@linux.ibm.com, chenhuacai@kernel.org,
	dev.jain@arm.com, gor@linux.ibm.com, hca@linux.ibm.com,
	palmer@dabbelt.com, pjw@kernel.org, shijie@os.amperecomputing.com,
	svens@linux.ibm.com, thuth@redhat.com, wyihan@google.com,
	yang@os.amperecomputing.com, Jonathan.Cameron@huawei.com,
	Liam.Howlett@oracle.com, urezki@gmail.com,
	zhengqi.arch@bytedance.com, gerald.schaefer@linux.ibm.com,
	jiayuan.chen@shopee.com, lenb@kernel.org, osalvador@suse.de,
	pavel@kernel.org, rafael@kernel.org, vannapurve@google.com,
	jackmanb@google.com, aneesh.kumar@kernel.org,
	patrick.roy@linux.dev, Thomson, Jack, Itazuri, Takahiro,
	Manwaring, Derek
In-Reply-To: <50bfaeb5-551e-403f-bd00-a7d8b6bbf6e2@kernel.org>

"David Hildenbrand (Arm)" <david@kernel.org> writes:

>
> [...snip...]
>
>> +static int kvm_gmem_folio_zap_direct_map(struct folio *folio)
>> +{
>> +	u64 gmem_flags = GMEM_I(folio_inode(folio))->flags;
>> +	int r = 0;
>> +
>> +	if (kvm_gmem_folio_no_direct_map(folio) || !(gmem_flags & GUEST_MEMFD_FLAG_NO_DIRECT_MAP))
>
> The function is only called when
>
> 	kvm_gmem_no_direct_map(folio_inode(folio))
>
> Does it really make sense to check for GUEST_MEMFD_FLAG_NO_DIRECT_MAP again?
>

Good point that GUEST_MEMFD_FLAG_NO_DIRECT_MAP was already checked in
the caller. I think we can drop this second check.

> If, at all, it should be a warning if GUEST_MEMFD_FLAG_NO_DIRECT_MAP is
> not set?
>
> Further, kvm_gmem_folio_zap_direct_map() uses the folio lock to
> synchronize, right? Might be worth pointing that out somehow (e.g.,
> lockdep check if possible).
>
>> +		goto out;
>> +
>> +	r = folio_zap_direct_map(folio);
>> +	if (!r)
>> +		folio->private = (void *)((u64)folio->private | KVM_GMEM_FOLIO_NO_DIRECT_MAP);
>> +
>> +out:
>> +	return r;
>> +}
>> +
>> +static void kvm_gmem_folio_restore_direct_map(struct folio *folio)
>> +{
>
> kvm_gmem_folio_zap_direct_map() is allowed to be called on folios that
> already have the directmap remove, kvm_gmem_folio_restore_direct_map()
> cannot be called if the directmap was already restored.
>

This inconsistency was probably introduced by my comments [1] (sorry!)

I think the inconsistency here is mostly because
kvm_gmem_folio_zap_direct_map() is called from two places but restore is
only called from one place :P

[1] https://lore.kernel.org/all/CAEvNRgEzVhEzr-3GWTsE7GSBsPdvVLq7WFEeLHzcmMe=R9S51w@mail.gmail.com/

> Should we make that more consistent?
>
>
> Hoping Sean can find some time to review
>
> --
> Cheers,
>
> David

^ permalink raw reply

* Re: [PATCH v13.1] rust: interop: Add list module for C linked list interface
From: Danilo Krummrich @ 2026-03-23 21:02 UTC (permalink / raw)
  To: Joel Fernandes
  Cc: linux-kernel, Gary Guo, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Alex Gaynor, Dave Airlie, David Airlie,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Simona Vetter, Daniel Almeida, Koen Koning, Nikola Djukic,
	Alexandre Courbot, Philipp Stanner, Elle Rhumsaa, Jonathan Corbet,
	Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Matthew Brost, Lucas De Marchi, Thomas Hellström,
	Helge Deller, John Hubbard, Alistair Popple, Timur Tabi,
	Edwin Peer, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh,
	alexeyi, Eliot Courtney, dri-devel, rust-for-linux, linux-doc,
	amd-gfx, intel-gfx, intel-xe, linux-fbdev
In-Reply-To: <20260319210722.1543776-1-joelagnelf@nvidia.com>

On Thu Mar 19, 2026 at 10:07 PM CET, Joel Fernandes wrote:
> Add a new module `kernel::interop::list` for working with C's doubly
> circular linked lists. Provide low-level iteration over list nodes.
>
> Typed iteration over actual items is provided with a `clist_create`
> macro to assist in creation of the `CList` type.
>
> Cc: Nikola Djukic <ndjukic@nvidia.com>
> Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
> Reviewed-by: Alice Ryhl <aliceryhl@google.com>
> Acked-by: Alexandre Courbot <acourbot@nvidia.com>
> Acked-by: Gary Guo <gary@garyguo.net>
> Acked-by: Miguel Ojeda <ojeda@kernel.org>
> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>

Applied to drm-rust-next, thanks!

    [ * Remove stray empty comment and double blank line in doctest,
      * Improve wording and fix a few typos,
      * Use markdown emphasis instead of caps,
      * Move interop/mod.rs to interop.rs.

        - Danilo ]

(I moved interop/mod.rs to interop.rs as it is the predominant variant in
throughout the tree, consistent with all other Rust core infrastructure and we
concluded to follow up on this topic subsequently.)

^ permalink raw reply

* Re: [PATCH v14 0/2] Rust GPU buddy allocator bindings
From: Danilo Krummrich @ 2026-03-23 21:02 UTC (permalink / raw)
  To: Joel Fernandes
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel,
	rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet,
	Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Matthew Brost, Lucas De Marchi, Thomas Hellström,
	Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard,
	Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot,
	Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh,
	Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel,
	linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev
In-Reply-To: <20260320045711.43494-1-joelagnelf@nvidia.com>

On Fri Mar 20, 2026 at 5:57 AM CET, Joel Fernandes wrote:

Applied to drm-rust-next, thanks!

> Joel Fernandes (2):
>   rust: gpu: Add GPU buddy allocator bindings

    [ * Use doc-comments for GpuBuddyAllocMode methods and GpuBuddyGuard,
      * Fix comma splice in GpuBuddyParams::chunk_size doc-comment,
      * Remove redundant summary in GpuBuddy::new doc-comment,
      * Drop Rust helper for gpu_buddy_block_size().

        - Danilo ]

>   MAINTAINERS: gpu: buddy: Update reviewer

^ permalink raw reply

* Re: [PATCH v11 10/16] KVM: guest_memfd: Add flag to remove from direct map
From: Ackerley Tng @ 2026-03-23 21:15 UTC (permalink / raw)
  To: Kalyazin, Nikita, kvm@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
	linux-fsdevel@vger.kernel.org, linux-mm@kvack.org,
	bpf@vger.kernel.org, linux-kselftest@vger.kernel.org,
	kernel@xen0n.name, linux-riscv@lists.infradead.org,
	linux-s390@vger.kernel.org, loongarch@lists.linux.dev,
	linux-pm@vger.kernel.org
  Cc: pbonzini@redhat.com, corbet@lwn.net, maz@kernel.org,
	oupton@kernel.org, joey.gouly@arm.com, suzuki.poulose@arm.com,
	yuzenghui@huawei.com, catalin.marinas@arm.com, will@kernel.org,
	seanjc@google.com, tglx@kernel.org, mingo@redhat.com,
	bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
	hpa@zytor.com, luto@kernel.org, peterz@infradead.org,
	willy@infradead.org, akpm@linux-foundation.org, david@kernel.org,
	lorenzo.stoakes@oracle.com, vbabka@kernel.org, rppt@kernel.org,
	surenb@google.com, mhocko@suse.com, ast@kernel.org,
	daniel@iogearbox.net, andrii@kernel.org, martin.lau@linux.dev,
	eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev,
	john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me,
	haoluo@google.com, jolsa@kernel.org, jgg@ziepe.ca,
	jhubbard@nvidia.com, peterx@redhat.com, jannh@google.com,
	pfalcato@suse.de, skhan@linuxfoundation.org, riel@surriel.com,
	ryan.roberts@arm.com, jgross@suse.com, yu-cheng.yu@intel.com,
	kas@kernel.org, coxu@redhat.com, kevin.brodsky@arm.com,
	yosry@kernel.org, ajones@ventanamicro.com, maobibo@loongson.cn,
	tabba@google.com, prsampat@amd.com, wu.fei9@sanechips.com.cn,
	mlevitsk@redhat.com, jmattson@google.com, jthoughton@google.com,
	agordeev@linux.ibm.com, alex@ghiti.fr, aou@eecs.berkeley.edu,
	borntraeger@linux.ibm.com, chenhuacai@kernel.org,
	dev.jain@arm.com, gor@linux.ibm.com, hca@linux.ibm.com,
	palmer@dabbelt.com, pjw@kernel.org, shijie@os.amperecomputing.com,
	svens@linux.ibm.com, thuth@redhat.com, wyihan@google.com,
	yang@os.amperecomputing.com, Jonathan.Cameron@huawei.com,
	Liam.Howlett@oracle.com, urezki@gmail.com,
	zhengqi.arch@bytedance.com, gerald.schaefer@linux.ibm.com,
	jiayuan.chen@shopee.com, lenb@kernel.org, osalvador@suse.de,
	pavel@kernel.org, rafael@kernel.org, vannapurve@google.com,
	jackmanb@google.com, aneesh.kumar@kernel.org,
	patrick.roy@linux.dev, Thomson, Jack, Itazuri, Takahiro,
	Manwaring, Derek
In-Reply-To: <20260317141031.514-11-kalyazin@amazon.com>

"Kalyazin, Nikita" <kalyazin@amazon.co.uk> writes:

>
> [...snip...]
>
>  static vm_fault_t kvm_gmem_fault_user_mapping(struct vm_fault *vmf)
>  {
>  	struct inode *inode = file_inode(vmf->vma->vm_file);
>  	struct folio *folio;
>  	vm_fault_t ret = VM_FAULT_LOCKED;
> +	int err;
>
>  	if (((loff_t)vmf->pgoff << PAGE_SHIFT) >= i_size_read(inode))
>  		return VM_FAULT_SIGBUS;
> @@ -418,6 +454,14 @@ static vm_fault_t kvm_gmem_fault_user_mapping(struct vm_fault *vmf)
>  		folio_mark_uptodate(folio);
>  	}
>
> +	if (kvm_gmem_no_direct_map(folio_inode(folio))) {
> +		err = kvm_gmem_folio_zap_direct_map(folio);
> +		if (err) {
> +			ret = vmf_error(err);
> +			goto out_folio;
> +		}
> +	}
> +
>  	vmf->page = folio_file_page(folio, vmf->pgoff);
>

Sashiko pointed out that kvm_gmem_populate() might try and write to
direct-map-removed folios, but I think that's handled because populate
will first try and GUP folios, which is already blocked for
direct-map-removed folios.

>  out_folio:
> @@ -528,6 +572,9 @@ static void kvm_gmem_free_folio(struct folio *folio)
>  	kvm_pfn_t pfn = page_to_pfn(page);
>  	int order = folio_order(folio);
>
> +	if (kvm_gmem_folio_no_direct_map(folio))
> +		kvm_gmem_folio_restore_direct_map(folio);
> +
>  	kvm_arch_gmem_invalidate(pfn, pfn + (1ul << order));
>  }
>

Sashiko says to invalidate then restore direct map, I think in this case
it doesn't matter since if the folio needed invalidation, it must be
private, and the host shouldn't be writing to the private pages anyway.

One benefit of retaining this order (restore, invalidate) is that it
opens the invalidate hook to possibly do something regarding memory
contents?

Or perhaps we should just take the suggestion (invalidate, restore) and
align that invalidate should not touch memory contents.

> @@ -591,6 +638,9 @@ static int __kvm_gmem_create(struct kvm *kvm, loff_t size, u64 flags)
>  	/* Unmovable mappings are supposed to be marked unevictable as well. */
>  	WARN_ON_ONCE(!mapping_unevictable(inode->i_mapping));
>
> +	if (flags & GUEST_MEMFD_FLAG_NO_DIRECT_MAP)
> +		mapping_set_no_direct_map(inode->i_mapping);
> +
>  	GMEM_I(inode)->flags = flags;
>
>  	file = alloc_file_pseudo(inode, kvm_gmem_mnt, name, O_RDWR, &kvm_gmem_fops);
> @@ -803,13 +853,22 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot,
>  	}
>
>  	r = kvm_gmem_prepare_folio(kvm, slot, gfn, folio);
> +	if (r)
> +		goto out_unlock;
>
> +	if (kvm_gmem_no_direct_map(folio_inode(folio))) {
> +		r = kvm_gmem_folio_zap_direct_map(folio);
> +		if (r)
> +			goto out_unlock;
> +	}
> +
>
> [...snip...]
>

Preparing a folio used to involve zeroing, but that has since been
refactored out, so I believe zapping can come before preparing.

Similar to the above point on invalidation: perhaps we should take the
suggestion to zap then prepare

+ And align that preparation should not touch memory contents
+ Avoid needing to undo the preparation on zapping failure (.free_folio
  is not called on folio_put(), it is only called folio on removal from
  filemap).

^ permalink raw reply

* Re: [PATCH v6 20/40] arm_mpam: resctrl: Add CDP emulation
From: Gavin Shan @ 2026-03-23 22:35 UTC (permalink / raw)
  To: Ben Horgan
  Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
	dfustini, fenghuay, james.morse, jonathan.cameron, kobak,
	lcherian, linux-arm-kernel, linux-kernel, peternewman,
	punit.agrawal, quic_jiles, reinette.chatre, rohit.mathew, scott,
	sdonthineni, tan.shaopeng, xhao, catalin.marinas, will, corbet,
	maz, oupton, joey.gouly, suzuki.poulose, kvmarm, zengheng4,
	linux-doc, Shaopeng Tan
In-Reply-To: <20260313144617.3420416-21-ben.horgan@arm.com>

On 3/14/26 12:45 AM, Ben Horgan wrote:
> From: James Morse <james.morse@arm.com>
> 
> Intel RDT's CDP feature allows the cache to use a different control value
> depending on whether the accesses was for instruction fetch or a data
> access. MPAM's equivalent feature is the other way up: the CPU assigns a
> different partid label to traffic depending on whether it was instruction
> fetch or a data access, which causes the cache to use a different control
> value based solely on the partid.
> 
> MPAM can emulate CDP, with the side effect that the alternative partid is
> seen by all MSC, it can't be enabled per-MSC.
> 
> Add the resctrl hooks to turn this on or off. Add the helpers that match a
> closid against a task, which need to be aware that the value written to
> hardware is not the same as the one resctrl is using.
> 
> Update the 'arm64_mpam_global_default' variable the arch code uses during
> context switch to know when the per-cpu value should be used instead. Also,
> update these per-cpu values and sync the resulting mpam partid/pmg
> configuration to hardware.
> 
> resctrl can enable CDP for L2 caches, L3 caches or both. When it is enabled
> by one and not the other MPAM globally enabled CDP but hides the effect
> on the other cache resource. This hiding is possible as CPOR is the only
> supported cache control and that uses a resource bitmap; two partids with
> the same bitmap act as one.
> 
> Awkwardly, the MB controls don't implement CDP and CDP can't be hidden as
> the memory bandwidth control is a maximum per partid which can't be
> modelled with more partids. If the total maximum is used for both the data
> and instruction partids then then the maximum may be exceeded and if it is
> split in two then the one using more bandwidth will hit a lower
> limit. Hence, hide the MB controls completely if CDP is enabled for any
> resource.
> 
> Tested-by: Gavin Shan <gshan@redhat.com>
> Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
> Tested-by: Peter Newman <peternewman@google.com>
> Tested-by: Zeng Heng <zengheng4@huawei.com>
> Tested-by: Punit Agrawal <punit.agrawal@oss.qualcomm.com>
> Cc: Dave Martin <Dave.Martin@arm.com>
> Cc: Amit Singh Tomar <amitsinght@marvell.com>
> Reviewed-by: Zeng Heng <zengheng4@huawei.com>
> Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> Signed-off-by: James Morse <james.morse@arm.com>
> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
> ---
> Changes since rfc:
> Fail cdp initialisation if there is only one partid
> Correct data/code confusion
> 
> Changes since v2:
> Don't include unused header
> 
> Changes since v3:
> Update the per-cpu values and sync to h/w
> 
> Changes since v4:
> Enable separately for L2 and L3
> Disable MB controls if CDP enabled
> Consider cdp hiding in resctrl_arch_update_one()
> 
> Changes since v5:
> Update comment on call sites
> ---
>   arch/arm64/include/asm/mpam.h   |   1 +
>   drivers/resctrl/mpam_internal.h |   1 +
>   drivers/resctrl/mpam_resctrl.c  | 122 ++++++++++++++++++++++++++++++++
>   include/linux/arm_mpam.h        |   2 +
>   4 files changed, 126 insertions(+)
> 
Reviewed-by: Gavin Shan <gshan@redhat.com>


^ permalink raw reply

* Re: [PATCH v6 21/40] arm_mpam: resctrl: Hide CDP emulation behind CONFIG_EXPERT
From: Gavin Shan @ 2026-03-23 22:36 UTC (permalink / raw)
  To: Ben Horgan
  Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
	dfustini, fenghuay, james.morse, jonathan.cameron, kobak,
	lcherian, linux-arm-kernel, linux-kernel, peternewman,
	punit.agrawal, quic_jiles, reinette.chatre, rohit.mathew, scott,
	sdonthineni, tan.shaopeng, xhao, catalin.marinas, will, corbet,
	maz, oupton, joey.gouly, suzuki.poulose, kvmarm, zengheng4,
	linux-doc
In-Reply-To: <20260313144617.3420416-22-ben.horgan@arm.com>

On 3/14/26 12:45 AM, Ben Horgan wrote:
> When CDP is not enabled, the 'rmid_entry's in the limbo list,
> rmid_busy_llc, map directly to a (PARTID,PMG) pair and when CDP is enabled
> the mapping is to two different pairs. As the limbo list is reused between
> mounts and CDP disabled on unmount this can lead to stale mapping and the
> limbo handler will then make monitor reads with potentially out of range
> PARTID. This may then cause an MPAM error interrupt and the driver will
> disable MPAM.
> 
> No problems are expected if you just mount the resctrl file system
> once with CDP enabled and never unmount it. Hide CDP emulation behind
> CONFIG_EXPERT to protect the unwary.
> 
> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
> ---
> Adding this ugliness in the hope of avoiding patch churn and extra
> reviewer work. I am looking into the resctrl changes needed to fix this.
> ---
>   drivers/resctrl/mpam_resctrl.c | 12 ++++++++++++
>   1 file changed, 12 insertions(+)
> 
Reviewed-by: Gavin Shan <gshan@redhat.com>


^ permalink raw reply

* Re: [PATCH v2 5/5] doc: watchdog: Document buddy detector
From: Doug Anderson @ 2026-03-23 22:45 UTC (permalink / raw)
  To: Petr Mladek
  Cc: mrungta, Jinchao Wang, Yunhui Cui, Stephane Eranian, Ian Rogers,
	Li Huafei, Feng Tang, Max Kellermann, Jonathan Corbet,
	Andrew Morton, Florian Delizy, Shuah Khan, linux-kernel,
	linux-doc
In-Reply-To: <acF3tXBxSr0KOP9b@pathway.suse.cz>

Hi,

On Mon, Mar 23, 2026 at 10:26 AM Petr Mladek <pmladek@suse.com> wrote:
>
> From f1cfdc330cfbc68568dfe6bf2513bde9373c89d7 Mon Sep 17 00:00:00 2001
> From: Petr Mladek <pmladek@suse.com>
> Date: Mon, 23 Mar 2026 18:21:38 +0100
> Subject: [PATCH] doc: watchdog: Futher improvements
>
> Signed-off-by: Petr Mladek <pmladek@suse.com>
> ---
>  .../admin-guide/lockup-watchdogs.rst          | 44 ++++++++++---------
>  1 file changed, 24 insertions(+), 20 deletions(-)
>
> diff --git a/Documentation/admin-guide/lockup-watchdogs.rst b/Documentation/admin-guide/lockup-watchdogs.rst
> index 7ae7ce3abd2c..d0773edf3396 100644
> --- a/Documentation/admin-guide/lockup-watchdogs.rst
> +++ b/Documentation/admin-guide/lockup-watchdogs.rst
> @@ -41,31 +41,35 @@ is a trade-off between fast response to lockups and detection overhead.
>  Implementation
>  ==============
>
> -The soft lockup detector is built on top of the hrtimer subsystem.
> -The hard lockup detector is built on top of the perf subsystem
> -(on architectures that support it) or uses an SMP "buddy" system.
> -
> -Softlockup Detector
> --------------------
> -
> -The watchdog job runs in a stop scheduling thread that updates a
> -timestamp every time it is scheduled. If that timestamp is not updated
> -for 2*watchdog_thresh seconds (the softlockup threshold) the
> -'softlockup detector' (coded inside the hrtimer callback function)
> -will dump useful debug information to the system log, after which it
> -will call panic if it was instructed to do so or resume execution of
> -other kernel code.
> +The soft and hard lockup detectors are built around a hrtimer.
> +In addition, the softlockup detector regularly schedules a job, and
> +the hard lockup detector might use Perf/NMI events on architectures
> +that support it.
>
>  Frequency and Heartbeats
>  ------------------------
>
> -The hrtimer used by the softlockup detector serves a dual purpose:
> -it detects softlockups, and it also generates the interrupts
> -(heartbeats) that the hardlockup detectors use to verify CPU liveness.
> +The core of the detectors in a hrtimer. It servers multiple purpose:
>
> -The period of this hrtimer is 2*watchdog_thresh/5. This means the
> -hrtimer has two or three chances to generate an interrupt before the
> -NMI hardlockup detector kicks in.
> +- schedules watchdog job for the softlockup detector
> +- bumps the interrupt counter for hardlockup detectors (heartbeat)
> +- detects softlockups
> +- detects hardlockups in Buddy mode
> +
> +The period of this hrtimer is 2*watchdog_thresh/5, which is 4 seconds
> +by default. The hrtimer has two or three chances to generate an interrupt
> +(heartbeat) before the hardlockup detector kicks in.
> +
> +Softlockup Detector
> +-------------------
> +
> +The watchdog job is scheduled by the hrtimer and runs in a stop scheduling
> +thread. It updates a timestamp every time it is scheduled. If that timestamp
> +is not updated for 2*watchdog_thresh seconds (the softlockup threshold) the
> +'softlockup detector' (coded inside the hrtimer callback function)
> +will dump useful debug information to the system log, after which it
> +will call panic if it was instructed to do so or resume execution of
> +other kernel code.

I'm happy with Petr's further improvements.

Reviewed-by: Douglas Anderson <dianders@chromium.org>

I think Andrew can just pick it up atop Mayank's. Andrew: If you need
any reposting, please yell.

Petr: thank you very much for your review of these patches! I'm super
happy you found the bug in Mayank's V1 that I missed and I think
things look nice now. :-)

-Doug

^ permalink raw reply

* Re: [PATCH v6 22/40] arm_mpam: resctrl: Convert to/from MPAMs fixed-point formats
From: Gavin Shan @ 2026-03-23 22:49 UTC (permalink / raw)
  To: Ben Horgan
  Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
	dfustini, fenghuay, james.morse, jonathan.cameron, kobak,
	lcherian, linux-arm-kernel, linux-kernel, peternewman,
	punit.agrawal, quic_jiles, reinette.chatre, rohit.mathew, scott,
	sdonthineni, tan.shaopeng, xhao, catalin.marinas, will, corbet,
	maz, oupton, joey.gouly, suzuki.poulose, kvmarm, zengheng4,
	linux-doc, Shaopeng Tan
In-Reply-To: <20260313144617.3420416-23-ben.horgan@arm.com>

Hi Ben,

On 3/14/26 12:45 AM, Ben Horgan wrote:
> From: Dave Martin <Dave.Martin@arm.com>
> 
> MPAM uses a fixed-point formats for some hardware controls.  Resctrl
> provides the bandwidth controls as a percentage. Add helpers to convert
> between these.
> 
> Ensure bwa_wd is at most 16 to make it clear higher values have no meaning.
> 
> Tested-by: Gavin Shan <gshan@redhat.com>
> Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
> Tested-by: Peter Newman <peternewman@google.com>
> Tested-by: Zeng Heng <zengheng4@huawei.com>
> Tested-by: Punit Agrawal <punit.agrawal@oss.qualcomm.com>
> Reviewed-by: Zeng Heng <zengheng4@huawei.com>
> Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Signed-off-by: James Morse <james.morse@arm.com>
> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
> ---
> Changes since v2:
> Ensure bwa_wd is at most 16 (moved from patch 40: arm_mpam: Generate a
> configuration for min controls)
> Expand comments
> ---
>   drivers/resctrl/mpam_devices.c |  7 +++++
>   drivers/resctrl/mpam_resctrl.c | 51 ++++++++++++++++++++++++++++++++++
>   2 files changed, 58 insertions(+)
> 

One nitpick below, but this looks good to me in either way.

Reviewed-by: Gavin Shan <gshan@redhat.com>

> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
> index 0e5e24ef60fe..0c97f7708722 100644
> --- a/drivers/resctrl/mpam_devices.c
> +++ b/drivers/resctrl/mpam_devices.c
> @@ -713,6 +713,13 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
>   			mpam_set_feature(mpam_feat_mbw_part, props);
>   
>   		props->bwa_wd = FIELD_GET(MPAMF_MBW_IDR_BWA_WD, mbw_features);
> +
> +		/*
> +		 * The BWA_WD field can represent 0-63, but the control fields it
> +		 * describes have a maximum of 16 bits.
> +		 */
> +		props->bwa_wd = min(props->bwa_wd, 16);
> +

16 may deserve a definition for it since it's a constant value and referred
for multiple times in this patch, if we need to give this series another
respin :-)

>   		if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MAX, mbw_features))
>   			mpam_set_feature(mpam_feat_mbw_max, props);
>   
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index cab3e9ccb5c7..adaec522c1a1 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -10,6 +10,7 @@
>   #include <linux/errno.h>
>   #include <linux/limits.h>
>   #include <linux/list.h>
> +#include <linux/math.h>
>   #include <linux/printk.h>
>   #include <linux/rculist.h>
>   #include <linux/resctrl.h>
> @@ -242,6 +243,56 @@ static bool cache_has_usable_cpor(struct mpam_class *class)
>   	return class->props.cpbm_wd <= 32;
>   }
>   
> +/*
> + * Each fixed-point hardware value architecturally represents a range
> + * of values: the full range 0% - 100% is split contiguously into
> + * (1 << cprops->bwa_wd) equal bands.
> + *
> + * Although the bwa_bwd fields have 6 bits the maximum valid value is 16
> + * as it reports the width of fields that are at most 16 bits. When
> + * fewer than 16 bits are valid the least significant bits are
> + * ignored. The implied binary point is kept between bits 15 and 16 and
> + * so the valid bits are leftmost.
> + *
> + * See ARM IHI0099B.a "MPAM system component specification", Section 9.3,
> + * "The fixed-point fractional format" for more information.
> + *
> + * Find the nearest percentage value to the upper bound of the selected band:
> + */
> +static u32 mbw_max_to_percent(u16 mbw_max, struct mpam_props *cprops)
> +{
> +	u32 val = mbw_max;
> +
> +	val >>= 16 - cprops->bwa_wd;
> +	val += 1;
> +	val *= MAX_MBA_BW;
> +	val = DIV_ROUND_CLOSEST(val, 1 << cprops->bwa_wd);
> +
> +	return val;
> +}
> +
> +/*
> + * Find the band whose upper bound is closest to the specified percentage.
> + *
> + * A round-to-nearest policy is followed here as a balanced compromise
> + * between unexpected under-commit of the resource (where the total of
> + * a set of resource allocations after conversion is less than the
> + * expected total, due to rounding of the individual converted
> + * percentages) and over-commit (where the total of the converted
> + * allocations is greater than expected).
> + */
> +static u16 percent_to_mbw_max(u8 pc, struct mpam_props *cprops)
> +{
> +	u32 val = pc;
> +
> +	val <<= cprops->bwa_wd;
> +	val = DIV_ROUND_CLOSEST(val, MAX_MBA_BW);
> +	val = max(val, 1) - 1;
> +	val <<= 16 - cprops->bwa_wd;
> +
> +	return val;
> +}
> +
>   /* Test whether we can export MPAM_CLASS_CACHE:{2,3}? */
>   static void mpam_resctrl_pick_caches(void)
>   {

Thanks,
Gavin


^ permalink raw reply

* Re: [PATCH v6 23/40] arm_mpam: resctrl: Add rmid index helpers
From: Gavin Shan @ 2026-03-23 22:50 UTC (permalink / raw)
  To: Ben Horgan
  Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
	dfustini, fenghuay, james.morse, jonathan.cameron, kobak,
	lcherian, linux-arm-kernel, linux-kernel, peternewman,
	punit.agrawal, quic_jiles, reinette.chatre, rohit.mathew, scott,
	sdonthineni, tan.shaopeng, xhao, catalin.marinas, will, corbet,
	maz, oupton, joey.gouly, suzuki.poulose, kvmarm, zengheng4,
	linux-doc, Shaopeng Tan
In-Reply-To: <20260313144617.3420416-24-ben.horgan@arm.com>

On 3/14/26 12:46 AM, Ben Horgan wrote:
> Because MPAM's pmg aren't identical to RDT's rmid, resctrl handles some
> data structures by index. This allows x86 to map indexes to RMID, and MPAM
> to map them to partid-and-pmg.
> 
> Add the helpers to do this.
> 
> Tested-by: Gavin Shan <gshan@redhat.com>
> Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
> Tested-by: Peter Newman <peternewman@google.com>
> Tested-by: Zeng Heng <zengheng4@huawei.com>
> Tested-by: Punit Agrawal <punit.agrawal@oss.qualcomm.com>
> Reviewed-by: Zeng Heng <zengheng4@huawei.com>
> Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
> Suggested-by: James Morse <james.morse@arm.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
> ---
> Changes since rfc:
> Use ~0U instead of ~0 in lhs of left shift
> 
> Changes since v2:
> Drop changes signed-off-by as reworked patch
> Use multiply and add rather than shift to avoid holes
> ---
>   drivers/resctrl/mpam_resctrl.c | 16 ++++++++++++++++
>   include/linux/arm_mpam.h       |  3 +++
>   2 files changed, 19 insertions(+)
> 

Reviewed-by: Gavin Shan <gshan@redhat.com>



^ permalink raw reply

* Re: [PATCH] docs: add advanced search for kernel documentation
From: Rito Rhymes @ 2026-03-23 22:50 UTC (permalink / raw)
  To: Randy Dunlap, Rito Rhymes, Jonathan Corbet, Mauro Carvalho Chehab,
	linux-doc
  Cc: Shuah Khan, linux-kernel
In-Reply-To: <4620a35c-5293-4973-aa71-49046fae9911@infradead.org>

I believe I identified the issue as a Sphinx version compatibility
problem.

I've been working on a more robust reroll. I expect to have it by
tomorrow, and we can test it when you're ready.

Rito

^ permalink raw reply

* Re: [PATCH 0/2] kallsyms: show typed function parameters in oops/WARN dumps
From: Andrew Morton @ 2026-03-23 22:50 UTC (permalink / raw)
  To: Sasha Levin
  Cc: Masahiro Yamada, Nathan Chancellor, Nicolas Schier,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H. Peter Anvin, Peter Zijlstra, Josh Poimboeuf, Petr Mladek,
	Alexei Starovoitov, Jonathan Corbet, David Gow, Kees Cook,
	Greg KH, Luis Chamberlain, Steven Rostedt, Helge Deller,
	Randy Dunlap, Geert Uytterhoeven, Juergen Gross, James Bottomley,
	Alexey Dobriyan, Vlastimil Babka, Laurent Pinchart, Petr Pavlu,
	x86, linux-kernel, linux-kbuild, linux-doc, linux-modules, bpf
In-Reply-To: <20260323164858.1939248-1-sashal@kernel.org>

On Mon, 23 Mar 2026 12:48:55 -0400 Sasha Levin <sashal@kernel.org> wrote:

> Building on the lineinfo series, this adds typed function parameter
> display to oops and WARN dumps.  A build-time tool extracts parameter
> names and types from DWARF, and the kernel maps pt_regs to the calling
> convention at crash time.  When BTF is available, struct pointer
> parameters are dereferenced and their members displayed.

mm.git is full and I'm seriously looking at loadshedded.  Can we please
leave this until next cycle, give your "kallsyms: embed source file:line
info in kernel stack traces", v4 time to settle in?

^ permalink raw reply


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