Linux Documentation
 help / color / mirror / Atom feed
* [PATCH v5 3/4] coresight: pass THIS_MODULE implicitly through a macro
From: Shashank Balaji @ 2026-05-18 10:19 UTC (permalink / raw)
  To: Suzuki K Poulose, James Clark, Alexander Shishkin,
	Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Jonathan Corbet, Shuah Khan, Luis Chamberlain, Petr Pavlu,
	Daniel Gomez, Sami Tolvanen, Aaron Tomlin, Mike Leach, Leo Yan,
	Thierry Reding, Jonathan Hunter, Mike Leach
  Cc: Rahul Bukte, Shashank Balaji, linux-kernel, coresight,
	linux-arm-kernel, driver-core, rust-for-linux, linux-doc,
	Daniel Palmer, Tim Bird, linux-modules, linux-tegra, Sumit Gupta
In-Reply-To: <20260518-acpi_mod_name-v5-0-705ccc430885@sony.com>

Rename coresight_init_driver() to coresight_init_driver_with_owner() and replace
it with a macro wrapper that passes THIS_MODULE implicitly. This is in line with
what other buses do.

Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Leo Yan <leo.yan@arm.com>
Co-developed-by: Rahul Bukte <rahul.bukte@sony.com>
Signed-off-by: Rahul Bukte <rahul.bukte@sony.com>
Signed-off-by: Shashank Balaji <shashank.mahadasyam@sony.com>
---
Patch 4 depends on this patch
---
 drivers/hwtracing/coresight/coresight-catu.c       | 2 +-
 drivers/hwtracing/coresight/coresight-core.c       | 6 +++---
 drivers/hwtracing/coresight/coresight-cpu-debug.c  | 3 +--
 drivers/hwtracing/coresight/coresight-funnel.c     | 3 +--
 drivers/hwtracing/coresight/coresight-replicator.c | 3 +--
 drivers/hwtracing/coresight/coresight-stm.c        | 2 +-
 drivers/hwtracing/coresight/coresight-tmc-core.c   | 2 +-
 drivers/hwtracing/coresight/coresight-tnoc.c       | 2 +-
 drivers/hwtracing/coresight/coresight-tpdm.c       | 3 +--
 drivers/hwtracing/coresight/coresight-tpiu.c       | 2 +-
 include/linux/coresight.h                          | 6 ++++--
 11 files changed, 16 insertions(+), 18 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c
index ce71dcddfca2..0c8698c8fc5e 100644
--- a/drivers/hwtracing/coresight/coresight-catu.c
+++ b/drivers/hwtracing/coresight/coresight-catu.c
@@ -706,7 +706,7 @@ static int __init catu_init(void)
 {
 	int ret;
 
-	ret = coresight_init_driver("catu", &catu_driver, &catu_platform_driver, THIS_MODULE);
+	ret = coresight_init_driver("catu", &catu_driver, &catu_platform_driver);
 	tmc_etr_set_catu_ops(&etr_catu_buf_ops);
 	return ret;
 }
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 46f247f73cf6..54ad5193b850 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -1694,8 +1694,8 @@ static void __exit coresight_exit(void)
 module_init(coresight_init);
 module_exit(coresight_exit);
 
-int coresight_init_driver(const char *drv, struct amba_driver *amba_drv,
-			  struct platform_driver *pdev_drv, struct module *owner)
+int coresight_init_driver_with_owner(const char *drv, struct amba_driver *amba_drv,
+				     struct platform_driver *pdev_drv, struct module *owner)
 {
 	int ret;
 
@@ -1713,7 +1713,7 @@ int coresight_init_driver(const char *drv, struct amba_driver *amba_drv,
 	amba_driver_unregister(amba_drv);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(coresight_init_driver);
+EXPORT_SYMBOL_GPL(coresight_init_driver_with_owner);
 
 void coresight_remove_driver(struct amba_driver *amba_drv,
 			     struct platform_driver *pdev_drv)
diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c
index 629614278e46..3a806c1d50ea 100644
--- a/drivers/hwtracing/coresight/coresight-cpu-debug.c
+++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c
@@ -757,8 +757,7 @@ static struct platform_driver debug_platform_driver = {
 
 static int __init debug_init(void)
 {
-	return coresight_init_driver("debug", &debug_driver, &debug_platform_driver,
-				     THIS_MODULE);
+	return coresight_init_driver("debug", &debug_driver, &debug_platform_driver);
 }
 
 static void __exit debug_exit(void)
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
index 3f56ceccd8c9..0abc11f0690c 100644
--- a/drivers/hwtracing/coresight/coresight-funnel.c
+++ b/drivers/hwtracing/coresight/coresight-funnel.c
@@ -412,8 +412,7 @@ static struct amba_driver dynamic_funnel_driver = {
 
 static int __init funnel_init(void)
 {
-	return coresight_init_driver("funnel", &dynamic_funnel_driver, &funnel_driver,
-				     THIS_MODULE);
+	return coresight_init_driver("funnel", &dynamic_funnel_driver, &funnel_driver);
 }
 
 static void __exit funnel_exit(void)
diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
index 07fc04f53b88..2f382de357ee 100644
--- a/drivers/hwtracing/coresight/coresight-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-replicator.c
@@ -418,8 +418,7 @@ static struct amba_driver dynamic_replicator_driver = {
 
 static int __init replicator_init(void)
 {
-	return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver,
-				     THIS_MODULE);
+	return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver);
 }
 
 static void __exit replicator_exit(void)
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index aca6cec7885a..4e860519a73f 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -1050,7 +1050,7 @@ static struct platform_driver stm_platform_driver = {
 
 static int __init stm_init(void)
 {
-	return coresight_init_driver("stm", &stm_driver, &stm_platform_driver, THIS_MODULE);
+	return coresight_init_driver("stm", &stm_driver, &stm_platform_driver);
 }
 
 static void __exit stm_exit(void)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index c89fe996af23..bc5a133ada3e 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -1046,7 +1046,7 @@ static struct platform_driver tmc_platform_driver = {
 
 static int __init tmc_init(void)
 {
-	return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver, THIS_MODULE);
+	return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver);
 }
 
 static void __exit tmc_exit(void)
diff --git a/drivers/hwtracing/coresight/coresight-tnoc.c b/drivers/hwtracing/coresight/coresight-tnoc.c
index 96a25877b824..9e8de4323d28 100644
--- a/drivers/hwtracing/coresight/coresight-tnoc.c
+++ b/drivers/hwtracing/coresight/coresight-tnoc.c
@@ -344,7 +344,7 @@ static struct platform_driver itnoc_driver = {
 
 static int __init tnoc_init(void)
 {
-	return coresight_init_driver("tnoc", &trace_noc_driver, &itnoc_driver, THIS_MODULE);
+	return coresight_init_driver("tnoc", &trace_noc_driver, &itnoc_driver);
 }
 
 static void __exit tnoc_exit(void)
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
index eaf7210af648..8464edbba2d4 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.c
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -1563,8 +1563,7 @@ static struct platform_driver static_tpdm_driver = {
 
 static int __init tpdm_init(void)
 {
-	return coresight_init_driver("tpdm", &dynamic_tpdm_driver, &static_tpdm_driver,
-				     THIS_MODULE);
+	return coresight_init_driver("tpdm", &dynamic_tpdm_driver, &static_tpdm_driver);
 }
 
 static void __exit tpdm_exit(void)
diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c
index b8560b140e0f..7b029d2eb389 100644
--- a/drivers/hwtracing/coresight/coresight-tpiu.c
+++ b/drivers/hwtracing/coresight/coresight-tpiu.c
@@ -310,7 +310,7 @@ static struct platform_driver tpiu_platform_driver = {
 
 static int __init tpiu_init(void)
 {
-	return coresight_init_driver("tpiu", &tpiu_driver, &tpiu_platform_driver, THIS_MODULE);
+	return coresight_init_driver("tpiu", &tpiu_driver, &tpiu_platform_driver);
 }
 
 static void __exit tpiu_exit(void)
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 2131febebee9..cd8fb47a1192 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -691,8 +691,10 @@ coresight_find_output_type(struct coresight_platform_data *pdata,
 			   enum coresight_dev_type type,
 			   union coresight_dev_subtype subtype);
 
-int coresight_init_driver(const char *drv, struct amba_driver *amba_drv,
-			  struct platform_driver *pdev_drv, struct module *owner);
+int coresight_init_driver_with_owner(const char *drv, struct amba_driver *amba_drv,
+				     struct platform_driver *pdev_drv, struct module *owner);
+#define coresight_init_driver(drv, amba_drv, pdev_drv) \
+	coresight_init_driver_with_owner(drv, amba_drv, pdev_drv, THIS_MODULE)
 
 void coresight_remove_driver(struct amba_driver *amba_drv,
 			     struct platform_driver *pdev_drv);

-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH] docs: submitting-patches: Clarify that in English "reviewer" is a person
From: Krzysztof Kozlowski @ 2026-05-18 10:16 UTC (permalink / raw)
  To: David Hildenbrand (Arm), Vlastimil Babka (SUSE), Jonathan Corbet,
	Shuah Khan, workflows, linux-doc, linux-kernel
  Cc: Greg Kroah-Hartman, Andrew Morton, Linus Torvalds, Guenter Roeck,
	Mark Brown
In-Reply-To: <1d350564-0127-48c1-8988-54245fdb9b23@kernel.org>

On 18/05/2026 10:31, David Hildenbrand (Arm) wrote:
> On 5/16/26 16:39, Vlastimil Babka (SUSE) wrote:
>> On 5/16/26 14:38, Krzysztof Kozlowski wrote:
>>> Common understanding of word "Reviewer" is: a person performing a review
>>> work [1]. Tools are not persons, thus cannot be reviewers in this term.
>>> Also tools cannot make statements ("A Reviewed-by tag is a statement of
>>> opinion"), since making a statement needs some sort of conscious mind.
>>>
>>> Our docs already clearly mark that "Reviewed-by" must come from a
>>> person:
>>>
>>>  - "By offering my Reviewed-by: tag, I state that:"
>>>
>>>    Usage of first person "I" and word "state"
>>>
>>>  - "A Reviewed-by tag is *a statement of opinion* that the patch is an
>>>     appropriate modification of the kernel without any remaining serious"
>>>
>>>    Only a person can make a statement of opinion.
>>>
>>>  - "Any interested reviewer (who has done the work) can offer a
>>>    Reviewed-by"
>>>
>>>    A person can offer a tag thus above does not grant the tool
>>>    permission to offer a tag.
>>>
>>> However this is not enough and apparently English is not that precise,
>>> so let's clarify that only a person can state the "Reviewer's statement
>>> of oversight".
>>>
>>> Link: https://en.wiktionary.org/wiki/reviewer [1]
>>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>>> Cc: Vlastimil Babka <vbabka@kernel.org>
>>> Cc: Andrew Morton <akpm@linux-foundation.org>
>>> Cc: David Hildenbrand <david@kernel.org>
>>> Cc: Linus Torvalds <torvalds@linux-foundation.org>
>>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
>>
>> I agree with the intent that the tag is for people (whether they use a tool
>> or not to help them). We also don't put "Tested-by: kernel test robot" or
>> syzkaller on every commit that they test and find no bugs. Review is also
>> not just about absence of bugs, but agreeing with the larger design and
>> whether the change makes sense to do in the first place.
> 
> I'd assume that SOB/RB/ACK would all be real persons, not tools.
> 
> For SOB we term it as "known identity". I'd assume that a tool is not an
> identity ...
> 
> So maybe we should also talk about "know identity" here?

I think this - s/person/known identity/ - is a good idea. We should not
have aliases and anonymous reviews because these are not accountable.

I got few acks already and I plan to retain them in v2, so please let me
know if you disagree with keeping Ack/Reviewed-by while replacing this
to known identity.



Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH net-next v3 08/14] idpf: refactor idpf to use libie control queues
From: Larysa Zaremba @ 2026-05-18 10:14 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev, Tony Nguyen
  Cc: Pavan Kumar Linga, przemyslaw.kitszel, aleksander.lobakin,
	sridhar.samudrala, anjali.singhai, michal.swiatkowski,
	maciej.fijalkowski, emil.s.tantilov, joshua.a.hay, jacob.e.keller,
	jayaprakash.shanmugam, jiri, horms, corbet, richardcochran,
	linux-doc, Aleksandr Loktionov, Samuel Salin
In-Reply-To: <agrHcqdDR5j50ql7@soc-5CG4396X81.clients.intel.com>

On Mon, May 18, 2026 at 10:01:54AM +0200, Larysa Zaremba wrote:
> On Fri, May 15, 2026 at 03:44:32PM -0700, Tony Nguyen wrote:
> > 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.

Here is the diff that could address the comments.

diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 13c8505d126f..df86af790dad 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -2584,7 +2584,7 @@ int idpf_send_get_set_rss_key_msg(struct idpf_adapter *adapter,
        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 (recv_len < key_size) {
+       if (recv_len < struct_size(recv_rk, key_flex, key_size)) {
                err = -EIO;
                goto free_rx_buf;
        }
@@ -2850,8 +2850,14 @@ static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)
                        pt_10 = le16_to_cpu(ptype->ptype_id_10);
                        pt_8 = ptype->ptype_id_8;

+                       if (xn_params.recv_mem.iov_len <
+                           ptype_offset + sizeof(struct virtchnl2_ptype)) {
+                               err = -EINVAL;
+                               goto free_rx_buf;
+                       }
+
                        ptype_offset += IDPF_GET_PTYPE_SIZE(ptype);
-                       if (ptype_offset > LIBIE_CTLQ_MAX_BUF_LEN) {
+                       if (xn_params.recv_mem.iov_len < ptype_offset) {
                                err = -EINVAL;
                                goto free_rx_buf;
                        }
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c
index 6d44021c222b..a71c041ec9e8 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c
@@ -556,6 +556,9 @@ idpf_ptp_get_tx_tstamp_async_handler(void *ctx, struct kvec *mem, int status)
                return;

        recv_tx_tstamp_msg = mem->iov_base;
+       if (mem->iov_len < sizeof(*recv_tx_tstamp_msg))
+               return;
+
        vport_id = le32_to_cpu(recv_tx_tstamp_msg->vport_id);

        idpf_for_each_vport(adapter, vport) {

> 
> I had reviewed the Sashiko feedback [0]. Here is why I not find the feedback 
> very helpful for this particular patch:
> 
> 1. "Could this parse arbitrary messages as asynchronous events if the opcode 
>     isn't checked?" - fixed in a later patch.
> 2. idpf_send_create_vport_msg() - recv_mem.iov_len is verified by libeth to be 
>    no bigger than LIBIE_CTLQ_MAX_BUF_LEN, so this memcpy is always OK.
> 3. "Should the check instead be against struct_size(recv_rk, key_flex, 
>     key_size)?" Yes, it should, but this is old code.
> 4. idpf_send_get_rx_ptype_msg() "Does this correctly prevent reading past the 
>     end of the received buffer?" - no, but this is not introduced by the patch.
> 5. "Can this race with mbx_task and cause a NULL pointer dereference or
>     use-after-free?" - fixed by a later patch.
> 6. "Does this require a bounds check to verify the received message length?" - 
>    yes.
> 
> I will send the diff for 3, 4 and 6 in the next message.
> 
> [0] https://sashiko.dev/#/patchset/20260515224443.2772147-1-anthony.l.nguyen%40intel.com
> 
> 
> > 
> > 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.
> > 
> > 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.
> > 
> > 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.
> > 
> > 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>
> > Tested-by: Samuel Salin <Samuel.salin@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 |   64 +-
> >  .../net/ethernet/intel/idpf/idpf_virtchnl.c   | 1632 +++++++----------
> >  .../net/ethernet/intel/idpf/idpf_virtchnl.h   |   94 +-
> >  .../ethernet/intel/idpf/idpf_virtchnl_ptp.c   |  248 ++-
> >  16 files changed, 832 insertions(+), 2521 deletions(-)
> >  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 efdb58990a8b..679539a1b947 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 e36b0017186f..3a357d5dea20 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 93b11fb1609f..db91039c54d0 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 98b8f678bd9a..3dafe680b701 100644
> > --- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
> > +++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
> > @@ -9,42 +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)
> >  {
> > -	for (int 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;
> > -			ccq->reg.tail = VF_ATQT;
> > -			ccq->reg.len = VF_ATQLEN;
> > -			ccq->reg.bah = VF_ATQBAH;
> > -			ccq->reg.bal = VF_ATQBAL;
> > -			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;
> > -			ccq->reg.tail = VF_ARQT;
> > -			ccq->reg.len = VF_ARQLEN;
> > -			ccq->reg.bah = VF_ARQBAH;
> > -			ccq->reg.bal = VF_ARQBAL;
> > -			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;
> >  }
> >  
> >  /**
> > @@ -157,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 3e6411a07e4d..13c8505d126f 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,528 +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
> > - *
> > - * Will prepare the control queue message and initiates the send api
> > - *
> > - * 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). */
> > -
> > -/**
> > - * idpf_vc_xn_lock - Request exclusive access to vc transaction
> > - * @xn: struct idpf_vc_xn* to access
> > - */
> > -#define idpf_vc_xn_lock(xn)			\
> > -	spin_lock(&(xn)->lock)
> > -
> > -/**
> > - * idpf_vc_xn_unlock - Release exclusive access to vc transaction
> > - * @xn: struct idpf_vc_xn* to access
> > - */
> > -#define idpf_vc_xn_unlock(xn)		\
> > -	spin_unlock(&(xn)->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);
> > -		spin_lock_init(&xn->lock);
> > -		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
> > + * @xn_params: Xn send parameters to fill
> > + * @send_buf: buffer to send
> > + * @send_buf_size: size of the send buffer
> >   *
> > - * All waiting threads will be woken-up and their transaction aborted. Further
> > - * operations on that object will fail.
> > - */
> > -void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr)
> > -{
> > -	int i;
> > -
> > -	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);
> > -
> > -	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);
> > -	}
> > -}
> > -
> > -/**
> > - * idpf_vc_xn_pop_free - Pop a free transaction from free list
> > - * @vcxn_mngr: transaction manager to pop from
> > + * 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.
> >   *
> > - * 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;
> > -
> > -	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;
> > -
> > -	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_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);
> > -	spin_lock_bh(&vcxn_mngr->xn_bm_lock);
> > -	set_bit(xn->idx, vcxn_mngr->free_xn_bm);
> > -	spin_unlock_bh(&vcxn_mngr->xn_bm_lock);
> > -}
> > -
> > -/**
> > - * 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
> > + * Cleanup the mailbox queue entries of the previously sent message to
> > + * unmap and release the buffer.
> >   *
> > - * 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.
> > + * Return: 0 if the request was successful, -%EBUSY if reset is detected
> > + *	   or Tx control queue is full, other negative error code on failure.
> >   */
> > -static int
> > -idpf_vc_xn_forward_async(struct idpf_adapter *adapter, struct idpf_vc_xn *xn,
> > -			 const struct idpf_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 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:
> > -		/* Set reply_sz from the actual payload so that async_handler
> > -		 * can evaluate the response.
> > -		 */
> > -		xn->reply_sz = ctlq_msg->data_len;
> > -		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;
> > -	}
> > +	struct libie_ctlq_msg ctlq_msg = {};
> >  
> > -	if (ctlq_msg->cookie.mbx.chnl_retval) {
> > -		xn->reply_sz = 0;
> > -		xn->state = IDPF_VC_XN_COMPLETED_FAILED;
> > -		err = -EINVAL;
> > -		goto out_unlock;
> > -	}
> > +	if (idpf_is_reset_detected(adapter)) {
> > +		if (!libie_cp_can_send_onstack(send_buf_size))
> > +			kfree(send_buf);
> >  
> > -	if (ctlq_msg->data_len) {
> > -		payload = ctlq_msg->ctx.indirect.payload->va;
> > -		payload_size = ctlq_msg->data_len;
> > +		return -EBUSY;
> >  	}
> >  
> > -	xn->reply_sz = payload_size;
> > -	xn->state = IDPF_VC_XN_COMPLETED_SUCCESS;
> > +	idpf_prepare_ptp_mb_msg(adapter, xn_params->chnl_opcode, &ctlq_msg);
> > +	xn_params->ctlq_msg = ctlq_msg.opcode ? &ctlq_msg : NULL;
> >  
> > -	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));
> > +	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;
> >  
> > -out_unlock:
> > -	idpf_vc_xn_unlock(xn);
> > -	/* we _cannot_ hold lock while calling complete */
> > -	complete(&xn->completed);
> > +	idpf_mb_clean(adapter, xn_params->ctlq, false);
> >  
> > -	return err;
> > +	return libie_ctlq_xn_send(xn_params);
> >  }
> >  
> >  /**
> > - * 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;
> >  }
> > @@ -768,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;
> > @@ -881,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);
> > @@ -895,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 &&
> > @@ -930,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;
> >  }
> >  
> > @@ -942,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	|
> > @@ -1004,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;
> >  }
> >  
> >  /**
> > @@ -1062,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;
> > @@ -1102,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 (len && !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;
> >  }
> >  
> > @@ -1164,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_kfree(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;
> >  }
> >  
> >  /**
> > @@ -1555,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);
> > @@ -1586,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);
> >  
> > @@ -1674,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;
> >  }
> >  
> >  /**
> > @@ -1698,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;
> >  
> > -	return reply_sz < 0 ? reply_sz : 0;
> > +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> > +
> > +	return 0;
> >  }
> >  
> >  /**
> > @@ -1722,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;
> >  }
> >  
> >  /**
> > @@ -2573,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);
> > @@ -2592,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;
> >  
> > -	return reply_sz < 0 ? reply_sz : 0;
> > +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> > +
> > +	return 0;
> >  }
> >  
> >  /**
> > @@ -2636,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);
> > @@ -2652,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);
> > +
> > +free_rx_buf:
> > +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> >  
> > -	return idpf_vport_init_queue_reg_chunks(vport_config, &vc_msg->chunks);
> > +	return err;
> >  }
> >  
> >  /**
> > @@ -2686,49 +2264,51 @@ 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;
> > +	if (xn_params.recv_mem.iov_len < sizeof(*rcvd_vec)) {
> > +		err = -EIO;
> > +		goto free_rx_buf;
> > +	}
> >  
> >  	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;
> >  }
> >  
> >  /**
> > @@ -2740,24 +2320,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;
> >  }
> >  
> > @@ -2781,18 +2365,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;
> >  }
> >  
> >  /**
> > @@ -2805,10 +2393,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 */
> > @@ -2817,38 +2409,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;
> >  }
> >  
> >  /**
> > @@ -2868,14 +2463,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)
> > @@ -2889,37 +2486,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(*recv_rl)) {
> > +		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 + sizeof(*recv_rl)) {
> > +		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))
> > @@ -2931,13 +2522,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);
> > +	memcpy(rss_data->rss_lut, recv_rl->lut, lut_buf_size);
> > +free_rx_buf:
> > +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> >  
> > -	return 0;
> > +	return err;
> >  }
> >  
> >  /**
> > @@ -2953,12 +2547,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);
> > @@ -2966,37 +2562,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)
> > @@ -3007,13 +2598,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;
> >  }
> >  
> >  /**
> > @@ -3190,15 +2784,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)
> > @@ -3208,42 +2805,38 @@ 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;
> > +		if (xn_params.recv_mem.iov_len < sizeof(*ptype_info)) {
> > +			err = -EIO;
> > +			goto free_rx_buf;
> > +		}
> >  		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++) {
> > @@ -3258,14 +2851,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);
> > @@ -3279,13 +2876,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;
> >  }
> >  
> >  /**
> > @@ -3313,40 +2915,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;
> >  }
> >  
> >  /**
> > @@ -3357,40 +2943,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;
> > @@ -3402,12 +2991,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;
> >  }
> >  
> >  /**
> > @@ -3478,15 +3068,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:
> > @@ -3633,8 +3214,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));
> > @@ -3657,7 +3237,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);
> > @@ -3666,7 +3246,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);
> > @@ -4203,9 +3783,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
> > @@ -4213,13 +3793,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;
> > @@ -4227,18 +3808,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));
> > @@ -4258,16 +3839,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);
> >  }
> >  
> >  /**
> > @@ -4286,19 +3864,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);
> >  
> > @@ -4353,32 +3933,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;
> > @@ -4387,6 +3966,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
> > @@ -4401,9 +4000,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))
> > @@ -4414,15 +4017,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));
> >  }
> >  
> >  /**
> > @@ -4440,26 +4035,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 6992b768cef4..86a44b6e1488 100644
> > --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
> > +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
> > @@ -7,86 +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
> > - * @lock: protects the transaction state fields below
> > - * @state: virtchnl event loop stores the data below, protected by @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;
> > -	spinlock_t lock;
> > -	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;
> > @@ -96,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);
> > @@ -124,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;
> > @@ -214,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..6d44021c222b 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,19 @@ 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;
> > +	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;
> > +	if (reply_sz < sizeof(*rcv_tx_tstamp_caps)) {
> > +		err = -EIO;
> >  		goto get_tstamp_caps_out;
> >  	}
> > -
> >  	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 +419,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 +432,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 +529,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 +539,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 +569,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 +583,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 +604,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 +619,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;
> >  	bool state_upd;
> >  	u16 id = 0;
> >  
> > @@ -668,11 +660,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);
> >  }
> > -- 
> > 2.47.1
> > 
> 

^ permalink raw reply related

* [PATCH v2] docs: dt: maintainer: Add Devicetree and OF maintainer profile document
From: Krzysztof Kozlowski @ 2026-05-18 10:12 UTC (permalink / raw)
  To: Jonathan Corbet, Shuah Khan, workflows, linux-doc, linux-kernel
  Cc: Krzysztof Kozlowski, Rob Herring, Conor Dooley, Saravana Kannan,
	devicetree

Document how Devicetree and Open Firmware maintainers handle their
subsystem, especially focusing on two caveats:

Devicetree subsystem handles patches with a minor difference comparing
to other subsystems: while DT maintainers pick up OF code, they only
provide review of DT bindings without applying these.

All three DT bindings maintainers rely currently on Patchwork and due to
enormous amount of emails per day, regardless how much DT maintainers
try, they cannot read all the emails.

Cc: Rob Herring <robh@kernel.org>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Saravana Kannan <saravanak@kernel.org>
Cc: devicetree@vger.kernel.org
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

---

I expect patch to be picked up by Rob, after review.

Changes in v2:
1. Correct typos and trailing white spaces.
2. Fix order of P: after C: in maintainers.
---
 .../process/maintainer-devicetree.rst         | 70 +++++++++++++++++++
 MAINTAINERS                                   |  2 +
 2 files changed, 72 insertions(+)
 create mode 100644 Documentation/process/maintainer-devicetree.rst

diff --git a/Documentation/process/maintainer-devicetree.rst b/Documentation/process/maintainer-devicetree.rst
new file mode 100644
index 000000000000..d8ffe752bf5d
--- /dev/null
+++ b/Documentation/process/maintainer-devicetree.rst
@@ -0,0 +1,70 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================================
+Devicetree and Open Firmware Subsystem
+======================================
+
+Other Process Documents
+-----------------------
+
+Please see the documents in Documentation/devicetree/bindings/ for information
+on how to write proper Devicetree bindings and how to submit patches.
+
+Patch Review and Handling
+-------------------------
+
+Patches handled by Devicetree maintainers are processed differently depending
+on the patch type:
+
+1. Core OF driver code, e.g. drivers/of/:
+   patches are reviewed and applied by DT maintainers.
+
+2. Devicetree bindings:
+   patches are reviewed by DT maintainers but, except in certain cases, should
+   be applied by subsystem maintainers.  See also *For kernel maintainers* in
+   Documentation/devicetree/bindings/submitting-patches.rst.
+
+3. DTS and drivers:
+   DT maintainers might provide comments, but review is generally not expected.
+
+Patchwork
+~~~~~~~~~
+
+Devicetree maintainers review patches using Patchwork, so the current status of
+a patch can be checked there. For typical driver submissions, Patchwork
+receives the entire patch set, but only a few patches are usually Devicetree
+bindings that are reviewed by DT maintainers.
+
+Explanation of Patchwork statuses:
+
+ - **New**: Not yet processed by the automation toolset.
+ - **Needs ACK**: Waiting for review by DT maintainers.
+ - **Handled Elsewhere**: Non-DT patch; not being reviewed here.
+ - **RFC**: Patch was likely ignored because it was an incomplete RFC.
+ - **Changes Requested**: Patch was reviewed and DT maintainers expect changes.
+ - **Accepted**: Patch was reviewed and applied by DT maintainers to their tree.
+ - **Not Applicable**: Patch was reviewed and is likely in good shape, with a
+   *Reviewed-by* or *Acked-by* tag provided, but DT maintainers expect someone
+   else to apply it.
+
+Patch Re-review and Pinging
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Due to the high volume of email traffic, Devicetree maintainers do not read
+every email they receive and instead rely on Patchwork during the review
+process. They also often skip patches that have already been reviewed.
+
+As a result, maintainers might miss:
+
+1. Questions about already reviewed patches.
+2. Pings, for example when a patch has been reviewed by DT maintainers but has
+   not been picked up by subsystem maintainers.
+
+Such cases can be addressed by:
+
+1. Pinging DT maintainers on the IRC channel.
+2. Dropping the DT maintainer’s *Acked-by* or *Reviewed-by* tag when sending a new
+   version of the patch set, together with an explanation in the patch
+   changelog describing why the tag was removed and what is expected from DT
+   maintainers.
+
diff --git a/MAINTAINERS b/MAINTAINERS
index f877e5aaf2c7..843f1d124446 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20050,6 +20050,7 @@ S:	Maintained
 Q:	http://patchwork.kernel.org/project/devicetree/list/
 W:	http://www.devicetree.org/
 C:	irc://irc.libera.chat/devicetree
+P:	Documentation/process/maintainer-devicetree.rst
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
 F:	Documentation/ABI/testing/sysfs-firmware-ofw
 F:	drivers/of/
@@ -20071,6 +20072,7 @@ L:	devicetree@vger.kernel.org
 S:	Maintained
 Q:	http://patchwork.kernel.org/project/devicetree/list/
 C:	irc://irc.libera.chat/devicetree
+P:	Documentation/process/maintainer-devicetree.rst
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
 F:	Documentation/devicetree/
 F:	arch/*/boot/dts/
-- 
2.51.0


^ permalink raw reply related

* Re: [PATCH net-next v3 14/14] ixd: add devlink support
From: Larysa Zaremba @ 2026-05-18 10:11 UTC (permalink / raw)
  To: Tony Nguyen
  Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
	przemyslaw.kitszel, aleksander.lobakin, sridhar.samudrala,
	anjali.singhai, michal.swiatkowski, maciej.fijalkowski,
	emil.s.tantilov, madhu.chittim, joshua.a.hay, jacob.e.keller,
	jayaprakash.shanmugam, jiri, horms, corbet, richardcochran,
	linux-doc, Bharath R
In-Reply-To: <20260515224443.2772147-15-anthony.l.nguyen@intel.com>

On Fri, May 15, 2026 at 03:44:38PM -0700, Tony Nguyen wrote:
> From: Amritha Nambiar <amritha.nambiar@intel.com>
> 
> Enable initial support for the devlink interface with the ixd driver. The
> ixd hardware is a single function PCIe device. So, the PCIe adapter gets
> its own devlink instance to manage device-wide resources or configuration.

I have accidentally posted the answer to the previous patch, here is a 
duplicate:

Sashiko's concern about devlink being registered too early is actually valid.
Would say this is not a serious issue at this stage in the development, but here 
is a diff addressing this:


diff --git a/drivers/net/ethernet/intel/ixd/ixd_lib.c b/drivers/net/ethernet/intel/ixd/ixd_lib.c
index 24080cb30c43..abf78966de61 100644
--- a/drivers/net/ethernet/intel/ixd/ixd_lib.c
+++ b/drivers/net/ethernet/intel/ixd/ixd_lib.c
@@ -2,6 +2,7 @@
 /* Copyright (C) 2025 Intel Corporation */

 #include "ixd.h"
+#include "ixd_devlink.h"
 #include "ixd_virtchnl.h"

 #define IXD_DFLT_MBX_Q_LEN 64
@@ -150,6 +151,7 @@ void ixd_init_task(struct work_struct *work)

        if (!ixd_vc_dev_init(adapter)) {
                adapter->init_task.vc_retries = 0;
+               ixd_devlink_register(adapter);
                return;
        }

diff --git a/drivers/net/ethernet/intel/ixd/ixd_main.c b/drivers/net/ethernet/intel/ixd/ixd_main.c
index 7ff51865af68..aa894482ee35 100644
--- a/drivers/net/ethernet/intel/ixd/ixd_main.c
+++ b/drivers/net/ethernet/intel/ixd/ixd_main.c
@@ -125,8 +125,6 @@ static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        queue_delayed_work(system_unbound_wq, &adapter->init_task.init_work,
                           msecs_to_jiffies(500));

-       ixd_devlink_register(adapter);
-
        return 0;

 free_adapter:


> 
> $ devlink dev show
> pci/0000:83:00.6
> 
> $ devlink dev info pci/0000:83:00.6
> pci/0000:83:00.6:
>   driver ixd
>   serial_number 00-a0-c9-ff-ff-23-45-67
>   versions:
>       fixed:
>         device.type MEV
>       running:
>         virtchnl 2.0
> 
> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
> Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
> Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
> Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
> Tested-by: Bharath R <Bharath.r@intel.com>
> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
> ---
>  Documentation/networking/devlink/index.rst   |  1 +
>  Documentation/networking/devlink/ixd.rst     | 30 ++++++
>  drivers/net/ethernet/intel/ixd/Kconfig       |  1 +
>  drivers/net/ethernet/intel/ixd/Makefile      |  1 +
>  drivers/net/ethernet/intel/ixd/ixd_devlink.c | 97 ++++++++++++++++++++
>  drivers/net/ethernet/intel/ixd/ixd_devlink.h | 44 +++++++++
>  drivers/net/ethernet/intel/ixd/ixd_main.c    | 16 +++-
>  7 files changed, 187 insertions(+), 3 deletions(-)
>  create mode 100644 Documentation/networking/devlink/ixd.rst
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd_devlink.c
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd_devlink.h
> 
> diff --git a/Documentation/networking/devlink/index.rst b/Documentation/networking/devlink/index.rst
> index f7ba7dcf477d..f0c077843fa7 100644
> --- a/Documentation/networking/devlink/index.rst
> +++ b/Documentation/networking/devlink/index.rst
> @@ -88,6 +88,7 @@ parameters, info versions, and other features it supports.
>     ionic
>     iosm
>     ixgbe
> +   ixd
>     kvaser_pciefd
>     kvaser_usb
>     mlx4
> diff --git a/Documentation/networking/devlink/ixd.rst b/Documentation/networking/devlink/ixd.rst
> new file mode 100644
> index 000000000000..17b63c8425aa
> --- /dev/null
> +++ b/Documentation/networking/devlink/ixd.rst
> @@ -0,0 +1,30 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +===================
> +ixd devlink support
> +===================
> +
> +This document describes the devlink features implemented by the ``ixd``
> +device driver.
> +
> +Info versions
> +=============
> +
> +The ``ixd`` driver reports the following versions
> +
> +.. list-table:: devlink info versions implemented
> +    :widths: 5 5 5 90
> +
> +    * - Name
> +      - Type
> +      - Example
> +      - Description
> +    * - ``device.type``
> +      - fixed
> +      - MEV
> +      - The hardware type for this device
> +    * - ``virtchnl``
> +      - running
> +      - 2.0
> +      - 2-digit version number (major.minor) of the communication channel
> +        (virtchnl) used by the device.
> diff --git a/drivers/net/ethernet/intel/ixd/Kconfig b/drivers/net/ethernet/intel/ixd/Kconfig
> index 24510c50070e..34181c59dcdc 100644
> --- a/drivers/net/ethernet/intel/ixd/Kconfig
> +++ b/drivers/net/ethernet/intel/ixd/Kconfig
> @@ -7,6 +7,7 @@ config IXD
>  	select LIBETH
>  	select LIBIE_CP
>  	select LIBIE_PCI
> +	select NET_DEVLINK
>  	help
>  	  This driver supports Intel(R) Control Plane PCI Function
>  	  of Intel E2100 and later IPUs and FNICs.
> diff --git a/drivers/net/ethernet/intel/ixd/Makefile b/drivers/net/ethernet/intel/ixd/Makefile
> index 90abf231fb16..03760a2580b9 100644
> --- a/drivers/net/ethernet/intel/ixd/Makefile
> +++ b/drivers/net/ethernet/intel/ixd/Makefile
> @@ -8,5 +8,6 @@ obj-$(CONFIG_IXD) += ixd.o
>  ixd-y := ixd_main.o
>  ixd-y += ixd_ctlq.o
>  ixd-y += ixd_dev.o
> +ixd-y += ixd_devlink.o
>  ixd-y += ixd_lib.o
>  ixd-y += ixd_virtchnl.o
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_devlink.c b/drivers/net/ethernet/intel/ixd/ixd_devlink.c
> new file mode 100644
> index 000000000000..23ab11226978
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd_devlink.c
> @@ -0,0 +1,97 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2025, Intel Corporation. */
> +
> +#include "ixd.h"
> +#include "ixd_devlink.h"
> +
> +#define IXD_DEVLINK_INFO_LEN	128
> +
> +/**
> + * ixd_fill_dsn - Get the serial number for the ixd device
> + * @adapter: adapter to query
> + * @buf: storage buffer for the info request
> + */
> +static void ixd_fill_dsn(struct ixd_adapter *adapter, char *buf)
> +{
> +	u8 dsn[8];
> +
> +	/* Copy the DSN into an array in Big Endian format */
> +	put_unaligned_be64(pci_get_dsn(adapter->cp_ctx.mmio_info.pdev), dsn);
> +
> +	snprintf(buf, IXD_DEVLINK_INFO_LEN, "%8phD", dsn);
> +}
> +
> +/**
> + * ixd_fill_device_name - Get the name of the underlying hardware
> + * @adapter: adapter to query
> + * @buf: storage buffer for the info request
> + * @buf_size: size of the storage buffer
> + */
> +static void ixd_fill_device_name(struct ixd_adapter *adapter, char *buf,
> +				 size_t buf_size)
> +{
> +	if (adapter->caps.device_type == cpu_to_le32(VIRTCHNL2_MEV_DEVICE))
> +		snprintf(buf, buf_size, "%s", "MEV");
> +	else
> +		snprintf(buf, buf_size, "%s", "UNKNOWN");
> +}
> +
> +/**
> + * ixd_devlink_info_get - .info_get devlink handler
> + * @devlink: devlink instance structure
> + * @req: the devlink info request
> + * @extack: extended netdev ack structure
> + *
> + * Callback for the devlink .info_get operation. Reports information about the
> + * device.
> + *
> + * Return: zero on success or an error code on failure.
> + */
> +static int ixd_devlink_info_get(struct devlink *devlink,
> +				struct devlink_info_req *req,
> +				struct netlink_ext_ack *extack)
> +{
> +	struct ixd_adapter *adapter = devlink_priv(devlink);
> +	char buf[IXD_DEVLINK_INFO_LEN];
> +	int err;
> +
> +	ixd_fill_dsn(adapter, buf);
> +	err = devlink_info_serial_number_put(req, buf);
> +	if (err)
> +		return err;
> +
> +	ixd_fill_device_name(adapter, buf, IXD_DEVLINK_INFO_LEN);
> +	err = devlink_info_version_fixed_put(req, "device.type", buf);
> +	if (err)
> +		return err;
> +
> +	snprintf(buf, sizeof(buf), "%u.%u",
> +		 adapter->vc_ver.major, adapter->vc_ver.minor);
> +
> +	return devlink_info_version_running_put(req, "virtchnl", buf);
> +}
> +
> +static const struct devlink_ops ixd_devlink_ops = {
> +	.info_get = ixd_devlink_info_get,
> +};
> +
> +/**
> + * ixd_adapter_alloc - Allocate devlink and return adapter pointer
> + * @dev: the device to allocate for
> + *
> + * Allocate a devlink instance for this device and return the private area as
> + * the adapter structure.
> + *
> + * Return: adapter structure on success, NULL on failure
> + */
> +struct ixd_adapter *ixd_adapter_alloc(struct device *dev)
> +{
> +	struct devlink *devlink;
> +
> +	devlink = devlink_alloc(&ixd_devlink_ops, sizeof(struct ixd_adapter),
> +				dev);
> +	if (!devlink)
> +		return NULL;
> +
> +	return devlink_priv(devlink);
> +}
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_devlink.h b/drivers/net/ethernet/intel/ixd/ixd_devlink.h
> new file mode 100644
> index 000000000000..c43ce0655de2
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd_devlink.h
> @@ -0,0 +1,44 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (c) 2025, Intel Corporation. */
> +
> +#ifndef _IXD_DEVLINK_H_
> +#define _IXD_DEVLINK_H_
> +#include <net/devlink.h>
> +
> +struct ixd_adapter *ixd_adapter_alloc(struct device *dev);
> +
> +/**
> + * ixd_devlink_free - teardown the devlink
> + * @adapter: the adapter structure to free
> + *
> + */
> +static inline void ixd_devlink_free(struct ixd_adapter *adapter)
> +{
> +	struct devlink *devlink = priv_to_devlink(adapter);
> +
> +	devlink_free(devlink);
> +}
> +
> +/**
> + * ixd_devlink_unregister - Unregister devlink resources for this adapter.
> + * @adapter: the adapter structure to cleanup
> + *
> + * Releases resources used by devlink and cleans up associated memory.
> + */
> +static inline void ixd_devlink_unregister(struct ixd_adapter *adapter)
> +{
> +	devlink_unregister(priv_to_devlink(adapter));
> +}
> +
> +/**
> + * ixd_devlink_register - Register devlink interface for this adapter
> + * @adapter: pointer to ixd adapter structure to be associated with devlink
> + *
> + * Register the devlink instance associated with this adapter
> + */
> +static inline void ixd_devlink_register(struct ixd_adapter *adapter)
> +{
> +	devlink_register(priv_to_devlink(adapter));
> +}
> +
> +#endif /* _IXD_DEVLINK_H_ */
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_main.c b/drivers/net/ethernet/intel/ixd/ixd_main.c
> index 6d5e6aca77df..ea6aa793a6a7 100644
> --- a/drivers/net/ethernet/intel/ixd/ixd_main.c
> +++ b/drivers/net/ethernet/intel/ixd/ixd_main.c
> @@ -4,6 +4,7 @@
>  #include "ixd.h"
>  #include "ixd_ctlq.h"
>  #include "ixd_lan_regs.h"
> +#include "ixd_devlink.h"
>  
>  MODULE_DESCRIPTION("Intel(R) Control Plane Function Device Driver");
>  MODULE_IMPORT_NS("LIBIE_CP");
> @@ -21,11 +22,14 @@ static void ixd_remove(struct pci_dev *pdev)
>  	/* Do not mix removal with (re)initialization */
>  	cancel_delayed_work_sync(&adapter->init_task.init_work);
>  
> +	ixd_devlink_unregister(adapter);
> +
>  	/* Leave the device clean on exit */
>  	ixd_trigger_reset(adapter);
>  	ixd_deinit_dflt_mbx(adapter);
>  
>  	libie_pci_unmap_all_mmio_regions(&adapter->cp_ctx.mmio_info);
> +	ixd_devlink_free(adapter);
>  }
>  
>  /**
> @@ -93,7 +97,7 @@ static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>  	if (WARN_ON(ent->device != IXD_DEV_ID_CPF))
>  		return -EINVAL;
>  
> -	adapter = devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL);
> +	adapter = ixd_adapter_alloc(&pdev->dev);
>  	if (!adapter)
>  		return -ENOMEM;
>  
> @@ -102,13 +106,13 @@ static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>  
>  	err = libie_pci_init_dev(pdev);
>  	if (err)
> -		return err;
> +		goto free_adapter;
>  
>  	pci_set_drvdata(pdev, adapter);
>  
>  	err = ixd_iomap_regions(adapter);
>  	if (err)
> -		return err;
> +		goto free_adapter;
>  
>  	INIT_DELAYED_WORK(&adapter->init_task.init_work,
>  			  ixd_init_task);
> @@ -118,7 +122,13 @@ static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>  	queue_delayed_work(system_unbound_wq, &adapter->init_task.init_work,
>  			   msecs_to_jiffies(500));
>  
> +	ixd_devlink_register(adapter);
> +
>  	return 0;
> +
> +free_adapter:
> +	ixd_devlink_free(adapter);
> +	return err;
>  }
>  
>  static const struct pci_device_id ixd_pci_tbl[] = {
> -- 
> 2.47.1
> 

^ permalink raw reply related

* Re: [PATCH net-next v3 13/14] ixd: add the core initialization
From: Larysa Zaremba @ 2026-05-18 10:10 UTC (permalink / raw)
  To: Tony Nguyen
  Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
	przemyslaw.kitszel, aleksander.lobakin, sridhar.samudrala,
	anjali.singhai, michal.swiatkowski, maciej.fijalkowski,
	emil.s.tantilov, madhu.chittim, joshua.a.hay, jacob.e.keller,
	jayaprakash.shanmugam, jiri, horms, corbet, richardcochran,
	linux-doc, Bharath R
In-Reply-To: <20260515224443.2772147-14-anthony.l.nguyen@intel.com>

On Fri, May 15, 2026 at 03:44:37PM -0700, Tony Nguyen wrote:
> From: Larysa Zaremba <larysa.zaremba@intel.com>
> 
> As the mailbox is setup, initialize the core. This makes use of the send
> and receive mailbox message framework for virtchnl communication between
> the driver and device Control Plane (CP).
> 
> To start with, driver confirms the virtchnl version with the CP. Once that
> is done, it requests and gets the required capabilities and resources
> needed such as max vectors, queues, vports etc.
> 
> Use a unified way of handling the virtchnl messages, where a single
> function handles all related memory management and the caller only provides
> the callbacks to fill the send buffer and to handle the response.
> 
> Place generic control queue message handling separately to facilitate the
> addition of protocols other than virtchannel in the future.

Sashiko's concern about devlink being registered too early is actually valid.
Would say this is not a serious issue at this stage in the development, but here 
is a diff addressing this:

diff --git a/drivers/net/ethernet/intel/ixd/ixd_lib.c b/drivers/net/ethernet/intel/ixd/ixd_lib.c
index 24080cb30c43..abf78966de61 100644
--- a/drivers/net/ethernet/intel/ixd/ixd_lib.c
+++ b/drivers/net/ethernet/intel/ixd/ixd_lib.c
@@ -2,6 +2,7 @@
 /* Copyright (C) 2025 Intel Corporation */

 #include "ixd.h"
+#include "ixd_devlink.h"
 #include "ixd_virtchnl.h"

 #define IXD_DFLT_MBX_Q_LEN 64
@@ -150,6 +151,7 @@ void ixd_init_task(struct work_struct *work)

        if (!ixd_vc_dev_init(adapter)) {
                adapter->init_task.vc_retries = 0;
+               ixd_devlink_register(adapter);
                return;
        }

diff --git a/drivers/net/ethernet/intel/ixd/ixd_main.c b/drivers/net/ethernet/intel/ixd/ixd_main.c
index 7ff51865af68..aa894482ee35 100644
--- a/drivers/net/ethernet/intel/ixd/ixd_main.c
+++ b/drivers/net/ethernet/intel/ixd/ixd_main.c
@@ -125,8 +125,6 @@ static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        queue_delayed_work(system_unbound_wq, &adapter->init_task.init_work,
                           msecs_to_jiffies(500));

-       ixd_devlink_register(adapter);
-
        return 0;

 free_adapter:


> 
> Co-developed-by: Amritha Nambiar <amritha.nambiar@intel.com>
> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
> Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
> Tested-by: Bharath R <Bharath.r@intel.com>
> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
> ---
>  drivers/net/ethernet/intel/ixd/Makefile       |   2 +
>  drivers/net/ethernet/intel/ixd/ixd.h          |  10 +
>  drivers/net/ethernet/intel/ixd/ixd_ctlq.c     | 149 +++++++++++++++
>  drivers/net/ethernet/intel/ixd/ixd_ctlq.h     |  33 ++++
>  drivers/net/ethernet/intel/ixd/ixd_lib.c      |  25 ++-
>  drivers/net/ethernet/intel/ixd/ixd_main.c     |   3 +
>  drivers/net/ethernet/intel/ixd/ixd_virtchnl.c | 178 ++++++++++++++++++
>  drivers/net/ethernet/intel/ixd/ixd_virtchnl.h |  12 ++
>  8 files changed, 411 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd_ctlq.c
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd_ctlq.h
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd_virtchnl.c
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd_virtchnl.h
> 
> diff --git a/drivers/net/ethernet/intel/ixd/Makefile b/drivers/net/ethernet/intel/ixd/Makefile
> index 164b2c86952f..90abf231fb16 100644
> --- a/drivers/net/ethernet/intel/ixd/Makefile
> +++ b/drivers/net/ethernet/intel/ixd/Makefile
> @@ -6,5 +6,7 @@
>  obj-$(CONFIG_IXD) += ixd.o
>  
>  ixd-y := ixd_main.o
> +ixd-y += ixd_ctlq.o
>  ixd-y += ixd_dev.o
>  ixd-y += ixd_lib.o
> +ixd-y += ixd_virtchnl.o
> diff --git a/drivers/net/ethernet/intel/ixd/ixd.h b/drivers/net/ethernet/intel/ixd/ixd.h
> index 99c44f2aa659..98d1f22534b5 100644
> --- a/drivers/net/ethernet/intel/ixd/ixd.h
> +++ b/drivers/net/ethernet/intel/ixd/ixd.h
> @@ -10,19 +10,29 @@
>   * struct ixd_adapter - Data structure representing a CPF
>   * @cp_ctx: Control plane communication context
>   * @init_task: Delayed initialization after reset
> + * @mbx_task: Control queue Rx handling
>   * @xnm: virtchnl transaction manager
>   * @asq: Send control queue info
>   * @arq: Receive control queue info
> + * @vc_ver: Negotiated virtchnl version
> + * @caps: Negotiated virtchnl capabilities
>   */
>  struct ixd_adapter {
>  	struct libie_ctlq_ctx cp_ctx;
>  	struct {
>  		struct delayed_work init_work;
>  		u8 reset_retries;
> +		u8 vc_retries;
>  	} init_task;
> +	struct delayed_work mbx_task;
>  	struct libie_ctlq_xn_manager *xnm;
>  	struct libie_ctlq_info *asq;
>  	struct libie_ctlq_info *arq;
> +	struct {
> +		u32 major;
> +		u32 minor;
> +	} vc_ver;
> +	struct virtchnl2_get_capabilities caps;
>  };
>  
>  /**
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_ctlq.c b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
> new file mode 100644
> index 000000000000..216aa5c02122
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
> @@ -0,0 +1,149 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright (C) 2025 Intel Corporation */
> +
> +#include "ixd.h"
> +#include "ixd_ctlq.h"
> +#include "ixd_virtchnl.h"
> +
> +/**
> + * ixd_ctlq_clean_sq - Clean the send control queue after sending the message
> + * @adapter: The adapter that sent the messages
> + * @num_sent: Number of sent messages to be released
> + *
> + * Free the libie send resources after sending the message and handling
> + * the response.
> + */
> +static void ixd_ctlq_clean_sq(struct ixd_adapter *adapter, u16 num_sent)
> +{
> +	if (!num_sent)
> +		return;
> +
> +	struct libie_ctlq_xn_clean_params params = {
> +		.ctlq = adapter->asq,
> +		.ctx = &adapter->cp_ctx,
> +		.num_msgs = num_sent,
> +		.rel_tx_buf = kfree,
> +	};
> +
> +	libie_ctlq_xn_send_clean(&params);
> +}
> +
> +/**
> + * ixd_ctlq_init_sparams - Initialize control queue send parameters
> + * @adapter: The adapter with initialized mailbox
> + * @sparams: Parameters to initialize
> + * @msg_buf: DMA-mappable pointer to the message being sent
> + * @msg_size: Message size
> + */
> +static void ixd_ctlq_init_sparams(struct ixd_adapter *adapter,
> +				  struct libie_ctlq_xn_send_params *sparams,
> +				  void *msg_buf, size_t msg_size)
> +{
> +	*sparams = (struct libie_ctlq_xn_send_params) {
> +		.rel_tx_buf = kfree,
> +		.xnm = adapter->xnm,
> +		.ctlq = adapter->asq,
> +		.timeout_ms = IXD_CTLQ_TIMEOUT,
> +		.send_buf = (struct kvec) {
> +			.iov_base = msg_buf,
> +			.iov_len = msg_size,
> +		},
> +	};
> +}
> +
> +/**
> + * ixd_ctlq_do_req - Perform a standard virtchnl request
> + * @adapter: The adapter with initialized mailbox
> + * @req: virtchnl request description
> + *
> + * Return: %0 if a message was sent and received a response
> + * that was successfully handled by the custom callback,
> + * negative error otherwise.
> + */
> +int ixd_ctlq_do_req(struct ixd_adapter *adapter, const struct ixd_ctlq_req *req)
> +{
> +	struct libie_ctlq_xn_send_params send_params = {};
> +	u8 onstack_send_buff[LIBIE_CP_TX_COPYBREAK] = {};
> +	struct kvec *recv_mem;
> +	void *send_buff;
> +	int err;
> +
> +	send_buff = libie_cp_can_send_onstack(req->send_size) ?
> +		    &onstack_send_buff : kzalloc(req->send_size, GFP_KERNEL);
> +	if (!send_buff)
> +		return -ENOMEM;
> +
> +	ixd_ctlq_init_sparams(adapter, &send_params, send_buff,
> +			      req->send_size);
> +
> +	send_params.chnl_opcode = req->opcode;
> +
> +	if (req->send_buff_init)
> +		req->send_buff_init(adapter, send_buff, req->ctx);
> +
> +	err = libie_ctlq_xn_send(&send_params);
> +	if (err)
> +		return err;
> +
> +	recv_mem = &send_params.recv_mem;
> +	if (req->recv_process)
> +		err = req->recv_process(adapter, recv_mem->iov_base,
> +					recv_mem->iov_len, req->ctx);
> +
> +	ixd_ctlq_clean_sq(adapter, 1);
> +	libie_ctlq_release_rx_buf(recv_mem);
> +
> +	return err;
> +}
> +
> +/**
> + * ixd_ctlq_handle_msg - Default control queue message handler
> + * @ctx: Control plane communication context
> + * @msg: Message received
> + */
> +static void ixd_ctlq_handle_msg(struct libie_ctlq_ctx *ctx,
> +				struct libie_ctlq_msg *msg)
> +{
> +	struct ixd_adapter *adapter = pci_get_drvdata(ctx->mmio_info.pdev);
> +
> +	if (ixd_vc_can_handle_msg(msg))
> +		ixd_vc_recv_event_msg(adapter, msg);
> +	else
> +		dev_dbg_ratelimited(ixd_to_dev(adapter),
> +				    "Received an unsupported opcode 0x%x from the CP\n",
> +				    msg->chnl_opcode);
> +
> +	libie_ctlq_release_rx_buf(&msg->recv_mem);
> +}
> +
> +/**
> + * ixd_ctlq_recv_mb_msg - Receive a potential message over mailbox periodically
> + * @adapter: The adapter with initialized mailbox
> + */
> +static void ixd_ctlq_recv_mb_msg(struct ixd_adapter *adapter)
> +{
> +	struct libie_ctlq_xn_recv_params xn_params = {
> +		.xnm = adapter->xnm,
> +		.ctlq = adapter->arq,
> +		.ctlq_msg_handler = ixd_ctlq_handle_msg,
> +		.budget = LIBIE_CTLQ_MAX_XN_ENTRIES,
> +	};
> +
> +	libie_ctlq_xn_recv(&xn_params);
> +}
> +
> +/**
> + * ixd_ctlq_rx_task - Periodically check for mailbox responses and events
> + * @work: work handle
> + */
> +void ixd_ctlq_rx_task(struct work_struct *work)
> +{
> +	struct ixd_adapter *adapter;
> +
> +	adapter = container_of(work, struct ixd_adapter, mbx_task.work);
> +
> +	queue_delayed_work(system_unbound_wq, &adapter->mbx_task,
> +			   msecs_to_jiffies(300));
> +
> +	ixd_ctlq_recv_mb_msg(adapter);
> +}
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_ctlq.h b/drivers/net/ethernet/intel/ixd/ixd_ctlq.h
> new file mode 100644
> index 000000000000..e7191d3870b7
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd_ctlq.h
> @@ -0,0 +1,33 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/* Copyright (C) 2025 Intel Corporation */
> +
> +#ifndef _IXD_CTLQ_H_
> +#define _IXD_CTLQ_H_
> +
> +#include <linux/intel/virtchnl2.h>
> +
> +#define IXD_CTLQ_TIMEOUT 2000
> +
> +/**
> + * struct ixd_ctlq_req - Standard virtchnl request description
> + * @opcode: protocol opcode, only virtchnl2 is needed for now
> + * @send_size: required length of the send buffer
> + * @send_buff_init: function to initialize the allocated send buffer
> + * @recv_process: function to handle the CP response
> + * @ctx: additional context for callbacks
> + */
> +struct ixd_ctlq_req {
> +	enum virtchnl2_op opcode;
> +	size_t send_size;
> +	void (*send_buff_init)(struct ixd_adapter *adapter, void *send_buff,
> +			       void *ctx);
> +	int (*recv_process)(struct ixd_adapter *adapter, void *recv_buff,
> +			    size_t recv_size, void *ctx);
> +	void *ctx;
> +};
> +
> +int ixd_ctlq_do_req(struct ixd_adapter *adapter,
> +		    const struct ixd_ctlq_req *req);
> +void ixd_ctlq_rx_task(struct work_struct *work);
> +
> +#endif /* _IXD_CTLQ_H_ */
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_lib.c b/drivers/net/ethernet/intel/ixd/ixd_lib.c
> index afc413d3650f..24080cb30c43 100644
> --- a/drivers/net/ethernet/intel/ixd/ixd_lib.c
> +++ b/drivers/net/ethernet/intel/ixd/ixd_lib.c
> @@ -2,6 +2,7 @@
>  /* Copyright (C) 2025 Intel Corporation */
>  
>  #include "ixd.h"
> +#include "ixd_virtchnl.h"
>  
>  #define IXD_DFLT_MBX_Q_LEN 64
>  
> @@ -67,6 +68,8 @@ static void ixd_adapter_fill_dflt_ctlqs(struct ixd_adapter *adapter)
>   */
>  void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter)
>  {
> +	cancel_delayed_work_sync(&adapter->mbx_task);
> +
>  	if (adapter->xnm)
>  		libie_ctlq_xn_deinit(adapter->xnm, &adapter->cp_ctx);
>  
> @@ -108,6 +111,8 @@ int ixd_init_dflt_mbx(struct ixd_adapter *adapter)
>  		return -ENOENT;
>  	}
>  
> +	queue_delayed_work(system_unbound_wq, &adapter->mbx_task, 0);
> +
>  	return 0;
>  }
>  
> @@ -136,8 +141,26 @@ void ixd_init_task(struct work_struct *work)
>  
>  	adapter->init_task.reset_retries = 0;
>  	err = ixd_init_dflt_mbx(adapter);
> -	if (err)
> +	if (err) {
>  		dev_err(ixd_to_dev(adapter),
>  			"Failed to initialize the default mailbox: %pe\n",
>  			ERR_PTR(err));
> +		return;
> +	}
> +
> +	if (!ixd_vc_dev_init(adapter)) {
> +		adapter->init_task.vc_retries = 0;
> +		return;
> +	}
> +
> +	ixd_deinit_dflt_mbx(adapter);
> +	if (++adapter->init_task.vc_retries > 5) {
> +		dev_err(ixd_to_dev(adapter),
> +			"Failed to establish mailbox communications with the hardware\n");
> +		return;
> +	}
> +
> +	ixd_trigger_reset(adapter);
> +	queue_delayed_work(system_unbound_wq, &adapter->init_task.init_work,
> +			   msecs_to_jiffies(500));
>  }
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_main.c b/drivers/net/ethernet/intel/ixd/ixd_main.c
> index b4d4000b63ed..6d5e6aca77df 100644
> --- a/drivers/net/ethernet/intel/ixd/ixd_main.c
> +++ b/drivers/net/ethernet/intel/ixd/ixd_main.c
> @@ -2,6 +2,7 @@
>  /* Copyright (C) 2025 Intel Corporation */
>  
>  #include "ixd.h"
> +#include "ixd_ctlq.h"
>  #include "ixd_lan_regs.h"
>  
>  MODULE_DESCRIPTION("Intel(R) Control Plane Function Device Driver");
> @@ -19,6 +20,7 @@ static void ixd_remove(struct pci_dev *pdev)
>  
>  	/* Do not mix removal with (re)initialization */
>  	cancel_delayed_work_sync(&adapter->init_task.init_work);
> +
>  	/* Leave the device clean on exit */
>  	ixd_trigger_reset(adapter);
>  	ixd_deinit_dflt_mbx(adapter);
> @@ -110,6 +112,7 @@ static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>  
>  	INIT_DELAYED_WORK(&adapter->init_task.init_work,
>  			  ixd_init_task);
> +	INIT_DELAYED_WORK(&adapter->mbx_task, ixd_ctlq_rx_task);
>  
>  	ixd_trigger_reset(adapter);
>  	queue_delayed_work(system_unbound_wq, &adapter->init_task.init_work,
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c
> new file mode 100644
> index 000000000000..66049d1b1d15
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c
> @@ -0,0 +1,178 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright (C) 2025 Intel Corporation */
> +
> +#include "ixd.h"
> +#include "ixd_ctlq.h"
> +#include "ixd_virtchnl.h"
> +
> +/**
> + * ixd_vc_recv_event_msg - Handle virtchnl event message
> + * @adapter: The adapter handling the message
> + * @ctlq_msg: Message received
> + */
> +void ixd_vc_recv_event_msg(struct ixd_adapter *adapter,
> +			   struct libie_ctlq_msg *ctlq_msg)
> +{
> +	int payload_size = ctlq_msg->data_len;
> +	struct virtchnl2_event *v2e;
> +
> +	if (payload_size < sizeof(*v2e)) {
> +		dev_warn_ratelimited(ixd_to_dev(adapter),
> +				     "Failed to receive valid payload for event msg (op 0x%X len %u)\n",
> +				     ctlq_msg->chnl_opcode,
> +				     payload_size);
> +		return;
> +	}
> +
> +	v2e = (struct virtchnl2_event *)ctlq_msg->recv_mem.iov_base;
> +
> +	dev_dbg(ixd_to_dev(adapter), "Got event 0x%X from the CP\n",
> +		le32_to_cpu(v2e->event));
> +}
> +
> +/**
> + * ixd_vc_can_handle_msg - Decide if an event has to be handled by virtchnl code
> + * @ctlq_msg: Message received
> + *
> + * Return: %true if virtchnl code can handle the event, %false otherwise
> + */
> +bool ixd_vc_can_handle_msg(struct libie_ctlq_msg *ctlq_msg)
> +{
> +	return ctlq_msg->chnl_opcode == VIRTCHNL2_OP_EVENT;
> +}
> +
> +/**
> + * ixd_handle_caps - Handle VIRTCHNL2_OP_GET_CAPS response
> + * @adapter: The adapter for which the capabilities are being updated
> + * @recv_buff: Buffer containing the response
> + * @recv_size: Response buffer size
> + * @ctx: unused
> + *
> + * Return: %0 if the response format is correct and was handled as expected,
> + * negative error otherwise.
> + */
> +static int ixd_handle_caps(struct ixd_adapter *adapter, void *recv_buff,
> +			   size_t recv_size, void *ctx)
> +{
> +	if (recv_size < sizeof(adapter->caps))
> +		return -EBADMSG;
> +
> +	adapter->caps = *(typeof(adapter->caps) *)recv_buff;
> +
> +	return 0;
> +}
> +
> +/**
> + * ixd_req_vc_caps - Request and save device capability
> + * @adapter: The adapter to get the capabilities for
> + *
> + * Return: success or error if sending the get capability message fails
> + */
> +static int ixd_req_vc_caps(struct ixd_adapter *adapter)
> +{
> +	const struct ixd_ctlq_req req = {
> +		.opcode = VIRTCHNL2_OP_GET_CAPS,
> +		.send_size = sizeof(struct virtchnl2_get_capabilities),
> +		.ctx = NULL,
> +		.send_buff_init = NULL,
> +		.recv_process = ixd_handle_caps,
> +	};
> +
> +	return ixd_ctlq_do_req(adapter, &req);
> +}
> +
> +/**
> + * ixd_get_vc_ver - Get version info from adapter
> + *
> + * Return: filled in virtchannel2 version info, ready for sending
> + */
> +static struct virtchnl2_version_info ixd_get_vc_ver(void)
> +{
> +	return (struct virtchnl2_version_info) {
> +		.major = cpu_to_le32(VIRTCHNL2_VERSION_MAJOR_2),
> +		.minor = cpu_to_le32(VIRTCHNL2_VERSION_MINOR_0),
> +	};
> +}
> +
> +static void ixd_fill_vc_ver(struct ixd_adapter *adapter, void *send_buff,
> +			    void *ctx)
> +{
> +	*(struct virtchnl2_version_info *)send_buff = ixd_get_vc_ver();
> +}
> +
> +/**
> + * ixd_handle_vc_ver - Handle VIRTCHNL2_OP_VERSION response
> + * @adapter: The adapter for which the version is being updated
> + * @recv_buff: Buffer containing the response
> + * @recv_size: Response buffer size
> + * @ctx: Unused
> + *
> + * Return: %0 if the response format is correct and was handled as expected,
> + * negative error otherwise.
> + */
> +static int ixd_handle_vc_ver(struct ixd_adapter *adapter, void *recv_buff,
> +			     size_t recv_size, void *ctx)
> +{
> +	struct virtchnl2_version_info need_ver = ixd_get_vc_ver();
> +	struct virtchnl2_version_info *recv_ver;
> +
> +	if (recv_size < sizeof(need_ver))
> +		return -EBADMSG;
> +
> +	recv_ver = recv_buff;
> +	if (le32_to_cpu(need_ver.major) > le32_to_cpu(recv_ver->major))
> +		return -EOPNOTSUPP;
> +
> +	adapter->vc_ver.major = le32_to_cpu(recv_ver->major);
> +	adapter->vc_ver.minor = le32_to_cpu(recv_ver->minor);
> +
> +	return 0;
> +}
> +
> +/**
> + * ixd_req_vc_version - Request and save Virtchannel2 version
> + * @adapter: The adapter to get the version for
> + *
> + * Return: success or error if sending fails or the response was not as expected
> + */
> +static int ixd_req_vc_version(struct ixd_adapter *adapter)
> +{
> +	const struct ixd_ctlq_req req = {
> +		.opcode = VIRTCHNL2_OP_VERSION,
> +		.send_size = sizeof(struct virtchnl2_version_info),
> +		.ctx = NULL,
> +		.send_buff_init = ixd_fill_vc_ver,
> +		.recv_process = ixd_handle_vc_ver,
> +	};
> +
> +	return ixd_ctlq_do_req(adapter, &req);
> +}
> +
> +/**
> + * ixd_vc_dev_init - virtchnl device core initialization
> + * @adapter: device information
> + *
> + * Return: %0 on success or error if any step of the initialization fails
> + */
> +int ixd_vc_dev_init(struct ixd_adapter *adapter)
> +{
> +	int err;
> +
> +	err = ixd_req_vc_version(adapter);
> +	if (err) {
> +		dev_warn(ixd_to_dev(adapter),
> +			 "Getting virtchnl version failed, error=%pe\n",
> +			 ERR_PTR(err));
> +		return err;
> +	}
> +
> +	err = ixd_req_vc_caps(adapter);
> +	if (err) {
> +		dev_warn(ixd_to_dev(adapter),
> +			 "Getting virtchnl capabilities failed, error=%pe\n",
> +			 ERR_PTR(err));
> +		return err;
> +	}
> +
> +	return err;
> +}
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_virtchnl.h b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.h
> new file mode 100644
> index 000000000000..1a53da8b545c
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/* Copyright (C) 2025 Intel Corporation */
> +
> +#ifndef _IXD_VIRTCHNL_H_
> +#define _IXD_VIRTCHNL_H_
> +
> +int ixd_vc_dev_init(struct ixd_adapter *adapter);
> +bool ixd_vc_can_handle_msg(struct libie_ctlq_msg *ctlq_msg);
> +void ixd_vc_recv_event_msg(struct ixd_adapter *adapter,
> +			   struct libie_ctlq_msg *ctlq_msg);
> +
> +#endif /* _IXD_VIRTCHNL_H_ */
> -- 
> 2.47.1
> 

^ permalink raw reply related

* Re: [PATCH v5 05/13] dt-bindings: iio: frequency: add ad9910
From: Rodrigo Alencar @ 2026-05-18 10:03 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Rodrigo Alencar
  Cc: linux-iio, devicetree, linux-kernel, linux-doc, linux-hardening,
	Lars-Peter Clausen, Michael Hennerich, Jonathan Cameron,
	David Lechner, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Philipp Zabel, Jonathan Corbet, Shuah Khan,
	Kees Cook, Gustavo A. R. Silva
In-Reply-To: <20260518-zippy-ingenious-aardwolf-df46a2@quoll>

On 26/05/18 09:52AM, Krzysztof Kozlowski wrote:
> On Sun, May 17, 2026 at 07:37:49PM +0100, Rodrigo Alencar wrote:
> > +maintainers:
> > +  - Rodrigo Alencar <rodrigo.alencar@analog.com>
> > +
> > +description:
> > +  The AD9910 is a 1 GSPS direct digital synthesizer (DDS) with an integrated
> > +  14-bit DAC. It features single tone mode with 8 configurable profiles,
> > +  a digital ramp generator, RAM control, OSK, and a parallel data port for
> > +  high-speed streaming.
> > +
> > +  https://www.analog.com/en/products/ad9910.html
> > +
> > +properties:
> > +  compatible:
> > +    const: adi,ad9910
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  spi-max-frequency:
> > +    maximum: 70000000
> > +
> > +  clocks:
> > +    minItems: 1
> > +    items:
> > +      - description: Reference clock (REF_CLK).
> > +      - description: Optional synchronization clock (SYNC_IN).
> > +
> > +  clock-names:
> > +    oneOf:
> > +      - items:
> > +          - const: ref_clk
> > +      - items:
> > +          - const: ref_clk
> > +          - const: sync_in
> 
> So that's just items with two items and minItems: 1. Like you have in
> "clocks:".
> 
> You got this comment already at v2.

You're right! will adjust. For some reason I thought I had problems with
the dt-binding check without this.

> 
> > +
> > +  '#clock-cells':
> > +    const: 1
> > +
> > +  clock-output-names:
> > +    minItems: 1
> > +    maxItems: 3
> > +    items:
> > +      enum: [ sync_clk, pdclk, sync_out ]
> 
> Why are the names fixed? And why is the order random?

All of those would be optional. Having it in a specific order we would need
to register all the clocks even if only one (or none) is used?

> > +
> > +  interrupts:
> > +    minItems: 1
> > +    items:
> > +      - description:
> > +          Signal that indicates that Digital Ramp Generator has reached a limit.
> > +      - description:
> > +          Signal that indicates the end of a RAM Sweep.
> > +
> > +  interrupt-names:
> > +    minItems: 1
> > +    maxItems: 2
> > +    items:
> > +      enum: [ drover, ram_swp_ovr ]
> 
> Your "interrupts:" do not allow flexibility. Are you sure interrupts are
> optional in the hardware?

Good point, They are optional. Should I drop the items and descriptions in "interrupts"?

> > +
> > +  dvdd-io33-supply:
> > +    description: 3.3V Digital I/O supply.
> > +
> > +  avdd33-supply:
> > +    description: 3.3V Analog DAC supply.
> 
> Best regards,
> Krzysztof
> 

-- 
Kind regards,

Rodrigo Alencar

^ permalink raw reply

* Re: [PATCH net-next v3 13/14] ixd: add the core initialization
From: Larysa Zaremba @ 2026-05-18 10:01 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev, Tony Nguyen
  Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
	przemyslaw.kitszel, aleksander.lobakin, sridhar.samudrala,
	anjali.singhai, michal.swiatkowski, maciej.fijalkowski,
	emil.s.tantilov, madhu.chittim, joshua.a.hay, jacob.e.keller,
	jayaprakash.shanmugam, jiri, horms, corbet, richardcochran,
	linux-doc, Bharath R
In-Reply-To: <20260515224443.2772147-14-anthony.l.nguyen@intel.com>

On Fri, May 15, 2026 at 03:44:37PM -0700, Tony Nguyen wrote:
> From: Larysa Zaremba <larysa.zaremba@intel.com>
> 
> As the mailbox is setup, initialize the core. This makes use of the send
> and receive mailbox message framework for virtchnl communication between
> the driver and device Control Plane (CP).
> 
> To start with, driver confirms the virtchnl version with the CP. Once that
> is done, it requests and gets the required capabilities and resources
> needed such as max vectors, queues, vports etc.
> 
> Use a unified way of handling the virtchnl messages, where a single
> function handles all related memory management and the caller only provides
> the callbacks to fill the send buffer and to handle the response.
> 
> Place generic control queue message handling separately to facilitate the
> addition of protocols other than virtchannel in the future.
>

Regarding Sashiko feedback [0]:

1. Major version handling is OK.
2. Regarding other concerns, I think code is good enough for an introductory 
   boilerplate patch. Below is a diff addressing those issues, it still does not 
   handle HW Tx queue stalls, but I think this is fine at this development 
   stage.

diff --git a/drivers/net/ethernet/intel/ixd/ixd_ctlq.c b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
index 216aa5c02122..1b8f1394754b 100644
--- a/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
+++ b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
@@ -62,8 +62,8 @@ static void ixd_ctlq_init_sparams(struct ixd_adapter *adapter,
  */
 int ixd_ctlq_do_req(struct ixd_adapter *adapter, const struct ixd_ctlq_req *req)
 {
+       u8 onstack_send_buff[LIBIE_CP_TX_COPYBREAK] __aligned_largest = {};
        struct libie_ctlq_xn_send_params send_params = {};
-       u8 onstack_send_buff[LIBIE_CP_TX_COPYBREAK] = {};
        struct kvec *recv_mem;
        void *send_buff;
        int err;
@@ -82,6 +82,7 @@ int ixd_ctlq_do_req(struct ixd_adapter *adapter, const struct ixd_ctlq_req *req)
                req->send_buff_init(adapter, send_buff, req->ctx);

        err = libie_ctlq_xn_send(&send_params);
+       ixd_ctlq_clean_sq(adapter, 1);
        if (err)
                return err;

@@ -90,7 +91,6 @@ int ixd_ctlq_do_req(struct ixd_adapter *adapter, const struct ixd_ctlq_req *req)
                err = req->recv_process(adapter, recv_mem->iov_base,
                                        recv_mem->iov_len, req->ctx);

-       ixd_ctlq_clean_sq(adapter, 1);
        libie_ctlq_release_rx_buf(recv_mem);

        return err;


[0] https://sashiko.dev/#/patchset/20260515224443.2772147-1-anthony.l.nguyen%40intel.com

> Co-developed-by: Amritha Nambiar <amritha.nambiar@intel.com>
> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
> Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
> Tested-by: Bharath R <Bharath.r@intel.com>
> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
> ---
>  drivers/net/ethernet/intel/ixd/Makefile       |   2 +
>  drivers/net/ethernet/intel/ixd/ixd.h          |  10 +
>  drivers/net/ethernet/intel/ixd/ixd_ctlq.c     | 149 +++++++++++++++
>  drivers/net/ethernet/intel/ixd/ixd_ctlq.h     |  33 ++++
>  drivers/net/ethernet/intel/ixd/ixd_lib.c      |  25 ++-
>  drivers/net/ethernet/intel/ixd/ixd_main.c     |   3 +
>  drivers/net/ethernet/intel/ixd/ixd_virtchnl.c | 178 ++++++++++++++++++
>  drivers/net/ethernet/intel/ixd/ixd_virtchnl.h |  12 ++
>  8 files changed, 411 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd_ctlq.c
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd_ctlq.h
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd_virtchnl.c
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd_virtchnl.h
> 
> diff --git a/drivers/net/ethernet/intel/ixd/Makefile b/drivers/net/ethernet/intel/ixd/Makefile
> index 164b2c86952f..90abf231fb16 100644
> --- a/drivers/net/ethernet/intel/ixd/Makefile
> +++ b/drivers/net/ethernet/intel/ixd/Makefile
> @@ -6,5 +6,7 @@
>  obj-$(CONFIG_IXD) += ixd.o
>  
>  ixd-y := ixd_main.o
> +ixd-y += ixd_ctlq.o
>  ixd-y += ixd_dev.o
>  ixd-y += ixd_lib.o
> +ixd-y += ixd_virtchnl.o
> diff --git a/drivers/net/ethernet/intel/ixd/ixd.h b/drivers/net/ethernet/intel/ixd/ixd.h
> index 99c44f2aa659..98d1f22534b5 100644
> --- a/drivers/net/ethernet/intel/ixd/ixd.h
> +++ b/drivers/net/ethernet/intel/ixd/ixd.h
> @@ -10,19 +10,29 @@
>   * struct ixd_adapter - Data structure representing a CPF
>   * @cp_ctx: Control plane communication context
>   * @init_task: Delayed initialization after reset
> + * @mbx_task: Control queue Rx handling
>   * @xnm: virtchnl transaction manager
>   * @asq: Send control queue info
>   * @arq: Receive control queue info
> + * @vc_ver: Negotiated virtchnl version
> + * @caps: Negotiated virtchnl capabilities
>   */
>  struct ixd_adapter {
>  	struct libie_ctlq_ctx cp_ctx;
>  	struct {
>  		struct delayed_work init_work;
>  		u8 reset_retries;
> +		u8 vc_retries;
>  	} init_task;
> +	struct delayed_work mbx_task;
>  	struct libie_ctlq_xn_manager *xnm;
>  	struct libie_ctlq_info *asq;
>  	struct libie_ctlq_info *arq;
> +	struct {
> +		u32 major;
> +		u32 minor;
> +	} vc_ver;
> +	struct virtchnl2_get_capabilities caps;
>  };
>  
>  /**
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_ctlq.c b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
> new file mode 100644
> index 000000000000..216aa5c02122
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
> @@ -0,0 +1,149 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright (C) 2025 Intel Corporation */
> +
> +#include "ixd.h"
> +#include "ixd_ctlq.h"
> +#include "ixd_virtchnl.h"
> +
> +/**
> + * ixd_ctlq_clean_sq - Clean the send control queue after sending the message
> + * @adapter: The adapter that sent the messages
> + * @num_sent: Number of sent messages to be released
> + *
> + * Free the libie send resources after sending the message and handling
> + * the response.
> + */
> +static void ixd_ctlq_clean_sq(struct ixd_adapter *adapter, u16 num_sent)
> +{
> +	if (!num_sent)
> +		return;
> +
> +	struct libie_ctlq_xn_clean_params params = {
> +		.ctlq = adapter->asq,
> +		.ctx = &adapter->cp_ctx,
> +		.num_msgs = num_sent,
> +		.rel_tx_buf = kfree,
> +	};
> +
> +	libie_ctlq_xn_send_clean(&params);
> +}
> +
> +/**
> + * ixd_ctlq_init_sparams - Initialize control queue send parameters
> + * @adapter: The adapter with initialized mailbox
> + * @sparams: Parameters to initialize
> + * @msg_buf: DMA-mappable pointer to the message being sent
> + * @msg_size: Message size
> + */
> +static void ixd_ctlq_init_sparams(struct ixd_adapter *adapter,
> +				  struct libie_ctlq_xn_send_params *sparams,
> +				  void *msg_buf, size_t msg_size)
> +{
> +	*sparams = (struct libie_ctlq_xn_send_params) {
> +		.rel_tx_buf = kfree,
> +		.xnm = adapter->xnm,
> +		.ctlq = adapter->asq,
> +		.timeout_ms = IXD_CTLQ_TIMEOUT,
> +		.send_buf = (struct kvec) {
> +			.iov_base = msg_buf,
> +			.iov_len = msg_size,
> +		},
> +	};
> +}
> +
> +/**
> + * ixd_ctlq_do_req - Perform a standard virtchnl request
> + * @adapter: The adapter with initialized mailbox
> + * @req: virtchnl request description
> + *
> + * Return: %0 if a message was sent and received a response
> + * that was successfully handled by the custom callback,
> + * negative error otherwise.
> + */
> +int ixd_ctlq_do_req(struct ixd_adapter *adapter, const struct ixd_ctlq_req *req)
> +{
> +	struct libie_ctlq_xn_send_params send_params = {};
> +	u8 onstack_send_buff[LIBIE_CP_TX_COPYBREAK] = {};
> +	struct kvec *recv_mem;
> +	void *send_buff;
> +	int err;
> +
> +	send_buff = libie_cp_can_send_onstack(req->send_size) ?
> +		    &onstack_send_buff : kzalloc(req->send_size, GFP_KERNEL);
> +	if (!send_buff)
> +		return -ENOMEM;
> +
> +	ixd_ctlq_init_sparams(adapter, &send_params, send_buff,
> +			      req->send_size);
> +
> +	send_params.chnl_opcode = req->opcode;
> +
> +	if (req->send_buff_init)
> +		req->send_buff_init(adapter, send_buff, req->ctx);
> +
> +	err = libie_ctlq_xn_send(&send_params);
> +	if (err)
> +		return err;
> +
> +	recv_mem = &send_params.recv_mem;
> +	if (req->recv_process)
> +		err = req->recv_process(adapter, recv_mem->iov_base,
> +					recv_mem->iov_len, req->ctx);
> +
> +	ixd_ctlq_clean_sq(adapter, 1);
> +	libie_ctlq_release_rx_buf(recv_mem);
> +
> +	return err;
> +}
> +
> +/**
> + * ixd_ctlq_handle_msg - Default control queue message handler
> + * @ctx: Control plane communication context
> + * @msg: Message received
> + */
> +static void ixd_ctlq_handle_msg(struct libie_ctlq_ctx *ctx,
> +				struct libie_ctlq_msg *msg)
> +{
> +	struct ixd_adapter *adapter = pci_get_drvdata(ctx->mmio_info.pdev);
> +
> +	if (ixd_vc_can_handle_msg(msg))
> +		ixd_vc_recv_event_msg(adapter, msg);
> +	else
> +		dev_dbg_ratelimited(ixd_to_dev(adapter),
> +				    "Received an unsupported opcode 0x%x from the CP\n",
> +				    msg->chnl_opcode);
> +
> +	libie_ctlq_release_rx_buf(&msg->recv_mem);
> +}
> +
> +/**
> + * ixd_ctlq_recv_mb_msg - Receive a potential message over mailbox periodically
> + * @adapter: The adapter with initialized mailbox
> + */
> +static void ixd_ctlq_recv_mb_msg(struct ixd_adapter *adapter)
> +{
> +	struct libie_ctlq_xn_recv_params xn_params = {
> +		.xnm = adapter->xnm,
> +		.ctlq = adapter->arq,
> +		.ctlq_msg_handler = ixd_ctlq_handle_msg,
> +		.budget = LIBIE_CTLQ_MAX_XN_ENTRIES,
> +	};
> +
> +	libie_ctlq_xn_recv(&xn_params);
> +}
> +
> +/**
> + * ixd_ctlq_rx_task - Periodically check for mailbox responses and events
> + * @work: work handle
> + */
> +void ixd_ctlq_rx_task(struct work_struct *work)
> +{
> +	struct ixd_adapter *adapter;
> +
> +	adapter = container_of(work, struct ixd_adapter, mbx_task.work);
> +
> +	queue_delayed_work(system_unbound_wq, &adapter->mbx_task,
> +			   msecs_to_jiffies(300));
> +
> +	ixd_ctlq_recv_mb_msg(adapter);
> +}
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_ctlq.h b/drivers/net/ethernet/intel/ixd/ixd_ctlq.h
> new file mode 100644
> index 000000000000..e7191d3870b7
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd_ctlq.h
> @@ -0,0 +1,33 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/* Copyright (C) 2025 Intel Corporation */
> +
> +#ifndef _IXD_CTLQ_H_
> +#define _IXD_CTLQ_H_
> +
> +#include <linux/intel/virtchnl2.h>
> +
> +#define IXD_CTLQ_TIMEOUT 2000
> +
> +/**
> + * struct ixd_ctlq_req - Standard virtchnl request description
> + * @opcode: protocol opcode, only virtchnl2 is needed for now
> + * @send_size: required length of the send buffer
> + * @send_buff_init: function to initialize the allocated send buffer
> + * @recv_process: function to handle the CP response
> + * @ctx: additional context for callbacks
> + */
> +struct ixd_ctlq_req {
> +	enum virtchnl2_op opcode;
> +	size_t send_size;
> +	void (*send_buff_init)(struct ixd_adapter *adapter, void *send_buff,
> +			       void *ctx);
> +	int (*recv_process)(struct ixd_adapter *adapter, void *recv_buff,
> +			    size_t recv_size, void *ctx);
> +	void *ctx;
> +};
> +
> +int ixd_ctlq_do_req(struct ixd_adapter *adapter,
> +		    const struct ixd_ctlq_req *req);
> +void ixd_ctlq_rx_task(struct work_struct *work);
> +
> +#endif /* _IXD_CTLQ_H_ */
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_lib.c b/drivers/net/ethernet/intel/ixd/ixd_lib.c
> index afc413d3650f..24080cb30c43 100644
> --- a/drivers/net/ethernet/intel/ixd/ixd_lib.c
> +++ b/drivers/net/ethernet/intel/ixd/ixd_lib.c
> @@ -2,6 +2,7 @@
>  /* Copyright (C) 2025 Intel Corporation */
>  
>  #include "ixd.h"
> +#include "ixd_virtchnl.h"
>  
>  #define IXD_DFLT_MBX_Q_LEN 64
>  
> @@ -67,6 +68,8 @@ static void ixd_adapter_fill_dflt_ctlqs(struct ixd_adapter *adapter)
>   */
>  void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter)
>  {
> +	cancel_delayed_work_sync(&adapter->mbx_task);
> +
>  	if (adapter->xnm)
>  		libie_ctlq_xn_deinit(adapter->xnm, &adapter->cp_ctx);
>  
> @@ -108,6 +111,8 @@ int ixd_init_dflt_mbx(struct ixd_adapter *adapter)
>  		return -ENOENT;
>  	}
>  
> +	queue_delayed_work(system_unbound_wq, &adapter->mbx_task, 0);
> +
>  	return 0;
>  }
>  
> @@ -136,8 +141,26 @@ void ixd_init_task(struct work_struct *work)
>  
>  	adapter->init_task.reset_retries = 0;
>  	err = ixd_init_dflt_mbx(adapter);
> -	if (err)
> +	if (err) {
>  		dev_err(ixd_to_dev(adapter),
>  			"Failed to initialize the default mailbox: %pe\n",
>  			ERR_PTR(err));
> +		return;
> +	}
> +
> +	if (!ixd_vc_dev_init(adapter)) {
> +		adapter->init_task.vc_retries = 0;
> +		return;
> +	}
> +
> +	ixd_deinit_dflt_mbx(adapter);
> +	if (++adapter->init_task.vc_retries > 5) {
> +		dev_err(ixd_to_dev(adapter),
> +			"Failed to establish mailbox communications with the hardware\n");
> +		return;
> +	}
> +
> +	ixd_trigger_reset(adapter);
> +	queue_delayed_work(system_unbound_wq, &adapter->init_task.init_work,
> +			   msecs_to_jiffies(500));
>  }
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_main.c b/drivers/net/ethernet/intel/ixd/ixd_main.c
> index b4d4000b63ed..6d5e6aca77df 100644
> --- a/drivers/net/ethernet/intel/ixd/ixd_main.c
> +++ b/drivers/net/ethernet/intel/ixd/ixd_main.c
> @@ -2,6 +2,7 @@
>  /* Copyright (C) 2025 Intel Corporation */
>  
>  #include "ixd.h"
> +#include "ixd_ctlq.h"
>  #include "ixd_lan_regs.h"
>  
>  MODULE_DESCRIPTION("Intel(R) Control Plane Function Device Driver");
> @@ -19,6 +20,7 @@ static void ixd_remove(struct pci_dev *pdev)
>  
>  	/* Do not mix removal with (re)initialization */
>  	cancel_delayed_work_sync(&adapter->init_task.init_work);
> +
>  	/* Leave the device clean on exit */
>  	ixd_trigger_reset(adapter);
>  	ixd_deinit_dflt_mbx(adapter);
> @@ -110,6 +112,7 @@ static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>  
>  	INIT_DELAYED_WORK(&adapter->init_task.init_work,
>  			  ixd_init_task);
> +	INIT_DELAYED_WORK(&adapter->mbx_task, ixd_ctlq_rx_task);
>  
>  	ixd_trigger_reset(adapter);
>  	queue_delayed_work(system_unbound_wq, &adapter->init_task.init_work,
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c
> new file mode 100644
> index 000000000000..66049d1b1d15
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c
> @@ -0,0 +1,178 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright (C) 2025 Intel Corporation */
> +
> +#include "ixd.h"
> +#include "ixd_ctlq.h"
> +#include "ixd_virtchnl.h"
> +
> +/**
> + * ixd_vc_recv_event_msg - Handle virtchnl event message
> + * @adapter: The adapter handling the message
> + * @ctlq_msg: Message received
> + */
> +void ixd_vc_recv_event_msg(struct ixd_adapter *adapter,
> +			   struct libie_ctlq_msg *ctlq_msg)
> +{
> +	int payload_size = ctlq_msg->data_len;
> +	struct virtchnl2_event *v2e;
> +
> +	if (payload_size < sizeof(*v2e)) {
> +		dev_warn_ratelimited(ixd_to_dev(adapter),
> +				     "Failed to receive valid payload for event msg (op 0x%X len %u)\n",
> +				     ctlq_msg->chnl_opcode,
> +				     payload_size);
> +		return;
> +	}
> +
> +	v2e = (struct virtchnl2_event *)ctlq_msg->recv_mem.iov_base;
> +
> +	dev_dbg(ixd_to_dev(adapter), "Got event 0x%X from the CP\n",
> +		le32_to_cpu(v2e->event));
> +}
> +
> +/**
> + * ixd_vc_can_handle_msg - Decide if an event has to be handled by virtchnl code
> + * @ctlq_msg: Message received
> + *
> + * Return: %true if virtchnl code can handle the event, %false otherwise
> + */
> +bool ixd_vc_can_handle_msg(struct libie_ctlq_msg *ctlq_msg)
> +{
> +	return ctlq_msg->chnl_opcode == VIRTCHNL2_OP_EVENT;
> +}
> +
> +/**
> + * ixd_handle_caps - Handle VIRTCHNL2_OP_GET_CAPS response
> + * @adapter: The adapter for which the capabilities are being updated
> + * @recv_buff: Buffer containing the response
> + * @recv_size: Response buffer size
> + * @ctx: unused
> + *
> + * Return: %0 if the response format is correct and was handled as expected,
> + * negative error otherwise.
> + */
> +static int ixd_handle_caps(struct ixd_adapter *adapter, void *recv_buff,
> +			   size_t recv_size, void *ctx)
> +{
> +	if (recv_size < sizeof(adapter->caps))
> +		return -EBADMSG;
> +
> +	adapter->caps = *(typeof(adapter->caps) *)recv_buff;
> +
> +	return 0;
> +}
> +
> +/**
> + * ixd_req_vc_caps - Request and save device capability
> + * @adapter: The adapter to get the capabilities for
> + *
> + * Return: success or error if sending the get capability message fails
> + */
> +static int ixd_req_vc_caps(struct ixd_adapter *adapter)
> +{
> +	const struct ixd_ctlq_req req = {
> +		.opcode = VIRTCHNL2_OP_GET_CAPS,
> +		.send_size = sizeof(struct virtchnl2_get_capabilities),
> +		.ctx = NULL,
> +		.send_buff_init = NULL,
> +		.recv_process = ixd_handle_caps,
> +	};
> +
> +	return ixd_ctlq_do_req(adapter, &req);
> +}
> +
> +/**
> + * ixd_get_vc_ver - Get version info from adapter
> + *
> + * Return: filled in virtchannel2 version info, ready for sending
> + */
> +static struct virtchnl2_version_info ixd_get_vc_ver(void)
> +{
> +	return (struct virtchnl2_version_info) {
> +		.major = cpu_to_le32(VIRTCHNL2_VERSION_MAJOR_2),
> +		.minor = cpu_to_le32(VIRTCHNL2_VERSION_MINOR_0),
> +	};
> +}
> +
> +static void ixd_fill_vc_ver(struct ixd_adapter *adapter, void *send_buff,
> +			    void *ctx)
> +{
> +	*(struct virtchnl2_version_info *)send_buff = ixd_get_vc_ver();
> +}
> +
> +/**
> + * ixd_handle_vc_ver - Handle VIRTCHNL2_OP_VERSION response
> + * @adapter: The adapter for which the version is being updated
> + * @recv_buff: Buffer containing the response
> + * @recv_size: Response buffer size
> + * @ctx: Unused
> + *
> + * Return: %0 if the response format is correct and was handled as expected,
> + * negative error otherwise.
> + */
> +static int ixd_handle_vc_ver(struct ixd_adapter *adapter, void *recv_buff,
> +			     size_t recv_size, void *ctx)
> +{
> +	struct virtchnl2_version_info need_ver = ixd_get_vc_ver();
> +	struct virtchnl2_version_info *recv_ver;
> +
> +	if (recv_size < sizeof(need_ver))
> +		return -EBADMSG;
> +
> +	recv_ver = recv_buff;
> +	if (le32_to_cpu(need_ver.major) > le32_to_cpu(recv_ver->major))
> +		return -EOPNOTSUPP;
> +
> +	adapter->vc_ver.major = le32_to_cpu(recv_ver->major);
> +	adapter->vc_ver.minor = le32_to_cpu(recv_ver->minor);
> +
> +	return 0;
> +}
> +
> +/**
> + * ixd_req_vc_version - Request and save Virtchannel2 version
> + * @adapter: The adapter to get the version for
> + *
> + * Return: success or error if sending fails or the response was not as expected
> + */
> +static int ixd_req_vc_version(struct ixd_adapter *adapter)
> +{
> +	const struct ixd_ctlq_req req = {
> +		.opcode = VIRTCHNL2_OP_VERSION,
> +		.send_size = sizeof(struct virtchnl2_version_info),
> +		.ctx = NULL,
> +		.send_buff_init = ixd_fill_vc_ver,
> +		.recv_process = ixd_handle_vc_ver,
> +	};
> +
> +	return ixd_ctlq_do_req(adapter, &req);
> +}
> +
> +/**
> + * ixd_vc_dev_init - virtchnl device core initialization
> + * @adapter: device information
> + *
> + * Return: %0 on success or error if any step of the initialization fails
> + */
> +int ixd_vc_dev_init(struct ixd_adapter *adapter)
> +{
> +	int err;
> +
> +	err = ixd_req_vc_version(adapter);
> +	if (err) {
> +		dev_warn(ixd_to_dev(adapter),
> +			 "Getting virtchnl version failed, error=%pe\n",
> +			 ERR_PTR(err));
> +		return err;
> +	}
> +
> +	err = ixd_req_vc_caps(adapter);
> +	if (err) {
> +		dev_warn(ixd_to_dev(adapter),
> +			 "Getting virtchnl capabilities failed, error=%pe\n",
> +			 ERR_PTR(err));
> +		return err;
> +	}
> +
> +	return err;
> +}
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_virtchnl.h b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.h
> new file mode 100644
> index 000000000000..1a53da8b545c
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/* Copyright (C) 2025 Intel Corporation */
> +
> +#ifndef _IXD_VIRTCHNL_H_
> +#define _IXD_VIRTCHNL_H_
> +
> +int ixd_vc_dev_init(struct ixd_adapter *adapter);
> +bool ixd_vc_can_handle_msg(struct libie_ctlq_msg *ctlq_msg);
> +void ixd_vc_recv_event_msg(struct ixd_adapter *adapter,
> +			   struct libie_ctlq_msg *ctlq_msg);
> +
> +#endif /* _IXD_VIRTCHNL_H_ */
> -- 
> 2.47.1
> 

^ permalink raw reply related

* Re: [PATCH v6 03/11] dt-bindings: mfd: add documentation for S2MU005 PMIC
From: Conor Dooley @ 2026-05-18  9:45 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Kaustabh Chakraborty, Lee Jones, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, MyungJoo Ham, Chanwoo Choi,
	Sebastian Reichel, André Draszik, Alexandre Belloni,
	Jonathan Corbet, Shuah Khan, Nam Tran,
	Łukasz Lebiedziński, linux-leds, devicetree,
	linux-kernel, linux-pm, linux-samsung-soc, linux-rtc, linux-doc
In-Reply-To: <d2f4cb7d-5c3e-4b9a-86ca-04262cbb9775@kernel.org>

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

On Mon, May 18, 2026 at 09:15:11AM +0200, Krzysztof Kozlowski wrote:
> On 17/05/2026 22:52, Conor Dooley wrote:
> > On Sun, May 17, 2026 at 06:39:37PM +0530, Kaustabh Chakraborty wrote:
> >>>>>>> +
> >>>>>> +    properties:
> >>>>>> +      compatible:
> >>>>>> +        const: samsung,s2mu005-rgb
> >>>>>> +
> >>>>>> +    required:
> >>>>>> +      - compatible
> >>>>>> +
> >>>>>> +    unevaluatedProperties: false
> >>>>>> +
> >>>>>> +  reg:
> >>>>>> +    maxItems: 1
> >>>>>
> >>>>> Move this above the child nodes please.
> >>>>
> >>>> But properties are sorted in lex order?
> >>>
> >>> Typically the binding is sorted in the same order as properties go in
> >>> nodes. Common stuff like reg/clocks/interrupts therefore send up above
> >>> child nodes.
> >>
> >> So, do I change this? For one, I don't see the same being followed in
> >> other schemas of samsung in the same dir (not that I'm trying to pose it
> >> as an argument against your suggestion), and this was reviewed by
> >> Krzysztof and is adderssed in v7.
> > 
> > If Krzysztof doesn't care, then I won't ask you to change it.
> 
> This builds on top of bindings for previous Samsung PMIC devices, so
> that's why it keeps the compatibles for children, I guess. No one
> complained about this at v1-v2 reviews, so when I joined reviewing in v3
> I did not, either.
> 
> I don't think the compatible should be here, but I also don't want to
> stall that patchset. I understand that it is inconsistent review from my
> side, because other similar patchsets receive comment to drop the
> compatible. But I don't think we will be fair asking to drop the
> compatible now, when we did not ask for that in the early versions at all.


I think you misunderstood, we were talking about the ordering of the
properties in the binding file being alphanumerical, rather than the
more typical approach of approximately following the order of
dts-coding-style.

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

^ permalink raw reply

* Re: [PATCH] nios2: remove the architecture
From: Arnd Bergmann @ 2026-05-18  9:29 UTC (permalink / raw)
  To: Ethan Nelson-Moore, linux-doc, devicetree, workflows, Linux-Arch,
	dmaengine, linux-i2c, linux-iio, Netdev, linux-pci, linux-pwm,
	linux-hardening, linux-kbuild, linux-csky@vger.kernel.org
  Cc: Jonathan Corbet, Shuah Khan, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Daniel Lezcano, Thomas Gleixner, Alex Shi,
	Yanteng Si, Dongliang Mu, Hu Haowen, Dinh Nguyen, Kees Cook,
	Oleg Nesterov, Will Deacon, Aneesh Kumar K.V (Arm), Andrew Morton,
	Nicholas Piggin, Peter Zijlstra, Vinod Koul, Frank Li,
	Dave Penkler, Andi Shyti, Jonathan Cameron, David Lechner,
	Nuno Sá, Andy Shevchenko, Andrew Lunn, David S . Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Simon Schuster, Andreas Oetken
In-Reply-To: <20260518042833.272221-1-enelsonmoore@gmail.com>

On Mon, May 18, 2026, at 06:28, Ethan Nelson-Moore wrote:
> The Nios II architecture is a soft-core architecture developed by
> Altera (since acquired by Intel) and intended to run on their FPGAs.
>
> Licenses for the architecture have not been available for purchase
> since 2024 [1], and support for it has been removed from GCC 15 [2],
> Buildroot [3], and QEMU [4].
>
> Given all of these factors, it is time to remove Nios II support from
> the kernel. The maintainer stated in 2024 that they were planning to do
> so soon [5], but this did not come to pass.
>
> Remove Nios II support from the kernel and move the former maintainer
> to CREDITS. Thank you, Dinh Nguyen, for maintaining Nios II support!

Hi Ethan,

We last discussed this a year ago when Simon Schuster mentioned[1]
that Siemens Energy is still using NIOS-2 in production and would
prefer to have this still included in Linux for at least another
few years until the obligation for kernel updates ends.

My feeling is that the maintenance burden of keeping nios2 is
relatively low. On the other hand, maintaining it out of tree
as a patch set is also something that should not be all that
hard if it does get removed.

Simon mentioned that he expected others to also use nios2 with
new kernels, but I have not heard from anyone else actually
doing it.

I've added Simon and Andreas to Cc here to let them comment
more here.

     Arnd

[1] https://sourceware.org/pipermail/binutils/2025-March/140140.html

^ permalink raw reply

* [PATCH] docs: dt: maintainer: Add Devicetree and OF maintainer profile document
From: Krzysztof Kozlowski @ 2026-05-18  9:19 UTC (permalink / raw)
  To: Jonathan Corbet, Shuah Khan, workflows, linux-doc, linux-kernel
  Cc: Krzysztof Kozlowski, Rob Herring, Conor Dooley, Saravana Kannan,
	devicetree

Document how Devicetree and Open Firmware maintainers handle their
subsystem, especially focusing on two caveats:

Devicetree subsystem handles patches with a minor difference comparing
to other subsystems: while DT maintainers pick up OF code, they only
provide review of DT bindings without applying these.

All three DT bindings maintainers rely currently on Patchwork and due to
enormous amount of emails per day, regardless how much DT maintainers
try, they cannot read all the emails.

Cc: Rob Herring <robh@kernel.org>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Saravana Kannan <saravanak@kernel.org>
Cc: devicetree@vger.kernel.org
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

---

I expect patch to be picked up by Rob, after review.
---
 .../process/maintainer-devicetree.rst         | 70 +++++++++++++++++++
 MAINTAINERS                                   |  2 +
 2 files changed, 72 insertions(+)
 create mode 100644 Documentation/process/maintainer-devicetree.rst

diff --git a/Documentation/process/maintainer-devicetree.rst b/Documentation/process/maintainer-devicetree.rst
new file mode 100644
index 000000000000..331701bb2282
--- /dev/null
+++ b/Documentation/process/maintainer-devicetree.rst
@@ -0,0 +1,70 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================================
+Devicetree and Open Firmware Subsystem
+======================================
+
+Other Process Documents
+-----------------------
+
+Please see the documents in Documentation/devicetree/bindings/ for information
+on how to write proper Devicetree bindings and how to submit patches.
+
+Patch Review and Handling
+-------------------------
+
+Patches handled by Devicetree maintainers are processed differently depending
+on the patch type:
+
+1. Core OF driver code, e.g. drivers/of/:
+   patches are reviewed and applied by DT maintainers.
+
+2. Devicetree bindings:
+   patches are reviewed by DT maintainers but, except in certain cases, should
+   be applied by subsystem maintainers.  See also *For kernel maintainers* in
+   Documentation/devicetree/bindings/submitting-patches.rst.
+   
+3. DTS and drivers:
+   DT maintainers might provide comments, but review is generally not expected.
+
+Pachwork
+~~~~~~~~
+
+Devicetree maintainers review patches using Patchwork, so the current status of
+a patch can be checked there. For typical driver submissions, Patchwork
+receives the entire patch set, but only a few patches are usually Devicetree
+bindings that are reviewed by DT maintainers.
+
+Explanation of Patchwork statutes:
+
+ - **New**: Not yet processed by the automation toolset.
+ - **Needs ACK**: Waiting for review by DT maintainers.
+ - **Handled Elsewhere**: Non-DT patch; not being reviewed here.
+ - **RFC**: Patch was likely ignored because it was an incomplete RFC.
+ - **Changes Requested**: Patch was reviewed and DT maintainers expect changes.
+ - **Accepted**: Patch was reviewed and applied by DT maintainers to their tree.
+ - **Not Applicable**: Patch was reviewed and is likely in good shape, with a
+   *Reviewed-by* or *Acked-by* tag provided, but DT maintainers expect someone
+   else to apply it.
+
+Patch Re-review and Pinging
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Due to the high volume of email traffic, Devicetree maintainers do not read
+every email they receive and instead rely on Patchwork during the review
+process. They also often skip patches that have already been reviewed.
+
+As a result, maintainers might miss:
+
+1. Questions about already reviewed patches.
+2. Pings, for example when a patch has been reviewed by DT maintainers but has
+   not been picked up by subsystem maintainers.
+
+Such cases can be addressed by:
+
+1. Pinging DT maintainers on the IRC channel.
+2. Dropping the DT maintainer’s *Acked-by* or *Reviewed-by* tag when sending a new
+   version of the patch set, together with an explanation in the patch
+   changelog describing why the tag was removed and what is expected from DT
+   maintainers.
+
diff --git a/MAINTAINERS b/MAINTAINERS
index f877e5aaf2c7..c4929de50ab7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20050,6 +20050,7 @@ S:	Maintained
 Q:	http://patchwork.kernel.org/project/devicetree/list/
 W:	http://www.devicetree.org/
 C:	irc://irc.libera.chat/devicetree
+P:	Documentation/process/maintainer-devicetree.rst
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
 F:	Documentation/ABI/testing/sysfs-firmware-ofw
 F:	drivers/of/
@@ -20070,6 +20071,7 @@ M:	Conor Dooley <conor+dt@kernel.org>
 L:	devicetree@vger.kernel.org
 S:	Maintained
 Q:	http://patchwork.kernel.org/project/devicetree/list/
+P:	Documentation/process/maintainer-devicetree.rst
 C:	irc://irc.libera.chat/devicetree
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
 F:	Documentation/devicetree/
-- 
2.51.0


^ permalink raw reply related

* Re: [PATCH net-next v3 12/14] ixd: add reset checks and initialize the mailbox
From: Larysa Zaremba @ 2026-05-18  9:12 UTC (permalink / raw)
  To: Tony Nguyen
  Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
	przemyslaw.kitszel, aleksander.lobakin, sridhar.samudrala,
	anjali.singhai, michal.swiatkowski, maciej.fijalkowski,
	emil.s.tantilov, madhu.chittim, joshua.a.hay, jacob.e.keller,
	jayaprakash.shanmugam, jiri, horms, corbet, richardcochran,
	linux-doc, Aleksandr Loktionov, Bharath R
In-Reply-To: <20260515224443.2772147-13-anthony.l.nguyen@intel.com>

On Fri, May 15, 2026 at 03:44:36PM -0700, Tony Nguyen wrote:
> From: Larysa Zaremba <larysa.zaremba@intel.com>
> 
> At the end of the probe, trigger hard reset, initialize and schedule the
> after-reset task. If the reset is complete in a pre-determined time,
> initialize the default mailbox, through which other resources will be
> negotiated.

Sashiko says [0]:

"
Does this teardown sequence properly ensure the hardware is quiescent before
freeing its DMA memory?
Looking at ixd_trigger_reset(), it performs a writel(), which is a posted
write over PCIe.
The code here does not flush this write with a dummy read, nor does it
wait for the reset to complete by polling ixd_check_reset_complete().
Since ixd_deinit_dflt_mbx() immediately proceeds to free the DMA memory
via libie_ctlq_xn_deinit(), could the hardware continue executing DMA
operations into the freed memory, potentially causing IOMMU faults or memory
corruption?
"

Reset flow is consistent with what pre-refactor idpf does, and is the intended 
way to perform removal.

[0] https://sashiko.dev/#/patchset/20260515224443.2772147-1-anthony.l.nguyen%40intel.com

> 
> Co-developed-by: Amritha Nambiar <amritha.nambiar@intel.com>
> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
> Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Tested-by: Bharath R <Bharath.r@intel.com>
> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
> ---
>  drivers/net/ethernet/intel/ixd/Kconfig        |   1 +
>  drivers/net/ethernet/intel/ixd/Makefile       |   2 +
>  drivers/net/ethernet/intel/ixd/ixd.h          |  28 +++-
>  drivers/net/ethernet/intel/ixd/ixd_dev.c      |  89 +++++++++++
>  drivers/net/ethernet/intel/ixd/ixd_lan_regs.h |  40 +++++
>  drivers/net/ethernet/intel/ixd/ixd_lib.c      | 143 ++++++++++++++++++
>  drivers/net/ethernet/intel/ixd/ixd_main.c     |  32 +++-
>  7 files changed, 326 insertions(+), 9 deletions(-)
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd_dev.c
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd_lib.c
> 
> diff --git a/drivers/net/ethernet/intel/ixd/Kconfig b/drivers/net/ethernet/intel/ixd/Kconfig
> index f5594efe292c..24510c50070e 100644
> --- a/drivers/net/ethernet/intel/ixd/Kconfig
> +++ b/drivers/net/ethernet/intel/ixd/Kconfig
> @@ -5,6 +5,7 @@ config IXD
>  	tristate "Intel(R) Control Plane Function Support"
>  	depends on PCI_MSI
>  	select LIBETH
> +	select LIBIE_CP
>  	select LIBIE_PCI
>  	help
>  	  This driver supports Intel(R) Control Plane PCI Function
> diff --git a/drivers/net/ethernet/intel/ixd/Makefile b/drivers/net/ethernet/intel/ixd/Makefile
> index 3849bc240600..164b2c86952f 100644
> --- a/drivers/net/ethernet/intel/ixd/Makefile
> +++ b/drivers/net/ethernet/intel/ixd/Makefile
> @@ -6,3 +6,5 @@
>  obj-$(CONFIG_IXD) += ixd.o
>  
>  ixd-y := ixd_main.o
> +ixd-y += ixd_dev.o
> +ixd-y += ixd_lib.o
> diff --git a/drivers/net/ethernet/intel/ixd/ixd.h b/drivers/net/ethernet/intel/ixd/ixd.h
> index d813c27941a5..99c44f2aa659 100644
> --- a/drivers/net/ethernet/intel/ixd/ixd.h
> +++ b/drivers/net/ethernet/intel/ixd/ixd.h
> @@ -4,14 +4,25 @@
>  #ifndef _IXD_H_
>  #define _IXD_H_
>  
> -#include <linux/intel/libie/pci.h>
> +#include <linux/intel/libie/controlq.h>
>  
>  /**
>   * struct ixd_adapter - Data structure representing a CPF
> - * @hw: Device access data
> + * @cp_ctx: Control plane communication context
> + * @init_task: Delayed initialization after reset
> + * @xnm: virtchnl transaction manager
> + * @asq: Send control queue info
> + * @arq: Receive control queue info
>   */
>  struct ixd_adapter {
> -	struct libie_mmio_info hw;
> +	struct libie_ctlq_ctx cp_ctx;
> +	struct {
> +		struct delayed_work init_work;
> +		u8 reset_retries;
> +	} init_task;
> +	struct libie_ctlq_xn_manager *xnm;
> +	struct libie_ctlq_info *asq;
> +	struct libie_ctlq_info *arq;
>  };
>  
>  /**
> @@ -22,7 +33,16 @@ struct ixd_adapter {
>   */
>  static inline struct device *ixd_to_dev(struct ixd_adapter *adapter)
>  {
> -	return &adapter->hw.pdev->dev;
> +	return &adapter->cp_ctx.mmio_info.pdev->dev;
>  }
>  
> +void ixd_ctlq_reg_init(struct ixd_adapter *adapter,
> +		       struct libie_ctlq_reg *ctlq_reg_tx,
> +		       struct libie_ctlq_reg *ctlq_reg_rx);
> +void ixd_trigger_reset(struct ixd_adapter *adapter);
> +bool ixd_check_reset_complete(struct ixd_adapter *adapter);
> +void ixd_init_task(struct work_struct *work);
> +int ixd_init_dflt_mbx(struct ixd_adapter *adapter);
> +void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter);
> +
>  #endif /* _IXD_H_ */
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_dev.c b/drivers/net/ethernet/intel/ixd/ixd_dev.c
> new file mode 100644
> index 000000000000..cdd5477cc1f4
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd_dev.c
> @@ -0,0 +1,89 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright (C) 2025 Intel Corporation */
> +
> +#include "ixd.h"
> +#include "ixd_lan_regs.h"
> +
> +/**
> + * ixd_ctlq_reg_init - Initialize default mailbox registers
> + * @adapter: PCI device driver-specific private data
> + * @ctlq_reg_tx: Transmit queue registers info to be filled
> + * @ctlq_reg_rx: Receive queue registers info to be filled
> + */
> +void ixd_ctlq_reg_init(struct ixd_adapter *adapter,
> +		       struct libie_ctlq_reg *ctlq_reg_tx,
> +		       struct libie_ctlq_reg *ctlq_reg_rx)
> +{
> +	struct libie_mmio_info *mmio_info = &adapter->cp_ctx.mmio_info;
> +	*ctlq_reg_tx = (struct libie_ctlq_reg) {
> +		.head = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQH),
> +		.tail = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQT),
> +		.len = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQLEN),
> +		.addr_high = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQBAH),
> +		.addr_low = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQBAL),
> +		.len_mask = PF_FW_ATQLEN_ATQLEN_M,
> +		.len_ena_mask = PF_FW_ATQLEN_ATQENABLE_M,
> +		.head_mask = PF_FW_ATQH_ATQH_M,
> +	};
> +
> +	*ctlq_reg_rx = (struct libie_ctlq_reg) {
> +		.head = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQH),
> +		.tail = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQT),
> +		.len = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQLEN),
> +		.addr_high = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQBAH),
> +		.addr_low = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQBAL),
> +		.len_mask = PF_FW_ARQLEN_ARQLEN_M,
> +		.len_ena_mask = PF_FW_ARQLEN_ARQENABLE_M,
> +		.head_mask = PF_FW_ARQH_ARQH_M,
> +	};
> +}
> +
> +static const struct ixd_reset_reg ixd_reset_reg = {
> +	.rstat  = PFGEN_RSTAT,
> +	.rstat_m = PFGEN_RSTAT_PFR_STATE_M,
> +	.rstat_ok_v = 0b01,
> +	.rtrigger = PFGEN_CTRL,
> +	.rtrigger_m = PFGEN_CTRL_PFSWR,
> +};
> +
> +/**
> + * ixd_trigger_reset - Trigger PFR reset
> + * @adapter: the device with mapped reset register
> + */
> +void ixd_trigger_reset(struct ixd_adapter *adapter)
> +{
> +	void __iomem *addr;
> +	u32 reg_val;
> +
> +	addr = libie_pci_get_mmio_addr(&adapter->cp_ctx.mmio_info,
> +				       ixd_reset_reg.rtrigger);
> +	reg_val = readl(addr);
> +	writel(reg_val | ixd_reset_reg.rtrigger_m, addr);
> +}
> +
> +/**
> + * ixd_check_reset_complete - Check if the PFR reset is completed
> + * @adapter: CPF being reset
> + *
> + * Return: %true if the register read indicates reset has been finished,
> + *	   %false otherwise
> + */
> +bool ixd_check_reset_complete(struct ixd_adapter *adapter)
> +{
> +	u32 reg_val, reset_status;
> +	void __iomem *addr;
> +
> +	addr = libie_pci_get_mmio_addr(&adapter->cp_ctx.mmio_info,
> +				       ixd_reset_reg.rstat);
> +	reg_val = readl(addr);
> +	reset_status = reg_val & ixd_reset_reg.rstat_m;
> +
> +	/* 0xFFFFFFFF might be read if the other side hasn't cleared
> +	 * the register for us yet.
> +	 */
> +	if (reg_val != GENMASK(31, 0) &&
> +	    reset_status == ixd_reset_reg.rstat_ok_v)
> +		return true;
> +
> +	return false;
> +}
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h b/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h
> index fbb88929d0de..58e58c75981b 100644
> --- a/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h
> +++ b/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h
> @@ -11,9 +11,33 @@
>  #define PF_FW_MBX_REG_LEN		4096
>  #define PF_FW_MBX			0x08400000
>  
> +#define PF_FW_ARQBAL			(PF_FW_MBX)
> +#define PF_FW_ARQBAH			(PF_FW_MBX + 0x4)
> +#define PF_FW_ARQLEN			(PF_FW_MBX + 0x8)
> +#define PF_FW_ARQLEN_ARQLEN_M		GENMASK(12, 0)
> +#define PF_FW_ARQLEN_ARQENABLE_S	31
> +#define PF_FW_ARQLEN_ARQENABLE_M	BIT(PF_FW_ARQLEN_ARQENABLE_S)
> +#define PF_FW_ARQH_ARQH_M		GENMASK(12, 0)
> +#define PF_FW_ARQH			(PF_FW_MBX + 0xC)
> +#define PF_FW_ARQT			(PF_FW_MBX + 0x10)
> +
> +#define PF_FW_ATQBAL			(PF_FW_MBX + 0x14)
> +#define PF_FW_ATQBAH			(PF_FW_MBX + 0x18)
> +#define PF_FW_ATQLEN			(PF_FW_MBX + 0x1C)
> +#define PF_FW_ATQLEN_ATQLEN_M		GENMASK(9, 0)
> +#define PF_FW_ATQLEN_ATQENABLE_S	31
> +#define PF_FW_ATQLEN_ATQENABLE_M	BIT(PF_FW_ATQLEN_ATQENABLE_S)
> +#define PF_FW_ATQH_ATQH_M		GENMASK(9, 0)
> +#define PF_FW_ATQH			(PF_FW_MBX + 0x20)
> +#define PF_FW_ATQT			(PF_FW_MBX + 0x24)
> +
>  /* Reset registers */
>  #define PFGEN_RTRIG_REG_LEN		2048
>  #define PFGEN_RTRIG			0x08407000	/* Device resets */
> +#define PFGEN_RSTAT			0x08407008	/* PFR status */
> +#define PFGEN_RSTAT_PFR_STATE_M		GENMASK(1, 0)
> +#define PFGEN_CTRL			0x0840700C	/* PFR trigger */
> +#define PFGEN_CTRL_PFSWR		BIT(0)
>  
>  /**
>   * struct ixd_bar_region - BAR region description
> @@ -25,4 +49,20 @@ struct ixd_bar_region {
>  	resource_size_t size;
>  };
>  
> +/**
> + * struct ixd_reset_reg - structure for reset registers
> + * @rstat: offset of status in register
> + * @rstat_m: status mask
> + * @rstat_ok_v: value that indicates PFR completed status
> + * @rtrigger: offset of reset trigger in register
> + * @rtrigger_m: reset trigger mask
> + */
> +struct ixd_reset_reg {
> +	u32	rstat;
> +	u32	rstat_m;
> +	u32	rstat_ok_v;
> +	u32	rtrigger;
> +	u32	rtrigger_m;
> +};
> +
>  #endif /* _IXD_LAN_REGS_H_ */
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_lib.c b/drivers/net/ethernet/intel/ixd/ixd_lib.c
> new file mode 100644
> index 000000000000..afc413d3650f
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd_lib.c
> @@ -0,0 +1,143 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright (C) 2025 Intel Corporation */
> +
> +#include "ixd.h"
> +
> +#define IXD_DFLT_MBX_Q_LEN 64
> +
> +/**
> + * ixd_init_ctlq_create_info - Initialize control queue info for creation
> + * @info: destination
> + * @type: type of the queue to create
> + * @ctlq_reg: register assigned to the control queue
> + */
> +static void ixd_init_ctlq_create_info(struct libie_ctlq_create_info *info,
> +				      enum virtchnl2_queue_type type,
> +				      const struct libie_ctlq_reg *ctlq_reg)
> +{
> +	*info = (struct libie_ctlq_create_info) {
> +		.type = type,
> +		.id = -1,
> +		.reg = *ctlq_reg,
> +		.len = IXD_DFLT_MBX_Q_LEN,
> +	};
> +}
> +
> +/**
> + * ixd_init_libie_xn_params - Initialize xn transaction manager creation info
> + * @params: destination
> + * @adapter: adapter info struct
> + * @ctlqs: list of the managed queues to create
> + * @num_queues: length of the queue list
> + */
> +static void ixd_init_libie_xn_params(struct libie_ctlq_xn_init_params *params,
> +				     struct ixd_adapter *adapter,
> +				      struct libie_ctlq_create_info *ctlqs,
> +				      uint num_queues)
> +{
> +	*params = (struct libie_ctlq_xn_init_params){
> +		.cctlq_info = ctlqs,
> +		.ctx = &adapter->cp_ctx,
> +		.num_qs = num_queues,
> +	};
> +}
> +
> +/**
> + * ixd_adapter_fill_dflt_ctlqs - Find default control queues and store them
> + * @adapter: adapter info struct
> + */
> +static void ixd_adapter_fill_dflt_ctlqs(struct ixd_adapter *adapter)
> +{
> +	guard(spinlock)(&adapter->cp_ctx.ctlqs_lock);
> +	struct libie_ctlq_info *cq;
> +
> +	list_for_each_entry(cq, &adapter->cp_ctx.ctlqs, list) {
> +		if (cq->qid != -1)
> +			continue;
> +		if (cq->type == LIBIE_CTLQ_TYPE_RX)
> +			adapter->arq = cq;
> +		else if (cq->type == LIBIE_CTLQ_TYPE_TX)
> +			adapter->asq = cq;
> +	}
> +}
> +
> +/**
> + * ixd_deinit_dflt_mbx - Deinitialize default mailbox
> + * @adapter: adapter info struct
> + */
> +void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter)
> +{
> +	if (adapter->xnm)
> +		libie_ctlq_xn_deinit(adapter->xnm, &adapter->cp_ctx);
> +
> +	adapter->arq = NULL;
> +	adapter->asq = NULL;
> +	adapter->xnm = NULL;
> +}
> +
> +/**
> + * ixd_init_dflt_mbx - Setup default mailbox parameters and make request
> + * @adapter: adapter info struct
> + *
> + * Return: %0 on success, negative errno code on failure
> + */
> +int ixd_init_dflt_mbx(struct ixd_adapter *adapter)
> +{
> +	struct libie_ctlq_create_info ctlqs_info[2];
> +	struct libie_ctlq_xn_init_params xn_params;
> +	struct libie_ctlq_reg ctlq_reg_tx;
> +	struct libie_ctlq_reg ctlq_reg_rx;
> +	int err;
> +
> +	ixd_ctlq_reg_init(adapter, &ctlq_reg_tx, &ctlq_reg_rx);
> +	ixd_init_ctlq_create_info(&ctlqs_info[0], LIBIE_CTLQ_TYPE_TX,
> +				  &ctlq_reg_tx);
> +	ixd_init_ctlq_create_info(&ctlqs_info[1], LIBIE_CTLQ_TYPE_RX,
> +				  &ctlq_reg_rx);
> +	ixd_init_libie_xn_params(&xn_params, adapter, ctlqs_info,
> +				 ARRAY_SIZE(ctlqs_info));
> +	err = libie_ctlq_xn_init(&xn_params);
> +	if (err)
> +		return err;
> +	adapter->xnm = xn_params.xnm;
> +
> +	ixd_adapter_fill_dflt_ctlqs(adapter);
> +
> +	if (!adapter->asq || !adapter->arq) {
> +		ixd_deinit_dflt_mbx(adapter);
> +		return -ENOENT;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * ixd_init_task - Initialize after reset
> + * @work: init work struct
> + */
> +void ixd_init_task(struct work_struct *work)
> +{
> +	struct ixd_adapter *adapter;
> +	int err;
> +
> +	adapter = container_of(work, struct ixd_adapter,
> +			       init_task.init_work.work);
> +
> +	if (!ixd_check_reset_complete(adapter)) {
> +		if (++adapter->init_task.reset_retries < 10)
> +			queue_delayed_work(system_unbound_wq,
> +					   &adapter->init_task.init_work,
> +					   msecs_to_jiffies(500));
> +		else
> +			dev_err(ixd_to_dev(adapter),
> +				"Device reset failed. The driver was unable to contact the device's firmware. Check that the FW is running.\n");
> +		return;
> +	}
> +
> +	adapter->init_task.reset_retries = 0;
> +	err = ixd_init_dflt_mbx(adapter);
> +	if (err)
> +		dev_err(ixd_to_dev(adapter),
> +			"Failed to initialize the default mailbox: %pe\n",
> +			ERR_PTR(err));
> +}
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_main.c b/drivers/net/ethernet/intel/ixd/ixd_main.c
> index 75ee53152e61..b4d4000b63ed 100644
> --- a/drivers/net/ethernet/intel/ixd/ixd_main.c
> +++ b/drivers/net/ethernet/intel/ixd/ixd_main.c
> @@ -5,6 +5,7 @@
>  #include "ixd_lan_regs.h"
>  
>  MODULE_DESCRIPTION("Intel(R) Control Plane Function Device Driver");
> +MODULE_IMPORT_NS("LIBIE_CP");
>  MODULE_IMPORT_NS("LIBIE_PCI");
>  MODULE_LICENSE("GPL");
>  
> @@ -16,7 +17,13 @@ static void ixd_remove(struct pci_dev *pdev)
>  {
>  	struct ixd_adapter *adapter = pci_get_drvdata(pdev);
>  
> -	libie_pci_unmap_all_mmio_regions(&adapter->hw);
> +	/* Do not mix removal with (re)initialization */
> +	cancel_delayed_work_sync(&adapter->init_task.init_work);
> +	/* Leave the device clean on exit */
> +	ixd_trigger_reset(adapter);
> +	ixd_deinit_dflt_mbx(adapter);
> +
> +	libie_pci_unmap_all_mmio_regions(&adapter->cp_ctx.mmio_info);
>  }
>  
>  /**
> @@ -51,7 +58,7 @@ static int ixd_iomap_regions(struct ixd_adapter *adapter)
>  	};
>  
>  	for (int i = 0; i < ARRAY_SIZE(regions); i++) {
> -		struct libie_mmio_info *mmio_info = &adapter->hw;
> +		struct libie_mmio_info *mmio_info = &adapter->cp_ctx.mmio_info;
>  		bool map_ok;
>  
>  		map_ok = libie_pci_map_mmio_region(mmio_info,
> @@ -81,11 +88,15 @@ static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>  	struct ixd_adapter *adapter;
>  	int err;
>  
> +	if (WARN_ON(ent->device != IXD_DEV_ID_CPF))
> +		return -EINVAL;
> +
>  	adapter = devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL);
>  	if (!adapter)
>  		return -ENOMEM;
> -	adapter->hw.pdev = pdev;
> -	INIT_LIST_HEAD(&adapter->hw.mmio_list);
> +
> +	adapter->cp_ctx.mmio_info.pdev = pdev;
> +	INIT_LIST_HEAD(&adapter->cp_ctx.mmio_info.mmio_list);
>  
>  	err = libie_pci_init_dev(pdev);
>  	if (err)
> @@ -93,7 +104,18 @@ static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>  
>  	pci_set_drvdata(pdev, adapter);
>  
> -	return ixd_iomap_regions(adapter);
> +	err = ixd_iomap_regions(adapter);
> +	if (err)
> +		return err;
> +
> +	INIT_DELAYED_WORK(&adapter->init_task.init_work,
> +			  ixd_init_task);
> +
> +	ixd_trigger_reset(adapter);
> +	queue_delayed_work(system_unbound_wq, &adapter->init_task.init_work,
> +			   msecs_to_jiffies(500));
> +
> +	return 0;
>  }
>  
>  static const struct pci_device_id ixd_pci_tbl[] = {
> -- 
> 2.47.1
> 

^ permalink raw reply

* RE: [PATCH net-next 2/2] net/mlx5: implement max_sfs parameter
From: Loktionov, Aleksandr @ 2026-05-18  9:05 UTC (permalink / raw)
  To: Tariq Toukan, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Andrew Lunn, David S. Miller
  Cc: Jiri Pirko, Simon Horman, Jonathan Corbet, Shuah Khan,
	Saeed Mahameed, Leon Romanovsky, Mark Bloch, Vlad Dumitrescu,
	Daniel Zahka, David Ahern, Nikolay Aleksandrov,
	netdev@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-rdma@vger.kernel.org,
	Gal Pressman, Dragos Tatulea, Jiri Pirko, Nikolay Aleksandrov
In-Reply-To: <20260517112700.343575-3-tariqt@nvidia.com>



> -----Original Message-----
> From: Tariq Toukan <tariqt@nvidia.com>
> Sent: Sunday, May 17, 2026 1:27 PM
> To: Eric Dumazet <edumazet@google.com>; Jakub Kicinski
> <kuba@kernel.org>; Paolo Abeni <pabeni@redhat.com>; Andrew Lunn
> <andrew+netdev@lunn.ch>; David S. Miller <davem@davemloft.net>
> Cc: Jiri Pirko <jiri@resnulli.us>; Simon Horman <horms@kernel.org>;
> Jonathan Corbet <corbet@lwn.net>; Shuah Khan
> <skhan@linuxfoundation.org>; Saeed Mahameed <saeedm@nvidia.com>; Leon
> Romanovsky <leon@kernel.org>; Tariq Toukan <tariqt@nvidia.com>; Mark
> Bloch <mbloch@nvidia.com>; Vlad Dumitrescu <vdumitrescu@nvidia.com>;
> Loktionov, Aleksandr <aleksandr.loktionov@intel.com>; Daniel Zahka
> <daniel.zahka@gmail.com>; David Ahern <dsahern@kernel.org>; Nikolay
> Aleksandrov <razor@blackwall.org>; netdev@vger.kernel.org; linux-
> doc@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> rdma@vger.kernel.org; Gal Pressman <gal@nvidia.com>; Dragos Tatulea
> <dtatulea@nvidia.com>; Jiri Pirko <jiri@nvidia.com>; Nikolay
> Aleksandrov <nikolay@nvidia.com>
> Subject: [PATCH net-next 2/2] net/mlx5: implement max_sfs parameter
> 
> From: Nikolay Aleksandrov <nikolay@nvidia.com>
> 
> Implement max_sfs generic parameter to allow users to control the
> total light-weight NIC subfunctions that can be created using devlink
> instead of external vendor tools. A value of 0 will effectively
> disable creation of new subfunction devices. A warning is sent to
> user-space via extack (returning extack without error code is
> interpreted as a warning by user-space tools).
> 
> Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
> Reviewed-by: David Ahern <dsahern@kernel.org>
> Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
> ---
>  Documentation/networking/devlink/mlx5.rst     |  7 +-
>  .../mellanox/mlx5/core/lib/nv_param.c         | 83
> ++++++++++++++++++-
>  2 files changed, 86 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/networking/devlink/mlx5.rst
> b/Documentation/networking/devlink/mlx5.rst
> index 4bba4d780a4a..283b93d16861 100644
> --- a/Documentation/networking/devlink/mlx5.rst
> +++ b/Documentation/networking/devlink/mlx5.rst
> @@ -45,8 +45,13 @@ Parameters
>       - The range is between 1 and a device-specific max.
>       - Applies to each physical function (PF) independently, if the
> device
>         supports it. Otherwise, it applies symmetrically to all PFs.
> +   * - ``max_sfs``
> +     - permanent
> +     - The range is between 0 and a device-specific max.
> +     - Applies to each physical function (PF) independently.
> 
> -Note: permanent parameters such as ``enable_sriov`` and ``total_vfs``
> require FW reset to take effect
> +Note: permanent parameters such as ``enable_sriov``, ``total_vfs` and
> ``max_sfs``
I think one ` is missed after the ``total_vfs` ?


...

> 
> 	DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_ID_CQE_COMPRESSION_TYPE
> ,
>  			     "cqe_compress_type",
> DEVLINK_PARAM_TYPE_STRING,
>  			     BIT(DEVLINK_PARAM_CMODE_PERMANENT),
> --
> 2.44.0


^ permalink raw reply

* Re: [PATCH v2] cpufreq-stats: document limitations on modern cpufreq drivers
From: Zhongqiu Han @ 2026-05-18  9:00 UTC (permalink / raw)
  To: NicoErdmann, linux-pm
  Cc: linux-doc, rafael, viresh.kumar, corbet, skhan, zhongqiu.han
In-Reply-To: <20260510193352.195181-1-nicobsc4@yahoo.com>

On 5/11/2026 3:33 AM, NicoErdmann wrote:
> Add a note clarifying that cpufreq-stats may not be present or may not provide meaningful statistics depending
> on the active CPU frequency scaling driver.
> 
> In particular, drivers such as intel_pstate and amd_pstate may use alternative mechanisms for frequency scaling
> and accounting.
> 

Hi NicoErdmann,

Thanks for working on this — this documentation gap seems worth
addressing.

Please run ./scripts/checkpatch.pl cpufreq-stats-document-xx.patch to
avoid style/format issue.

I see the below Error/Warning, please fix.

-----------------------------------------------------------------------
WARNING: Prefer a maximum 75 chars per line (possible unwrapped commit 
description?)
#6:
Add a note clarifying that cpufreq-stats may not be present or may not 
provide meaningful statistics depending

ERROR: trailing whitespace
#29: FILE: Documentation/cpu-freq/cpufreq-stats.rst:32:
+^I$

total: 1 errors, 1 warnings, 13 lines checked
-----------------------------------------------------------------------

> v2:
>   - Add missing period at end of sentence (reported by Randy)
> 
> Signed-off-by: NicoErdmann <nicobsc4@yahoo.com>
> ---
>   Documentation/cpu-freq/cpufreq-stats.rst | 7 +++++++
>   1 file changed, 7 insertions(+)
> 
> diff --git a/Documentation/cpu-freq/cpufreq-stats.rst b/Documentation/cpu-freq/cpufreq-stats.rst
> index 9ad695b1c7db..6ffa5a6a63c9 100644
> --- a/Documentation/cpu-freq/cpufreq-stats.rst
> +++ b/Documentation/cpu-freq/cpufreq-stats.rst
> @@ -28,6 +28,13 @@ Various statistics will form read_only files under this directory.
>   This driver is designed to be independent of any particular cpufreq_driver
>   that may be running on your CPU. So, it will work with any cpufreq_driver.


The existing statement "it will work with any cpufreq_driver" may not be
entirely accurate in practice. The stats driver relies on the scaling
driver populating a frequency table (policy->freq_table), which is not
the case for some modern drivers. It might be better to clarify this
dependency rather than keeping the current wording and adding a
contradicting note.

>   
> +.. note::
> +	
> +   On some modern systems, this interface may not be available or may not
> +   expose meaningful statistics depending on the active CPU frequency scaling driver.


Also, "may not expose meaningful statistics" could be a bit misleading.
In these cases, the stats/ directory is typically not created at all,
since cpufreq_stats_create_table() returns early when the frequency
table is not available.


> +
> +   In particular, drivers such as intel_pstate or amd_pstate may use alternative
> +   mechanisms for frequency scaling and accounting.


Similarly, describing this as "alternative mechanisms for frequency
scaling and accounting" may be slightly vague. The key point is that
these drivers do not populate policy->freq_table, which prevents the
stats driver from creating its sysfs interface.


Small nit: The subject line "modern cpufreq drivers" feels a bit vague;
it might be clearer to refer to drivers that do not populate
policy->freq_table, since that is the actual condition under
which cpufreq-stats is not available.

For completeness, it may also be worth mentioning cppc_cpufreq, which
behaves in a similar way.


>   
>   2. Statistics Provided (with example)
>   =====================================


Perhaps something along the following lines would make the behavior
clearer:

This driver is designed to be independent of any particular
cpufreq_driver that may be running on your CPU. However, it requires
the scaling driver to populate a frequency table
(``policy->freq_table``). Drivers that operate on a continuous
performance range rather than a discrete set of frequencies, such
as ``intel_pstate``, ``amd_pstate``, and ``cppc_cpufreq``, do not
populate this table. As a result, the ``stats/`` directory will not
be present for those drivers.


Thanks again for looking into this.



-- 
Thx and BRs,
Zhongqiu Han

^ permalink raw reply

* RE: [PATCH net-next 1/2] devlink: add generic device max_sfs parameter
From: Loktionov, Aleksandr @ 2026-05-18  8:57 UTC (permalink / raw)
  To: Tariq Toukan, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Andrew Lunn, David S. Miller
  Cc: Jiri Pirko, Simon Horman, Jonathan Corbet, Shuah Khan,
	Saeed Mahameed, Leon Romanovsky, Mark Bloch, Vlad Dumitrescu,
	Daniel Zahka, David Ahern, Nikolay Aleksandrov,
	netdev@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-rdma@vger.kernel.org,
	Gal Pressman, Dragos Tatulea, Jiri Pirko, Nikolay Aleksandrov
In-Reply-To: <20260517112700.343575-2-tariqt@nvidia.com>



> -----Original Message-----
> From: Tariq Toukan <tariqt@nvidia.com>
> Sent: Sunday, May 17, 2026 1:27 PM
> To: Eric Dumazet <edumazet@google.com>; Jakub Kicinski
> <kuba@kernel.org>; Paolo Abeni <pabeni@redhat.com>; Andrew Lunn
> <andrew+netdev@lunn.ch>; David S. Miller <davem@davemloft.net>
> Cc: Jiri Pirko <jiri@resnulli.us>; Simon Horman <horms@kernel.org>;
> Jonathan Corbet <corbet@lwn.net>; Shuah Khan
> <skhan@linuxfoundation.org>; Saeed Mahameed <saeedm@nvidia.com>; Leon
> Romanovsky <leon@kernel.org>; Tariq Toukan <tariqt@nvidia.com>; Mark
> Bloch <mbloch@nvidia.com>; Vlad Dumitrescu <vdumitrescu@nvidia.com>;
> Loktionov, Aleksandr <aleksandr.loktionov@intel.com>; Daniel Zahka
> <daniel.zahka@gmail.com>; David Ahern <dsahern@kernel.org>; Nikolay
> Aleksandrov <razor@blackwall.org>; netdev@vger.kernel.org; linux-
> doc@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> rdma@vger.kernel.org; Gal Pressman <gal@nvidia.com>; Dragos Tatulea
> <dtatulea@nvidia.com>; Jiri Pirko <jiri@nvidia.com>; Nikolay
> Aleksandrov <nikolay@nvidia.com>
> Subject: [PATCH net-next 1/2] devlink: add generic device max_sfs
> parameter
> 
> From: Nikolay Aleksandrov <nikolay@nvidia.com>
> 
> Add a new generic devlink device parameter (max_sfs) to control if and
> how many light-weight NIC subfunctions can be created. Subfunctions
> are a light-weight network functions backed by an underlying PCI
> function.
> Their lifecycle can already be managed by devlink, but currently users
> cannot enable them in the device. They can be enabled/disabled only
> via external vendor tools. This parameter allows subfunctions to be
> enabled
> (>0) or disabled (0) via devlink. A subsequent patch will add support
> for max_sfs to the mlx5 driver.
> 
> Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
> Reviewed-by: David Ahern <dsahern@kernel.org>
> Reviewed-by: Jiri Pirko <jiri@nvidia.com>
> Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
> ---
>  Documentation/networking/devlink/devlink-params.rst | 6 ++++++
>  include/net/devlink.h                               | 4 ++++
>  net/devlink/param.c                                 | 5 +++++
>  3 files changed, 15 insertions(+)
> 
> diff --git a/Documentation/networking/devlink/devlink-params.rst
> b/Documentation/networking/devlink/devlink-params.rst
> index ea17756dcda6..29b8a9246fb6 100644
> --- a/Documentation/networking/devlink/devlink-params.rst
> +++ b/Documentation/networking/devlink/devlink-params.rst
> @@ -165,3 +165,9 @@ own name.
>       - u32
>       - Controls the maximum number of MAC address filters that can be
> assigned
>         to a Virtual Function (VF).
> +   * - ``max_sfs``
> +     - u32
> +     - The maximum number of subfunctions which can be created on the
> device.
> +       Modifying this parameter may require a device restart and PCI
> bus
> +       rescanning because the BAR layout may change. A value of 0
> disables
> +       subfunction creation.
> diff --git a/include/net/devlink.h b/include/net/devlink.h index
> bcd31de1f890..4ec455cfe7a4 100644
> --- a/include/net/devlink.h
> +++ b/include/net/devlink.h
> @@ -546,6 +546,7 @@ enum devlink_param_generic_id {
>  	DEVLINK_PARAM_GENERIC_ID_TOTAL_VFS,
>  	DEVLINK_PARAM_GENERIC_ID_NUM_DOORBELLS,
>  	DEVLINK_PARAM_GENERIC_ID_MAX_MAC_PER_VF,
> +	DEVLINK_PARAM_GENERIC_ID_MAX_SFS,
> 
>  	/* add new param generic ids above here*/
>  	__DEVLINK_PARAM_GENERIC_ID_MAX,
> @@ -619,6 +620,9 @@ enum devlink_param_generic_id {  #define
> DEVLINK_PARAM_GENERIC_MAX_MAC_PER_VF_NAME "max_mac_per_vf"
>  #define DEVLINK_PARAM_GENERIC_MAX_MAC_PER_VF_TYPE
> DEVLINK_PARAM_TYPE_U32
> 
> +#define DEVLINK_PARAM_GENERIC_MAX_SFS_NAME "max_sfs"
> +#define DEVLINK_PARAM_GENERIC_MAX_SFS_TYPE DEVLINK_PARAM_TYPE_U32
> +
>  #define DEVLINK_PARAM_GENERIC(_id, _cmodes, _get, _set, _validate)	\
>  {									\
>  	.id = DEVLINK_PARAM_GENERIC_ID_##_id,				\
> diff --git a/net/devlink/param.c b/net/devlink/param.c index
> cf95268da5b0..523243e49d88 100644
> --- a/net/devlink/param.c
> +++ b/net/devlink/param.c
> @@ -117,6 +117,11 @@ static const struct devlink_param
> devlink_param_generic[] = {
>  		.name = DEVLINK_PARAM_GENERIC_MAX_MAC_PER_VF_NAME,
>  		.type = DEVLINK_PARAM_GENERIC_MAX_MAC_PER_VF_TYPE,
>  	},
> +	{
> +		.id = DEVLINK_PARAM_GENERIC_ID_MAX_SFS,
> +		.name = DEVLINK_PARAM_GENERIC_MAX_SFS_NAME,
> +		.type = DEVLINK_PARAM_GENERIC_MAX_SFS_TYPE,
> +	},
>  };
> 
>  static int devlink_param_generic_verify(const struct devlink_param
> *param)
> --
> 2.44.0


Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>

^ permalink raw reply

* Re: [PATCH v4 04/30] KVM: x86: Add KVM_[GS]ET_CLOCK_GUEST for accurate KVM clock migration
From: David Woodhouse @ 2026-05-18  8:48 UTC (permalink / raw)
  To: Dongli Zhang, kvm
  Cc: Paolo Bonzini, Jonathan Corbet, Shuah Khan, Thomas Gleixner,
	Sean Christopherson, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	Dave Hansen, Vitaly Kuznetsov, x86, Marc Zyngier, Juergen Gross,
	Boris Ostrovsky, Paul Durrant, Jonathan Cameron, Sascha Bischoff,
	Jack Allister, Joey Gouly, joe.jin, linux-doc, linux-kernel,
	xen-devel, linux-kselftest
In-Reply-To: <0ae8e471-db7a-4842-aca4-8ef643acde8b@oracle.com>

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

On Mon, 2026-05-18 at 00:52 -0700, Dongli Zhang wrote:
> On 5/9/26 3:46 PM, David Woodhouse wrote:

Huh, I didn't write that then; it isn't September yet. Did you mean
2026-05-09? We aren't all in the US... 

Strictly speaking, you just misattributed a quote of mine, which is
very poor form :)

What mailer are you using? Can it be fixed?

> > From: Jack Allister <jalliste@amazon.com>
> > 
> > Where kvm->arch.use_master_clock is false (because the host TSC is
> > unreliable, or the guest TSCs are configured strangely), the KVM clock
> > is *not* defined as a function of the guest TSC so KVM_GET_CLOCK_GUEST
> > returns an error. In this case, as documented, userspace shall use the
> > legacy KVM_GET_CLOCK ioctl. The loss of precision is acceptable in this
> 
> The description here confused me a little. It sounds like userspace should call
> KVM_SET_CLOCK if KVM_SET_CLOCK_GUEST fails. However, I assume it actually means
> that userspace should do nothing extra if KVM_SET_CLOCK_GUEST fails, and simply
> rely on the prior KVM_SET_CLOCK and KVM_VCPU_TSC_OFFSET workflow described in
> patch 07. Is that correct?

Yes. If KVM_SET_CLOCK_GUEST doesn't work (which might be because
KVM_GET_CLOCK_GUEST didn't work so userspace doesn't have the data in
the first place, or because the actual ioctl returns failure), then
userspace should rely on the old method using KVM_SET_CLOCK imprecisely
instead. That includes on a migration from an older kernel that *lacks*
KVM_GET_CLOCK_GUEST, of course.

I don't think it strictly matters whether userspace does KVM_SET_CLOCK
first, then *tries* KVM_SET_CLOCK_GUEST, or whether it tries
KVM_SET_CLOCK_GUEST and then only calls KVM_SET_CLOCK on failure? I'd
probably be inclined not to use KVM_SET_CLOCK at all unless it is known
to be needed?

> > +4.145 KVM_GET_CLOCK_GUEST
> > +----------------------------
> > +
> > +:Capability: none
> > +:Architectures: x86_64
> > +:Type: vcpu ioctl
> > +:Parameters: struct pvclock_vcpu_time_info (out)
> > +:Returns: 0 on success, <0 on error
> > +
> > +Retrieves the current time information structure used for KVM/PV clocks,
> > +in precisely the form advertised to the guest vCPU, which gives parameters
> > +for a direct conversion from a guest TSC value to nanoseconds.
> > +
> > +When the KVM clock is not in "master clock" mode, for example because the
> > +host TSC is unreliable or the guest TSCs are oddly configured, the KVM clock
> > +is actually defined by the host CLOCK_MONOTONIC_RAW instead of the guest TSC.
> > +In this case, the KVM_GET_CLOCK_GUEST ioctl returns -EINVAL.
> > +
> > +4.146 KVM_SET_CLOCK_GUEST
> > +----------------------------
> > +
> > +:Capability: none
> 
> Do we need a KVM_CHECK_EXTENSION capability for this? If userspace wants to
> support the new API, should it detect availability via KVM_CHECK_EXTENSION, or
> simply try the ioctl and handle failure?

That might be conventional, I suppose. But I suspect Jack's thinking
was that userspace is going to have to *try* it anyway, and still might
have to fall back to what KVM_SET_CLOCK can manage, so userspace
probably wouldn't even bother to check that capability; it doesn't
matter.

Since then, we've added some more attributes in this series though, and
it probably is worth adding a cap which advertises them *all*?
Something like KVM_CAP_CLOCK_PRECISION_API?

> > +#ifdef CONFIG_X86_64
> > +static int kvm_vcpu_ioctl_get_clock_guest(struct kvm_vcpu *v, void __user *argp)
> > +{
> > +	struct pvclock_vcpu_time_info hv_clock = {};
> > +	struct kvm_vcpu_arch *vcpu = &v->arch;
> > +	struct kvm_arch *ka = &v->kvm->arch;
> > +	unsigned int seq;
> > +
> > +	/*
> > +	 * If KVM_REQ_CLOCK_UPDATE is already pending, or if the pvclock
> > +	 * has never been generated at all, call kvm_guest_time_update().
> > +	 */
> > +	if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, v) || !vcpu->hw_tsc_hz) {
> 
> This was flagged by AI, and I am still checking whether it is a real issue.
> 
> What happens if KVM_REQ_MASTERCLOCK_UPDATE and KVM_REQ_CLOCK_UPDATE are both
> pending?
> 
> From my perspective, I am also curious how we should reason about this in other
> scenarios in the future. Specifically, when do we need to process
> KVM_REQ_MASTERCLOCK_UPDATE before KVM_REQ_CLOCK_UPDATE, and when is it
> acceptable not to? I noticed that kvm_cpuid() already processes only
> KVM_REQ_CLOCK_UPDATE.

The way I've been thinking about it — and I'm only two cups of coffee
into Monday so take those words literally and don't think of them as
British understatement of something I believe is absolute truth — is
that MASTERCLOCK_UPDATE is updating the actual clock for the whole VM,
while CLOCK_UPDATE is about *putting* that information into the per-
vCPU pvclock structures.

So after a MASTERCLOCK_UPDATE, we need to do a CLOCK_UPDATE on all
vCPUs to disseminate the result. Which means that if CLOCK_UPDATE is
already pending before a MASTERCLOCK_UPDATE, it's probably redundant
and might as well be cleared because it's only going to get set *again*
in kvm_end_pvclock_update()? 


> > +	/*
> > +	 * Calculate the guest TSC at the new reference point, and the
> > +	 * corresponding KVM clock value according to user_hv_clock.
> > +	 * Adjust kvmclock_offset so both definitions agree.
> > +	 */
> > +	guest_tsc = kvm_read_l1_tsc(v, ka->master_cycle_now);
> > +	user_clk_ns = __pvclock_read_cycles(&user_hv_clock, guest_tsc);
> > +	ka->kvmclock_offset = user_clk_ns - ka->master_kernel_ns;
> 
> I used to explore adjusting ka->kvmclock_offset in KVM_SET_CLOCK based on the
> old hv_clock and the new hv_clock long time ago. At that time, my concern was
> what would happen if userspace provided bogus values. Theoretically, this is
> possible with any ioctl. My concern may be unnecessary.
> 
> Would it be helpful to validate that the delta is within a reasonable range,
> e.g. that the drift can never be more than five minutes (forward or backward)?

Setting confidential guests aside, which have their own way of trusting
the TSC and should never even *consider* using kvmclock, surely this is
supposed to be *entirely* under the control of the VMM? The kernel has
no business deciding what is 'bogus'?

If a guest has been running for months on a previous host and is
migrated to a new host, don't we expect that the KVM clock of the new
VM on the new host is tweaked from its default near-zero after
creation, to some large amount?


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 5069 bytes --]

^ permalink raw reply

* Re: [PATCH] docs: submitting-patches: Clarify that in English "reviewer" is a person
From: Mark Brown @ 2026-05-18  8:33 UTC (permalink / raw)
  To: Vlastimil Babka (SUSE)
  Cc: Krzysztof Kozlowski, Jonathan Corbet, Shuah Khan, workflows,
	linux-doc, linux-kernel, Greg Kroah-Hartman, Andrew Morton,
	David Hildenbrand, Linus Torvalds, Guenter Roeck
In-Reply-To: <ce1e5e9b-83d0-4971-aee3-dc5a8f85ce22@kernel.org>

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

On Sat, May 16, 2026 at 04:39:45PM +0200, Vlastimil Babka (SUSE) wrote:
> On 5/16/26 14:38, Krzysztof Kozlowski wrote:

> > Our docs already clearly mark that "Reviewed-by" must come from a
> > person:

...

> > However this is not enough and apparently English is not that precise,
> > so let's clarify that only a person can state the "Reviewer's statement
> > of oversight".

> I agree with the intent that the tag is for people (whether they use a tool
> or not to help them). We also don't put "Tested-by: kernel test robot" or
> syzkaller on every commit that they test and find no bugs. Review is also
> not just about absence of bugs, but agreeing with the larger design and
> whether the change makes sense to do in the first place.

Reviewed-by: Mark Brown <broonie@kernel.org>

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

^ permalink raw reply

* Re: [PATCH net-next v3 11/14] ixd: add basic driver framework for Intel(R) Control Plane Function
From: Larysa Zaremba @ 2026-05-18  8:32 UTC (permalink / raw)
  To: Tony Nguyen, davem, kuba, pabeni, edumazet, andrew+netdev, netdev
  Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
	przemyslaw.kitszel, aleksander.lobakin, sridhar.samudrala,
	anjali.singhai, michal.swiatkowski, maciej.fijalkowski,
	emil.s.tantilov, madhu.chittim, joshua.a.hay, jacob.e.keller,
	jayaprakash.shanmugam, jiri, horms, corbet, richardcochran,
	linux-doc, Bharath R, Aleksandr Loktionov
In-Reply-To: <20260515224443.2772147-12-anthony.l.nguyen@intel.com>

On Fri, May 15, 2026 at 03:44:35PM -0700, Tony Nguyen wrote:
> From: Larysa Zaremba <larysa.zaremba@intel.com>
> 
> Add module register and probe functionality. Add the required support to
> register IXD PCI driver, as well as probe and remove call backs. Enable the
> PCI device and request the kernel to reserve the memory resources that will
> be used by the driver. Finally map the BAR0 address space.
> 
> For now, use devm_alloc() to allocate adapter, as it requires the least
> amount of code. In a later commit, it will be replaced with a devlink
> alternative.

I had reviewed the Sashiko feedback [0]. Here are a few notes:

1. "Should this file explicitly include linux/module.h and linux/reboot.h?"
   we do not normally, do that, but if you want to, there is a diff below.
2. "Could leaving PCI bus mastering enabled during shutdown cause memory
    corruption or IOMMU faults during a kexec or warm reboot?" - Could it? 
   Current flow is the same as ice.

[0] https://sashiko.dev/#/patchset/20260515224443.2772147-1-anthony.l.nguyen%40intel.com

diff --git a/drivers/net/ethernet/intel/ixd/ixd_main.c b/drivers/net/ethernet/intel/ixd/ixd_main.c
index 75ee53152e61..a08c0076926a 100644
--- a/drivers/net/ethernet/intel/ixd/ixd_main.c
+++ b/drivers/net/ethernet/intel/ixd/ixd_main.c
@@ -1,6 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (C) 2025 Intel Corporation */

+#include <linux/module.h>
+#include <linux/reboot.h>
+
 #include "ixd.h"
 #include "ixd_lan_regs.h"


> 
> Co-developed-by: Amritha Nambiar <amritha.nambiar@intel.com>
> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
> Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
> Tested-by: Bharath R <Bharath.r@intel.com>
> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
> ---
>  .../device_drivers/ethernet/index.rst         |   1 +
>  .../device_drivers/ethernet/intel/ixd.rst     |  39 ++++++
>  drivers/net/ethernet/intel/Kconfig            |   2 +
>  drivers/net/ethernet/intel/Makefile           |   1 +
>  drivers/net/ethernet/intel/ixd/Kconfig        |  13 ++
>  drivers/net/ethernet/intel/ixd/Makefile       |   8 ++
>  drivers/net/ethernet/intel/ixd/ixd.h          |  28 +++++
>  drivers/net/ethernet/intel/ixd/ixd_lan_regs.h |  28 +++++
>  drivers/net/ethernet/intel/ixd/ixd_main.c     | 112 ++++++++++++++++++
>  9 files changed, 232 insertions(+)
>  create mode 100644 Documentation/networking/device_drivers/ethernet/intel/ixd.rst
>  create mode 100644 drivers/net/ethernet/intel/ixd/Kconfig
>  create mode 100644 drivers/net/ethernet/intel/ixd/Makefile
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd.h
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd_lan_regs.h
>  create mode 100644 drivers/net/ethernet/intel/ixd/ixd_main.c
> 
> diff --git a/Documentation/networking/device_drivers/ethernet/index.rst b/Documentation/networking/device_drivers/ethernet/index.rst
> index fd3be5d20397..39d2ff526cd8 100644
> --- a/Documentation/networking/device_drivers/ethernet/index.rst
> +++ b/Documentation/networking/device_drivers/ethernet/index.rst
> @@ -36,6 +36,7 @@ Contents:
>     intel/igbvf
>     intel/ixgbe
>     intel/ixgbevf
> +   intel/ixd
>     intel/i40e
>     intel/iavf
>     intel/ice
> diff --git a/Documentation/networking/device_drivers/ethernet/intel/ixd.rst b/Documentation/networking/device_drivers/ethernet/intel/ixd.rst
> new file mode 100644
> index 000000000000..1387626e5d20
> --- /dev/null
> +++ b/Documentation/networking/device_drivers/ethernet/intel/ixd.rst
> @@ -0,0 +1,39 @@
> +.. SPDX-License-Identifier: GPL-2.0+
> +
> +==========================================================================
> +iXD Linux* Base Driver for the Intel(R) Control Plane Function
> +==========================================================================
> +
> +Intel iXD Linux driver.
> +Copyright(C) 2025 Intel Corporation.
> +
> +.. contents::
> +
> +For questions related to hardware requirements, refer to the documentation
> +supplied with your Intel adapter. All hardware requirements listed apply to use
> +with Linux.
> +
> +
> +Identifying Your Adapter
> +========================
> +For information on how to identify your adapter, and for the latest Intel
> +network drivers, refer to the Intel Support website:
> +http://www.intel.com/support
> +
> +
> +Support
> +=======
> +For general information, go to the Intel support website at:
> +http://www.intel.com/support/
> +
> +If an issue is identified with the released source code on a supported kernel
> +with a supported adapter, email the specific information related to the issue
> +to intel-wired-lan@lists.osuosl.org.
> +
> +
> +Trademarks
> +==========
> +Intel is a trademark or registered trademark of Intel Corporation or its
> +subsidiaries in the United States and/or other countries.
> +
> +* Other names and brands may be claimed as the property of others.
> diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
> index 288fa8ce53af..780f113986ea 100644
> --- a/drivers/net/ethernet/intel/Kconfig
> +++ b/drivers/net/ethernet/intel/Kconfig
> @@ -398,4 +398,6 @@ config IGC_LEDS
>  
>  source "drivers/net/ethernet/intel/idpf/Kconfig"
>  
> +source "drivers/net/ethernet/intel/ixd/Kconfig"
> +
>  endif # NET_VENDOR_INTEL
> diff --git a/drivers/net/ethernet/intel/Makefile b/drivers/net/ethernet/intel/Makefile
> index 9a37dc76aef0..08b29f3b6801 100644
> --- a/drivers/net/ethernet/intel/Makefile
> +++ b/drivers/net/ethernet/intel/Makefile
> @@ -19,3 +19,4 @@ obj-$(CONFIG_IAVF) += iavf/
>  obj-$(CONFIG_FM10K) += fm10k/
>  obj-$(CONFIG_ICE) += ice/
>  obj-$(CONFIG_IDPF) += idpf/
> +obj-$(CONFIG_IXD) += ixd/
> diff --git a/drivers/net/ethernet/intel/ixd/Kconfig b/drivers/net/ethernet/intel/ixd/Kconfig
> new file mode 100644
> index 000000000000..f5594efe292c
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/Kconfig
> @@ -0,0 +1,13 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +# Copyright (C) 2025 Intel Corporation
> +
> +config IXD
> +	tristate "Intel(R) Control Plane Function Support"
> +	depends on PCI_MSI
> +	select LIBETH
> +	select LIBIE_PCI
> +	help
> +	  This driver supports Intel(R) Control Plane PCI Function
> +	  of Intel E2100 and later IPUs and FNICs.
> +	  It facilitates a centralized control over multiple IDPF PFs/VFs/SFs
> +	  exposed by the same card.
> diff --git a/drivers/net/ethernet/intel/ixd/Makefile b/drivers/net/ethernet/intel/ixd/Makefile
> new file mode 100644
> index 000000000000..3849bc240600
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/Makefile
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +# Copyright (C) 2025 Intel Corporation
> +
> +# Intel(R) Control Plane Function Linux Driver
> +
> +obj-$(CONFIG_IXD) += ixd.o
> +
> +ixd-y := ixd_main.o
> diff --git a/drivers/net/ethernet/intel/ixd/ixd.h b/drivers/net/ethernet/intel/ixd/ixd.h
> new file mode 100644
> index 000000000000..d813c27941a5
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd.h
> @@ -0,0 +1,28 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/* Copyright (C) 2025 Intel Corporation */
> +
> +#ifndef _IXD_H_
> +#define _IXD_H_
> +
> +#include <linux/intel/libie/pci.h>
> +
> +/**
> + * struct ixd_adapter - Data structure representing a CPF
> + * @hw: Device access data
> + */
> +struct ixd_adapter {
> +	struct libie_mmio_info hw;
> +};
> +
> +/**
> + * ixd_to_dev - Get the corresponding device struct from an adapter
> + * @adapter: PCI device driver-specific private data
> + *
> + * Return: struct device corresponding to the given adapter
> + */
> +static inline struct device *ixd_to_dev(struct ixd_adapter *adapter)
> +{
> +	return &adapter->hw.pdev->dev;
> +}
> +
> +#endif /* _IXD_H_ */
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h b/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h
> new file mode 100644
> index 000000000000..fbb88929d0de
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h
> @@ -0,0 +1,28 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/* Copyright (C) 2025 Intel Corporation */
> +
> +#ifndef _IXD_LAN_REGS_H_
> +#define _IXD_LAN_REGS_H_
> +
> +/* Control Plane Function PCI ID */
> +#define IXD_DEV_ID_CPF			0x1efe
> +
> +/* Control Queue (Mailbox) */
> +#define PF_FW_MBX_REG_LEN		4096
> +#define PF_FW_MBX			0x08400000
> +
> +/* Reset registers */
> +#define PFGEN_RTRIG_REG_LEN		2048
> +#define PFGEN_RTRIG			0x08407000	/* Device resets */
> +
> +/**
> + * struct ixd_bar_region - BAR region description
> + * @offset: BAR region offset
> + * @size: BAR region size
> + */
> +struct ixd_bar_region {
> +	resource_size_t offset;
> +	resource_size_t size;
> +};
> +
> +#endif /* _IXD_LAN_REGS_H_ */
> diff --git a/drivers/net/ethernet/intel/ixd/ixd_main.c b/drivers/net/ethernet/intel/ixd/ixd_main.c
> new file mode 100644
> index 000000000000..75ee53152e61
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ixd/ixd_main.c
> @@ -0,0 +1,112 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright (C) 2025 Intel Corporation */
> +
> +#include "ixd.h"
> +#include "ixd_lan_regs.h"
> +
> +MODULE_DESCRIPTION("Intel(R) Control Plane Function Device Driver");
> +MODULE_IMPORT_NS("LIBIE_PCI");
> +MODULE_LICENSE("GPL");
> +
> +/**
> + * ixd_remove - remove a CPF PCI device
> + * @pdev: PCI device being removed
> + */
> +static void ixd_remove(struct pci_dev *pdev)
> +{
> +	struct ixd_adapter *adapter = pci_get_drvdata(pdev);
> +
> +	libie_pci_unmap_all_mmio_regions(&adapter->hw);
> +}
> +
> +/**
> + * ixd_shutdown - shut down a CPF PCI device
> + * @pdev: PCI device being shut down
> + */
> +static void ixd_shutdown(struct pci_dev *pdev)
> +{
> +	ixd_remove(pdev);
> +
> +	if (system_state == SYSTEM_POWER_OFF)
> +		pci_set_power_state(pdev, PCI_D3hot);
> +}
> +
> +/**
> + * ixd_iomap_regions - iomap PCI BARs
> + * @adapter: adapter to map memory regions for
> + *
> + * Returns: %0 on success, negative on failure
> + */
> +static int ixd_iomap_regions(struct ixd_adapter *adapter)
> +{
> +	const struct ixd_bar_region regions[] = {
> +		{
> +			.offset = PFGEN_RTRIG,
> +			.size = PFGEN_RTRIG_REG_LEN,
> +		},
> +		{
> +			.offset = PF_FW_MBX,
> +			.size = PF_FW_MBX_REG_LEN,
> +		},
> +	};
> +
> +	for (int i = 0; i < ARRAY_SIZE(regions); i++) {
> +		struct libie_mmio_info *mmio_info = &adapter->hw;
> +		bool map_ok;
> +
> +		map_ok = libie_pci_map_mmio_region(mmio_info,
> +						   regions[i].offset,
> +						   regions[i].size);
> +		if (!map_ok) {
> +			dev_err(ixd_to_dev(adapter),
> +				"Failed to map PCI device MMIO region\n");
> +
> +			libie_pci_unmap_all_mmio_regions(mmio_info);
> +			return -EIO;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * ixd_probe - probe a CPF PCI device
> + * @pdev: corresponding PCI device
> + * @ent: entry in ixd_pci_tbl
> + *
> + * Returns: %0 on success, negative errno code on failure
> + */
> +static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
> +{
> +	struct ixd_adapter *adapter;
> +	int err;
> +
> +	adapter = devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL);
> +	if (!adapter)
> +		return -ENOMEM;
> +	adapter->hw.pdev = pdev;
> +	INIT_LIST_HEAD(&adapter->hw.mmio_list);
> +
> +	err = libie_pci_init_dev(pdev);
> +	if (err)
> +		return err;
> +
> +	pci_set_drvdata(pdev, adapter);
> +
> +	return ixd_iomap_regions(adapter);
> +}
> +
> +static const struct pci_device_id ixd_pci_tbl[] = {
> +	{ PCI_VDEVICE(INTEL, IXD_DEV_ID_CPF) },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(pci, ixd_pci_tbl);
> +
> +static struct pci_driver ixd_driver = {
> +	.name			= KBUILD_MODNAME,
> +	.id_table		= ixd_pci_tbl,
> +	.probe			= ixd_probe,
> +	.remove			= ixd_remove,
> +	.shutdown		= ixd_shutdown,
> +};
> +module_pci_driver(ixd_driver);
> -- 
> 2.47.1
> 

^ permalink raw reply related

* Re: [PATCH] docs: submitting-patches: Clarify that in English "reviewer" is a person
From: David Hildenbrand (Arm) @ 2026-05-18  8:31 UTC (permalink / raw)
  To: Vlastimil Babka (SUSE), Krzysztof Kozlowski, Jonathan Corbet,
	Shuah Khan, workflows, linux-doc, linux-kernel
  Cc: Greg Kroah-Hartman, Andrew Morton, Linus Torvalds, Guenter Roeck
In-Reply-To: <ce1e5e9b-83d0-4971-aee3-dc5a8f85ce22@kernel.org>

On 5/16/26 16:39, Vlastimil Babka (SUSE) wrote:
> On 5/16/26 14:38, Krzysztof Kozlowski wrote:
>> Common understanding of word "Reviewer" is: a person performing a review
>> work [1]. Tools are not persons, thus cannot be reviewers in this term.
>> Also tools cannot make statements ("A Reviewed-by tag is a statement of
>> opinion"), since making a statement needs some sort of conscious mind.
>>
>> Our docs already clearly mark that "Reviewed-by" must come from a
>> person:
>>
>>  - "By offering my Reviewed-by: tag, I state that:"
>>
>>    Usage of first person "I" and word "state"
>>
>>  - "A Reviewed-by tag is *a statement of opinion* that the patch is an
>>     appropriate modification of the kernel without any remaining serious"
>>
>>    Only a person can make a statement of opinion.
>>
>>  - "Any interested reviewer (who has done the work) can offer a
>>    Reviewed-by"
>>
>>    A person can offer a tag thus above does not grant the tool
>>    permission to offer a tag.
>>
>> However this is not enough and apparently English is not that precise,
>> so let's clarify that only a person can state the "Reviewer's statement
>> of oversight".
>>
>> Link: https://en.wiktionary.org/wiki/reviewer [1]
>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> Cc: Vlastimil Babka <vbabka@kernel.org>
>> Cc: Andrew Morton <akpm@linux-foundation.org>
>> Cc: David Hildenbrand <david@kernel.org>
>> Cc: Linus Torvalds <torvalds@linux-foundation.org>
>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
> 
> I agree with the intent that the tag is for people (whether they use a tool
> or not to help them). We also don't put "Tested-by: kernel test robot" or
> syzkaller on every commit that they test and find no bugs. Review is also
> not just about absence of bugs, but agreeing with the larger design and
> whether the change makes sense to do in the first place.

I'd assume that SOB/RB/ACK would all be real persons, not tools.

For SOB we term it as "known identity". I'd assume that a tool is not an
identity ...

So maybe we should also talk about "know identity" here?

In any case, bots providing RB tags is stupid

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

David

^ permalink raw reply

* Re: [PATCH v13 3/4] gpio: rpmsg: add generic rpmsg GPIO driver
From: Padhi, Beleswar @ 2026-05-18  8:24 UTC (permalink / raw)
  To: Mathieu Poirier, Andrew Lunn
  Cc: tanmay.shah, Arnaud POULIQUEN, Shenwei Wang, Linus Walleij,
	Bartosz Golaszewski, Jonathan Corbet, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Frank Li,
	Sascha Hauer, Shuah Khan, linux-gpio@vger.kernel.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	Pengutronix Kernel Team, Fabio Estevam, Peng Fan,
	devicetree@vger.kernel.org, linux-remoteproc@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org,
	dl-linux-imx, Bartosz Golaszewski
In-Reply-To: <CANLsYkwBk0KbN-k9ce+5=oT+scdZ3nU5AOr3Fz4zT=0AFzghDA@mail.gmail.com>


On 5/12/2026 8:51 PM, Mathieu Poirier wrote:
> On Mon, 11 May 2026 at 12:18, Andrew Lunn <andrew@lunn.ch> wrote:
>>> Arnaud, Beleswar, Andrew and I are all advocating for one endpoint per
>>> GPIO controller.  The remaining issue it about the best way to work
>>> out source and destination addresses between Linux and the remote
>>> processor.  I'm running out of time for today but I'll return to this
>>> thread with a final analysis by the end of the week.
>> How many of the participants here will be in Minneapolis next week for
>> the Embedded Linux Conference? There is even a talk about this:
>>
>> https://osselcna2026.sched.com/event/2JQpx/building-virtual-drivers-with-rpmsg-key-design-principles-challenges-trade-offs-beleswar-prasad-padhi-texas-instruments?iframe=yes&w=100%&sidebar=yes&bg=no
>>
>> Maybe we can get together and decide on the final design after the
>> session.
>>
> I will not be in Minneapolis next week.  At this point I think things
> are converging into 2 main takeaways:
>
> 1) A serious refactoring of the protocol to include only what is
> available in the virtio-gpio specification [1].
> 2) The specification of GPIO controller number in an extension of the
> namespace announcement [2].


Fair enough. I am also aligned to use this solution with the support for
wildcard name service matching.

Thanks,
Beleswar

>
> Shenwei proposed embedding the GPIO controller number in the
> endpoint's source address [3], something I'm ambivalent about and
> still have to look into.  I also have to read Tanmay's latest
> comments.  I'm hoping to be done with all that by the end of the week.
> With the above (1) and (2), a new patchset will be required to reset
> this thread.
>
> Thanks,
> Mathieu
>
> [1]. https://lwn.net/ml/all/afjyH5JT0JS2j0L5@p14s/
> [2]. https://lwn.net/ml/all/afzIABSh1xtMEGbf%40p14s/
> [3]. https://lwn.net/ml/all/PAXPR04MB9185BFA6E7375FAD0B15B021893C2@PAXPR04MB9185.eurprd04.prod.outlook.com/
>
>>          Andrew

^ permalink raw reply

* Re: [PATCH] dcache: add fs.dentry-limit sysctl with negative-first reaper
From: Jan Kara @ 2026-05-18  8:19 UTC (permalink / raw)
  To: Ian Kent
  Cc: NeilBrown, Horst Birthelmer, Amir Goldstein, Miklos Szeredi,
	Jonathan Corbet, Shuah Khan, Alexander Viro, Christian Brauner,
	Jan Kara, linux-doc, linux-kernel, linux-fsdevel,
	Horst Birthelmer
In-Reply-To: <bc359831-e653-4269-9d57-742b48d56d9f@themaw.net>

Hi Ian,

On Mon 18-05-26 10:55:43, Ian Kent wrote:
> On 18/5/26 07:55, NeilBrown wrote:
> > On Fri, 15 May 2026, Horst Birthelmer wrote:
> > According to the email you linked, a problem arises when a directory has
> > a great many negative children.  Code which walks the list of children
> > (such as fsnotify) while holding a lock can suffer unpredictable delays
> > and result in long lock-hold times.  So maybe a limit on negative
> > dentries for any parent is what we really want.  That would be clumsy to
> > implement I imagine.
> 
> But the notion of dropping the dentry in ->d_delete() on last dput() is
> simple enough but did see regressions (the only other place in the VFS
> besides dentry_kill() that the inode is unlinked from the dentry on
> dput()). I wonder if the regression was related to the test itself
> deliberately recreating deleted files and if that really is normal
> behaviour. By itself that should prevent almost all negative dentries
> being retained. Although file systems could do this as well (think XFS
> inode recycling) it should be reasonable to require it be left to the
> VFS.
> 
> But even that's not enough given that, in my case, there would still be
> around 4 million dentries in the LRU cache and in fsnotify there are
> directory child traversals holding the parent i_lock "spinlock" that are
> going to cause problems.

Do you mean there are very many positive children of a directory?

> That's all that much more puzzling when I see things like commit
> 172e422ffea2 ("fsnotify: clear PARENT_WATCHED flags lazily") which looks
> like it implies the child flag depends entirely on the parent state (what
> am I missing Amir?)

PARENT_WATCHED dentry flags (as the name suggests) are only caching the
information whether the parent has notification marks receiving events from
the child. So yes, the flag fully depends on the parent state.

> so why is this traversal even retained in fsnotify?

Not sure which traversal you mean but if you set watch on a parent, you
have to walk all children to set PARENT_WATCHED flag so that you don't miss
events on children...

> > But what if we move dentries to the end of the list when they become
> > negative, and to the start of the list when they become positive?  Then
> > code which walks the child list could simply abort on the first
> > negative.
> > 
> > I doubt that would be quite as easy as it sounds, but it would at least
> > be more focused on the observed symptom rather than some whole-system
> > number which only vaguely correlates with the observed symptom.
> > 
> > Maybe a completely different approach: change children-walking code to
> > drop and retake the lock (with appropriate validation) periodically.
> > What too would address the specific symptom.
> 
> Another good question.
> 
> I have assumed that dropping and re-taking the lock cannot be done but
> this is a question I would like answered as well. Dropping and re-taking
> lock would require, as Miklos pointed out to me off-list, recording the
> list position with say a cursor, introducing unwanted complexity when it
> would be better to accept the cost of a single extra access to the parent
> flags (which I assume is one reason to set the flag in the child).

The parent access is actually more expensive than you might think. Based on
experience with past fsnotify related performance regression I expect some
20% performance hit for small tmpfs writes if you add unconditional parent
access to the write path.

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply

* Re: [RFC PATCH v3 1/3] scripts: add kconfirm
From: Arnd Bergmann @ 2026-05-18  8:08 UTC (permalink / raw)
  To: Miguel Ojeda, Demi Marie Obenour
  Cc: Julian Braha, Nathan Chancellor, Nicolas Schier, Jani Nikula,
	Andrew Morton, Gary Guo, ljs, Greg Kroah-Hartman, Masahiro Yamada,
	Miguel Ojeda, Jonathan Corbet, qingfang.deng, yann.prono, ej,
	linux-kernel, rust-for-linux, linux-doc, linux-kbuild
In-Reply-To: <CANiq72mGTehUWS2-MgukOKmwAn3fB63boFNqbNENse6B00M7Zg@mail.gmail.com>

On Mon, May 18, 2026, at 00:53, Miguel Ojeda wrote:
> On Sun, May 17, 2026 at 10:25 PM Demi Marie Obenour
> <demiobenour@gmail.com> wrote:
>>
>> I was hoping for Linux to avoid the Rust trend of downloading tons
>> of third-party crates, with all the supply-chain risks that entails.
>
> I completely agree -- it is why I said a well-known, vetted set of crates.
>
> That is, we should decide on e.g. a single CLI arg parser, a single
> logger, etc. for most of our tools, and ideally they should be
> well-known crates (ideally already trusted via use in the compiler
> itself).
>
> Moreover, they should be pinned with `--locked` or similar (like we
> already recommend for `bindgen-cli`), so that we only ever use
> something that matches the hash in the lockfile that would be
> committed in the tree.

What about dependencies that are normally shipped by the distros
along with the rust compiler? Would it be possible to allow a
range of version that matches the ones that are present on
common distros like we do with C libraries, or would that cause
more problems than it solves?

     Arnd

^ permalink raw reply

* Re: [PATCH net-next v3 08/14] idpf: refactor idpf to use libie control queues
From: Larysa Zaremba @ 2026-05-18  8:01 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev, Tony Nguyen
  Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
	Pavan Kumar Linga, przemyslaw.kitszel, aleksander.lobakin,
	sridhar.samudrala, anjali.singhai, michal.swiatkowski,
	maciej.fijalkowski, emil.s.tantilov, joshua.a.hay, jacob.e.keller,
	jayaprakash.shanmugam, jiri, horms, corbet, richardcochran,
	linux-doc, Aleksandr Loktionov, Samuel Salin
In-Reply-To: <20260515224443.2772147-9-anthony.l.nguyen@intel.com>

On Fri, May 15, 2026 at 03:44:32PM -0700, Tony Nguyen wrote:
> 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.

I had reviewed the Sashiko feedback [0]. Here is why I not find the feedback 
very helpful for this particular patch:

1. "Could this parse arbitrary messages as asynchronous events if the opcode 
    isn't checked?" - fixed in a later patch.
2. idpf_send_create_vport_msg() - recv_mem.iov_len is verified by libeth to be 
   no bigger than LIBIE_CTLQ_MAX_BUF_LEN, so this memcpy is always OK.
3. "Should the check instead be against struct_size(recv_rk, key_flex, 
    key_size)?" Yes, it should, but this is old code.
4. idpf_send_get_rx_ptype_msg() "Does this correctly prevent reading past the 
    end of the received buffer?" - no, but this is not introduced by the patch.
5. "Can this race with mbx_task and cause a NULL pointer dereference or
    use-after-free?" - fixed by a later patch.
6. "Does this require a bounds check to verify the received message length?" - 
   yes.

I will send the diff for 3, 4 and 6 in the next message.

[0] https://sashiko.dev/#/patchset/20260515224443.2772147-1-anthony.l.nguyen%40intel.com


> 
> 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.
> 
> 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.
> 
> 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.
> 
> 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>
> Tested-by: Samuel Salin <Samuel.salin@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 |   64 +-
>  .../net/ethernet/intel/idpf/idpf_virtchnl.c   | 1632 +++++++----------
>  .../net/ethernet/intel/idpf/idpf_virtchnl.h   |   94 +-
>  .../ethernet/intel/idpf/idpf_virtchnl_ptp.c   |  248 ++-
>  16 files changed, 832 insertions(+), 2521 deletions(-)
>  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 efdb58990a8b..679539a1b947 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 e36b0017186f..3a357d5dea20 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 93b11fb1609f..db91039c54d0 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 98b8f678bd9a..3dafe680b701 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
> @@ -9,42 +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)
>  {
> -	for (int 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;
> -			ccq->reg.tail = VF_ATQT;
> -			ccq->reg.len = VF_ATQLEN;
> -			ccq->reg.bah = VF_ATQBAH;
> -			ccq->reg.bal = VF_ATQBAL;
> -			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;
> -			ccq->reg.tail = VF_ARQT;
> -			ccq->reg.len = VF_ARQLEN;
> -			ccq->reg.bah = VF_ARQBAH;
> -			ccq->reg.bal = VF_ARQBAL;
> -			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;
>  }
>  
>  /**
> @@ -157,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 3e6411a07e4d..13c8505d126f 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,528 +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
> - *
> - * Will prepare the control queue message and initiates the send api
> - *
> - * 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). */
> -
> -/**
> - * idpf_vc_xn_lock - Request exclusive access to vc transaction
> - * @xn: struct idpf_vc_xn* to access
> - */
> -#define idpf_vc_xn_lock(xn)			\
> -	spin_lock(&(xn)->lock)
> -
> -/**
> - * idpf_vc_xn_unlock - Release exclusive access to vc transaction
> - * @xn: struct idpf_vc_xn* to access
> - */
> -#define idpf_vc_xn_unlock(xn)		\
> -	spin_unlock(&(xn)->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);
> -		spin_lock_init(&xn->lock);
> -		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
> + * @xn_params: Xn send parameters to fill
> + * @send_buf: buffer to send
> + * @send_buf_size: size of the send buffer
>   *
> - * All waiting threads will be woken-up and their transaction aborted. Further
> - * operations on that object will fail.
> - */
> -void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr)
> -{
> -	int i;
> -
> -	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);
> -
> -	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);
> -	}
> -}
> -
> -/**
> - * idpf_vc_xn_pop_free - Pop a free transaction from free list
> - * @vcxn_mngr: transaction manager to pop from
> + * 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.
>   *
> - * 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;
> -
> -	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;
> -
> -	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_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);
> -	spin_lock_bh(&vcxn_mngr->xn_bm_lock);
> -	set_bit(xn->idx, vcxn_mngr->free_xn_bm);
> -	spin_unlock_bh(&vcxn_mngr->xn_bm_lock);
> -}
> -
> -/**
> - * 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
> + * Cleanup the mailbox queue entries of the previously sent message to
> + * unmap and release the buffer.
>   *
> - * 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.
> + * Return: 0 if the request was successful, -%EBUSY if reset is detected
> + *	   or Tx control queue is full, other negative error code on failure.
>   */
> -static int
> -idpf_vc_xn_forward_async(struct idpf_adapter *adapter, struct idpf_vc_xn *xn,
> -			 const struct idpf_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 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:
> -		/* Set reply_sz from the actual payload so that async_handler
> -		 * can evaluate the response.
> -		 */
> -		xn->reply_sz = ctlq_msg->data_len;
> -		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;
> -	}
> +	struct libie_ctlq_msg ctlq_msg = {};
>  
> -	if (ctlq_msg->cookie.mbx.chnl_retval) {
> -		xn->reply_sz = 0;
> -		xn->state = IDPF_VC_XN_COMPLETED_FAILED;
> -		err = -EINVAL;
> -		goto out_unlock;
> -	}
> +	if (idpf_is_reset_detected(adapter)) {
> +		if (!libie_cp_can_send_onstack(send_buf_size))
> +			kfree(send_buf);
>  
> -	if (ctlq_msg->data_len) {
> -		payload = ctlq_msg->ctx.indirect.payload->va;
> -		payload_size = ctlq_msg->data_len;
> +		return -EBUSY;
>  	}
>  
> -	xn->reply_sz = payload_size;
> -	xn->state = IDPF_VC_XN_COMPLETED_SUCCESS;
> +	idpf_prepare_ptp_mb_msg(adapter, xn_params->chnl_opcode, &ctlq_msg);
> +	xn_params->ctlq_msg = ctlq_msg.opcode ? &ctlq_msg : NULL;
>  
> -	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));
> +	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;
>  
> -out_unlock:
> -	idpf_vc_xn_unlock(xn);
> -	/* we _cannot_ hold lock while calling complete */
> -	complete(&xn->completed);
> +	idpf_mb_clean(adapter, xn_params->ctlq, false);
>  
> -	return err;
> +	return libie_ctlq_xn_send(xn_params);
>  }
>  
>  /**
> - * 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;
>  }
> @@ -768,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;
> @@ -881,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);
> @@ -895,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 &&
> @@ -930,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;
>  }
>  
> @@ -942,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	|
> @@ -1004,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;
>  }
>  
>  /**
> @@ -1062,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;
> @@ -1102,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 (len && !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;
>  }
>  
> @@ -1164,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_kfree(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;
>  }
>  
>  /**
> @@ -1555,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);
> @@ -1586,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);
>  
> @@ -1674,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;
>  }
>  
>  /**
> @@ -1698,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;
>  
> -	return reply_sz < 0 ? reply_sz : 0;
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +
> +	return 0;
>  }
>  
>  /**
> @@ -1722,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;
>  }
>  
>  /**
> @@ -2573,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);
> @@ -2592,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;
>  
> -	return reply_sz < 0 ? reply_sz : 0;
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
> +
> +	return 0;
>  }
>  
>  /**
> @@ -2636,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);
> @@ -2652,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);
> +
> +free_rx_buf:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>  
> -	return idpf_vport_init_queue_reg_chunks(vport_config, &vc_msg->chunks);
> +	return err;
>  }
>  
>  /**
> @@ -2686,49 +2264,51 @@ 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;
> +	if (xn_params.recv_mem.iov_len < sizeof(*rcvd_vec)) {
> +		err = -EIO;
> +		goto free_rx_buf;
> +	}
>  
>  	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;
>  }
>  
>  /**
> @@ -2740,24 +2320,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;
>  }
>  
> @@ -2781,18 +2365,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;
>  }
>  
>  /**
> @@ -2805,10 +2393,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 */
> @@ -2817,38 +2409,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;
>  }
>  
>  /**
> @@ -2868,14 +2463,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)
> @@ -2889,37 +2486,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(*recv_rl)) {
> +		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 + sizeof(*recv_rl)) {
> +		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))
> @@ -2931,13 +2522,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);
> +	memcpy(rss_data->rss_lut, recv_rl->lut, lut_buf_size);
> +free_rx_buf:
> +	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
>  
> -	return 0;
> +	return err;
>  }
>  
>  /**
> @@ -2953,12 +2547,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);
> @@ -2966,37 +2562,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)
> @@ -3007,13 +2598,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;
>  }
>  
>  /**
> @@ -3190,15 +2784,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)
> @@ -3208,42 +2805,38 @@ 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;
> +		if (xn_params.recv_mem.iov_len < sizeof(*ptype_info)) {
> +			err = -EIO;
> +			goto free_rx_buf;
> +		}
>  		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++) {
> @@ -3258,14 +2851,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);
> @@ -3279,13 +2876,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;
>  }
>  
>  /**
> @@ -3313,40 +2915,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;
>  }
>  
>  /**
> @@ -3357,40 +2943,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;
> @@ -3402,12 +2991,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;
>  }
>  
>  /**
> @@ -3478,15 +3068,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:
> @@ -3633,8 +3214,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));
> @@ -3657,7 +3237,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);
> @@ -3666,7 +3246,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);
> @@ -4203,9 +3783,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
> @@ -4213,13 +3793,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;
> @@ -4227,18 +3808,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));
> @@ -4258,16 +3839,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);
>  }
>  
>  /**
> @@ -4286,19 +3864,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);
>  
> @@ -4353,32 +3933,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;
> @@ -4387,6 +3966,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
> @@ -4401,9 +4000,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))
> @@ -4414,15 +4017,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));
>  }
>  
>  /**
> @@ -4440,26 +4035,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 6992b768cef4..86a44b6e1488 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
> +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
> @@ -7,86 +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
> - * @lock: protects the transaction state fields below
> - * @state: virtchnl event loop stores the data below, protected by @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;
> -	spinlock_t lock;
> -	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;
> @@ -96,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);
> @@ -124,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;
> @@ -214,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..6d44021c222b 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,19 @@ 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;
> +	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;
> +	if (reply_sz < sizeof(*rcv_tx_tstamp_caps)) {
> +		err = -EIO;
>  		goto get_tstamp_caps_out;
>  	}
> -
>  	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 +419,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 +432,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 +529,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 +539,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 +569,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 +583,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 +604,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 +619,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;
>  	bool state_upd;
>  	u16 id = 0;
>  
> @@ -668,11 +660,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);
>  }
> -- 
> 2.47.1
> 

^ permalink raw reply

* Re: [PATCH v4 04/30] KVM: x86: Add KVM_[GS]ET_CLOCK_GUEST for accurate KVM clock migration
From: Dongli Zhang @ 2026-05-18  7:52 UTC (permalink / raw)
  To: David Woodhouse, kvm
  Cc: Paolo Bonzini, Jonathan Corbet, Shuah Khan, Thomas Gleixner,
	Sean Christopherson, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	Dave Hansen, Vitaly Kuznetsov, x86, Marc Zyngier, Juergen Gross,
	Boris Ostrovsky, Paul Durrant, Jonathan Cameron, Sascha Bischoff,
	Jack Allister, Joey Gouly, joe.jin, linux-doc, linux-kernel,
	xen-devel, linux-kselftest
In-Reply-To: <20260509224824.3264567-5-dwmw2@infradead.org>



On 5/9/26 3:46 PM, David Woodhouse wrote:
> From: Jack Allister <jalliste@amazon.com>
> 
> In the common case (where kvm->arch.use_master_clock is true), the KVM
> clock is defined as a simple arithmetic function of the guest TSC, based
> on a reference point stored in kvm->arch.master_kernel_ns and
> kvm->arch.master_cycle_now.
> 
> The existing KVM_[GS]ET_CLOCK functionality does not allow for this
> relationship to be precisely saved and restored by userspace. All it can
> currently do is set the KVM clock at a given UTC reference time, which
> is necessarily imprecise.
> 
> So on live update, the guest TSC can remain cycle accurate at precisely
> the same offset from the host TSC, but there is no way for userspace to
> restore the KVM clock accurately.
> 
> Even on live migration to a new host, where the accuracy of the guest
> time-keeping is fundamentally limited by the accuracy of wallclock
> synchronization between the source and destination hosts, the clock jump
> experienced by the guest's TSC and its KVM clock should at least be
> *consistent*. Even when the guest TSC suffers a discontinuity, its KVM
> clock should still remain the *same* arithmetic function of the guest
> TSC, and not suffer an *additional* discontinuity.
> 
> To allow for accurate migration of the KVM clock, add per-vCPU ioctls
> which save and restore the actual PV clock info in
> pvclock_vcpu_time_info.
> 
> The restoration in KVM_SET_CLOCK_GUEST works by creating a new reference
> point in time just as kvm_update_masterclock() does, and calculating the
> corresponding guest TSC value. This guest TSC value is then passed
> through the user-provided pvclock structure to generate the *intended*
> KVM clock value at that point in time, and through the *actual* KVM
> clock calculation. Then kvm->arch.kvmclock_offset is adjusted to
> eliminate the difference.
> 
> Where kvm->arch.use_master_clock is false (because the host TSC is
> unreliable, or the guest TSCs are configured strangely), the KVM clock
> is *not* defined as a function of the guest TSC so KVM_GET_CLOCK_GUEST
> returns an error. In this case, as documented, userspace shall use the
> legacy KVM_GET_CLOCK ioctl. The loss of precision is acceptable in this

The description here confused me a little. It sounds like userspace should call
KVM_SET_CLOCK if KVM_SET_CLOCK_GUEST fails. However, I assume it actually means
that userspace should do nothing extra if KVM_SET_CLOCK_GUEST fails, and simply
rely on the prior KVM_SET_CLOCK and KVM_VCPU_TSC_OFFSET workflow described in
patch 07. Is that correct?

> case since the clocks are imprecise in this mode anyway.
> 
> On *restoration*, if kvm->arch.use_master_clock is false, an error is
> returned for similar reasons and userspace shall fall back to using
> KVM_SET_CLOCK. This does mean that, as documented, userspace needs to
> use *both* KVM_GET_CLOCK_GUEST and KVM_GET_CLOCK and send both results
> with the migration data (unless the intent is to refuse to resume on a
> host with bad TSC).
> 
> Co-developed-by: David Woodhouse <dwmw@amazon.co.uk>
> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
> Signed-off-by: Jack Allister <jalliste@amazon.com>
> Reviewed-by: Paul Durrant <paul@xen.org>
> Cc: Dongli Zhang <dongli.zhang@oracle.com>
> ---
>  Documentation/virt/kvm/api.rst |  37 ++++++++
>  arch/x86/kvm/x86.c             | 151 +++++++++++++++++++++++++++++++++
>  include/uapi/linux/kvm.h       |   3 +
>  3 files changed, 191 insertions(+)
> 
> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> index 52bbbb553ce1..2268b4442df6 100644
> --- a/Documentation/virt/kvm/api.rst
> +++ b/Documentation/virt/kvm/api.rst
> @@ -6553,6 +6553,43 @@ KVM_S390_KEYOP_SSKE
>    Sets the storage key for the guest address ``guest_addr`` to the key
>    specified in ``key``, returning the previous value in ``key``.
>  
> +4.145 KVM_GET_CLOCK_GUEST
> +----------------------------
> +
> +:Capability: none
> +:Architectures: x86_64
> +:Type: vcpu ioctl
> +:Parameters: struct pvclock_vcpu_time_info (out)
> +:Returns: 0 on success, <0 on error
> +
> +Retrieves the current time information structure used for KVM/PV clocks,
> +in precisely the form advertised to the guest vCPU, which gives parameters
> +for a direct conversion from a guest TSC value to nanoseconds.
> +
> +When the KVM clock is not in "master clock" mode, for example because the
> +host TSC is unreliable or the guest TSCs are oddly configured, the KVM clock
> +is actually defined by the host CLOCK_MONOTONIC_RAW instead of the guest TSC.
> +In this case, the KVM_GET_CLOCK_GUEST ioctl returns -EINVAL.
> +
> +4.146 KVM_SET_CLOCK_GUEST
> +----------------------------
> +
> +:Capability: none

Do we need a KVM_CHECK_EXTENSION capability for this? If userspace wants to
support the new API, should it detect availability via KVM_CHECK_EXTENSION, or
simply try the ioctl and handle failure?

> +:Architectures: x86_64
> +:Type: vcpu ioctl
> +:Parameters: struct pvclock_vcpu_time_info (in)
> +:Returns: 0 on success, <0 on error
> +
> +Sets the KVM clock (for the whole VM) in terms of the vCPU TSC, using the
> +pvclock structure as returned by KVM_GET_CLOCK_GUEST. This allows the precise
> +arithmetic relationship between guest TSC and KVM clock to be preserved by
> +userspace across migration.
> +
> +When the KVM clock is not in "master clock" mode, and the KVM clock is actually
> +defined by the host CLOCK_MONOTONIC_RAW, this ioctl returns -EINVAL. Userspace
> +may choose to set the clock using the less precise KVM_SET_CLOCK ioctl, or may
> +choose to fail, denying migration to a host whose TSC is misbehaving.
> +
>  .. _kvm_run:
>  
>  5. The kvm_run structure
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index d9ef165df6a1..d1327d5fba3f 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -6205,6 +6205,149 @@ static int kvm_get_reg_list(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +#ifdef CONFIG_X86_64
> +static int kvm_vcpu_ioctl_get_clock_guest(struct kvm_vcpu *v, void __user *argp)
> +{
> +	struct pvclock_vcpu_time_info hv_clock = {};
> +	struct kvm_vcpu_arch *vcpu = &v->arch;
> +	struct kvm_arch *ka = &v->kvm->arch;
> +	unsigned int seq;
> +
> +	/*
> +	 * If KVM_REQ_CLOCK_UPDATE is already pending, or if the pvclock
> +	 * has never been generated at all, call kvm_guest_time_update().
> +	 */
> +	if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, v) || !vcpu->hw_tsc_hz) {

This was flagged by AI, and I am still checking whether it is a real issue.

What happens if KVM_REQ_MASTERCLOCK_UPDATE and KVM_REQ_CLOCK_UPDATE are both
pending?

From my perspective, I am also curious how we should reason about this in other
scenarios in the future. Specifically, when do we need to process
KVM_REQ_MASTERCLOCK_UPDATE before KVM_REQ_CLOCK_UPDATE, and when is it
acceptable not to? I noticed that kvm_cpuid() already processes only
KVM_REQ_CLOCK_UPDATE.

> +		int idx = srcu_read_lock(&v->kvm->srcu);
> +		int ret = kvm_guest_time_update(v);
> +
> +		srcu_read_unlock(&v->kvm->srcu, idx);
> +		if (ret)
> +			return -EINVAL;
> +	}
> +
> +	/*
> +	 * Reconstruct the pvclock from the master clock state, matching
> +	 * exactly what kvm_guest_time_update() writes to the guest.
> +	 */
> +	do {
> +		seq = read_seqcount_begin(&ka->pvclock_sc);
> +
> +		if (!ka->use_master_clock)
> +			return -EINVAL;
> +
> +		hv_clock.tsc_timestamp = kvm_read_l1_tsc(v, ka->master_cycle_now);
> +		hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset;
> +	} while (read_seqcount_retry(&ka->pvclock_sc, seq));
> +
> +	hv_clock.tsc_shift = vcpu->pvclock_tsc_shift;
> +	hv_clock.tsc_to_system_mul = vcpu->pvclock_tsc_mul;
> +	hv_clock.flags = PVCLOCK_TSC_STABLE_BIT;
> +
> +	if (copy_to_user(argp, &hv_clock, sizeof(hv_clock)))
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
> +/*
> + * Reverse the calculation in the hv_clock definition.
> + *
> + * time_ns = ( (cycles << shift) * mul ) >> 32;
> + * (although shift can be negative, so that's bad C)
> + *
> + * So for a single second,
> + * NSEC_PER_SEC = ( ( FREQ_HZ << shift) * mul ) >> 32
> + * NSEC_PER_SEC << 32 = ( FREQ_HZ << shift ) * mul
> + * ( NSEC_PER_SEC << 32 ) / mul = FREQ_HZ << shift
> + * ( NSEC_PER_SEC << 32 ) / mul ) >> shift = FREQ_HZ
> + */
> +static u64 hvclock_to_hz(u32 mul, s8 shift)
> +{
> +	u64 tm = NSEC_PER_SEC << 32;
> +
> +	/* Maximise precision. Shift right until the top bit is set */
> +	tm <<= 2;
> +	shift += 2;
> +
> +	/* While 'mul' is even, increase the shift *after* the division */
> +	while (!(mul & 1)) {
> +		shift++;
> +		mul >>= 1;
> +	}
> +
> +	tm /= mul;
> +
> +	if (shift > 0)
> +		return tm >> shift;
> +	else
> +		return tm << -shift;
> +}
> +
> +static int kvm_vcpu_ioctl_set_clock_guest(struct kvm_vcpu *v, void __user *argp)
> +{
> +	struct pvclock_vcpu_time_info user_hv_clock;
> +	struct kvm *kvm = v->kvm;
> +	struct kvm_arch *ka = &kvm->arch;
> +	u64 curr_tsc_hz, user_tsc_hz;
> +	u64 user_clk_ns;
> +	u64 guest_tsc;
> +	int rc = 0;
> +
> +	if (copy_from_user(&user_hv_clock, argp, sizeof(user_hv_clock)))
> +		return -EFAULT;
> +
> +	if (!user_hv_clock.tsc_to_system_mul)
> +		return -EINVAL;
> +
> +	user_tsc_hz = hvclock_to_hz(user_hv_clock.tsc_to_system_mul,
> +				    user_hv_clock.tsc_shift);
> +
> +	kvm_hv_request_tsc_page_update(kvm);
> +	kvm_start_pvclock_update(kvm);
> +	pvclock_update_vm_gtod_copy(kvm);
> +
> +	if (!ka->use_master_clock) {
> +		rc = -EINVAL;
> +		goto out;
> +	}
> +
> +	curr_tsc_hz = (u64)get_cpu_tsc_khz() * 1000;
> +	if (unlikely(curr_tsc_hz == 0)) {
> +		rc = -EINVAL;
> +		goto out;
> +	}
> +
> +	if (kvm_caps.has_tsc_control)
> +		curr_tsc_hz = kvm_scale_tsc(curr_tsc_hz,
> +					    v->arch.l1_tsc_scaling_ratio);
> +
> +	/*
> +	 * Allow for a discrepancy of 1 kHz either way between the TSC
> +	 * frequency used to generate the user's pvclock and the current
> +	 * host's measured frequency, since they may not precisely match.
> +	 */
> +	if (user_tsc_hz < curr_tsc_hz - 1000 ||
> +	    user_tsc_hz > curr_tsc_hz + 1000) {
> +		rc = -ERANGE;
> +		goto out;
> +	}
> +
> +	/*
> +	 * Calculate the guest TSC at the new reference point, and the
> +	 * corresponding KVM clock value according to user_hv_clock.
> +	 * Adjust kvmclock_offset so both definitions agree.
> +	 */
> +	guest_tsc = kvm_read_l1_tsc(v, ka->master_cycle_now);
> +	user_clk_ns = __pvclock_read_cycles(&user_hv_clock, guest_tsc);
> +	ka->kvmclock_offset = user_clk_ns - ka->master_kernel_ns;

I used to explore adjusting ka->kvmclock_offset in KVM_SET_CLOCK based on the
old hv_clock and the new hv_clock long time ago. At that time, my concern was
what would happen if userspace provided bogus values. Theoretically, this is
possible with any ioctl. My concern may be unnecessary.

Would it be helpful to validate that the delta is within a reasonable range,
e.g. that the drift can never be more than five minutes (forward or backward)?

Thank you very much!

Dongli Zhang

> +
> +out:
> +	kvm_end_pvclock_update(kvm);
> +	return rc;
> +}
> +#endif
> +
>  long kvm_arch_vcpu_ioctl(struct file *filp,
>  			 unsigned int ioctl, unsigned long arg)
>  {
> @@ -6605,6 +6748,14 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>  		srcu_read_unlock(&vcpu->kvm->srcu, idx);
>  		break;
>  	}
> +#ifdef CONFIG_X86_64
> +	case KVM_SET_CLOCK_GUEST:
> +		r = kvm_vcpu_ioctl_set_clock_guest(vcpu, argp);
> +		break;
> +	case KVM_GET_CLOCK_GUEST:
> +		r = kvm_vcpu_ioctl_get_clock_guest(vcpu, argp);
> +		break;
> +#endif
>  #ifdef CONFIG_KVM_HYPERV
>  	case KVM_GET_SUPPORTED_HV_CPUID:
>  		r = kvm_ioctl_get_supported_hv_cpuid(vcpu, argp);
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 6c8afa2047bf..9b50191b859c 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1669,4 +1669,7 @@ struct kvm_pre_fault_memory {
>  	__u64 padding[5];
>  };
>  
> +#define KVM_SET_CLOCK_GUEST	_IOW(KVMIO, 0xd6, struct pvclock_vcpu_time_info)
> +#define KVM_GET_CLOCK_GUEST	_IOR(KVMIO, 0xd7, struct pvclock_vcpu_time_info)
> +
>  #endif /* __LINUX_KVM_H */


^ permalink raw reply

* Re: [PATCH v5 05/13] dt-bindings: iio: frequency: add ad9910
From: Krzysztof Kozlowski @ 2026-05-18  7:52 UTC (permalink / raw)
  To: Rodrigo Alencar
  Cc: linux-iio, devicetree, linux-kernel, linux-doc, linux-hardening,
	Lars-Peter Clausen, Michael Hennerich, Jonathan Cameron,
	David Lechner, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Philipp Zabel, Jonathan Corbet, Shuah Khan,
	Kees Cook, Gustavo A. R. Silva
In-Reply-To: <20260517-ad9910-iio-driver-v5-5-31599c88314a@analog.com>

On Sun, May 17, 2026 at 07:37:49PM +0100, Rodrigo Alencar wrote:
> +maintainers:
> +  - Rodrigo Alencar <rodrigo.alencar@analog.com>
> +
> +description:
> +  The AD9910 is a 1 GSPS direct digital synthesizer (DDS) with an integrated
> +  14-bit DAC. It features single tone mode with 8 configurable profiles,
> +  a digital ramp generator, RAM control, OSK, and a parallel data port for
> +  high-speed streaming.
> +
> +  https://www.analog.com/en/products/ad9910.html
> +
> +properties:
> +  compatible:
> +    const: adi,ad9910
> +
> +  reg:
> +    maxItems: 1
> +
> +  spi-max-frequency:
> +    maximum: 70000000
> +
> +  clocks:
> +    minItems: 1
> +    items:
> +      - description: Reference clock (REF_CLK).
> +      - description: Optional synchronization clock (SYNC_IN).
> +
> +  clock-names:
> +    oneOf:
> +      - items:
> +          - const: ref_clk
> +      - items:
> +          - const: ref_clk
> +          - const: sync_in

So that's just items with two items and minItems: 1. Like you have in
"clocks:".

You got this comment already at v2.


> +
> +  '#clock-cells':
> +    const: 1
> +
> +  clock-output-names:
> +    minItems: 1
> +    maxItems: 3
> +    items:
> +      enum: [ sync_clk, pdclk, sync_out ]

Why are the names fixed? And why is the order random?

> +
> +  interrupts:
> +    minItems: 1
> +    items:
> +      - description:
> +          Signal that indicates that Digital Ramp Generator has reached a limit.
> +      - description:
> +          Signal that indicates the end of a RAM Sweep.
> +
> +  interrupt-names:
> +    minItems: 1
> +    maxItems: 2
> +    items:
> +      enum: [ drover, ram_swp_ovr ]

Your "interrupts:" do not allow flexibility. Are you sure interrupts are
optional in the hardware?

> +
> +  dvdd-io33-supply:
> +    description: 3.3V Digital I/O supply.
> +
> +  avdd33-supply:
> +    description: 3.3V Analog DAC supply.

Best regards,
Krzysztof


^ 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