linux-doc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH iwl-next v4 00/15] Introduce iXD driver
@ 2025-05-16 14:57 Larysa Zaremba
  2025-05-16 14:57 ` [PATCH iwl-next v4 01/15] virtchnl: create 'include/linux/intel' and move necessary header files Larysa Zaremba
                   ` (14 more replies)
  0 siblings, 15 replies; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:57 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali

This patch series adds the iXD driver, which supports the Intel(R)
Control Plane PCI Function on Intel E2100 and later IPUs and FNICs.
It facilitates a centralized control over multiple IDPF PFs/VFs/SFs
exposed by the same card. The reason for the separation is to be able
to offload the control plane to the host different from where the data
plane is running.

This is the first phase in the release of this driver where we implement the
initialization of the core PCI driver. Subsequent phases will implement
advanced features like usage of idpf ethernet aux device, link management,
NVM update via devlink, switchdev port representors, data and exception path,
flow rule programming, etc.

The first phase entails the following aspects:

1. Additional libie functionalities:
Patches 1-6 introduces additional common library API for drivers to
communicate with the control plane through mailbox communication.
A control queue is a hardware interface which is used by the driver
to interact with other subsystems (like firmware). The library APIs
allow the driver to setup and configure the control queues to send and
receive virtchnl messages. The library has an internal bookkeeping
(XN API) mechanism to keep track of the send messages. It supports both
synchronous as well as asynchronous way of handling the messages. The
library also handles the timeout internally for synchronous messages
using events. This reduces the driver's overhead in handling the timeout
error cases.

The current patch series supports only APIs that are needed for device
initialization. These include APIs in the libie_pci module:
* Allocating/freeing the DMA memory and mapping the MMIO regions for
  BAR0, read/write APIs for drivers to access the MMIO memory

and libie_cp module:
* Control queue initialization and configuration
* Transport initialization for bookkeeping
* Blocking and asynchronous mailbox transactions

Once the mailbox is initialized, the drivers can send and receive virtchnl
messages to/from the control plane.

The modules above are not supposed to be linked witn the main libie library,
but do share the folder with it.

2. idpf :
Patches 7-10 refactor the idpf driver to use the libie APIs for control
queue configuration, virtchnl transaction, device initialization and
reset and adjust related code accordingly.

3. ixd:
Patches 11-14 add the ixd driver and implement multiple pieces of the
initialization flow as follows:
* Add the ability to load
* A reset is issued to ensure a clean device state, followed by
  initialization of the mailbox
* Device capabilities:
  As part of initialization, the driver has to determine what the device is
  capable of (ex. max queues, vports, etc). This information is obtained from
  the firmware and stored by the driver.
* Enable initial support for the devlink interface

v3->v4:
* non-trivial rebase affecting patch 1 (moving headers) and idpf refactoring
  patches

v2->v3:
* non-trivial rebase affecting idpf refactoring patches
* add include/linux/intel under both Tony and NETWORKING DRIVERS
* due to rebase, in libie account for libeth_rx now using netmem instead
  of plain pages
* make libie_ctlq_release_rx_buf() take only one argument, as the producing
  queue is not actually needed to release a page pool buffer
* fix return value not being set in idpf_send_get_rx_ptype_msg()
* fix kdoc comments, so libie and ixd generate it cleanly
* separate idpf refactoring into 2 patches: pci+mmio and ctlq+xn
* suplement idpf refactoring commit message with information about module size
  and resource usage changes
* reformat commit messages to reduce the number of wasted lines

v1->v2:
* rename libeth_cp and libeth_pci to libie_cp and libie_pci respectively,
  move them into an appropriate folder
* rebase on top of recent PTP changes, this alters idpf refactor
* update maintainers after moving headers
* cast resource_size_t to unsigned long long when printing
* add ixd devlink documentation into index
* fix xn system kdoc problems
* fix indentation in libeth_ctlq_xn_deinit()
* fix extra kdoc member vcxn_mngr in idpf_adapter

Amritha Nambiar (1):
  ixd: add devlink support

Larysa Zaremba (5):
  idpf: make mbx_task queueing and cancelling more consistent
  idpf: print a debug message and bail in case of non-event ctlq message
  ixd: add basic driver framework for Intel(R) Control Plane Function
  ixd: add reset checks and initialize the mailbox
  ixd: add the core initialization

Pavan Kumar Linga (4):
  libeth: allow to create fill queues without NAPI
  idpf: remove 'vport_params_reqd' field
  idpf: refactor idpf to use libie_pci APIs
  idpf: refactor idpf to use libie control queues

Phani R Burra (3):
  libie: add PCI device initialization helpers to libie
  libie: add control queue support
  libie: add bookkeeping support for control queue messages

Victor Raj (2):
  virtchnl: create 'include/linux/intel' and move necessary header files
  virtchnl: introduce control plane version fields

 .../device_drivers/ethernet/index.rst         |    1 +
 .../device_drivers/ethernet/intel/ixd.rst     |   39 +
 Documentation/networking/devlink/index.rst    |    1 +
 Documentation/networking/devlink/ixd.rst      |   35 +
 MAINTAINERS                                   |    6 +-
 drivers/infiniband/hw/irdma/i40iw_if.c        |    2 +-
 drivers/infiniband/hw/irdma/main.h            |    4 +-
 drivers/net/ethernet/intel/Kconfig            |    2 +
 drivers/net/ethernet/intel/Makefile           |    1 +
 drivers/net/ethernet/intel/i40e/i40e.h        |    4 +-
 .../net/ethernet/intel/i40e/i40e_adminq_cmd.h |    2 +-
 drivers/net/ethernet/intel/i40e/i40e_client.c |    2 +-
 drivers/net/ethernet/intel/i40e/i40e_common.c |    2 +-
 .../net/ethernet/intel/i40e/i40e_ethtool.c    |    2 +-
 drivers/net/ethernet/intel/i40e/i40e_main.c   |    2 +-
 .../net/ethernet/intel/i40e/i40e_prototype.h  |    2 +-
 drivers/net/ethernet/intel/i40e/i40e_txrx.c   |    4 +-
 drivers/net/ethernet/intel/i40e/i40e_txrx.h   |    2 +-
 .../ethernet/intel/i40e/i40e_virtchnl_pf.h    |    2 +-
 drivers/net/ethernet/intel/iavf/iavf.h        |    2 +-
 .../net/ethernet/intel/iavf/iavf_adminq_cmd.h |    2 +-
 drivers/net/ethernet/intel/iavf/iavf_common.c |    2 +-
 drivers/net/ethernet/intel/iavf/iavf_main.c   |    2 +-
 .../net/ethernet/intel/iavf/iavf_prototype.h  |    2 +-
 drivers/net/ethernet/intel/iavf/iavf_txrx.c   |    2 +-
 drivers/net/ethernet/intel/iavf/iavf_txrx.h   |    2 +-
 drivers/net/ethernet/intel/iavf/iavf_types.h  |    4 +-
 .../net/ethernet/intel/iavf/iavf_virtchnl.c   |    2 +-
 drivers/net/ethernet/intel/ice/ice.h          |    2 +-
 .../net/ethernet/intel/ice/ice_adminq_cmd.h   |    2 +-
 drivers/net/ethernet/intel/ice/ice_common.h   |    2 +-
 drivers/net/ethernet/intel/ice/ice_flow.h     |    2 +-
 drivers/net/ethernet/intel/ice/ice_idc_int.h  |    4 +-
 drivers/net/ethernet/intel/ice/ice_txrx_lib.c |    2 +-
 drivers/net/ethernet/intel/ice/ice_vf_lib.h   |    2 +-
 drivers/net/ethernet/intel/ice/ice_virtchnl.h |    2 +-
 drivers/net/ethernet/intel/idpf/Kconfig       |    1 +
 drivers/net/ethernet/intel/idpf/Makefile      |    2 -
 drivers/net/ethernet/intel/idpf/idpf.h        |   47 +-
 .../net/ethernet/intel/idpf/idpf_controlq.c   |  624 ------
 .../net/ethernet/intel/idpf/idpf_controlq.h   |  130 --
 .../ethernet/intel/idpf/idpf_controlq_api.h   |  177 --
 .../ethernet/intel/idpf/idpf_controlq_setup.c |  171 --
 drivers/net/ethernet/intel/idpf/idpf_dev.c    |   95 +-
 .../net/ethernet/intel/idpf/idpf_ethtool.c    |   37 +-
 drivers/net/ethernet/intel/idpf/idpf_lib.c    |   62 +-
 drivers/net/ethernet/intel/idpf/idpf_main.c   |   87 +-
 drivers/net/ethernet/intel/idpf/idpf_mem.h    |   20 -
 drivers/net/ethernet/intel/idpf/idpf_txrx.h   |    4 +-
 drivers/net/ethernet/intel/idpf/idpf_vf_dev.c |   93 +-
 .../net/ethernet/intel/idpf/idpf_virtchnl.c   | 1672 ++++++-----------
 .../net/ethernet/intel/idpf/idpf_virtchnl.h   |   90 +-
 .../ethernet/intel/idpf/idpf_virtchnl_ptp.c   |  256 ++-
 drivers/net/ethernet/intel/ixd/Kconfig        |   15 +
 drivers/net/ethernet/intel/ixd/Makefile       |   13 +
 drivers/net/ethernet/intel/ixd/ixd.h          |   58 +
 drivers/net/ethernet/intel/ixd/ixd_ctlq.c     |  148 ++
 drivers/net/ethernet/intel/ixd/ixd_ctlq.h     |   33 +
 drivers/net/ethernet/intel/ixd/ixd_dev.c      |   89 +
 drivers/net/ethernet/intel/ixd/ixd_devlink.c  |  105 ++
 drivers/net/ethernet/intel/ixd/ixd_devlink.h  |   44 +
 drivers/net/ethernet/intel/ixd/ixd_lan_regs.h |   68 +
 drivers/net/ethernet/intel/ixd/ixd_lib.c      |  166 ++
 drivers/net/ethernet/intel/ixd/ixd_main.c     |  150 ++
 drivers/net/ethernet/intel/ixd/ixd_virtchnl.c |  178 ++
 drivers/net/ethernet/intel/ixd/ixd_virtchnl.h |   12 +
 .../ethernet/intel/ixgbe/ixgbe_type_e610.h    |    2 +-
 drivers/net/ethernet/intel/libeth/rx.c        |    9 +-
 drivers/net/ethernet/intel/libie/Kconfig      |   14 +
 drivers/net/ethernet/intel/libie/Makefile     |    8 +
 drivers/net/ethernet/intel/libie/adminq.c     |    2 +-
 drivers/net/ethernet/intel/libie/controlq.c   | 1185 ++++++++++++
 drivers/net/ethernet/intel/libie/pci.c        |  184 ++
 drivers/net/ethernet/intel/libie/rx.c         |    2 +-
 include/linux/{net => }/intel/i40e_client.h   |    0
 include/linux/{net => }/intel/iidc_rdma.h     |    0
 include/linux/{net => }/intel/iidc_rdma_ice.h |    0
 include/linux/{net => }/intel/libie/adminq.h  |    0
 include/linux/intel/libie/controlq.h          |  419 +++++
 include/linux/intel/libie/pci.h               |   54 +
 include/linux/{net => }/intel/libie/pctype.h  |    0
 include/linux/{net => }/intel/libie/rx.h      |    0
 include/linux/{avf => intel}/virtchnl.h       |    0
 .../idpf => include/linux/intel}/virtchnl2.h  |    6 +-
 .../linux/intel}/virtchnl2_lan_desc.h         |    0
 include/net/libeth/rx.h                       |    4 +-
 86 files changed, 3993 insertions(+), 2696 deletions(-)
 create mode 100644 Documentation/networking/device_drivers/ethernet/intel/ixd.rst
 create mode 100644 Documentation/networking/devlink/ixd.rst
 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
 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_ctlq.c
 create mode 100644 drivers/net/ethernet/intel/ixd/ixd_ctlq.h
 create mode 100644 drivers/net/ethernet/intel/ixd/ixd_dev.c
 create mode 100644 drivers/net/ethernet/intel/ixd/ixd_devlink.c
 create mode 100644 drivers/net/ethernet/intel/ixd/ixd_devlink.h
 create mode 100644 drivers/net/ethernet/intel/ixd/ixd_lan_regs.h
 create mode 100644 drivers/net/ethernet/intel/ixd/ixd_lib.c
 create mode 100644 drivers/net/ethernet/intel/ixd/ixd_main.c
 create mode 100644 drivers/net/ethernet/intel/ixd/ixd_virtchnl.c
 create mode 100644 drivers/net/ethernet/intel/ixd/ixd_virtchnl.h
 create mode 100644 drivers/net/ethernet/intel/libie/controlq.c
 create mode 100644 drivers/net/ethernet/intel/libie/pci.c
 rename include/linux/{net => }/intel/i40e_client.h (100%)
 rename include/linux/{net => }/intel/iidc_rdma.h (100%)
 rename include/linux/{net => }/intel/iidc_rdma_ice.h (100%)
 rename include/linux/{net => }/intel/libie/adminq.h (100%)
 create mode 100644 include/linux/intel/libie/controlq.h
 create mode 100644 include/linux/intel/libie/pci.h
 rename include/linux/{net => }/intel/libie/pctype.h (100%)
 rename include/linux/{net => }/intel/libie/rx.h (100%)
 rename include/linux/{avf => intel}/virtchnl.h (100%)
 rename {drivers/net/ethernet/intel/idpf => include/linux/intel}/virtchnl2.h (99%)
 rename {drivers/net/ethernet/intel/idpf => include/linux/intel}/virtchnl2_lan_desc.h (100%)

-- 
2.47.0


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 01/15] virtchnl: create 'include/linux/intel' and move necessary header files
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
@ 2025-05-16 14:57 ` Larysa Zaremba
  2025-05-16 14:57 ` [PATCH iwl-next v4 02/15] virtchnl: introduce control plane version fields Larysa Zaremba
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:57 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali

From: Victor Raj <victor.raj@intel.com>

include/linux/net houses a single folder "intel", meanwhile
include/linux/intel is vacant. On top of that, it would be useful to place
all iavf headers together with other intel networking headers.

Move abovementioned intel header files into new folder include/linux/intel.
Also, assign new folder to both intel and general networking maintainers.

Suggested-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Reviewed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Signed-off-by: Victor Raj <victor.raj@intel.com>
Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
---
 MAINTAINERS                                                 | 6 +++---
 drivers/infiniband/hw/irdma/i40iw_if.c                      | 2 +-
 drivers/infiniband/hw/irdma/main.h                          | 4 ++--
 drivers/net/ethernet/intel/i40e/i40e.h                      | 4 ++--
 drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h           | 2 +-
 drivers/net/ethernet/intel/i40e/i40e_client.c               | 2 +-
 drivers/net/ethernet/intel/i40e/i40e_common.c               | 2 +-
 drivers/net/ethernet/intel/i40e/i40e_ethtool.c              | 2 +-
 drivers/net/ethernet/intel/i40e/i40e_main.c                 | 2 +-
 drivers/net/ethernet/intel/i40e/i40e_prototype.h            | 2 +-
 drivers/net/ethernet/intel/i40e/i40e_txrx.c                 | 4 ++--
 drivers/net/ethernet/intel/i40e/i40e_txrx.h                 | 2 +-
 drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h          | 2 +-
 drivers/net/ethernet/intel/iavf/iavf.h                      | 2 +-
 drivers/net/ethernet/intel/iavf/iavf_adminq_cmd.h           | 2 +-
 drivers/net/ethernet/intel/iavf/iavf_common.c               | 2 +-
 drivers/net/ethernet/intel/iavf/iavf_main.c                 | 2 +-
 drivers/net/ethernet/intel/iavf/iavf_prototype.h            | 2 +-
 drivers/net/ethernet/intel/iavf/iavf_txrx.c                 | 2 +-
 drivers/net/ethernet/intel/iavf/iavf_txrx.h                 | 2 +-
 drivers/net/ethernet/intel/iavf/iavf_types.h                | 4 +---
 drivers/net/ethernet/intel/iavf/iavf_virtchnl.c             | 2 +-
 drivers/net/ethernet/intel/ice/ice.h                        | 2 +-
 drivers/net/ethernet/intel/ice/ice_adminq_cmd.h             | 2 +-
 drivers/net/ethernet/intel/ice/ice_common.h                 | 2 +-
 drivers/net/ethernet/intel/ice/ice_flow.h                   | 2 +-
 drivers/net/ethernet/intel/ice/ice_idc_int.h                | 4 ++--
 drivers/net/ethernet/intel/ice/ice_txrx_lib.c               | 2 +-
 drivers/net/ethernet/intel/ice/ice_vf_lib.h                 | 2 +-
 drivers/net/ethernet/intel/ice/ice_virtchnl.h               | 2 +-
 drivers/net/ethernet/intel/idpf/idpf.h                      | 2 +-
 drivers/net/ethernet/intel/idpf/idpf_txrx.h                 | 2 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h          | 2 +-
 drivers/net/ethernet/intel/libie/adminq.c                   | 2 +-
 drivers/net/ethernet/intel/libie/rx.c                       | 2 +-
 include/linux/{net => }/intel/i40e_client.h                 | 0
 include/linux/{net => }/intel/iidc_rdma.h                   | 0
 include/linux/{net => }/intel/iidc_rdma_ice.h               | 0
 include/linux/{net => }/intel/libie/adminq.h                | 0
 include/linux/{net => }/intel/libie/pctype.h                | 0
 include/linux/{net => }/intel/libie/rx.h                    | 0
 include/linux/{avf => intel}/virtchnl.h                     | 0
 .../ethernet/intel/idpf => include/linux/intel}/virtchnl2.h | 0
 .../intel/idpf => include/linux/intel}/virtchnl2_lan_desc.h | 0
 44 files changed, 41 insertions(+), 43 deletions(-)
 rename include/linux/{net => }/intel/i40e_client.h (100%)
 rename include/linux/{net => }/intel/iidc_rdma.h (100%)
 rename include/linux/{net => }/intel/iidc_rdma_ice.h (100%)
 rename include/linux/{net => }/intel/libie/adminq.h (100%)
 rename include/linux/{net => }/intel/libie/pctype.h (100%)
 rename include/linux/{net => }/intel/libie/rx.h (100%)
 rename include/linux/{avf => intel}/virtchnl.h (100%)
 rename {drivers/net/ethernet/intel/idpf => include/linux/intel}/virtchnl2.h (100%)
 rename {drivers/net/ethernet/intel/idpf => include/linux/intel}/virtchnl2_lan_desc.h (100%)

diff --git a/MAINTAINERS b/MAINTAINERS
index 84e99e991f53..1a809db89df8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11900,8 +11900,7 @@ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue.git
 F:	Documentation/networking/device_drivers/ethernet/intel/
 F:	drivers/net/ethernet/intel/
 F:	drivers/net/ethernet/intel/*/
-F:	include/linux/avf/virtchnl.h
-F:	include/linux/net/intel/*/
+F:	include/linux/intel/
 
 INTEL ETHERNET PROTOCOL DRIVER FOR RDMA
 M:	Mustafa Ismail <mustafa.ismail@intel.com>
@@ -13550,7 +13549,7 @@ L:	netdev@vger.kernel.org
 S:	Maintained
 T:	git https://github.com/alobakin/linux.git
 F:	drivers/net/ethernet/intel/libie/
-F:	include/linux/net/intel/libie/
+F:	include/linux/intel/libie/
 K:	libie
 
 LIBNVDIMM BTT: BLOCK TRANSLATION TABLE
@@ -16886,6 +16885,7 @@ F:	include/linux/fddidevice.h
 F:	include/linux/hippidevice.h
 F:	include/linux/if_*
 F:	include/linux/inetdevice.h
+F:	include/linux/intel/
 F:	include/linux/ism.h
 F:	include/linux/netdev*
 F:	include/linux/platform_data/wiznet.h
diff --git a/drivers/infiniband/hw/irdma/i40iw_if.c b/drivers/infiniband/hw/irdma/i40iw_if.c
index cc50a7070371..cfd71fe5bd79 100644
--- a/drivers/infiniband/hw/irdma/i40iw_if.c
+++ b/drivers/infiniband/hw/irdma/i40iw_if.c
@@ -2,7 +2,7 @@
 /* Copyright (c) 2015 - 2021 Intel Corporation */
 #include "main.h"
 #include "i40iw_hw.h"
-#include <linux/net/intel/i40e_client.h>
+#include <linux/intel/i40e_client.h>
 
 static struct i40e_client i40iw_client;
 
diff --git a/drivers/infiniband/hw/irdma/main.h b/drivers/infiniband/hw/irdma/main.h
index 674acc952168..8bd0e6605293 100644
--- a/drivers/infiniband/hw/irdma/main.h
+++ b/drivers/infiniband/hw/irdma/main.h
@@ -29,8 +29,8 @@
 #include <linux/io-64-nonatomic-lo-hi.h>
 #endif
 #include <linux/auxiliary_bus.h>
-#include <linux/net/intel/iidc_rdma.h>
-#include <linux/net/intel/iidc_rdma_ice.h>
+#include <linux/intel/iidc_rdma.h>
+#include <linux/intel/iidc_rdma_ice.h>
 #include <rdma/ib_smi.h>
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_pack.h>
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 6250f5203c15..766f3acc7563 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -8,8 +8,8 @@
 #include <linux/pci.h>
 #include <linux/ptp_clock_kernel.h>
 #include <linux/types.h>
-#include <linux/avf/virtchnl.h>
-#include <linux/net/intel/i40e_client.h>
+#include <linux/intel/virtchnl.h>
+#include <linux/intel/i40e_client.h>
 #include <net/devlink.h>
 #include <net/pkt_cls.h>
 #include <net/udp_tunnel.h>
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
index 76d872b91a38..c75b5bd680c3 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
@@ -4,7 +4,7 @@
 #ifndef _I40E_ADMINQ_CMD_H_
 #define _I40E_ADMINQ_CMD_H_
 
-#include <linux/net/intel/libie/adminq.h>
+#include <linux/intel/libie/adminq.h>
 
 #include <linux/bits.h>
 #include <linux/types.h>
diff --git a/drivers/net/ethernet/intel/i40e/i40e_client.c b/drivers/net/ethernet/intel/i40e/i40e_client.c
index 5f1a405cbbf8..3c9c95a87489 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_client.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_client.c
@@ -3,7 +3,7 @@
 
 #include <linux/list.h>
 #include <linux/errno.h>
-#include <linux/net/intel/i40e_client.h>
+#include <linux/intel/i40e_client.h>
 
 #include "i40e.h"
 
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index 270e7e8cf9cf..f36870b2e460 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright(c) 2013 - 2021 Intel Corporation. */
 
-#include <linux/avf/virtchnl.h>
+#include <linux/intel/virtchnl.h>
 #include <linux/bitfield.h>
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index 07b5c3c233f2..e421d4f461b1 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -3,7 +3,7 @@
 
 /* ethtool support for i40e */
 
-#include <linux/net/intel/libie/pctype.h>
+#include <linux/intel/libie/pctype.h>
 #include "i40e_devids.h"
 #include "i40e_diag.h"
 #include "i40e_txrx_common.h"
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 871100086375..7bfccd8d370c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -3,7 +3,7 @@
 
 #include <generated/utsrelease.h>
 #include <linux/crash_dump.h>
-#include <linux/net/intel/libie/pctype.h>
+#include <linux/intel/libie/pctype.h>
 #include <linux/if_bridge.h>
 #include <linux/if_macvlan.h>
 #include <linux/module.h>
diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
index aef5de53ce3b..3872bc57e2a2 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
@@ -5,7 +5,7 @@
 #define _I40E_PROTOTYPE_H_
 
 #include <linux/ethtool.h>
-#include <linux/avf/virtchnl.h>
+#include <linux/intel/virtchnl.h>
 #include "i40e_debug.h"
 #include "i40e_type.h"
 
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index 048c33039130..dc304eddd6fa 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -2,8 +2,8 @@
 /* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #include <linux/bpf_trace.h>
-#include <linux/net/intel/libie/pctype.h>
-#include <linux/net/intel/libie/rx.h>
+#include <linux/intel/libie/pctype.h>
+#include <linux/intel/libie/rx.h>
 #include <linux/prefetch.h>
 #include <linux/sctp.h>
 #include <net/mpls.h>
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
index 1e5fd63d47f4..e630493e9139 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -4,7 +4,7 @@
 #ifndef _I40E_TXRX_H_
 #define _I40E_TXRX_H_
 
-#include <linux/net/intel/libie/pctype.h>
+#include <linux/intel/libie/pctype.h>
 #include <net/xdp.h>
 #include "i40e_type.h"
 
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
index 5cf74f16f433..acaae2f6d00b 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
@@ -4,7 +4,7 @@
 #ifndef _I40E_VIRTCHNL_PF_H_
 #define _I40E_VIRTCHNL_PF_H_
 
-#include <linux/avf/virtchnl.h>
+#include <linux/intel/virtchnl.h>
 #include <linux/netdevice.h>
 #include "i40e_type.h"
 
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index eb86cca38be2..37e01d1d8a59 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -37,7 +37,7 @@
 #include <net/net_shaper.h>
 
 #include "iavf_type.h"
-#include <linux/avf/virtchnl.h>
+#include <linux/intel/virtchnl.h>
 #include "iavf_txrx.h"
 #include "iavf_fdir.h"
 #include "iavf_adv_rss.h"
diff --git a/drivers/net/ethernet/intel/iavf/iavf_adminq_cmd.h b/drivers/net/ethernet/intel/iavf/iavf_adminq_cmd.h
index 0482c9ce9b9c..12e84e1e971b 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_adminq_cmd.h
@@ -4,7 +4,7 @@
 #ifndef _IAVF_ADMINQ_CMD_H_
 #define _IAVF_ADMINQ_CMD_H_
 
-#include <linux/net/intel/libie/adminq.h>
+#include <linux/intel/libie/adminq.h>
 
 /* This header file defines the iavf Admin Queue commands and is shared between
  * iavf Firmware and Software.
diff --git a/drivers/net/ethernet/intel/iavf/iavf_common.c b/drivers/net/ethernet/intel/iavf/iavf_common.c
index 614a886bca99..9bc8bdc339c7 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_common.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_common.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright(c) 2013 - 2018 Intel Corporation. */
 
-#include <linux/avf/virtchnl.h>
+#include <linux/intel/virtchnl.h>
 #include <linux/bitfield.h>
 #include "iavf_type.h"
 #include "iavf_adminq.h"
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index e4c28c1545a0..84c73bd2c533 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright(c) 2013 - 2018 Intel Corporation. */
 
-#include <linux/net/intel/libie/rx.h>
+#include <linux/intel/libie/rx.h>
 #include <net/netdev_lock.h>
 
 #include "iavf.h"
diff --git a/drivers/net/ethernet/intel/iavf/iavf_prototype.h b/drivers/net/ethernet/intel/iavf/iavf_prototype.h
index 7f9f9dbf959a..a3348b063723 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_prototype.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_prototype.h
@@ -6,7 +6,7 @@
 
 #include "iavf_type.h"
 #include "iavf_alloc.h"
-#include <linux/avf/virtchnl.h>
+#include <linux/intel/virtchnl.h>
 
 /* Prototypes for shared code functions that are not in
  * the standard function pointer structures.  These are
diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
index 35d353d38129..ae797d387c08 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
@@ -2,7 +2,7 @@
 /* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #include <linux/bitfield.h>
-#include <linux/net/intel/libie/rx.h>
+#include <linux/intel/libie/rx.h>
 #include <linux/prefetch.h>
 
 #include "iavf.h"
diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.h b/drivers/net/ethernet/intel/iavf/iavf_txrx.h
index df49b0b1d54a..bc8a6068461d 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_txrx.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.h
@@ -4,7 +4,7 @@
 #ifndef _IAVF_TXRX_H_
 #define _IAVF_TXRX_H_
 
-#include <linux/net/intel/libie/pctype.h>
+#include <linux/intel/libie/pctype.h>
 
 /* Interrupt Throttling and Rate Limiting Goodies */
 #define IAVF_DEFAULT_IRQ_WORK      256
diff --git a/drivers/net/ethernet/intel/iavf/iavf_types.h b/drivers/net/ethernet/intel/iavf/iavf_types.h
index a095855122bf..270bc35f933d 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_types.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_types.h
@@ -4,9 +4,7 @@
 #ifndef _IAVF_TYPES_H_
 #define _IAVF_TYPES_H_
 
-#include "iavf_types.h"
-
-#include <linux/avf/virtchnl.h>
+#include <linux/intel/virtchnl.h>
 #include <linux/ptp_clock_kernel.h>
 
 /* structure used to queue PTP commands for processing */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index 34a422a4a29c..a296fc3aef52 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright(c) 2013 - 2018 Intel Corporation. */
 
-#include <linux/net/intel/libie/rx.h>
+#include <linux/intel/libie/rx.h>
 
 #include "iavf.h"
 #include "iavf_ptp.h"
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index b500b900e8ca..c86bc68ae091 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -36,7 +36,7 @@
 #include <linux/bpf.h>
 #include <linux/btf.h>
 #include <linux/auxiliary_bus.h>
-#include <linux/avf/virtchnl.h>
+#include <linux/intel/virtchnl.h>
 #include <linux/cpu_rmap.h>
 #include <linux/dim.h>
 #include <linux/gnss.h>
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index 11e55e1d1424..8ed7a85e4676 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -4,7 +4,7 @@
 #ifndef _ICE_ADMINQ_CMD_H_
 #define _ICE_ADMINQ_CMD_H_
 
-#include <linux/net/intel/libie/adminq.h>
+#include <linux/intel/libie/adminq.h>
 
 /* This header file defines the Admin Queue commands, error codes and
  * descriptor format. It is shared between Firmware and Software.
diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index 3f74570b99bf..487259786cd2 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -11,7 +11,7 @@
 #include "ice_nvm.h"
 #include "ice_flex_pipe.h"
 #include "ice_parser.h"
-#include <linux/avf/virtchnl.h>
+#include <linux/intel/virtchnl.h>
 #include "ice_switch.h"
 #include "ice_fdir.h"
 
diff --git a/drivers/net/ethernet/intel/ice/ice_flow.h b/drivers/net/ethernet/intel/ice/ice_flow.h
index 52f906d89eca..6858e9dd16c4 100644
--- a/drivers/net/ethernet/intel/ice/ice_flow.h
+++ b/drivers/net/ethernet/intel/ice/ice_flow.h
@@ -4,7 +4,7 @@
 #ifndef _ICE_FLOW_H_
 #define _ICE_FLOW_H_
 
-#include <linux/net/intel/libie/pctype.h>
+#include <linux/intel/libie/pctype.h>
 
 #include "ice_flex_type.h"
 #include "ice_parser.h"
diff --git a/drivers/net/ethernet/intel/ice/ice_idc_int.h b/drivers/net/ethernet/intel/ice/ice_idc_int.h
index 17dbfcfb6a2a..abe91f313441 100644
--- a/drivers/net/ethernet/intel/ice/ice_idc_int.h
+++ b/drivers/net/ethernet/intel/ice/ice_idc_int.h
@@ -4,8 +4,8 @@
 #ifndef _ICE_IDC_INT_H_
 #define _ICE_IDC_INT_H_
 
-#include <linux/net/intel/iidc_rdma.h>
-#include <linux/net/intel/iidc_rdma_ice.h>
+#include <linux/intel/iidc_rdma.h>
+#include <linux/intel/iidc_rdma_ice.h>
 
 struct ice_pf;
 
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
index 45cfaabc41cb..fb90916e7ef7 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
@@ -2,7 +2,7 @@
 /* Copyright (c) 2019, Intel Corporation. */
 
 #include <linux/filter.h>
-#include <linux/net/intel/libie/rx.h>
+#include <linux/intel/libie/rx.h>
 
 #include "ice_txrx_lib.h"
 #include "ice_eswitch.h"
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
index 482f4285fd35..5cdc98985523 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
@@ -10,7 +10,7 @@
 #include <linux/mutex.h>
 #include <linux/pci.h>
 #include <net/devlink.h>
-#include <linux/avf/virtchnl.h>
+#include <linux/intel/virtchnl.h>
 #include "ice_type.h"
 #include "ice_flow.h"
 #include "ice_virtchnl_fdir.h"
diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.h b/drivers/net/ethernet/intel/ice/ice_virtchnl.h
index b3eece8c6780..d8eb3c70413d 100644
--- a/drivers/net/ethernet/intel/ice/ice_virtchnl.h
+++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.h
@@ -7,7 +7,7 @@
 #include <linux/types.h>
 #include <linux/bitops.h>
 #include <linux/if_ether.h>
-#include <linux/avf/virtchnl.h>
+#include <linux/intel/virtchnl.h>
 #include "ice_vf_lib.h"
 
 /* Restrict number of MAC Addr and VLAN that non-trusted VF can programmed */
diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index aa2e97e2cd32..47931b7593eb 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -20,7 +20,7 @@ struct idpf_rss_data;
 #include <linux/ethtool_netlink.h>
 #include <net/gro.h>
 
-#include "virtchnl2.h"
+#include <linux/intel/virtchnl2.h>
 #include "idpf_txrx.h"
 #include "idpf_controlq.h"
 
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
index e52c5033b25b..fbe09413cdf6 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -11,7 +11,7 @@
 #include <net/netdev_queues.h>
 
 #include "idpf_lan_txrx.h"
-#include "virtchnl2_lan_desc.h"
+#include <linux/intel/virtchnl2_lan_desc.h>
 
 #define IDPF_LARGE_MAX_Q			256
 #define IDPF_MAX_Q				16
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
index d2f22d8558f8..d76334b8fbad 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
@@ -4,7 +4,7 @@
 #ifndef _IXGBE_TYPE_E610_H_
 #define _IXGBE_TYPE_E610_H_
 
-#include <linux/net/intel/libie/adminq.h>
+#include <linux/intel/libie/adminq.h>
 
 #define BYTES_PER_DWORD	4
 
diff --git a/drivers/net/ethernet/intel/libie/adminq.c b/drivers/net/ethernet/intel/libie/adminq.c
index 55356548e3f0..35eefecec144 100644
--- a/drivers/net/ethernet/intel/libie/adminq.c
+++ b/drivers/net/ethernet/intel/libie/adminq.c
@@ -2,7 +2,7 @@
 /* Copyright (C) 2025 Intel Corporation */
 
 #include <linux/module.h>
-#include <linux/net/intel/libie/adminq.h>
+#include <linux/intel/libie/adminq.h>
 
 static const char * const libie_aq_str_arr[] = {
 #define LIBIE_AQ_STR(x)					\
diff --git a/drivers/net/ethernet/intel/libie/rx.c b/drivers/net/ethernet/intel/libie/rx.c
index 66a9825fe11f..668785974727 100644
--- a/drivers/net/ethernet/intel/libie/rx.c
+++ b/drivers/net/ethernet/intel/libie/rx.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (C) 2024 Intel Corporation */
 
-#include <linux/net/intel/libie/rx.h>
+#include <linux/intel/libie/rx.h>
 
 /* O(1) converting i40e/ice/iavf's 8/10-bit hardware packet type to a parsed
  * bitfield struct.
diff --git a/include/linux/net/intel/i40e_client.h b/include/linux/intel/i40e_client.h
similarity index 100%
rename from include/linux/net/intel/i40e_client.h
rename to include/linux/intel/i40e_client.h
diff --git a/include/linux/net/intel/iidc_rdma.h b/include/linux/intel/iidc_rdma.h
similarity index 100%
rename from include/linux/net/intel/iidc_rdma.h
rename to include/linux/intel/iidc_rdma.h
diff --git a/include/linux/net/intel/iidc_rdma_ice.h b/include/linux/intel/iidc_rdma_ice.h
similarity index 100%
rename from include/linux/net/intel/iidc_rdma_ice.h
rename to include/linux/intel/iidc_rdma_ice.h
diff --git a/include/linux/net/intel/libie/adminq.h b/include/linux/intel/libie/adminq.h
similarity index 100%
rename from include/linux/net/intel/libie/adminq.h
rename to include/linux/intel/libie/adminq.h
diff --git a/include/linux/net/intel/libie/pctype.h b/include/linux/intel/libie/pctype.h
similarity index 100%
rename from include/linux/net/intel/libie/pctype.h
rename to include/linux/intel/libie/pctype.h
diff --git a/include/linux/net/intel/libie/rx.h b/include/linux/intel/libie/rx.h
similarity index 100%
rename from include/linux/net/intel/libie/rx.h
rename to include/linux/intel/libie/rx.h
diff --git a/include/linux/avf/virtchnl.h b/include/linux/intel/virtchnl.h
similarity index 100%
rename from include/linux/avf/virtchnl.h
rename to include/linux/intel/virtchnl.h
diff --git a/drivers/net/ethernet/intel/idpf/virtchnl2.h b/include/linux/intel/virtchnl2.h
similarity index 100%
rename from drivers/net/ethernet/intel/idpf/virtchnl2.h
rename to include/linux/intel/virtchnl2.h
diff --git a/drivers/net/ethernet/intel/idpf/virtchnl2_lan_desc.h b/include/linux/intel/virtchnl2_lan_desc.h
similarity index 100%
rename from drivers/net/ethernet/intel/idpf/virtchnl2_lan_desc.h
rename to include/linux/intel/virtchnl2_lan_desc.h
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 02/15] virtchnl: introduce control plane version fields
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
  2025-05-16 14:57 ` [PATCH iwl-next v4 01/15] virtchnl: create 'include/linux/intel' and move necessary header files Larysa Zaremba
@ 2025-05-16 14:57 ` Larysa Zaremba
  2025-05-16 14:58 ` [PATCH iwl-next v4 03/15] libie: add PCI device initialization helpers to libie Larysa Zaremba
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:57 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali

From: Victor Raj <victor.raj@intel.com>

In the virtchnl header file, add the Control Plane software version fields.

Signed-off-by: Victor Raj <victor.raj@intel.com>
Reviewed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
---
 include/linux/intel/virtchnl2.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/linux/intel/virtchnl2.h b/include/linux/intel/virtchnl2.h
index af0f975060c9..c6db143371bb 100644
--- a/include/linux/intel/virtchnl2.h
+++ b/include/linux/intel/virtchnl2.h
@@ -502,7 +502,8 @@ VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_version_info);
  *			    sent per transmit packet without needing to be
  *			    linearized.
  * @pad: Padding.
- * @reserved: Reserved.
+ * @cp_ver_major: Control Plane major version number.
+ * @cp_ver_minor: Control Plane minor version number.
  * @device_type: See enum virtchl2_device_type.
  * @min_sso_packet_len: Min packet length supported by device for single
  *			segment offload.
@@ -551,7 +552,8 @@ struct virtchnl2_get_capabilities {
 	__le16 max_tx_hdr_size;
 	u8 max_sg_bufs_per_tx_pkt;
 	u8 pad[3];
-	u8 reserved[4];
+	__le16 cp_ver_major;
+	__le16 cp_ver_minor;
 	__le32 device_type;
 	u8 min_sso_packet_len;
 	u8 max_hdr_buf_per_lso;
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 03/15] libie: add PCI device initialization helpers to libie
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
  2025-05-16 14:57 ` [PATCH iwl-next v4 01/15] virtchnl: create 'include/linux/intel' and move necessary header files Larysa Zaremba
  2025-05-16 14:57 ` [PATCH iwl-next v4 02/15] virtchnl: introduce control plane version fields Larysa Zaremba
@ 2025-05-16 14:58 ` Larysa Zaremba
  2025-05-16 14:58 ` [PATCH iwl-next v4 04/15] libeth: allow to create fill queues without NAPI Larysa Zaremba
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:58 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali, Phani R Burra

From: Phani R Burra <phani.r.burra@intel.com>

Add memory related support functions for drivers to access MMIO space and
allocate/free dma buffers.

Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Signed-off-by: Phani R Burra <phani.r.burra@intel.com>
Co-developed-by: Victor Raj <victor.raj@intel.com>
Signed-off-by: Victor Raj <victor.raj@intel.com>
Co-developed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Signed-off-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Co-developed-by: Pavan Kumar Linga <pavan.kumar.linga@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>
---
 drivers/net/ethernet/intel/libie/Kconfig  |   6 +
 drivers/net/ethernet/intel/libie/Makefile |   4 +
 drivers/net/ethernet/intel/libie/pci.c    | 184 ++++++++++++++++++++++
 include/linux/intel/libie/pci.h           |  54 +++++++
 4 files changed, 248 insertions(+)
 create mode 100644 drivers/net/ethernet/intel/libie/pci.c
 create mode 100644 include/linux/intel/libie/pci.h

diff --git a/drivers/net/ethernet/intel/libie/Kconfig b/drivers/net/ethernet/intel/libie/Kconfig
index e6072758e3d8..e54a9ed24882 100644
--- a/drivers/net/ethernet/intel/libie/Kconfig
+++ b/drivers/net/ethernet/intel/libie/Kconfig
@@ -14,3 +14,9 @@ config LIBIE_ADMINQ
 	help
 	  Helper functions used by Intel Ethernet drivers for administration
 	  queue command interface (aka adminq).
+
+config LIBIE_PCI
+	tristate
+	help
+	  Helper functions for management of PCI resources belonging
+	  to networking devices.
diff --git a/drivers/net/ethernet/intel/libie/Makefile b/drivers/net/ethernet/intel/libie/Makefile
index e98f00b865d3..5f648d312a2a 100644
--- a/drivers/net/ethernet/intel/libie/Makefile
+++ b/drivers/net/ethernet/intel/libie/Makefile
@@ -8,3 +8,7 @@ libie-y			:= rx.o
 obj-$(CONFIG_LIBIE_ADMINQ) 	+= libie_adminq.o
 
 libie_adminq-y			:= adminq.o
+
+obj-$(CONFIG_LIBIE_PCI)		+= libie_pci.o
+
+libie_pci-y			:= pci.o
diff --git a/drivers/net/ethernet/intel/libie/pci.c b/drivers/net/ethernet/intel/libie/pci.c
new file mode 100644
index 000000000000..727ce7b200a5
--- /dev/null
+++ b/drivers/net/ethernet/intel/libie/pci.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include <linux/intel/libie/pci.h>
+
+/**
+ * libie_find_mmio_region - find if MMIO region is present in the list
+ * @mmio_list: list that contains MMIO region info
+ * @offset: MMIO region start offset
+ * @bar_idx: BAR index where the offset to search
+ *
+ * Return: MMIO region pointer or NULL if the region info is not present.
+ */
+static struct libie_pci_mmio_region *
+libie_find_mmio_region(const struct list_head *mmio_list,
+		       resource_size_t offset, int bar_idx)
+{
+	struct libie_pci_mmio_region *mr;
+
+	list_for_each_entry(mr, mmio_list, list)
+		if (mr->bar_idx == bar_idx && mr->offset == offset)
+			return mr;
+
+	return NULL;
+}
+
+/**
+ * __libie_pci_get_mmio_addr - get the MMIO virtual address
+ * @mmio_info: contains list of MMIO regions
+ * @offset: register offset of find
+ * @num_args: number of additional arguments present
+ *
+ * This function finds the virtual address of a register offset by iterating
+ * through the non-linear MMIO regions that are mapped by the driver.
+ *
+ * Return: valid MMIO virtual address or NULL.
+ */
+void __iomem *__libie_pci_get_mmio_addr(struct libie_mmio_info *mmio_info,
+					resource_size_t offset,
+					int num_args, ...)
+{
+	struct libie_pci_mmio_region *mr;
+	int bar_idx = 0;
+	va_list args;
+
+	if (num_args) {
+		va_start(args, num_args);
+		bar_idx = va_arg(args, int);
+		va_end(args);
+	}
+
+	list_for_each_entry(mr, &mmio_info->mmio_list, list)
+		if (bar_idx == mr->bar_idx && offset >= mr->offset &&
+		    offset < mr->offset + mr->size) {
+			offset -= mr->offset;
+
+			return mr->addr + offset;
+		}
+
+	return NULL;
+}
+EXPORT_SYMBOL_NS_GPL(__libie_pci_get_mmio_addr, "LIBIE_PCI");
+
+/**
+ * __libie_pci_map_mmio_region - map PCI device MMIO region
+ * @mmio_info: struct to store the mapped MMIO region
+ * @offset: MMIO region start offset
+ * @size: MMIO region size
+ * @num_args: number of additional arguments present
+ *
+ * Return: true on success, false on memory map failure.
+ */
+bool __libie_pci_map_mmio_region(struct libie_mmio_info *mmio_info,
+				 resource_size_t offset,
+				 resource_size_t size, int num_args, ...)
+{
+	struct pci_dev *pdev = mmio_info->pdev;
+	struct libie_pci_mmio_region *mr;
+	resource_size_t pa;
+	void __iomem *va;
+	int bar_idx = 0;
+	va_list args;
+
+	if (num_args) {
+		va_start(args, num_args);
+		bar_idx = va_arg(args, int);
+		va_end(args);
+	}
+
+	mr = libie_find_mmio_region(&mmio_info->mmio_list, offset, bar_idx);
+	if (mr) {
+		pci_warn(pdev, "Mapping of BAR%u with offset %llu already exists\n",
+			 bar_idx, (unsigned long long)offset);
+		return true;
+	}
+
+	pa = pci_resource_start(pdev, bar_idx) + offset;
+	va = ioremap(pa, size);
+	if (!va) {
+		pci_err(pdev, "Failed to allocate BAR%u region\n", bar_idx);
+		return false;
+	}
+
+	mr = kvzalloc(sizeof(*mr), GFP_KERNEL);
+	if (!mr) {
+		iounmap(va);
+		return false;
+	}
+
+	mr->addr = va;
+	mr->offset = offset;
+	mr->size = size;
+	mr->bar_idx = bar_idx;
+
+	list_add_tail(&mr->list, &mmio_info->mmio_list);
+
+	return true;
+}
+EXPORT_SYMBOL_NS_GPL(__libie_pci_map_mmio_region, "LIBIE_PCI");
+
+/**
+ * libie_pci_unmap_all_mmio_regions - unmap all PCI device MMIO regions
+ * @mmio_info: contains list of MMIO regions to unmap
+ */
+void libie_pci_unmap_all_mmio_regions(struct libie_mmio_info *mmio_info)
+{
+	struct libie_pci_mmio_region *mr, *tmp;
+
+	list_for_each_entry_safe(mr, tmp, &mmio_info->mmio_list, list) {
+		iounmap(mr->addr);
+		list_del(&mr->list);
+		kfree(mr);
+	}
+}
+EXPORT_SYMBOL_NS_GPL(libie_pci_unmap_all_mmio_regions, "LIBIE_PCI");
+
+/**
+ * libie_pci_init_dev - enable and reserve PCI regions of the device
+ * @pdev: PCI device information
+ *
+ * Return: %0 on success, -%errno on failure.
+ */
+int libie_pci_init_dev(struct pci_dev *pdev)
+{
+	int err;
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+
+	err = pci_request_mem_regions(pdev, pci_name(pdev));
+	if (err)
+		goto disable_dev;
+
+	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+	if (err)
+		goto rel_regions;
+
+	pci_set_master(pdev);
+
+	return 0;
+
+rel_regions:
+	pci_release_regions(pdev);
+disable_dev:
+	pci_disable_device(pdev);
+
+	return err;
+}
+EXPORT_SYMBOL_NS_GPL(libie_pci_init_dev, "LIBIE_PCI");
+
+/**
+ * libie_pci_deinit_dev - disable and release the PCI regions of the device
+ * @pdev: PCI device information
+ */
+void libie_pci_deinit_dev(struct pci_dev *pdev)
+{
+	pci_disable_device(pdev);
+	pci_release_regions(pdev);
+}
+EXPORT_SYMBOL_NS_GPL(libie_pci_deinit_dev, "LIBIE_PCI");
+
+MODULE_DESCRIPTION("Common Ethernet PCI library");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/intel/libie/pci.h b/include/linux/intel/libie/pci.h
new file mode 100644
index 000000000000..4601205adc22
--- /dev/null
+++ b/include/linux/intel/libie/pci.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2025 Intel Corporation */
+
+#ifndef __LIBIE_PCI_H
+#define __LIBIE_PCI_H
+
+#include <linux/pci.h>
+
+/**
+ * struct libie_pci_mmio_region - structure for MMIO region info
+ * @list: used to add a MMIO region to the list of MMIO regions in
+ *	  libie_mmio_info
+ * @addr: virtual address of MMIO region start
+ * @offset: start offset of the MMIO region
+ * @size: size of the MMIO region
+ * @bar_idx: BAR index to which the MMIO region belongs to
+ */
+struct libie_pci_mmio_region {
+	struct list_head	list;
+	void __iomem		*addr;
+	resource_size_t		offset;
+	resource_size_t		size;
+	u16			bar_idx;
+};
+
+/**
+ * struct libie_mmio_info - contains list of MMIO regions
+ * @pdev: PCI device pointer
+ * @mmio_list: list of MMIO regions
+ */
+struct libie_mmio_info {
+	struct pci_dev		*pdev;
+	struct list_head	mmio_list;
+};
+
+#define libie_pci_map_mmio_region(mmio_info, offset, size, ...)	\
+	__libie_pci_map_mmio_region(mmio_info, offset, size,		\
+				     COUNT_ARGS(__VA_ARGS__), ##__VA_ARGS__)
+
+#define libie_pci_get_mmio_addr(mmio_info, offset, ...)		\
+	__libie_pci_get_mmio_addr(mmio_info, offset,			\
+				   COUNT_ARGS(__VA_ARGS__), ##__VA_ARGS__)
+
+bool __libie_pci_map_mmio_region(struct libie_mmio_info *mmio_info,
+				 resource_size_t offset, resource_size_t size,
+				 int num_args, ...);
+void __iomem *__libie_pci_get_mmio_addr(struct libie_mmio_info *mmio_info,
+					resource_size_t region_offset,
+					int num_args, ...);
+void libie_pci_unmap_all_mmio_regions(struct libie_mmio_info *mmio_info);
+int libie_pci_init_dev(struct pci_dev *pdev);
+void libie_pci_deinit_dev(struct pci_dev *pdev);
+
+#endif /* __LIBIE_PCI_H */
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 04/15] libeth: allow to create fill queues without NAPI
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
                   ` (2 preceding siblings ...)
  2025-05-16 14:58 ` [PATCH iwl-next v4 03/15] libie: add PCI device initialization helpers to libie Larysa Zaremba
@ 2025-05-16 14:58 ` Larysa Zaremba
  2025-05-16 14:58 ` [PATCH iwl-next v4 05/15] libie: add control queue support Larysa Zaremba
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:58 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali

From: Pavan Kumar Linga <pavan.kumar.linga@intel.com>

Control queues can utilize libeth_rx fill queues, despite working outside
of NAPI context. The only problem is standard fill queues requiring NAPI
that provides them with the device pointer.

Introduce a way to provide the device directly without using NAPI.

Suggested-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Signed-off-by: Pavan Kumar Linga <pavan.kumar.linga@intel.com>
Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
---
 drivers/net/ethernet/intel/libeth/rx.c | 9 +++++----
 include/net/libeth/rx.h                | 4 +++-
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/intel/libeth/rx.c b/drivers/net/ethernet/intel/libeth/rx.c
index c0be9cb043a1..b077454c4100 100644
--- a/drivers/net/ethernet/intel/libeth/rx.c
+++ b/drivers/net/ethernet/intel/libeth/rx.c
@@ -143,19 +143,20 @@ static bool libeth_rx_page_pool_params_zc(struct libeth_fq *fq,
 /**
  * libeth_rx_fq_create - create a PP with the default libeth settings
  * @fq: buffer queue struct to fill
- * @napi: &napi_struct covering this PP (no usage outside its poll loops)
+ * @napi_dev: &napi_struct for NAPI (data) queues, &device for others
  *
  * Return: %0 on success, -%errno on failure.
  */
-int libeth_rx_fq_create(struct libeth_fq *fq, struct napi_struct *napi)
+int libeth_rx_fq_create(struct libeth_fq *fq, void *napi_dev)
 {
+	struct napi_struct *napi = fq->no_napi ? NULL : napi_dev;
 	struct page_pool_params pp = {
 		.flags		= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
 		.order		= LIBETH_RX_PAGE_ORDER,
 		.pool_size	= fq->count,
 		.nid		= fq->nid,
-		.dev		= napi->dev->dev.parent,
-		.netdev		= napi->dev,
+		.dev		= napi ? napi->dev->dev.parent : napi_dev,
+		.netdev		= napi ? napi->dev : NULL,
 		.napi		= napi,
 	};
 	struct libeth_fqe *fqes;
diff --git a/include/net/libeth/rx.h b/include/net/libeth/rx.h
index 5d991404845e..0e736846c5e8 100644
--- a/include/net/libeth/rx.h
+++ b/include/net/libeth/rx.h
@@ -69,6 +69,7 @@ enum libeth_fqe_type {
  * @type: type of the buffers this queue has
  * @hsplit: flag whether header split is enabled
  * @xdp: flag indicating whether XDP is enabled
+ * @no_napi: the queue is not a data queue and does not have NAPI
  * @buf_len: HW-writeable length per each buffer
  * @nid: ID of the closest NUMA node with memory
  */
@@ -85,12 +86,13 @@ struct libeth_fq {
 	enum libeth_fqe_type	type:2;
 	bool			hsplit:1;
 	bool			xdp:1;
+	bool			no_napi:1;
 
 	u32			buf_len;
 	int			nid;
 };
 
-int libeth_rx_fq_create(struct libeth_fq *fq, struct napi_struct *napi);
+int libeth_rx_fq_create(struct libeth_fq *fq, void *napi_dev);
 void libeth_rx_fq_destroy(struct libeth_fq *fq);
 
 /**
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 05/15] libie: add control queue support
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
                   ` (3 preceding siblings ...)
  2025-05-16 14:58 ` [PATCH iwl-next v4 04/15] libeth: allow to create fill queues without NAPI Larysa Zaremba
@ 2025-05-16 14:58 ` Larysa Zaremba
  2025-05-16 14:58 ` [PATCH iwl-next v4 06/15] libie: add bookkeeping support for control queue messages Larysa Zaremba
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:58 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali, Phani R Burra

From: Phani R Burra <phani.r.burra@intel.com>

Libie will now support control queue setup and configuration APIs. These
are mainly used for mailbox communication between drivers and control
plane.

Make use of the libeth_rx page pool support for managing controlq buffers.

Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Signed-off-by: Phani R Burra <phani.r.burra@intel.com>
Co-developed-by: Victor Raj <victor.raj@intel.com>
Signed-off-by: Victor Raj <victor.raj@intel.com>
Co-developed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Signed-off-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Co-developed-by: Pavan Kumar Linga <pavan.kumar.linga@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>
---
 drivers/net/ethernet/intel/libie/Kconfig    |   8 +
 drivers/net/ethernet/intel/libie/Makefile   |   4 +
 drivers/net/ethernet/intel/libie/controlq.c | 607 ++++++++++++++++++++
 include/linux/intel/libie/controlq.h        | 249 ++++++++
 4 files changed, 868 insertions(+)
 create mode 100644 drivers/net/ethernet/intel/libie/controlq.c
 create mode 100644 include/linux/intel/libie/controlq.h

diff --git a/drivers/net/ethernet/intel/libie/Kconfig b/drivers/net/ethernet/intel/libie/Kconfig
index e54a9ed24882..59c9018a0a16 100644
--- a/drivers/net/ethernet/intel/libie/Kconfig
+++ b/drivers/net/ethernet/intel/libie/Kconfig
@@ -15,6 +15,14 @@ config LIBIE_ADMINQ
 	  Helper functions used by Intel Ethernet drivers for administration
 	  queue command interface (aka adminq).
 
+config LIBIE_CP
+	tristate
+	select LIBETH
+	select LIBIE_PCI
+	help
+	  Common helper routines to communicate with the device Control Plane
+	  using virtchnl2 or related mailbox protocols.
+
 config LIBIE_PCI
 	tristate
 	help
diff --git a/drivers/net/ethernet/intel/libie/Makefile b/drivers/net/ethernet/intel/libie/Makefile
index 5f648d312a2a..65912a357886 100644
--- a/drivers/net/ethernet/intel/libie/Makefile
+++ b/drivers/net/ethernet/intel/libie/Makefile
@@ -9,6 +9,10 @@ obj-$(CONFIG_LIBIE_ADMINQ) 	+= libie_adminq.o
 
 libie_adminq-y			:= adminq.o
 
+obj-$(CONFIG_LIBIE_CP)		+= libie_cp.o
+
+libie_cp-y			:= controlq.o
+
 obj-$(CONFIG_LIBIE_PCI)		+= libie_pci.o
 
 libie_pci-y			:= pci.o
diff --git a/drivers/net/ethernet/intel/libie/controlq.c b/drivers/net/ethernet/intel/libie/controlq.c
new file mode 100644
index 000000000000..80b0f1c2cc0a
--- /dev/null
+++ b/drivers/net/ethernet/intel/libie/controlq.c
@@ -0,0 +1,607 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include <linux/bitfield.h>
+#include <net/libeth/rx.h>
+
+#include <linux/intel/libie/controlq.h>
+
+#define LIBIE_CTLQ_DESC_QWORD0(sz)			\
+	(LIBIE_CTLQ_DESC_FLAG_BUF |			\
+	 LIBIE_CTLQ_DESC_FLAG_RD |			\
+	 FIELD_PREP(LIBIE_CTLQ_DESC_DATA_LEN, sz))
+
+/**
+ * libie_ctlq_free_fq - free fill queue resources, including buffers
+ * @ctlq: Rx control queue whose resources need to be freed
+ */
+static void libie_ctlq_free_fq(struct libie_ctlq_info *ctlq)
+{
+	struct libeth_fq fq = {
+		.fqes		= ctlq->rx_fqes,
+		.pp		= ctlq->pp,
+	};
+
+	for (u32 ntc = ctlq->next_to_clean; ntc != ctlq->next_to_post; ) {
+		page_pool_put_full_netmem(fq.pp, fq.fqes[ntc].netmem, false);
+
+		if (++ntc >= ctlq->ring_len)
+			ntc = 0;
+	}
+
+	libeth_rx_fq_destroy(&fq);
+}
+
+/**
+ * libie_ctlq_init_fq - initialize fill queue for an Rx controlq
+ * @ctlq: control queue that needs a Rx buffer allocation
+ *
+ * Return: %0 on success, -%errno on failure
+ */
+static int libie_ctlq_init_fq(struct libie_ctlq_info *ctlq)
+{
+	struct libeth_fq fq = {
+		.count		= ctlq->ring_len,
+		.truesize	= LIBIE_CTLQ_MAX_BUF_LEN,
+		.nid		= NUMA_NO_NODE,
+		.type		= LIBETH_FQE_SHORT,
+		.hsplit		= true,
+		.no_napi	= true,
+	};
+	int err;
+
+	err = libeth_rx_fq_create(&fq, ctlq->dev);
+	if (err)
+		return err;
+
+	ctlq->pp = fq.pp;
+	ctlq->rx_fqes = fq.fqes;
+	ctlq->truesize = fq.truesize;
+
+	return 0;
+}
+
+/**
+ * libie_ctlq_reset_rx_desc - reset the descriptor with a new address
+ * @desc: descriptor to (re)initialize
+ * @addr: physical address to put into descriptor
+ * @mem_truesize: size of the accessible memory
+ */
+static void libie_ctlq_reset_rx_desc(struct libie_ctlq_desc *desc,
+				     dma_addr_t addr, u32 mem_truesize)
+{
+	u64 qword;
+
+	*desc = (struct libie_ctlq_desc) {};
+	qword = LIBIE_CTLQ_DESC_QWORD0(mem_truesize);
+	desc->qword0 = cpu_to_le64(qword);
+
+	qword = FIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_HIGH,
+			   upper_32_bits(addr)) |
+		FIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_LOW,
+			   lower_32_bits(addr));
+	desc->qword3 = cpu_to_le64(qword);
+}
+
+/**
+ * libie_ctlq_post_rx_buffs - post buffers to descriptor ring
+ * @ctlq: control queue that requires Rx descriptor ring to be initialized with
+ *	  new Rx buffers
+ *
+ * The caller must make sure that calls to libie_ctlq_post_rx_buffs()
+ * and libie_ctlq_recv() for separate queues are either serialized
+ * or used under ctlq->lock.
+ *
+ * Return: %0 on success, -%ENOMEM if any buffer could not be allocated
+ */
+int libie_ctlq_post_rx_buffs(struct libie_ctlq_info *ctlq)
+{
+	u32 ntp = ctlq->next_to_post, ntc = ctlq->next_to_clean, num_to_post;
+	const struct libeth_fq_fp fq = {
+		.pp		= ctlq->pp,
+		.fqes		= ctlq->rx_fqes,
+		.truesize	= ctlq->truesize,
+		.count		= ctlq->ring_len,
+	};
+	int ret = 0;
+
+	num_to_post = (ntc > ntp ? 0 : ctlq->ring_len) + ntc - ntp - 1;
+
+	while (num_to_post--) {
+		dma_addr_t addr;
+
+		addr = libeth_rx_alloc(&fq, ntp);
+		if (unlikely(addr == DMA_MAPPING_ERROR)) {
+			ret = -ENOMEM;
+			goto post_bufs;
+		}
+
+		libie_ctlq_reset_rx_desc(&ctlq->descs[ntp], addr, fq.truesize);
+
+		if (unlikely(++ntp == ctlq->ring_len))
+			ntp = 0;
+	}
+
+post_bufs:
+	if (likely(ctlq->next_to_post != ntp)) {
+		ctlq->next_to_post = ntp;
+
+		writel(ntp, ctlq->reg.tail);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_post_rx_buffs, "LIBIE_CP");
+
+/**
+ * libie_ctlq_free_tx_msgs - Free Tx control queue messages
+ * @ctlq: Tx control queue being destroyed
+ * @num_msgs: number of messages allocated so far
+ */
+static void libie_ctlq_free_tx_msgs(struct libie_ctlq_info *ctlq,
+				    u32 num_msgs)
+{
+	for (u32 i = 0; i < num_msgs; i++)
+		kfree(ctlq->tx_msg[i]);
+
+	kvfree(ctlq->tx_msg);
+}
+
+/**
+ * libie_ctlq_alloc_tx_msgs - Allocate Tx control queue messages
+ * @ctlq: Tx control queue being created
+ *
+ * Return: %0 on success, -%ENOMEM on allocation error
+ */
+static int libie_ctlq_alloc_tx_msgs(struct libie_ctlq_info *ctlq)
+{
+	ctlq->tx_msg = kvcalloc(ctlq->ring_len,
+				sizeof(*ctlq->tx_msg), GFP_KERNEL);
+	if (!ctlq->tx_msg)
+		return -ENOMEM;
+
+	for (u32 i = 0; i < ctlq->ring_len; i++) {
+		ctlq->tx_msg[i] = kzalloc(sizeof(*ctlq->tx_msg[i]), GFP_KERNEL);
+
+		if (!ctlq->tx_msg[i]) {
+			libie_ctlq_free_tx_msgs(ctlq, i);
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * libie_cp_free_dma_mem - Free the previously allocated DMA memory
+ * @dev: device information
+ * @mem: DMA memory information
+ */
+static void libie_cp_free_dma_mem(struct device *dev,
+				  struct libie_cp_dma_mem *mem)
+{
+	dma_free_coherent(dev, mem->size, mem->va, mem->pa);
+	mem->va = NULL;
+}
+
+/**
+ * libie_ctlq_dealloc_ring_res - Free memory allocated for control queue
+ * @ctlq: control queue that requires its ring memory to be freed
+ *
+ * Free the memory used by the ring, buffers and other related structures.
+ */
+static void libie_ctlq_dealloc_ring_res(struct libie_ctlq_info *ctlq)
+{
+	struct libie_cp_dma_mem *dma = &ctlq->ring_mem;
+
+	if (ctlq->type == LIBIE_CTLQ_TYPE_TX)
+		libie_ctlq_free_tx_msgs(ctlq, ctlq->ring_len);
+	else
+		libie_ctlq_free_fq(ctlq);
+
+	libie_cp_free_dma_mem(ctlq->dev, dma);
+}
+
+/**
+ * libie_cp_alloc_dma_mem - Allocate a DMA memory
+ * @dev: device information
+ * @mem: memory for DMA information to be stored
+ * @size: size of the memory to allocate
+ *
+ * Return: virtual address of DMA memory or NULL.
+ */
+static void *libie_cp_alloc_dma_mem(struct device *dev,
+				    struct libie_cp_dma_mem *mem, u32 size)
+{
+	size = ALIGN(size, SZ_4K);
+
+	mem->va = dma_alloc_coherent(dev, size, &mem->pa, GFP_KERNEL);
+	mem->size = size;
+
+	return mem->va;
+}
+
+/**
+ * libie_ctlq_alloc_queue_res - allocate memory for descriptor ring and bufs
+ * @ctlq: control queue that requires its ring resources to be allocated
+ *
+ * Return: %0 on success, -%errno on failure
+ */
+static int libie_ctlq_alloc_queue_res(struct libie_ctlq_info *ctlq)
+{
+	size_t size = array_size(ctlq->ring_len, sizeof(*ctlq->descs));
+	struct libie_cp_dma_mem *dma = &ctlq->ring_mem;
+	int err = -ENOMEM;
+
+	if (!libie_cp_alloc_dma_mem(ctlq->dev, dma, size))
+		return -ENOMEM;
+
+	ctlq->descs = dma->va;
+
+	if (ctlq->type == LIBIE_CTLQ_TYPE_TX) {
+		if (libie_ctlq_alloc_tx_msgs(ctlq))
+			goto free_dma_mem;
+	} else {
+		err = libie_ctlq_init_fq(ctlq);
+		if (err)
+			goto free_dma_mem;
+
+		err = libie_ctlq_post_rx_buffs(ctlq);
+		if (err) {
+			libie_ctlq_free_fq(ctlq);
+			goto free_dma_mem;
+		}
+	}
+
+	return 0;
+
+free_dma_mem:
+	libie_cp_free_dma_mem(ctlq->dev, dma);
+
+	return err;
+}
+
+/**
+ * libie_ctlq_init_regs - Initialize control queue registers
+ * @ctlq: control queue that needs to be initialized
+ *
+ * Initialize registers. The caller is expected to have already initialized the
+ * descriptor ring memory and buffer memory.
+ */
+static void libie_ctlq_init_regs(struct libie_ctlq_info *ctlq)
+{
+	u32 dword;
+
+	if (ctlq->type == VIRTCHNL2_QUEUE_TYPE_RX)
+		writel(ctlq->ring_len - 1, ctlq->reg.tail);
+
+	writel(0, ctlq->reg.head);
+	writel(lower_32_bits(ctlq->ring_mem.pa), ctlq->reg.addr_low);
+	writel(upper_32_bits(ctlq->ring_mem.pa), ctlq->reg.addr_high);
+
+	dword = FIELD_PREP(LIBIE_CTLQ_MBX_ATQ_LEN, ctlq->ring_len) |
+		ctlq->reg.len_ena_mask;
+	writel(dword, ctlq->reg.len);
+}
+
+/**
+ * libie_find_ctlq - find the controlq for the given id and type
+ * @ctx: controlq context structure
+ * @type: type of controlq to find
+ * @id: controlq id to find
+ *
+ * Return: control queue info pointer on success, NULL on failure
+ */
+struct libie_ctlq_info *libie_find_ctlq(struct libie_ctlq_ctx *ctx,
+					enum virtchnl2_queue_type type,
+					  int id)
+{
+	struct libie_ctlq_info *cq;
+
+	guard(spinlock)(&ctx->ctlqs_lock);
+
+	list_for_each_entry(cq, &ctx->ctlqs, list)
+		if (cq->qid == id && cq->type == type)
+			return cq;
+
+	return NULL;
+}
+EXPORT_SYMBOL_NS_GPL(libie_find_ctlq, "LIBIE_CP");
+
+/**
+ * libie_ctlq_add - add one control queue
+ * @ctx: controlq context information
+ * @qinfo: information that requires for queue creation
+ *
+ * Allocate and initialize a control queue and add it to the control queue list.
+ * The ctlq parameter will be allocated/initialized and passed back to the
+ * caller if no errors occur.
+ *
+ * Note: libie_ctlq_init must be called prior to any calls to libie_ctlq_add.
+ *
+ * Return: added control queue info pointer on success, error pointer on failure
+ */
+static struct libie_ctlq_info *
+libie_ctlq_add(struct libie_ctlq_ctx *ctx,
+	       const struct libie_ctlq_create_info *qinfo)
+{
+	struct libie_ctlq_info *ctlq;
+
+	if (qinfo->id != LIBIE_CTLQ_MBX_ID)
+		return ERR_PTR(-EOPNOTSUPP);
+
+	/* libie_ctlq_init was not called */
+	scoped_guard(spinlock, &ctx->ctlqs_lock)
+		if (!ctx->ctlqs.next)
+			return ERR_PTR(-EINVAL);
+
+	ctlq = kvzalloc(sizeof(*ctlq), GFP_KERNEL);
+	if (!ctlq)
+		return ERR_PTR(-ENOMEM);
+
+	ctlq->type = qinfo->type;
+	ctlq->qid = qinfo->id;
+	ctlq->ring_len = qinfo->len;
+	ctlq->dev = &ctx->mmio_info.pdev->dev;
+	ctlq->reg = qinfo->reg;
+
+	if (libie_ctlq_alloc_queue_res(ctlq)) {
+		kvfree(ctlq);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	libie_ctlq_init_regs(ctlq);
+
+	spin_lock_init(&ctlq->lock);
+
+	scoped_guard(spinlock, &ctx->ctlqs_lock)
+		list_add(&ctlq->list, &ctx->ctlqs);
+
+	return ctlq;
+}
+
+/**
+ * libie_ctlq_remove - deallocate and remove specified control queue
+ * @ctx: libie context information
+ * @ctlq: specific control queue that needs to be removed
+ */
+static void libie_ctlq_remove(struct libie_ctlq_ctx *ctx,
+			      struct libie_ctlq_info *ctlq)
+{
+	scoped_guard(spinlock, &ctx->ctlqs_lock)
+		list_del(&ctlq->list);
+
+	libie_ctlq_dealloc_ring_res(ctlq);
+	kvfree(ctlq);
+}
+
+/**
+ * libie_ctlq_init - main initialization routine for all control queues
+ * @ctx: libie context information
+ * @qinfo: array of structs containing info for each queue to be initialized
+ * @numq: number of queues to initialize
+ *
+ * This initializes queue list and adds 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.
+ *
+ * Return: %0 on success, -%errno on failure
+ */
+int libie_ctlq_init(struct libie_ctlq_ctx *ctx,
+		    const struct libie_ctlq_create_info *qinfo,
+		     u32 numq)
+{
+	INIT_LIST_HEAD(&ctx->ctlqs);
+	spin_lock_init(&ctx->ctlqs_lock);
+
+	for (u32 i = 0; i < numq; i++) {
+		struct libie_ctlq_info *ctlq;
+
+		ctlq = libie_ctlq_add(ctx, &qinfo[i]);
+		if (IS_ERR(ctlq)) {
+			libie_ctlq_deinit(ctx);
+			return PTR_ERR(ctlq);
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_init, "LIBIE_CP");
+
+/**
+ * libie_ctlq_deinit - destroy all control queues
+ * @ctx: libie CP context information
+ */
+void libie_ctlq_deinit(struct libie_ctlq_ctx *ctx)
+{
+	struct libie_ctlq_info *ctlq, *tmp;
+
+	list_for_each_entry_safe(ctlq, tmp, &ctx->ctlqs, list)
+		libie_ctlq_remove(ctx, ctlq);
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_deinit, "LIBIE_CP");
+
+/**
+ * libie_ctlq_tx_desc_from_msg - initialize a Tx descriptor from a message
+ * @desc: descriptor to be initialized
+ * @msg: filled control queue message
+ */
+static void libie_ctlq_tx_desc_from_msg(struct libie_ctlq_desc *desc,
+					const struct libie_ctlq_msg *msg)
+{
+	const struct libie_cp_dma_mem *dma = &msg->send_mem;
+	u64 qword;
+
+	qword = FIELD_PREP(LIBIE_CTLQ_DESC_FLAGS, msg->flags) |
+		FIELD_PREP(LIBIE_CTLQ_DESC_INFRA_OPCODE, msg->opcode) |
+		FIELD_PREP(LIBIE_CTLQ_DESC_PFID_VFID, msg->func_id);
+	desc->qword0 = cpu_to_le64(qword);
+
+	qword = FIELD_PREP(LIBIE_CTLQ_DESC_VIRTCHNL_OPCODE,
+			   msg->chnl_opcode) |
+		FIELD_PREP(LIBIE_CTLQ_DESC_VIRTCHNL_MSG_RET_VAL,
+			   msg->chnl_retval);
+	desc->qword1 = cpu_to_le64(qword);
+
+	qword = FIELD_PREP(LIBIE_CTLQ_DESC_MSG_PARAM0, msg->param0) |
+		FIELD_PREP(LIBIE_CTLQ_DESC_SW_COOKIE,
+			   msg->sw_cookie) |
+		FIELD_PREP(LIBIE_CTLQ_DESC_VIRTCHNL_FLAGS,
+			   msg->virt_flags);
+	desc->qword2 = cpu_to_le64(qword);
+
+	if (likely(msg->data_len)) {
+		desc->qword0 |=
+			cpu_to_le64(LIBIE_CTLQ_DESC_QWORD0(msg->data_len));
+		qword = FIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_HIGH,
+				   upper_32_bits(dma->pa)) |
+			FIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_LOW,
+				   lower_32_bits(dma->pa));
+	} else {
+		qword = msg->addr_param;
+	}
+
+	desc->qword3 = cpu_to_le64(qword);
+}
+
+/**
+ * libie_ctlq_send - send a message to Control Plane or Peer
+ * @ctlq: specific control queue which is used for sending a message
+ * @q_msg: array of queue messages to be sent
+ * @num_q_msg: number of messages to send on control queue
+ *
+ * The control queue will hold a reference to each send message until
+ * the completion for that message has been cleaned.
+ *
+ * The caller must hold ctlq->lock.
+ *
+ * Return: %0 on success, -%errno on failure.
+ */
+int libie_ctlq_send(struct libie_ctlq_info *ctlq,
+		    struct libie_ctlq_msg *q_msg, u32 num_q_msg)
+{
+	u32 num_desc_avail, ntu;
+
+	ntu = ctlq->next_to_use;
+
+	num_desc_avail = (ctlq->next_to_clean > ntu ? 0 : ctlq->ring_len) +
+			  ctlq->next_to_clean - ntu - 1;
+
+	if (num_desc_avail < num_q_msg)
+		return -EBUSY;
+
+	for (int i = 0; i < num_q_msg; i++) {
+		struct libie_ctlq_msg *msg = &q_msg[i];
+		struct libie_ctlq_desc *desc;
+
+		desc = &ctlq->descs[ntu];
+		libie_ctlq_tx_desc_from_msg(desc, msg);
+
+		if (unlikely(++ntu == ctlq->ring_len))
+			ntu = 0;
+	}
+	writel(ntu, ctlq->reg.tail);
+	ctlq->next_to_use = ntu;
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_send, "LIBIE_CP");
+
+/**
+ * libie_ctlq_fill_rx_msg - fill in a message from Rx descriptor and buffer
+ * @msg: message to be filled in
+ * @desc: received descriptor
+ * @rx_buf: fill queue buffer associated with the descriptor
+ */
+static void libie_ctlq_fill_rx_msg(struct libie_ctlq_msg *msg,
+				   const struct libie_ctlq_desc *desc,
+				    struct libeth_fqe *rx_buf)
+{
+	u64 qword = le64_to_cpu(desc->qword0);
+
+	msg->flags = FIELD_GET(LIBIE_CTLQ_DESC_FLAGS, qword);
+	msg->opcode = FIELD_GET(LIBIE_CTLQ_DESC_INFRA_OPCODE, qword);
+	msg->data_len = FIELD_GET(LIBIE_CTLQ_DESC_DATA_LEN, qword);
+	msg->hw_retval = FIELD_GET(LIBIE_CTLQ_DESC_HW_RETVAL, qword);
+
+	qword = le64_to_cpu(desc->qword1);
+	msg->chnl_opcode =
+		FIELD_GET(LIBIE_CTLQ_DESC_VIRTCHNL_OPCODE, qword);
+	msg->chnl_retval =
+		FIELD_GET(LIBIE_CTLQ_DESC_VIRTCHNL_MSG_RET_VAL, qword);
+
+	qword = le64_to_cpu(desc->qword2);
+	msg->param0 =
+		FIELD_GET(LIBIE_CTLQ_DESC_MSG_PARAM0, qword);
+	msg->sw_cookie =
+		FIELD_GET(LIBIE_CTLQ_DESC_SW_COOKIE, qword);
+	msg->virt_flags =
+		FIELD_GET(LIBIE_CTLQ_DESC_VIRTCHNL_FLAGS, qword);
+
+	if (likely(msg->data_len)) {
+		msg->recv_mem = (struct kvec) {
+			.iov_base = netmem_address(rx_buf->netmem),
+			.iov_len = msg->data_len,
+		};
+		libeth_rx_sync_for_cpu(rx_buf, msg->data_len);
+	} else {
+		msg->recv_mem = (struct kvec) {};
+		msg->addr_param = le64_to_cpu(desc->qword3);
+		page_pool_put_full_netmem(netmem_get_pp(rx_buf->netmem),
+					  rx_buf->netmem, false);
+	}
+}
+
+/**
+ * libie_ctlq_recv - receive control queue message call back
+ * @ctlq: control queue that needs to processed for receive
+ * @msg: array of received control queue messages on this q;
+ * needs to be pre-allocated by caller for as many messages as requested
+ * @num_q_msg: number of messages that can be stored in msg buffer
+ *
+ * Called by interrupt handler or polling mechanism. Caller is expected
+ * to free buffers.
+ *
+ * The caller must make sure that calls to libie_ctlq_post_rx_buffs()
+ * and libie_ctlq_recv() for separate queues are either serialized
+ * or used under ctlq->lock.
+ *
+ * Return: number of messages received
+ */
+u32 libie_ctlq_recv(struct libie_ctlq_info *ctlq, struct libie_ctlq_msg *msg,
+		    u32 num_q_msg)
+{
+	u32 ntc, i;
+
+	ntc = ctlq->next_to_clean;
+
+	for (i = 0; i < num_q_msg; i++) {
+		const struct libie_ctlq_desc *desc = &ctlq->descs[ntc];
+		struct libeth_fqe *rx_buf = &ctlq->rx_fqes[ntc];
+		u64 qword;
+
+		qword = le64_to_cpu(desc->qword0);
+		if (!FIELD_GET(LIBIE_CTLQ_DESC_FLAG_DD, qword))
+			break;
+
+		dma_rmb();
+
+		if (unlikely(FIELD_GET(LIBIE_CTLQ_DESC_FLAG_ERR, qword)))
+			break;
+
+		libie_ctlq_fill_rx_msg(&msg[i], desc, rx_buf);
+
+		if (unlikely(++ntc == ctlq->ring_len))
+			ntc = 0;
+	}
+
+	ctlq->next_to_clean = ntc;
+
+	return i;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_recv, "LIBIE_CP");
+
+MODULE_DESCRIPTION("Control Plane communication API");
+MODULE_IMPORT_NS("LIBETH");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/intel/libie/controlq.h b/include/linux/intel/libie/controlq.h
new file mode 100644
index 000000000000..534508fbb405
--- /dev/null
+++ b/include/linux/intel/libie/controlq.h
@@ -0,0 +1,249 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2025 Intel Corporation */
+
+#ifndef __LIBIE_CONTROLQ_H
+#define __LIBIE_CONTROLQ_H
+
+#include <net/libeth/rx.h>
+
+#include <linux/intel/libie/pci.h>
+#include <linux/intel/virtchnl2.h>
+
+/* Default mailbox control queue */
+#define LIBIE_CTLQ_MBX_ID			-1
+#define LIBIE_CTLQ_MAX_BUF_LEN			SZ_4K
+
+#define LIBIE_CTLQ_TYPE_TX			0
+#define LIBIE_CTLQ_TYPE_RX			1
+
+/* Opcode used to send controlq message to the control plane */
+#define LIBIE_CTLQ_SEND_MSG_TO_CP		0x801
+#define LIBIE_CTLQ_SEND_MSG_TO_PEER		0x804
+
+/**
+ * struct libie_ctlq_ctx - contains controlq info and MMIO region info
+ * @mmio_info: MMIO region info structure
+ * @ctlqs: list that stores all the control queues
+ * @ctlqs_lock: lock for control queue list
+ */
+struct libie_ctlq_ctx {
+	struct libie_mmio_info	mmio_info;
+	struct list_head	ctlqs;
+	spinlock_t		ctlqs_lock;	/* protects the ctlqs list */
+};
+
+/**
+ * struct libie_ctlq_reg - structure representing virtual addresses of the
+ *			    controlq registers and masks
+ * @head: controlq head register address
+ * @tail: controlq tail register address
+ * @len: register address to write controlq length and enable bit
+ * @addr_high: register address to write the upper 32b of ring physical address
+ * @addr_low: register address to write the lower 32b of ring physical address
+ * @len_mask: mask to read the controlq length
+ * @len_ena_mask: mask to write the controlq enable bit
+ * @head_mask: mask to read the head value
+ */
+struct libie_ctlq_reg {
+	void __iomem	*head;
+	void __iomem	*tail;
+	void __iomem	*len;
+	void __iomem	*addr_high;
+	void __iomem	*addr_low;
+	u32		len_mask;
+	u32		len_ena_mask;
+	u32		head_mask;
+};
+
+/**
+ * struct libie_cp_dma_mem - structure for DMA memory
+ * @va: virtual address
+ * @pa: physical address
+ * @size: memory size
+ */
+struct libie_cp_dma_mem {
+	void		*va;
+	dma_addr_t	pa;
+	size_t		size;
+};
+
+/**
+ * struct libie_ctlq_msg - control queue message data
+ * @flags: refer to 'Flags sub-structure' definitions
+ * @opcode: infrastructure message opcode
+ * @data_len: size of the payload
+ * @func_id: queue id for the secondary mailbox queue, 0 for default mailbox
+ * @hw_retval: execution status from the HW
+ * @chnl_opcode: virtchnl message opcode
+ * @chnl_retval: virtchnl return value
+ * @param0: indirect message raw parameter0
+ * @sw_cookie: used to verify the response of the sent virtchnl message
+ * @virt_flags: virtchnl capability flags
+ * @addr_param: additional parameters in place of the address, given no buffer
+ * @recv_mem: virtual address and size of the buffer that contains
+ *	      the indirect response
+ * @send_mem: physical and virtual address of the DMA buffer,
+ *	      used for sending
+ */
+struct libie_ctlq_msg {
+	u16			flags;
+	u16			opcode;
+	u16			data_len;
+	union {
+		u16		func_id;
+		u16		hw_retval;
+	};
+	u32			chnl_opcode;
+	u32			chnl_retval;
+	u32			param0;
+	u16			sw_cookie;
+	u16			virt_flags;
+	u64			addr_param;
+	union {
+		struct kvec	recv_mem;
+		struct	libie_cp_dma_mem send_mem;
+	};
+};
+
+/**
+ * struct libie_ctlq_create_info - control queue create information
+ * @type: control queue type (Rx or Tx)
+ * @id: queue offset passed as input, -1 for default mailbox
+ * @reg: registers accessed by control queue
+ * @len: controlq length
+ */
+struct libie_ctlq_create_info {
+	enum virtchnl2_queue_type	type;
+	int				id;
+	struct libie_ctlq_reg		reg;
+	u16				len;
+};
+
+/**
+ * struct libie_ctlq_info - control queue information
+ * @list: used to add a controlq to the list of queues in libie_ctlq_ctx
+ * @type: control queue type
+ * @qid: queue identifier
+ * @lock: control queue lock
+ * @ring_mem: descrtiptor ring DMA memory
+ * @descs: array of descrtiptors
+ * @rx_fqes: array of controlq Rx buffers
+ * @tx_msg: Tx messages sent to hardware
+ * @reg: registers used by control queue
+ * @dev: device that owns this control queue
+ * @pp: page pool for controlq Rx buffers
+ * @truesize: size to allocate per buffer
+ * @next_to_use: next available slot to send buffer
+ * @next_to_clean: next descrtiptor to be cleaned
+ * @next_to_post: next available slot to post buffers to after receive
+ * @ring_len: length of the descriptor ring
+ */
+struct libie_ctlq_info {
+	struct list_head		list;
+	enum virtchnl2_queue_type	type;
+	int				qid;
+	spinlock_t			lock;	/* for concurrent processing */
+	struct libie_cp_dma_mem	ring_mem;
+	struct libie_ctlq_desc		*descs;
+	union {
+		struct libeth_fqe		*rx_fqes;
+		struct libie_ctlq_msg		**tx_msg;
+	};
+	struct libie_ctlq_reg		reg;
+	struct device			*dev;
+	struct page_pool		*pp;
+	u32				truesize;
+	u32				next_to_clean;
+	union {
+		u32			next_to_use;
+		u32			next_to_post;
+	};
+	u32				ring_len;
+};
+
+#define LIBIE_CTLQ_MBX_ATQ_LEN			GENMASK(9, 0)
+
+/* 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  |
+ */
+ /* libie controlq descriptor qword0 details */
+#define LIBIE_CTLQ_DESC_FLAG_DD		BIT(0)
+#define LIBIE_CTLQ_DESC_FLAG_CMP		BIT(1)
+#define LIBIE_CTLQ_DESC_FLAG_ERR		BIT(2)
+#define LIBIE_CTLQ_DESC_FLAG_FTYPE_VM		BIT(6)
+#define LIBIE_CTLQ_DESC_FLAG_FTYPE_PF		BIT(7)
+#define LIBIE_CTLQ_DESC_FLAG_FTYPE		GENMASK(7, 6)
+#define LIBIE_CTLQ_DESC_FLAG_RD		BIT(10)
+#define LIBIE_CTLQ_DESC_FLAG_VFC		BIT(11)
+#define LIBIE_CTLQ_DESC_FLAG_BUF		BIT(12)
+#define LIBIE_CTLQ_DESC_FLAG_HOST_ID		GENMASK(15, 13)
+
+#define LIBIE_CTLQ_DESC_FLAGS			GENMASK(15, 0)
+#define LIBIE_CTLQ_DESC_INFRA_OPCODE		GENMASK_ULL(31, 16)
+#define LIBIE_CTLQ_DESC_DATA_LEN		GENMASK_ULL(47, 32)
+#define LIBIE_CTLQ_DESC_HW_RETVAL		GENMASK_ULL(63, 48)
+
+#define LIBIE_CTLQ_DESC_PFID_VFID		GENMASK_ULL(63, 48)
+
+/* libie controlq descriptor qword1 details */
+#define LIBIE_CTLQ_DESC_VIRTCHNL_OPCODE	GENMASK(27, 0)
+#define LIBIE_CTLQ_DESC_VIRTCHNL_DESC_TYPE	GENMASK_ULL(31, 28)
+#define LIBIE_CTLQ_DESC_VIRTCHNL_MSG_RET_VAL	GENMASK_ULL(63, 32)
+
+/* libie controlq descriptor qword2 details */
+#define LIBIE_CTLQ_DESC_MSG_PARAM0		GENMASK_ULL(31, 0)
+#define LIBIE_CTLQ_DESC_SW_COOKIE		GENMASK_ULL(47, 32)
+#define LIBIE_CTLQ_DESC_VIRTCHNL_FLAGS		GENMASK_ULL(63, 48)
+
+/* libie controlq descriptor qword3 details */
+#define LIBIE_CTLQ_DESC_DATA_ADDR_HIGH		GENMASK_ULL(31, 0)
+#define LIBIE_CTLQ_DESC_DATA_ADDR_LOW		GENMASK_ULL(63, 32)
+
+/**
+ * struct libie_ctlq_desc - control queue descriptor format
+ * @qword0: flags, message opcode, data length etc
+ * @qword1: virtchnl opcode, descriptor type and return value
+ * @qword2: indirect message parameters
+ * @qword3: indirect message buffer address
+ */
+struct libie_ctlq_desc {
+	__le64			qword0;
+	__le64			qword1;
+	__le64			qword2;
+	__le64			qword3;
+};
+
+/**
+ * libie_ctlq_release_rx_buf - Release Rx buffer for a specific control queue
+ * @rx_buf: Rx buffer to be freed
+ *
+ * Driver uses this function to post back the Rx buffer after the usage.
+ */
+static inline void libie_ctlq_release_rx_buf(struct kvec *rx_buf)
+{
+	netmem_ref netmem;
+
+	if (!rx_buf->iov_base)
+		return;
+
+	netmem = virt_to_netmem(rx_buf->iov_base);
+	page_pool_put_full_netmem(netmem_get_pp(netmem), netmem, false);
+}
+
+int libie_ctlq_init(struct libie_ctlq_ctx *ctx,
+		    const struct libie_ctlq_create_info *qinfo,  u32 numq);
+void libie_ctlq_deinit(struct libie_ctlq_ctx *ctx);
+
+struct libie_ctlq_info *libie_find_ctlq(struct libie_ctlq_ctx *ctx,
+					enum virtchnl2_queue_type type,
+					  int id);
+
+int libie_ctlq_send(struct libie_ctlq_info *ctlq,
+		    struct libie_ctlq_msg *q_msg, u32 num_q_msg);
+u32 libie_ctlq_recv(struct libie_ctlq_info *ctlq, struct libie_ctlq_msg *msg,
+		    u32 num_q_msg);
+
+int libie_ctlq_post_rx_buffs(struct libie_ctlq_info *ctlq);
+
+#endif /* __LIBIE_CONTROLQ_H */
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 06/15] libie: add bookkeeping support for control queue messages
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
                   ` (4 preceding siblings ...)
  2025-05-16 14:58 ` [PATCH iwl-next v4 05/15] libie: add control queue support Larysa Zaremba
@ 2025-05-16 14:58 ` Larysa Zaremba
  2025-05-16 14:58 ` [PATCH iwl-next v4 07/15] idpf: remove 'vport_params_reqd' field Larysa Zaremba
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:58 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali, Phani R Burra

From: Phani R Burra <phani.r.burra@intel.com>

All send control queue messages are allocated/freed in libie itself and
tracked with the unique transaction (Xn) ids until they receive response or
time out. Responses can be received out of order, therefore transactions
are stored in an array and tracked though a bitmap.

Pre-allocated DMA memory is used where possible. It reduces the driver
overhead in handling memory allocation/free and message timeouts.

Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Signed-off-by: Phani R Burra <phani.r.burra@intel.com>
Co-developed-by: Victor Raj <victor.raj@intel.com>
Signed-off-by: Victor Raj <victor.raj@intel.com>
Co-developed-by: Pavan Kumar Linga <pavan.kumar.linga@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>
---
 drivers/net/ethernet/intel/libie/controlq.c | 578 ++++++++++++++++++++
 include/linux/intel/libie/controlq.h        | 170 ++++++
 2 files changed, 748 insertions(+)

diff --git a/drivers/net/ethernet/intel/libie/controlq.c b/drivers/net/ethernet/intel/libie/controlq.c
index 80b0f1c2cc0a..90f62bd00382 100644
--- a/drivers/net/ethernet/intel/libie/controlq.c
+++ b/drivers/net/ethernet/intel/libie/controlq.c
@@ -602,6 +602,584 @@ u32 libie_ctlq_recv(struct libie_ctlq_info *ctlq, struct libie_ctlq_msg *msg,
 }
 EXPORT_SYMBOL_NS_GPL(libie_ctlq_recv, "LIBIE_CP");
 
+/**
+ * libie_ctlq_xn_pop_free - get a free Xn entry from the free list
+ * @xnm: Xn transaction manager
+ *
+ * Retrieve a free Xn entry from the free list.
+ *
+ * Return: valid Xn entry pointer or NULL if there are no free Xn entries.
+ */
+static struct libie_ctlq_xn *
+libie_ctlq_xn_pop_free(struct libie_ctlq_xn_manager *xnm)
+{
+	struct libie_ctlq_xn *xn;
+	u32 free_idx;
+
+	guard(spinlock)(&xnm->free_xns_bm_lock);
+
+	if (unlikely(xnm->shutdown))
+		return NULL;
+
+	free_idx = find_next_bit(xnm->free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES,
+				 0);
+	if (free_idx == LIBIE_CTLQ_MAX_XN_ENTRIES)
+		return NULL;
+
+	__clear_bit(free_idx, xnm->free_xns_bm);
+	xn = &xnm->ring[free_idx];
+	xn->cookie = xnm->cookie++;
+
+	return xn;
+}
+
+/**
+ * __libie_ctlq_xn_push_free - unsafely push a Xn entry into the free list
+ * @xnm: Xn transaction manager
+ * @xn: xn entry to be added into the free list
+ */
+static void __libie_ctlq_xn_push_free(struct libie_ctlq_xn_manager *xnm,
+				      struct libie_ctlq_xn *xn)
+{
+	__set_bit(xn->index, xnm->free_xns_bm);
+
+	if (likely(!xnm->shutdown))
+		return;
+
+	if (bitmap_full(xnm->free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES))
+		complete(&xnm->can_destroy);
+}
+
+/**
+ * libie_ctlq_xn_push_free - push a Xn entry into the free list
+ * @xnm: Xn transaction manager
+ * @xn: xn entry to be added into the free list, not locked
+ *
+ * Safely add a used Xn entry back to the free list.
+ */
+static void libie_ctlq_xn_push_free(struct libie_ctlq_xn_manager *xnm,
+				    struct libie_ctlq_xn *xn)
+{
+	guard(spinlock)(&xnm->free_xns_bm_lock);
+
+	__libie_ctlq_xn_push_free(xnm, xn);
+}
+
+/**
+ * libie_ctlq_xn_put - put an Xn that will not be used in the current thread
+ * @xnm: Xn transaction manager
+ * @xn: async xn entry to be put for now, not locked
+ *
+ * If the Xn manager is being shutdown, nothing will handle the related
+ * async request.
+ */
+static void libie_ctlq_xn_put(struct libie_ctlq_xn_manager *xnm,
+			      struct libie_ctlq_xn *xn)
+{
+	guard(spinlock)(&xnm->free_xns_bm_lock);
+
+	if (unlikely(xnm->shutdown))
+		__libie_ctlq_xn_push_free(xnm, xn);
+}
+
+/**
+ * libie_ctlq_xn_deinit_dma - free the DMA memory allocated for send messages
+ * @dev: device pointer
+ * @xnm: pointer to the transaction manager
+ * @num_entries: number of Xn entries to free the DMA for
+ */
+static void libie_ctlq_xn_deinit_dma(struct device *dev,
+				     struct libie_ctlq_xn_manager *xnm,
+				      u32 num_entries)
+{
+	for (u32 i = 0; i < num_entries; i++) {
+		struct libie_ctlq_xn *xn = &xnm->ring[i];
+
+		libie_cp_free_dma_mem(dev, xn->dma_mem);
+		kfree(xn->dma_mem);
+	}
+}
+
+/**
+ * libie_ctlq_xn_init_dma - pre-allocate DMA memory for send messages that use
+ * stack variables
+ * @dev: device pointer
+ * @xnm: pointer to transaction manager
+ *
+ * Return: %0 on success or error if memory allocation fails
+ */
+static int libie_ctlq_xn_init_dma(struct device *dev,
+				  struct libie_ctlq_xn_manager *xnm)
+{
+	u32 i;
+
+	for (i = 0; i < LIBIE_CTLQ_MAX_XN_ENTRIES; i++) {
+		struct libie_ctlq_xn *xn = &xnm->ring[i];
+		struct libie_cp_dma_mem *dma_mem;
+
+		dma_mem = kzalloc(sizeof(*dma_mem), GFP_KERNEL);
+		if (!dma_mem)
+			goto dealloc_dma;
+
+		dma_mem->va = libie_cp_alloc_dma_mem(dev, dma_mem,
+						     LIBIE_CTLQ_MAX_BUF_LEN);
+		if (!dma_mem->va) {
+			kfree(dma_mem);
+			goto dealloc_dma;
+		}
+
+		xn->dma_mem = dma_mem;
+	}
+
+	return 0;
+
+dealloc_dma:
+	libie_ctlq_xn_deinit_dma(dev, xnm, i);
+
+	return -ENOMEM;
+}
+
+/**
+ * libie_ctlq_xn_process_recv - process Xn data in receive message
+ * @params: Xn receive param information to handle a receive message
+ * @ctlq_msg: received control queue message
+ *
+ * Process a control queue receive message and send a complete event
+ * notification.
+ *
+ * Return: true if a message has been processed, false otherwise.
+ */
+static bool
+libie_ctlq_xn_process_recv(struct libie_ctlq_xn_recv_params *params,
+			   struct libie_ctlq_msg *ctlq_msg)
+{
+	struct libie_ctlq_xn_manager *xnm = params->xnm;
+	struct libie_ctlq_xn *xn;
+	u16 msg_cookie, xn_index;
+	struct kvec *response;
+	int status;
+	u16 data;
+
+	data = ctlq_msg->sw_cookie;
+	xn_index = FIELD_GET(LIBIE_CTLQ_XN_INDEX_M, data);
+	msg_cookie = FIELD_GET(LIBIE_CTLQ_XN_COOKIE_M, data);
+	status = ctlq_msg->chnl_retval ? -EFAULT : 0;
+
+	xn = &xnm->ring[xn_index];
+	if (ctlq_msg->chnl_opcode != xn->virtchnl_opcode ||
+	    msg_cookie != xn->cookie)
+		return false;
+
+	spin_lock(&xn->xn_lock);
+	if (xn->state != LIBIE_CTLQ_XN_ASYNC &&
+	    xn->state != LIBIE_CTLQ_XN_WAITING) {
+		spin_unlock(&xn->xn_lock);
+		return false;
+	}
+
+	response = &ctlq_msg->recv_mem;
+	if (xn->state == LIBIE_CTLQ_XN_ASYNC) {
+		xn->resp_cb(xn->send_ctx, response, status);
+		xn->state = LIBIE_CTLQ_XN_IDLE;
+		spin_unlock(&xn->xn_lock);
+		libie_ctlq_xn_push_free(xnm, xn);
+
+		return true;
+	}
+
+	xn->recv_mem = *response;
+	xn->state = status ? LIBIE_CTLQ_XN_COMPLETED_FAILED :
+			     LIBIE_CTLQ_XN_COMPLETED_SUCCESS;
+
+	complete(&xn->cmd_completion_event);
+	spin_unlock(&xn->xn_lock);
+
+	return true;
+}
+
+/**
+ * libie_xn_check_async_timeout - Check for asynchronous message timeouts
+ * @xnm: Xn transaction manager
+ *
+ * Call the corresponding callback to notify the caller about the timeout.
+ */
+static void libie_xn_check_async_timeout(struct libie_ctlq_xn_manager *xnm)
+{
+	u32 idx;
+
+	for_each_clear_bit(idx, xnm->free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES) {
+		struct libie_ctlq_xn *xn = &xnm->ring[idx];
+		u64 timeout_ms;
+
+		spin_lock(&xn->xn_lock);
+
+		timeout_ms = ktime_ms_delta(ktime_get(), xn->timestamp);
+		if (xn->state != LIBIE_CTLQ_XN_ASYNC ||
+		    timeout_ms < xn->timeout_ms) {
+			spin_unlock(&xn->xn_lock);
+			continue;
+		}
+
+		xn->resp_cb(xn->send_ctx, NULL, -ETIMEDOUT);
+		xn->state = LIBIE_CTLQ_XN_IDLE;
+		spin_unlock(&xn->xn_lock);
+		libie_ctlq_xn_push_free(xnm, xn);
+	}
+}
+
+/**
+ * libie_ctlq_xn_recv - process control queue receive message
+ * @params: Xn receive param information to handle a receive message
+ *
+ * Process a receive message and update the receive queue buffer.
+ *
+ * Return: true if a message has been processed, false otherwise.
+ */
+bool libie_ctlq_xn_recv(struct libie_ctlq_xn_recv_params *params)
+{
+	struct libie_ctlq_msg ctlq_msg;
+	u32 num_msgs;
+
+	num_msgs = libie_ctlq_recv(params->ctlq, &ctlq_msg, 1);
+
+	if (num_msgs && !libie_ctlq_xn_process_recv(params, &ctlq_msg))
+		params->ctlq_msg_handler(params->xnm->ctx, &ctlq_msg);
+
+	libie_ctlq_post_rx_buffs(params->ctlq);
+	libie_xn_check_async_timeout(params->xnm);
+
+	return !!num_msgs;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_recv, "LIBIE_CP");
+
+/**
+ * libie_cp_map_dma_mem - map a given virtual address for DMA
+ * @dev: device information
+ * @va: virtual address to be mapped
+ * @size: size of the memory
+ * @direction: DMA direction either from/to device
+ * @dma_mem: memory for DMA information to be stored
+ *
+ * Return: true on success, false on DMA map failure.
+ */
+static bool libie_cp_map_dma_mem(struct device *dev, void *va, size_t size,
+				 int direction,
+				  struct libie_cp_dma_mem *dma_mem)
+{
+	dma_mem->pa = dma_map_single(dev, va, size, direction);
+
+	return dma_mapping_error(dev, dma_mem->pa) ? false : true;
+}
+
+/**
+ * libie_cp_unmap_dma_mem - unmap previously mapped DMA address
+ * @dev: device information
+ * @dma_mem: DMA memory information
+ */
+static void libie_cp_unmap_dma_mem(struct device *dev,
+				   const struct libie_cp_dma_mem *dma_mem)
+{
+	dma_unmap_single(dev, dma_mem->pa, dma_mem->size,
+			 dma_mem->direction);
+}
+
+/**
+ * libie_ctlq_xn_process_send - process and send a control queue message
+ * @params: Xn send param information for sending a control queue message
+ * @xn: Assigned Xn entry for tracking the control queue message
+ *
+ * Return: %0 on success, -%errno on failure.
+ */
+static
+int libie_ctlq_xn_process_send(struct libie_ctlq_xn_send_params *params,
+			       struct libie_ctlq_xn *xn)
+{
+	size_t buf_len = params->send_buf.iov_len;
+	struct device *dev = params->ctlq->dev;
+	void *buf = params->send_buf.iov_base;
+	struct libie_cp_dma_mem *dma_mem;
+	u16 cookie;
+	int ret;
+
+	if (!buf || !buf_len)
+		return -EOPNOTSUPP;
+
+	if (libie_cp_can_send_onstack(buf_len)) {
+		dma_mem = xn->dma_mem;
+		memcpy(dma_mem->va, buf, buf_len);
+	} else {
+		dma_mem = &xn->send_dma_mem;
+		dma_mem->va = buf;
+		dma_mem->size = buf_len;
+		dma_mem->direction = DMA_TO_DEVICE;
+
+		if (!libie_cp_map_dma_mem(dev, buf, buf_len, DMA_TO_DEVICE,
+					  dma_mem))
+			return -ENOMEM;
+	}
+
+	cookie = FIELD_PREP(LIBIE_CTLQ_XN_COOKIE_M, xn->cookie) |
+		 FIELD_PREP(LIBIE_CTLQ_XN_INDEX_M, xn->index);
+
+	scoped_guard(spinlock, &params->ctlq->lock) {
+		if (!params->ctlq_msg || params->resp_cb) {
+			struct libie_ctlq_info *ctlq = params->ctlq;
+
+			*ctlq->tx_msg[ctlq->next_to_use] =
+				params->ctlq_msg ? *params->ctlq_msg :
+				(struct libie_ctlq_msg) {
+					.opcode = LIBIE_CTLQ_SEND_MSG_TO_CP
+				};
+			params->ctlq_msg = ctlq->tx_msg[ctlq->next_to_use];
+		}
+
+		params->ctlq_msg->sw_cookie = cookie;
+		params->ctlq_msg->send_mem = *dma_mem;
+		params->ctlq_msg->data_len = buf_len;
+		params->ctlq_msg->chnl_opcode = params->chnl_opcode;
+		ret = libie_ctlq_send(params->ctlq, params->ctlq_msg, 1);
+	}
+
+	if (ret && !libie_cp_can_send_onstack(buf_len))
+		libie_cp_unmap_dma_mem(dev, dma_mem);
+
+	return ret;
+}
+
+/**
+ * libie_ctlq_xn_send - Function to send a control queue message
+ * @params: Xn send param information for sending a control queue message
+ *
+ * Send a control queue (mailbox or config) message.
+ * Based on the params value, the call can be completed synchronously or
+ * asynchronously.
+ *
+ * Return: %0 on success, -%errno on failure.
+ */
+int libie_ctlq_xn_send(struct libie_ctlq_xn_send_params *params)
+{
+	bool free_send = !libie_cp_can_send_onstack(params->send_buf.iov_len);
+	struct libie_ctlq_xn *xn;
+	int ret;
+
+	if (params->send_buf.iov_len > LIBIE_CTLQ_MAX_BUF_LEN) {
+		ret = -EINVAL;
+		goto free_buf;
+	}
+
+	xn = libie_ctlq_xn_pop_free(params->xnm);
+	/* no free transactions available */
+	if (unlikely(!xn)) {
+		ret = -EAGAIN;
+		goto free_buf;
+	}
+
+	spin_lock(&xn->xn_lock);
+
+	xn->state = params->resp_cb ? LIBIE_CTLQ_XN_ASYNC :
+				      LIBIE_CTLQ_XN_WAITING;
+	xn->ctlq = params->ctlq;
+	xn->virtchnl_opcode = params->chnl_opcode;
+
+	if (params->resp_cb) {
+		xn->send_ctx = params->send_ctx;
+		xn->resp_cb = params->resp_cb;
+		xn->timeout_ms = params->timeout_ms;
+		xn->timestamp = ktime_get();
+	}
+
+	ret = libie_ctlq_xn_process_send(params, xn);
+	if (ret)
+		goto release_xn;
+	else
+		free_send = false;
+
+	spin_unlock(&xn->xn_lock);
+
+	if (params->resp_cb) {
+		libie_ctlq_xn_put(params->xnm, xn);
+		return 0;
+	}
+
+	wait_for_completion_timeout(&xn->cmd_completion_event,
+				    msecs_to_jiffies(params->timeout_ms));
+
+	spin_lock(&xn->xn_lock);
+	switch (xn->state) {
+	case LIBIE_CTLQ_XN_WAITING:
+		ret = -ETIMEDOUT;
+		break;
+	case LIBIE_CTLQ_XN_COMPLETED_SUCCESS:
+		params->recv_mem = xn->recv_mem;
+		break;
+	default:
+		ret = -EBADMSG;
+		break;
+	}
+
+	/* Free the receive buffer in case of failure. On timeout, receive
+	 * buffer is not allocated.
+	 */
+	if (ret && ret != -ETIMEDOUT)
+		libie_ctlq_release_rx_buf(&xn->recv_mem);
+
+release_xn:
+	xn->state = LIBIE_CTLQ_XN_IDLE;
+	reinit_completion(&xn->cmd_completion_event);
+	spin_unlock(&xn->xn_lock);
+	libie_ctlq_xn_push_free(params->xnm, xn);
+free_buf:
+	if (free_send)
+		params->rel_tx_buf(params->send_buf.iov_base);
+
+	return ret;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_send, "LIBIE_CP");
+
+/**
+ * libie_ctlq_xn_send_clean - cleanup the send control queue message buffers
+ * @params: Xn clean param information for send complete handling
+ *
+ * Cleanup the send buffers for the given control queue, if force is set, then
+ * clear all the outstanding send messages irrrespective their send status.
+ * Force should be used during deinit or reset.
+ *
+ * Return: number of send buffers cleaned.
+ */
+u32 libie_ctlq_xn_send_clean(const struct libie_ctlq_xn_clean_params *params)
+{
+	struct libie_ctlq_info *ctlq = params->ctlq;
+	struct device *dev = ctlq->dev;
+	u32 ntc, i;
+
+	spin_lock(&ctlq->lock);
+	ntc = ctlq->next_to_clean;
+
+	for (i = 0; i < params->num_msgs; i++) {
+		struct libie_ctlq_msg *msg = ctlq->tx_msg[ntc];
+		struct libie_ctlq_desc *desc;
+		u64 qword;
+
+		desc = &ctlq->descs[ntc];
+		qword = le64_to_cpu(desc->qword0);
+
+		if (!FIELD_GET(LIBIE_CTLQ_DESC_FLAG_DD, qword))
+			break;
+
+		dma_rmb();
+
+		if (!libie_cp_can_send_onstack(msg->data_len)) {
+			libie_cp_unmap_dma_mem(dev, &msg->send_mem);
+			params->rel_tx_buf(msg->send_mem.va);
+		}
+
+		memset(msg, 0, sizeof(*msg));
+		desc->qword0 = 0;
+
+		if (unlikely(++ntc == ctlq->ring_len))
+			ntc = 0;
+	}
+
+	ctlq->next_to_clean = ntc;
+	spin_unlock(&ctlq->lock);
+
+	return i;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_send_clean, "LIBIE_CP");
+
+/**
+ * libie_ctlq_xn_deinit - deallocate and free the transaction manager resources
+ * @xnm: pointer to the transaction manager
+ * @ctx: controlq context structure
+ *
+ * All Rx processing must be stopped beforehand.
+ */
+void libie_ctlq_xn_deinit(struct libie_ctlq_xn_manager *xnm,
+			  struct libie_ctlq_ctx *ctx)
+{
+	bool must_wait = false;
+	u32 i;
+
+	/* Should be no new clear bits after this */
+	spin_lock(&xnm->free_xns_bm_lock);
+	xnm->shutdown = true;
+
+	for_each_clear_bit(i, xnm->free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES) {
+		struct libie_ctlq_xn *xn = &xnm->ring[i];
+
+		spin_lock(&xn->xn_lock);
+
+		if (xn->state == LIBIE_CTLQ_XN_WAITING ||
+		    xn->state == LIBIE_CTLQ_XN_IDLE) {
+			complete(&xn->cmd_completion_event);
+			must_wait = true;
+		} else if (xn->state == LIBIE_CTLQ_XN_ASYNC) {
+			__libie_ctlq_xn_push_free(xnm, xn);
+		}
+
+		spin_unlock(&xn->xn_lock);
+	}
+
+	spin_unlock(&xnm->free_xns_bm_lock);
+
+	if (must_wait)
+		wait_for_completion(&xnm->can_destroy);
+
+	libie_ctlq_xn_deinit_dma(&ctx->mmio_info.pdev->dev, xnm,
+				 LIBIE_CTLQ_MAX_XN_ENTRIES);
+	kfree(xnm);
+	libie_ctlq_deinit(ctx);
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_deinit, "LIBIE_CP");
+
+/**
+ * libie_ctlq_xn_init - initialize the Xn transaction manager
+ * @params: Xn init param information for allocating Xn manager resources
+ *
+ * Return: %0 on success, -%errno on failure.
+ */
+int libie_ctlq_xn_init(struct libie_ctlq_xn_init_params *params)
+{
+	struct libie_ctlq_xn_manager *xnm;
+	int ret;
+
+	ret = libie_ctlq_init(params->ctx, params->cctlq_info, params->num_qs);
+	if (ret)
+		return ret;
+
+	xnm = kzalloc(sizeof(*xnm), GFP_KERNEL);
+	if (!xnm)
+		goto ctlq_deinit;
+
+	ret = libie_ctlq_xn_init_dma(&params->ctx->mmio_info.pdev->dev, xnm);
+	if (ret)
+		goto free_xnm;
+
+	spin_lock_init(&xnm->free_xns_bm_lock);
+	init_completion(&xnm->can_destroy);
+	bitmap_fill(xnm->free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES);
+
+	for (u32 i = 0; i < LIBIE_CTLQ_MAX_XN_ENTRIES; i++) {
+		struct libie_ctlq_xn *xn = &xnm->ring[i];
+
+		xn->index = i;
+		init_completion(&xn->cmd_completion_event);
+		spin_lock_init(&xn->xn_lock);
+	}
+	xnm->ctx = params->ctx;
+	params->xnm = xnm;
+
+	return 0;
+
+free_xnm:
+	kfree(xnm);
+ctlq_deinit:
+	libie_ctlq_deinit(params->ctx);
+
+	return -ENOMEM;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_init, "LIBIE_CP");
+
 MODULE_DESCRIPTION("Control Plane communication API");
 MODULE_IMPORT_NS("LIBETH");
 MODULE_LICENSE("GPL");
diff --git a/include/linux/intel/libie/controlq.h b/include/linux/intel/libie/controlq.h
index 534508fbb405..7a4e56025e5b 100644
--- a/include/linux/intel/libie/controlq.h
+++ b/include/linux/intel/libie/controlq.h
@@ -20,6 +20,8 @@
 #define LIBIE_CTLQ_SEND_MSG_TO_CP		0x801
 #define LIBIE_CTLQ_SEND_MSG_TO_PEER		0x804
 
+#define LIBIE_CP_TX_COPYBREAK		128
+
 /**
  * struct libie_ctlq_ctx - contains controlq info and MMIO region info
  * @mmio_info: MMIO region info structure
@@ -60,11 +62,13 @@ struct libie_ctlq_reg {
  * @va: virtual address
  * @pa: physical address
  * @size: memory size
+ * @direction: memory to device or device to memory
  */
 struct libie_cp_dma_mem {
 	void		*va;
 	dma_addr_t	pa;
 	size_t		size;
+	int		direction;
 };
 
 /**
@@ -246,4 +250,170 @@ u32 libie_ctlq_recv(struct libie_ctlq_info *ctlq, struct libie_ctlq_msg *msg,
 
 int libie_ctlq_post_rx_buffs(struct libie_ctlq_info *ctlq);
 
+/* Only 8 bits are available in descriptor for Xn index */
+#define LIBIE_CTLQ_MAX_XN_ENTRIES		256
+#define LIBIE_CTLQ_XN_COOKIE_M			GENMASK(15, 8)
+#define LIBIE_CTLQ_XN_INDEX_M			GENMASK(7, 0)
+
+/**
+ * enum libie_ctlq_xn_state - Transaction state of a virtchnl message
+ * @LIBIE_CTLQ_XN_IDLE: transaction is available to use
+ * @LIBIE_CTLQ_XN_WAITING: waiting for transaction to complete
+ * @LIBIE_CTLQ_XN_COMPLETED_SUCCESS: transaction completed with success
+ * @LIBIE_CTLQ_XN_COMPLETED_FAILED: transaction completed with failure
+ * @LIBIE_CTLQ_XN_ASYNC: asynchronous virtchnl message transaction type
+ */
+enum libie_ctlq_xn_state {
+	LIBIE_CTLQ_XN_IDLE = 0,
+	LIBIE_CTLQ_XN_WAITING,
+	LIBIE_CTLQ_XN_COMPLETED_SUCCESS,
+	LIBIE_CTLQ_XN_COMPLETED_FAILED,
+	LIBIE_CTLQ_XN_ASYNC,
+};
+
+/**
+ * struct libie_ctlq_xn - structure representing a virtchnl transaction entry
+ * @resp_cb: callback to handle the response of an asynchronous virtchnl message
+ * @xn_lock: lock to protect the transaction entry state
+ * @ctlq: send control queue information
+ * @cmd_completion_event: signal when a reply is available
+ * @dma_mem: DMA memory of send buffer that use stack variable
+ * @send_dma_mem: DMA memory of send buffer
+ * @recv_mem: receive buffer
+ * @send_ctx: context for callback function
+ * @timeout_ms: Xn transaction timeout in msecs
+ * @timestamp: timestamp to record the Xn send
+ * @virtchnl_opcode: virtchnl command opcode used for Xn transaction
+ * @state: transaction state of a virtchnl message
+ * @cookie: unique message identifier
+ * @index: index of the transaction entry
+ */
+struct libie_ctlq_xn {
+	void (*resp_cb)(void *ctx, struct kvec *mem, int status);
+	spinlock_t			xn_lock;	/* protects state */
+	struct libie_ctlq_info		*ctlq;
+	struct completion		cmd_completion_event;
+	struct libie_cp_dma_mem	*dma_mem;
+	struct libie_cp_dma_mem	send_dma_mem;
+	struct kvec			recv_mem;
+	void				*send_ctx;
+	u64				timeout_ms;
+	ktime_t				timestamp;
+	u32				virtchnl_opcode;
+	enum libie_ctlq_xn_state	state;
+	u8				cookie;
+	u8				index;
+};
+
+/**
+ * struct libie_ctlq_xn_manager - structure representing the array of virtchnl
+ *				   transaction entries
+ * @ctx: pointer to controlq context structure
+ * @free_xns_bm_lock: lock to protect the free Xn entries bit map
+ * @free_xns_bm: bitmap that represents the free Xn entries
+ * @ring: array of Xn entries
+ * @can_destroy: completion triggered by the last returned transaction
+ * @shutdown: shows the transactions the xnm shutdown is waiting for them
+ * @cookie: unique message identifier
+ */
+struct libie_ctlq_xn_manager {
+	struct libie_ctlq_ctx	*ctx;
+	spinlock_t		free_xns_bm_lock;	/* get/check entries */
+	DECLARE_BITMAP(free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES);
+	struct libie_ctlq_xn	ring[LIBIE_CTLQ_MAX_XN_ENTRIES];
+	struct completion	can_destroy;
+	bool			shutdown;
+	u8			cookie;
+};
+
+/**
+ * struct libie_ctlq_xn_send_params - structure representing send Xn entry
+ * @resp_cb: callback to handle the response of an asynchronous virtchnl message
+ * @rel_tx_buf: driver entry point for freeing the send buffer after send
+ * @xnm: Xn manager to process Xn entries
+ * @ctlq: send control queue information
+ * @ctlq_msg: control queue message information
+ * @send_buf: represents the buffer that carries outgoing information
+ * @recv_mem: receive buffer
+ * @send_ctx: context for call back function
+ * @timeout_ms: virtchnl transaction timeout in msecs
+ * @chnl_opcode: virtchnl message opcode
+ */
+struct libie_ctlq_xn_send_params {
+	void (*resp_cb)(void *ctx, struct kvec *mem, int status);
+	void (*rel_tx_buf)(const void *buf_va);
+	struct libie_ctlq_xn_manager		*xnm;
+	struct libie_ctlq_info			*ctlq;
+	struct libie_ctlq_msg			*ctlq_msg;
+	struct kvec				send_buf;
+	struct kvec				recv_mem;
+	void					*send_ctx;
+	u64					timeout_ms;
+	u32					chnl_opcode;
+};
+
+/**
+ * libie_cp_can_send_onstack - can a message be sent using a stack variable
+ * @size: ctlq data buffer size
+ *
+ * Return: %true if the message size is small enough for caller to pass
+ *	   an on-stack buffer, %false if kmalloc is needed
+ */
+static inline bool libie_cp_can_send_onstack(u32 size)
+{
+	return size <= LIBIE_CP_TX_COPYBREAK;
+}
+
+/**
+ * struct libie_ctlq_xn_recv_params - structure representing receive Xn entry
+ * @ctlq_msg_handler: callback to handle a message originated from the peer
+ * @xnm: Xn manager to process Xn entries
+ * @ctlq: control queue information
+ */
+struct libie_ctlq_xn_recv_params {
+	void (*ctlq_msg_handler)(struct libie_ctlq_ctx *ctx,
+				 struct libie_ctlq_msg *msg);
+	struct libie_ctlq_xn_manager		*xnm;
+	struct libie_ctlq_info			*ctlq;
+};
+
+/**
+ * struct libie_ctlq_xn_clean_params - Data structure used for cleaning the
+ * control queue messages
+ * @rel_tx_buf: driver entry point for freeing the send buffer after send
+ * @ctx: pointer to context structure
+ * @ctlq: control queue information
+ * @send_ctx: context for call back function
+ * @num_msgs: number of messages to be cleaned
+ */
+struct libie_ctlq_xn_clean_params {
+	void (*rel_tx_buf)(const void *buf_va);
+	struct libie_ctlq_ctx			*ctx;
+	struct libie_ctlq_info			*ctlq;
+	void					*send_ctx;
+	u16					num_msgs;
+};
+
+/**
+ * struct libie_ctlq_xn_init_params - Data structure used for initializing the
+ * Xn transaction manager
+ * @cctlq_info: control queue information
+ * @ctx: pointer to controlq context structure
+ * @xnm: Xn manager to process Xn entries
+ * @num_qs: number of control queues needs to initialized
+ */
+struct libie_ctlq_xn_init_params {
+	struct libie_ctlq_create_info		*cctlq_info;
+	struct libie_ctlq_ctx			*ctx;
+	struct libie_ctlq_xn_manager		*xnm;
+	u32					num_qs;
+};
+
+int libie_ctlq_xn_init(struct libie_ctlq_xn_init_params *params);
+void libie_ctlq_xn_deinit(struct libie_ctlq_xn_manager *xnm,
+			  struct libie_ctlq_ctx *ctx);
+int libie_ctlq_xn_send(struct libie_ctlq_xn_send_params *params);
+bool libie_ctlq_xn_recv(struct libie_ctlq_xn_recv_params *params);
+u32 libie_ctlq_xn_send_clean(const struct libie_ctlq_xn_clean_params *params);
+
 #endif /* __LIBIE_CONTROLQ_H */
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 07/15] idpf: remove 'vport_params_reqd' field
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
                   ` (5 preceding siblings ...)
  2025-05-16 14:58 ` [PATCH iwl-next v4 06/15] libie: add bookkeeping support for control queue messages Larysa Zaremba
@ 2025-05-16 14:58 ` Larysa Zaremba
  2025-06-10 21:50   ` [Intel-wired-lan] " Salin, Samuel
  2025-05-16 14:58 ` [PATCH iwl-next v4 08/15] idpf: refactor idpf to use libie_pci APIs Larysa Zaremba
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:58 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali

From: Pavan Kumar Linga <pavan.kumar.linga@intel.com>

While sending a create vport message to the device control plane, a create
vport virtchnl message is prepared with all the required info to initialize
the vport. This info is stored in the adapter struct but never used
thereafter. So, remove the said field.

Signed-off-by: Pavan Kumar Linga <pavan.kumar.linga@intel.com>
Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
---
 drivers/net/ethernet/intel/idpf/idpf.h        |  2 --
 drivers/net/ethernet/intel/idpf/idpf_lib.c    |  2 --
 .../net/ethernet/intel/idpf/idpf_virtchnl.c   | 31 ++++++-------------
 3 files changed, 10 insertions(+), 25 deletions(-)

diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index 47931b7593eb..0c8fc4c1e927 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -568,7 +568,6 @@ struct idpf_vc_xn_manager;
  * @avail_queues: Device given queue limits
  * @vports: Array to store vports created by the driver
  * @netdevs: Associated Vport netdevs
- * @vport_params_reqd: Vport params requested
  * @vport_params_recvd: Vport params received
  * @vport_ids: Array of device given vport identifiers
  * @singleq_pt_lkup: Lookup table for singleq RX ptypes
@@ -625,7 +624,6 @@ struct idpf_adapter {
 	struct idpf_avail_queue_info avail_queues;
 	struct idpf_vport **vports;
 	struct net_device **netdevs;
-	struct virtchnl2_create_vport **vport_params_reqd;
 	struct virtchnl2_create_vport **vport_params_recvd;
 	u32 *vport_ids;
 
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index 61448af2ab63..b7eaf39b1647 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -958,8 +958,6 @@ static void idpf_vport_rel(struct idpf_vport *vport)
 
 	kfree(adapter->vport_params_recvd[idx]);
 	adapter->vport_params_recvd[idx] = NULL;
-	kfree(adapter->vport_params_reqd[idx]);
-	adapter->vport_params_reqd[idx] = NULL;
 
 	kfree(vport);
 	adapter->num_alloc_vports--;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index bc29503a5f82..b93082b98f3a 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -1307,14 +1307,10 @@ int idpf_send_create_vport_msg(struct idpf_adapter *adapter,
 	ssize_t reply_sz;
 
 	buf_size = sizeof(struct virtchnl2_create_vport);
-	if (!adapter->vport_params_reqd[idx]) {
-		adapter->vport_params_reqd[idx] = kzalloc(buf_size,
-							  GFP_KERNEL);
-		if (!adapter->vport_params_reqd[idx])
-			return -ENOMEM;
-	}
+	vport_msg = kzalloc(buf_size, GFP_KERNEL);
+	if (!vport_msg)
+		return -ENOMEM;
 
-	vport_msg = adapter->vport_params_reqd[idx];
 	vport_msg->vport_type = cpu_to_le16(VIRTCHNL2_VPORT_TYPE_DEFAULT);
 	vport_msg->vport_index = cpu_to_le16(idx);
 
@@ -1331,8 +1327,7 @@ int idpf_send_create_vport_msg(struct idpf_adapter *adapter,
 	err = idpf_vport_calc_total_qs(adapter, idx, vport_msg, max_q);
 	if (err) {
 		dev_err(&adapter->pdev->dev, "Enough queues are not available");
-
-		return err;
+		goto rel_buf;
 	}
 
 	if (!adapter->vport_params_recvd[idx]) {
@@ -1340,7 +1335,7 @@ int idpf_send_create_vport_msg(struct idpf_adapter *adapter,
 							   GFP_KERNEL);
 		if (!adapter->vport_params_recvd[idx]) {
 			err = -ENOMEM;
-			goto free_vport_params;
+			goto rel_buf;
 		}
 	}
 
@@ -1356,13 +1351,15 @@ int idpf_send_create_vport_msg(struct idpf_adapter *adapter,
 		goto free_vport_params;
 	}
 
+	kfree(vport_msg);
+
 	return 0;
 
 free_vport_params:
 	kfree(adapter->vport_params_recvd[idx]);
 	adapter->vport_params_recvd[idx] = NULL;
-	kfree(adapter->vport_params_reqd[idx]);
-	adapter->vport_params_reqd[idx] = NULL;
+rel_buf:
+	kfree(vport_msg);
 
 	return err;
 }
@@ -2845,8 +2842,6 @@ static void idpf_vport_params_buf_rel(struct idpf_adapter *adapter)
 {
 	kfree(adapter->vport_params_recvd);
 	adapter->vport_params_recvd = NULL;
-	kfree(adapter->vport_params_reqd);
-	adapter->vport_params_reqd = NULL;
 	kfree(adapter->vport_ids);
 	adapter->vport_ids = NULL;
 }
@@ -2861,17 +2856,11 @@ static int idpf_vport_params_buf_alloc(struct idpf_adapter *adapter)
 {
 	u16 num_max_vports = idpf_get_max_vports(adapter);
 
-	adapter->vport_params_reqd = kcalloc(num_max_vports,
-					     sizeof(*adapter->vport_params_reqd),
-					     GFP_KERNEL);
-	if (!adapter->vport_params_reqd)
-		return -ENOMEM;
-
 	adapter->vport_params_recvd = kcalloc(num_max_vports,
 					      sizeof(*adapter->vport_params_recvd),
 					      GFP_KERNEL);
 	if (!adapter->vport_params_recvd)
-		goto err_mem;
+		return -ENOMEM;
 
 	adapter->vport_ids = kcalloc(num_max_vports, sizeof(u32), GFP_KERNEL);
 	if (!adapter->vport_ids)
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 08/15] idpf: refactor idpf to use libie_pci APIs
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
                   ` (6 preceding siblings ...)
  2025-05-16 14:58 ` [PATCH iwl-next v4 07/15] idpf: remove 'vport_params_reqd' field Larysa Zaremba
@ 2025-05-16 14:58 ` Larysa Zaremba
  2025-06-10 21:51   ` [Intel-wired-lan] " Salin, Samuel
  2025-05-16 14:58 ` [PATCH iwl-next v4 09/15] idpf: refactor idpf to use libie control queues Larysa Zaremba
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:58 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali, Michal Kubiak

From: Pavan Kumar Linga <pavan.kumar.linga@intel.com>

Use libie_pci init and MMIO APIs where possible, struct idpf_hw cannot be
deleted for now as it also houses control queues that will be refactored
later. Use libie_cp header for libie_ctlq_ctx that contains mmio info from
the start in order to not increase the diff later.

Reviewed-by: Michal Kubiak <michal.kubiak@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>
---
 drivers/net/ethernet/intel/idpf/Kconfig       |  1 +
 drivers/net/ethernet/intel/idpf/idpf.h        | 19 ++---
 drivers/net/ethernet/intel/idpf/idpf_dev.c    | 37 +++++----
 drivers/net/ethernet/intel/idpf/idpf_lib.c    |  7 +-
 drivers/net/ethernet/intel/idpf/idpf_main.c   | 83 +++++++++----------
 drivers/net/ethernet/intel/idpf/idpf_vf_dev.c | 29 ++++---
 .../net/ethernet/intel/idpf/idpf_virtchnl.c   | 13 +--
 .../ethernet/intel/idpf/idpf_virtchnl_ptp.c   | 52 +++++++-----
 8 files changed, 126 insertions(+), 115 deletions(-)

diff --git a/drivers/net/ethernet/intel/idpf/Kconfig b/drivers/net/ethernet/intel/idpf/Kconfig
index 2c359a8551c7..e0a50e60e1ad 100644
--- a/drivers/net/ethernet/intel/idpf/Kconfig
+++ b/drivers/net/ethernet/intel/idpf/Kconfig
@@ -7,6 +7,7 @@ config IDPF
 	depends on PTP_1588_CLOCK_OPTIONAL
 	select DIMLIB
 	select LIBETH
+	select LIBIE_PCI
 	help
 	  This driver supports Intel(R) Infrastructure Data Path Function
 	  devices.
diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index 0c8fc4c1e927..fb36dcbd8f5c 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -20,6 +20,7 @@ struct idpf_rss_data;
 #include <linux/ethtool_netlink.h>
 #include <net/gro.h>
 
+#include <linux/intel/libie/controlq.h>
 #include <linux/intel/virtchnl2.h>
 #include "idpf_txrx.h"
 #include "idpf_controlq.h"
@@ -556,6 +557,7 @@ struct idpf_vc_xn_manager;
  * @flags: See enum idpf_flags
  * @reset_reg: See struct idpf_reset_reg
  * @hw: Device access data
+ * @ctlq_ctx: controlq context
  * @num_req_msix: Requested number of MSIX vectors
  * @num_avail_msix: Available number of MSIX vectors
  * @num_msix_entries: Number of entries in MSIX table
@@ -611,6 +613,7 @@ struct idpf_adapter {
 	DECLARE_BITMAP(flags, IDPF_FLAGS_NBITS);
 	struct idpf_reset_reg reset_reg;
 	struct idpf_hw hw;
+	struct libie_ctlq_ctx ctlq_ctx;
 	u16 num_req_msix;
 	u16 num_avail_msix;
 	u16 num_msix_entries;
@@ -772,19 +775,6 @@ static inline u8 idpf_get_min_tx_pkt_len(struct idpf_adapter *adapter)
 	return pkt_len ? pkt_len : IDPF_TX_MIN_PKT_LEN;
 }
 
-/**
- * idpf_get_reg_addr - Get BAR0 register address
- * @adapter: private data struct
- * @reg_offset: register offset value
- *
- * Based on the register offset, return the actual BAR0 register address
- */
-static inline void __iomem *idpf_get_reg_addr(struct idpf_adapter *adapter,
-					      resource_size_t reg_offset)
-{
-	return (void __iomem *)(adapter->hw.hw_addr + reg_offset);
-}
-
 /**
  * idpf_is_reset_detected - check if we were reset at some point
  * @adapter: driver specific private structure
@@ -796,7 +786,8 @@ static inline bool idpf_is_reset_detected(struct idpf_adapter *adapter)
 	if (!adapter->hw.arq)
 		return true;
 
-	return !(readl(idpf_get_reg_addr(adapter, adapter->hw.arq->reg.len)) &
+	return !(readl(libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info,
+					       adapter->hw.arq->reg.len)) &
 		 adapter->hw.arq->reg.len_mask);
 }
 
diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c
index 6d5c9098f577..d89ee10a2efc 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c
@@ -54,13 +54,14 @@ static void idpf_ctlq_reg_init(struct idpf_ctlq_create_info *cq)
  */
 static void idpf_mb_intr_reg_init(struct idpf_adapter *adapter)
 {
+	struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
 	struct idpf_intr_reg *intr = &adapter->mb_vector.intr_reg;
 	u32 dyn_ctl = le32_to_cpu(adapter->caps.mailbox_dyn_ctl);
 
-	intr->dyn_ctl = idpf_get_reg_addr(adapter, dyn_ctl);
+	intr->dyn_ctl = libie_pci_get_mmio_addr(mmio, dyn_ctl);
 	intr->dyn_ctl_intena_m = PF_GLINT_DYN_CTL_INTENA_M;
 	intr->dyn_ctl_itridx_m = PF_GLINT_DYN_CTL_ITR_INDX_M;
-	intr->icr_ena = idpf_get_reg_addr(adapter, PF_INT_DIR_OICR_ENA);
+	intr->icr_ena = libie_pci_get_mmio_addr(mmio, PF_INT_DIR_OICR_ENA);
 	intr->icr_ena_ctlq_m = PF_INT_DIR_OICR_ENA_M;
 }
 
@@ -75,6 +76,7 @@ static int idpf_intr_reg_init(struct idpf_vport *vport,
 	struct idpf_adapter *adapter = vport->adapter;
 	u16 num_vecs = rsrc->num_q_vectors;
 	struct idpf_vec_regs *reg_vals;
+	struct libie_mmio_info *mmio;
 	int num_regs, i, err = 0;
 	u32 rx_itr, tx_itr;
 	u16 total_vecs;
@@ -91,14 +93,17 @@ static int idpf_intr_reg_init(struct idpf_vport *vport,
 		goto free_reg_vals;
 	}
 
+	mmio = &adapter->ctlq_ctx.mmio_info;
+
 	for (i = 0; i < num_vecs; i++) {
 		struct idpf_q_vector *q_vector = &rsrc->q_vectors[i];
 		u16 vec_id = rsrc->q_vector_idxs[i] - IDPF_MBX_Q_VEC;
 		struct idpf_intr_reg *intr = &q_vector->intr_reg;
+		struct idpf_vec_regs *reg = &reg_vals[vec_id];
 		u32 spacing;
 
-		intr->dyn_ctl = idpf_get_reg_addr(adapter,
-						  reg_vals[vec_id].dyn_ctl_reg);
+		intr->dyn_ctl =	libie_pci_get_mmio_addr(mmio,
+							reg->dyn_ctl_reg);
 		intr->dyn_ctl_intena_m = PF_GLINT_DYN_CTL_INTENA_M;
 		intr->dyn_ctl_intena_msk_m = PF_GLINT_DYN_CTL_INTENA_MSK_M;
 		intr->dyn_ctl_itridx_s = PF_GLINT_DYN_CTL_ITR_INDX_S;
@@ -108,16 +113,14 @@ static int idpf_intr_reg_init(struct idpf_vport *vport,
 		intr->dyn_ctl_sw_itridx_ena_m =
 			PF_GLINT_DYN_CTL_SW_ITR_INDX_ENA_M;
 
-		spacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing,
+		spacing = IDPF_ITR_IDX_SPACING(reg->itrn_index_spacing,
 					       IDPF_PF_ITR_IDX_SPACING);
 		rx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_0,
-					   reg_vals[vec_id].itrn_reg,
-					   spacing);
+					   reg->itrn_reg, spacing);
 		tx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_1,
-					   reg_vals[vec_id].itrn_reg,
-					   spacing);
-		intr->rx_itr = idpf_get_reg_addr(adapter, rx_itr);
-		intr->tx_itr = idpf_get_reg_addr(adapter, tx_itr);
+					   reg->itrn_reg, spacing);
+		intr->rx_itr = libie_pci_get_mmio_addr(mmio, rx_itr);
+		intr->tx_itr = libie_pci_get_mmio_addr(mmio, tx_itr);
 	}
 
 free_reg_vals:
@@ -132,7 +135,9 @@ static int idpf_intr_reg_init(struct idpf_vport *vport,
  */
 static void idpf_reset_reg_init(struct idpf_adapter *adapter)
 {
-	adapter->reset_reg.rstat = idpf_get_reg_addr(adapter, PFGEN_RSTAT);
+	adapter->reset_reg.rstat =
+		libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info,
+					PFGEN_RSTAT);
 	adapter->reset_reg.rstat_m = PFGEN_RSTAT_PFR_STATE_M;
 }
 
@@ -144,11 +149,11 @@ static void idpf_reset_reg_init(struct idpf_adapter *adapter)
 static void idpf_trigger_reset(struct idpf_adapter *adapter,
 			       enum idpf_flags __always_unused trig_cause)
 {
-	u32 reset_reg;
+	void __iomem *addr;
 
-	reset_reg = readl(idpf_get_reg_addr(adapter, PFGEN_CTRL));
-	writel(reset_reg | PFGEN_CTRL_PFSWR,
-	       idpf_get_reg_addr(adapter, PFGEN_CTRL));
+	addr = libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info,
+				       PFGEN_CTRL);
+	writel(readl(addr) | PFGEN_CTRL_PFSWR, addr);
 }
 
 /**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index b7eaf39b1647..68330b884967 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -1664,15 +1664,14 @@ void idpf_deinit_task(struct idpf_adapter *adapter)
 
 /**
  * idpf_check_reset_complete - check that reset is complete
- * @hw: pointer to hw struct
+ * @adapter: adapter to check
  * @reset_reg: struct with reset registers
  *
  * Returns 0 if device is ready to use, or -EBUSY if it's in reset.
  **/
-static int idpf_check_reset_complete(struct idpf_hw *hw,
+static int idpf_check_reset_complete(struct idpf_adapter *adapter,
 				     struct idpf_reset_reg *reset_reg)
 {
-	struct idpf_adapter *adapter = hw->back;
 	int i;
 
 	for (i = 0; i < 2000; i++) {
@@ -1766,7 +1765,7 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter)
 	}
 
 	/* Wait for reset to complete */
-	err = idpf_check_reset_complete(&adapter->hw, &adapter->reset_reg);
+	err = idpf_check_reset_complete(adapter, &adapter->reset_reg);
 	if (err) {
 		dev_err(dev, "The driver was unable to contact the device's firmware. Check that the FW is running. Driver state= 0x%x\n",
 			adapter->state);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c
index 0efd9c0c7a90..bb84b2871b84 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_main.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_main.c
@@ -9,8 +9,20 @@
 
 MODULE_DESCRIPTION(DRV_SUMMARY);
 MODULE_IMPORT_NS("LIBETH");
+MODULE_IMPORT_NS("LIBIE_CP");
+MODULE_IMPORT_NS("LIBIE_PCI");
 MODULE_LICENSE("GPL");
 
+/**
+ * idpf_decfg_device - deconfigure device and device specific resources
+ * @adapter: driver specific private structure
+ */
+static void idpf_decfg_device(struct idpf_adapter *adapter)
+{
+	libie_pci_unmap_all_mmio_regions(&adapter->ctlq_ctx.mmio_info);
+	libie_pci_deinit_dev(adapter->pdev);
+}
+
 /**
  * idpf_remove - Device removal routine
  * @pdev: PCI device information struct
@@ -77,7 +89,7 @@ static void idpf_remove(struct pci_dev *pdev)
 	mutex_destroy(&adapter->queue_lock);
 	mutex_destroy(&adapter->vc_buf_lock);
 
-	pci_set_drvdata(pdev, NULL);
+	idpf_decfg_device(adapter);
 	kfree(adapter);
 }
 
@@ -99,24 +111,36 @@ static void idpf_shutdown(struct pci_dev *pdev)
 }
 
 /**
- * idpf_cfg_hw - Initialize HW struct
- * @adapter: adapter to setup hw struct for
+ * idpf_cfg_device - configure device and device specific resources
+ * @adapter: driver specific private structure
  *
- * Returns 0 on success, negative on failure
+ * Return: %0 on success, -%errno on failure.
  */
-static int idpf_cfg_hw(struct idpf_adapter *adapter)
+static int idpf_cfg_device(struct idpf_adapter *adapter)
 {
+	struct libie_mmio_info *mmio_info = &adapter->ctlq_ctx.mmio_info;
 	struct pci_dev *pdev = adapter->pdev;
-	struct idpf_hw *hw = &adapter->hw;
+	int err;
 
-	hw->hw_addr = pcim_iomap_table(pdev)[0];
-	if (!hw->hw_addr) {
-		pci_err(pdev, "failed to allocate PCI iomap table\n");
+	err = libie_pci_init_dev(pdev);
+	if (err)
+		return err;
 
+	mmio_info->pdev = pdev;
+	INIT_LIST_HEAD(&mmio_info->mmio_list);
+
+	err = libie_pci_map_mmio_region(mmio_info, 0,
+					pci_resource_len(pdev, 0));
+	if (!err) {
+		libie_pci_deinit_dev(pdev);
 		return -ENOMEM;
 	}
 
-	hw->back = adapter;
+	err = pci_enable_ptm(pdev, NULL);
+	if (err)
+		pci_dbg(pdev, "PCIe PTM is not supported by PCIe bus/controller\n");
+
+	pci_set_drvdata(pdev, adapter);
 
 	return 0;
 }
@@ -157,32 +181,13 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	}
 
 	adapter->pdev = pdev;
-	err = pcim_enable_device(pdev);
-	if (err)
-		goto err_free;
-
-	err = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
+	err = idpf_cfg_device(adapter);
 	if (err) {
-		pci_err(pdev, "pcim_iomap_regions failed %pe\n", ERR_PTR(err));
-
+		pci_err(pdev, "Failed to configure device specific resources: %pe\n",
+			ERR_PTR(err));
 		goto err_free;
 	}
 
-	err = pci_enable_ptm(pdev, NULL);
-	if (err)
-		pci_dbg(pdev, "PCIe PTM is not supported by PCIe bus/controller\n");
-
-	/* set up for high or low dma */
-	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
-	if (err) {
-		pci_err(pdev, "DMA configuration failed: %pe\n", ERR_PTR(err));
-
-		goto err_free;
-	}
-
-	pci_set_master(pdev);
-	pci_set_drvdata(pdev, adapter);
-
 	adapter->init_wq = alloc_workqueue("%s-%s-init",
 					   WQ_UNBOUND | WQ_MEM_RECLAIM, 0,
 					   dev_driver_string(dev),
@@ -190,7 +195,7 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (!adapter->init_wq) {
 		dev_err(dev, "Failed to allocate init workqueue\n");
 		err = -ENOMEM;
-		goto err_free;
+		goto err_init_wq;
 	}
 
 	adapter->serv_wq = alloc_workqueue("%s-%s-service",
@@ -235,13 +240,6 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	/* setup msglvl */
 	adapter->msg_enable = netif_msg_init(-1, IDPF_AVAIL_NETIF_M);
 
-	err = idpf_cfg_hw(adapter);
-	if (err) {
-		dev_err(dev, "Failed to configure HW structure for adapter: %d\n",
-			err);
-		goto err_cfg_hw;
-	}
-
 	mutex_init(&adapter->vport_ctrl_lock);
 	mutex_init(&adapter->vector_lock);
 	mutex_init(&adapter->queue_lock);
@@ -260,8 +258,6 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	return 0;
 
-err_cfg_hw:
-	destroy_workqueue(adapter->vc_event_wq);
 err_vc_event_wq_alloc:
 	destroy_workqueue(adapter->stats_wq);
 err_stats_wq_alloc:
@@ -270,8 +266,11 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	destroy_workqueue(adapter->serv_wq);
 err_serv_wq_alloc:
 	destroy_workqueue(adapter->init_wq);
+err_init_wq:
+	idpf_decfg_device(adapter);
 err_free:
 	kfree(adapter);
+
 	return err;
 }
 
diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
index ac091280e828..ee4907bd4f28 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
@@ -53,13 +53,14 @@ static void idpf_vf_ctlq_reg_init(struct idpf_ctlq_create_info *cq)
  */
 static void idpf_vf_mb_intr_reg_init(struct idpf_adapter *adapter)
 {
+	struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
 	struct idpf_intr_reg *intr = &adapter->mb_vector.intr_reg;
 	u32 dyn_ctl = le32_to_cpu(adapter->caps.mailbox_dyn_ctl);
 
-	intr->dyn_ctl = idpf_get_reg_addr(adapter, dyn_ctl);
+	intr->dyn_ctl = libie_pci_get_mmio_addr(mmio, dyn_ctl);
 	intr->dyn_ctl_intena_m = VF_INT_DYN_CTL0_INTENA_M;
 	intr->dyn_ctl_itridx_m = VF_INT_DYN_CTL0_ITR_INDX_M;
-	intr->icr_ena = idpf_get_reg_addr(adapter, VF_INT_ICR0_ENA1);
+	intr->icr_ena = libie_pci_get_mmio_addr(mmio, VF_INT_ICR0_ENA1);
 	intr->icr_ena_ctlq_m = VF_INT_ICR0_ENA1_ADMINQ_M;
 }
 
@@ -74,6 +75,7 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport,
 	struct idpf_adapter *adapter = vport->adapter;
 	u16 num_vecs = rsrc->num_q_vectors;
 	struct idpf_vec_regs *reg_vals;
+	struct libie_mmio_info *mmio;
 	int num_regs, i, err = 0;
 	u32 rx_itr, tx_itr;
 	u16 total_vecs;
@@ -90,14 +92,17 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport,
 		goto free_reg_vals;
 	}
 
+	mmio = &adapter->ctlq_ctx.mmio_info;
+
 	for (i = 0; i < num_vecs; i++) {
 		struct idpf_q_vector *q_vector = &rsrc->q_vectors[i];
 		u16 vec_id = rsrc->q_vector_idxs[i] - IDPF_MBX_Q_VEC;
 		struct idpf_intr_reg *intr = &q_vector->intr_reg;
+		struct idpf_vec_regs *reg = &reg_vals[vec_id];
 		u32 spacing;
 
-		intr->dyn_ctl = idpf_get_reg_addr(adapter,
-						  reg_vals[vec_id].dyn_ctl_reg);
+		intr->dyn_ctl =	libie_pci_get_mmio_addr(mmio,
+							reg->dyn_ctl_reg);
 		intr->dyn_ctl_intena_m = VF_INT_DYN_CTLN_INTENA_M;
 		intr->dyn_ctl_intena_msk_m = VF_INT_DYN_CTLN_INTENA_MSK_M;
 		intr->dyn_ctl_itridx_s = VF_INT_DYN_CTLN_ITR_INDX_S;
@@ -107,16 +112,14 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport,
 		intr->dyn_ctl_sw_itridx_ena_m =
 			VF_INT_DYN_CTLN_SW_ITR_INDX_ENA_M;
 
-		spacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing,
+		spacing = IDPF_ITR_IDX_SPACING(reg->itrn_index_spacing,
 					       IDPF_VF_ITR_IDX_SPACING);
 		rx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_0,
-					  reg_vals[vec_id].itrn_reg,
-					  spacing);
+					  reg->itrn_reg, spacing);
 		tx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_1,
-					  reg_vals[vec_id].itrn_reg,
-					  spacing);
-		intr->rx_itr = idpf_get_reg_addr(adapter, rx_itr);
-		intr->tx_itr = idpf_get_reg_addr(adapter, tx_itr);
+					  reg->itrn_reg, spacing);
+		intr->rx_itr = libie_pci_get_mmio_addr(mmio, rx_itr);
+		intr->tx_itr = libie_pci_get_mmio_addr(mmio, tx_itr);
 	}
 
 free_reg_vals:
@@ -131,7 +134,9 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport,
  */
 static void idpf_vf_reset_reg_init(struct idpf_adapter *adapter)
 {
-	adapter->reset_reg.rstat = idpf_get_reg_addr(adapter, VFGEN_RSTAT);
+	adapter->reset_reg.rstat =
+		libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info,
+					VFGEN_RSTAT);
 	adapter->reset_reg.rstat_m = VFGEN_RSTAT_VFR_STATE_M;
 }
 
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index b93082b98f3a..d8b62ca46f60 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -1163,7 +1163,7 @@ static int __idpf_queue_reg_init(struct idpf_vport *vport,
 				 struct idpf_q_vec_rsrc *rsrc, u32 *reg_vals,
 				 int num_regs, u32 q_type)
 {
-	struct idpf_adapter *adapter = vport->adapter;
+	struct libie_mmio_info *mmio = &vport->adapter->ctlq_ctx.mmio_info;
 	int i, j, k = 0;
 
 	switch (q_type) {
@@ -1173,7 +1173,8 @@ static int __idpf_queue_reg_init(struct idpf_vport *vport,
 
 			for (j = 0; j < tx_qgrp->num_txq && k < num_regs; j++, k++)
 				tx_qgrp->txqs[j]->tail =
-					idpf_get_reg_addr(adapter, reg_vals[k]);
+					libie_pci_get_mmio_addr(mmio,
+								reg_vals[k]);
 		}
 		break;
 	case VIRTCHNL2_QUEUE_TYPE_RX:
@@ -1185,8 +1186,8 @@ static int __idpf_queue_reg_init(struct idpf_vport *vport,
 				struct idpf_rx_queue *q;
 
 				q = rx_qgrp->singleq.rxqs[j];
-				q->tail = idpf_get_reg_addr(adapter,
-							    reg_vals[k]);
+				q->tail = libie_pci_get_mmio_addr(mmio,
+								  reg_vals[k]);
 			}
 		}
 		break;
@@ -1199,8 +1200,8 @@ static int __idpf_queue_reg_init(struct idpf_vport *vport,
 				struct idpf_buf_queue *q;
 
 				q = &rx_qgrp->splitq.bufq_sets[j].bufq;
-				q->tail = idpf_get_reg_addr(adapter,
-							    reg_vals[k]);
+				q->tail = libie_pci_get_mmio_addr(mmio,
+								  reg_vals[k]);
 			}
 		}
 		break;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c
index bdcc54a5fb56..f9b23e98e55f 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c
@@ -30,6 +30,7 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)
 		.send_buf.iov_len = sizeof(send_ptp_caps_msg),
 		.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
 	};
+	struct libie_mmio_info	*mmio_info = &adapter->ctlq_ctx.mmio_info;
 	struct virtchnl2_ptp_clk_adj_reg_offsets clk_adj_offsets;
 	struct virtchnl2_ptp_clk_reg_offsets clock_offsets;
 	struct idpf_ptp_secondary_mbx *scnd_mbx;
@@ -76,19 +77,20 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)
 	clock_offsets = recv_ptp_caps_msg->clk_offsets;
 
 	temp_offset = le32_to_cpu(clock_offsets.dev_clk_ns_l);
-	ptp->dev_clk_regs.dev_clk_ns_l = idpf_get_reg_addr(adapter,
-							   temp_offset);
+	ptp->dev_clk_regs.dev_clk_ns_l =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 	temp_offset = le32_to_cpu(clock_offsets.dev_clk_ns_h);
-	ptp->dev_clk_regs.dev_clk_ns_h = idpf_get_reg_addr(adapter,
-							   temp_offset);
+	ptp->dev_clk_regs.dev_clk_ns_h =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 	temp_offset = le32_to_cpu(clock_offsets.phy_clk_ns_l);
-	ptp->dev_clk_regs.phy_clk_ns_l = idpf_get_reg_addr(adapter,
-							   temp_offset);
+	ptp->dev_clk_regs.phy_clk_ns_l =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 	temp_offset = le32_to_cpu(clock_offsets.phy_clk_ns_h);
-	ptp->dev_clk_regs.phy_clk_ns_h = idpf_get_reg_addr(adapter,
-							   temp_offset);
+	ptp->dev_clk_regs.phy_clk_ns_h =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 	temp_offset = le32_to_cpu(clock_offsets.cmd_sync_trigger);
-	ptp->dev_clk_regs.cmd_sync = idpf_get_reg_addr(adapter, temp_offset);
+	ptp->dev_clk_regs.cmd_sync =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 
 discipline_clock:
 	access_type = ptp->adj_dev_clk_time_access;
@@ -99,29 +101,37 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)
 
 	/* Device clock offsets */
 	temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_cmd_type);
-	ptp->dev_clk_regs.cmd = idpf_get_reg_addr(adapter, temp_offset);
+	ptp->dev_clk_regs.cmd =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 	temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_incval_l);
-	ptp->dev_clk_regs.incval_l = idpf_get_reg_addr(adapter, temp_offset);
+	ptp->dev_clk_regs.incval_l =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 	temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_incval_h);
-	ptp->dev_clk_regs.incval_h = idpf_get_reg_addr(adapter, temp_offset);
+	ptp->dev_clk_regs.incval_h =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 	temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_shadj_l);
-	ptp->dev_clk_regs.shadj_l = idpf_get_reg_addr(adapter, temp_offset);
+	ptp->dev_clk_regs.shadj_l =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 	temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_shadj_h);
-	ptp->dev_clk_regs.shadj_h = idpf_get_reg_addr(adapter, temp_offset);
+	ptp->dev_clk_regs.shadj_h =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 
 	/* PHY clock offsets */
 	temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_cmd_type);
-	ptp->dev_clk_regs.phy_cmd = idpf_get_reg_addr(adapter, temp_offset);
+	ptp->dev_clk_regs.phy_cmd =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 	temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_incval_l);
-	ptp->dev_clk_regs.phy_incval_l = idpf_get_reg_addr(adapter,
-							   temp_offset);
+	ptp->dev_clk_regs.phy_incval_l =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 	temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_incval_h);
-	ptp->dev_clk_regs.phy_incval_h = idpf_get_reg_addr(adapter,
-							   temp_offset);
+	ptp->dev_clk_regs.phy_incval_h =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 	temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_shadj_l);
-	ptp->dev_clk_regs.phy_shadj_l = idpf_get_reg_addr(adapter, temp_offset);
+	ptp->dev_clk_regs.phy_shadj_l =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 	temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_shadj_h);
-	ptp->dev_clk_regs.phy_shadj_h = idpf_get_reg_addr(adapter, temp_offset);
+	ptp->dev_clk_regs.phy_shadj_h =
+		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 
 	return 0;
 }
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 09/15] idpf: refactor idpf to use libie control queues
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
                   ` (7 preceding siblings ...)
  2025-05-16 14:58 ` [PATCH iwl-next v4 08/15] idpf: refactor idpf to use libie_pci APIs Larysa Zaremba
@ 2025-05-16 14:58 ` Larysa Zaremba
  2025-06-10 21:51   ` [Intel-wired-lan] " Salin, Samuel
  2025-06-18  0:04   ` Tantilov, Emil S
  2025-05-16 14:58 ` [PATCH iwl-next v4 10/15] idpf: make mbx_task queueing and cancelling more consistent Larysa Zaremba
                   ` (5 subsequent siblings)
  14 siblings, 2 replies; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:58 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali, Michal Kubiak

From: Pavan Kumar Linga <pavan.kumar.linga@intel.com>

Support to initialize and configure controlqs, and manage their
transactions was introduced in libie. As part of it, most of the existing
controlq structures are renamed and modified. Use those APIs in idpf and
make all the necessary changes.

Previously for the send and receive virtchnl messages, there used to be a
memcpy involved in controlq code to copy the buffer info passed by the send
function into the controlq specific buffers. There was no restriction to
use automatic memory in that case. The new implementation in libie removed
copying of the send buffer info and introduced DMA mapping of the send
buffer itself. To accommodate it, use dynamic memory for the larger send
buffers. For smaller ones (<= 128 bytes) libie still can copy them into the
pre-allocated message memory.

In case of receive, idpf receives a page pool buffer allocated by the libie
and care should be taken to release it after use in the idpf.

The changes are fairly trivial and localized, with a notable exception
being the consolidation of idpf_vc_xn_shutdown and idpf_deinit_dflt_mbx
under the latter name. This has some additional consequences that are
addressed in the following patches.

This refactoring introduces roughly additional 40KB of module storage used
for systems that only run idpf, so idpf + libie_cp + libie_pci takes about
7% more storage than just idpf before refactoring.

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: Michal Kubiak <michal.kubiak@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>
---
 drivers/net/ethernet/intel/idpf/Kconfig       |    2 +-
 drivers/net/ethernet/intel/idpf/Makefile      |    2 -
 drivers/net/ethernet/intel/idpf/idpf.h        |   27 +-
 .../net/ethernet/intel/idpf/idpf_controlq.c   |  624 -------
 .../net/ethernet/intel/idpf/idpf_controlq.h   |  130 --
 .../ethernet/intel/idpf/idpf_controlq_api.h   |  177 --
 .../ethernet/intel/idpf/idpf_controlq_setup.c |  171 --
 drivers/net/ethernet/intel/idpf/idpf_dev.c    |   54 +-
 .../net/ethernet/intel/idpf/idpf_ethtool.c    |   37 +-
 drivers/net/ethernet/intel/idpf/idpf_lib.c    |   44 +-
 drivers/net/ethernet/intel/idpf/idpf_main.c   |    4 -
 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 |   60 +-
 .../net/ethernet/intel/idpf/idpf_virtchnl.c   | 1617 ++++++-----------
 .../net/ethernet/intel/idpf/idpf_virtchnl.h   |   90 +-
 .../ethernet/intel/idpf/idpf_virtchnl_ptp.c   |  204 +--
 17 files changed, 765 insertions(+), 2500 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/Kconfig b/drivers/net/ethernet/intel/idpf/Kconfig
index e0a50e60e1ad..7b3c5b2877dc 100644
--- a/drivers/net/ethernet/intel/idpf/Kconfig
+++ b/drivers/net/ethernet/intel/idpf/Kconfig
@@ -7,7 +7,7 @@ config IDPF
 	depends on PTP_1588_CLOCK_OPTIONAL
 	select DIMLIB
 	select LIBETH
-	select LIBIE_PCI
+	select LIBIE_CP
 	help
 	  This driver supports Intel(R) Infrastructure Data Path Function
 	  devices.
diff --git a/drivers/net/ethernet/intel/idpf/Makefile b/drivers/net/ethernet/intel/idpf/Makefile
index 83ac5e296382..af12538dea09 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_lib.o		\
diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index fb36dcbd8f5c..ff69d920d7d3 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -23,7 +23,6 @@ struct idpf_rss_data;
 #include <linux/intel/libie/controlq.h>
 #include <linux/intel/virtchnl2.h>
 #include "idpf_txrx.h"
-#include "idpf_controlq.h"
 
 #define GETMAXVAL(num_bits)		GENMASK((num_bits) - 1, 0)
 
@@ -33,11 +32,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_MAX_WAIT			500
 
@@ -197,7 +195,8 @@ struct idpf_vport_max_q {
  * @ptp_reg_init: PTP register initialization
  */
 struct idpf_reg_ops {
-	void (*ctlq_reg_init)(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);
@@ -537,8 +536,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; \
@@ -556,8 +553,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
+ * @xn_init_params: Xn transaction manager parameters
  * @num_req_msix: Requested number of MSIX vectors
  * @num_avail_msix: Available number of MSIX vectors
  * @num_msix_entries: Number of entries in MSIX table
@@ -589,7 +588,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
  * @num_vfs: Number of allocated VFs through sysfs. PF does not directly talk
  *	     to VFs but is used to initialize them
@@ -612,8 +610,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_init_params xn_init_params;
 	u16 num_req_msix;
 	u16 num_avail_msix;
 	u16 num_msix_entries;
@@ -649,7 +649,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;
 	int num_vfs;
@@ -783,12 +782,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 b28991dd1870..000000000000
--- a/drivers/net/ethernet/intel/idpf/idpf_controlq.c
+++ /dev/null
@@ -1,624 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2023 Intel Corporation */
-
-#include "idpf_controlq.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)
-{
-	/* Update tail to post pre-allocated buffers for rx queues */
-	if (is_rxq)
-		wr32(hw, cq->reg.tail, (u32)(cq->ring_size - 1));
-
-	/* For non-Mailbox control queues only TAIL need to be set */
-	if (cq->q_id != -1)
-		return;
-
-	/* Clear Head for both send or receive */
-	wr32(hw, cq->reg.head, 0);
-
-	/* set starting point */
-	wr32(hw, cq->reg.bal, lower_32_bits(cq->desc_ring.pa));
-	wr32(hw, cq->reg.bah, upper_32_bits(cq->desc_ring.pa));
-	wr32(hw, cq->reg.len, (cq->ring_size | cq->reg.len_ena_mask));
-}
-
-/**
- * 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)
-{
-	mutex_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;
-
-	mutex_unlock(&cq->cq_lock);
-	mutex_destroy(&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(sizeof(*cq), GFP_KERNEL);
-	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 = kcalloc(qinfo->len,
-					sizeof(struct idpf_ctlq_msg *),
-					GFP_KERNEL);
-		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);
-
-	mutex_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;
-
-	mutex_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();
-
-	wr32(hw, cq->reg.tail, cq->next_to_use);
-
-err_unlock:
-	mutex_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;
-
-	mutex_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;
-
-	mutex_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;
-
-	mutex_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();
-
-		wr32(hw, cq->reg.tail, cq->next_to_post);
-	}
-
-	mutex_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 */
-	mutex_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;
-
-	mutex_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 c1aba09e9856..000000000000
--- a/drivers/net/ethernet/intel/idpf/idpf_controlq.h
+++ /dev/null
@@ -1,130 +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 */
-};
-
-/* Define the driver hardware struct to replace other control structs as needed
- * Align to ctlq_hw_info
- */
-struct idpf_hw {
-	void __iomem *hw_addr;
-	resource_size_t hw_addr_len;
-
-	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 9642494a67d8..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;
-	struct mutex 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 a942a6385d06..000000000000
--- a/drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c
+++ /dev/null
@@ -1,171 +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 = kcalloc(cq->ring_size, sizeof(struct idpf_dma_mem *),
-				 GFP_KERNEL);
-	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] = kcalloc(num, sizeof(struct idpf_dma_mem),
-					    GFP_KERNEL);
-		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 d89ee10a2efc..30e41f768d80 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c
@@ -10,42 +10,32 @@
 
 /**
  * idpf_ctlq_reg_init - initialize default mailbox registers
- * @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_ctlq_create_info *cq)
+static void idpf_ctlq_reg_init(struct libie_mmio_info *mmio,
+			       struct libie_ctlq_create_info *cci)
 {
-	int i;
+	struct libie_ctlq_reg *tx_reg = &cci[LIBIE_CTLQ_TYPE_TX].reg;
+	struct libie_ctlq_reg *rx_reg = &cci[LIBIE_CTLQ_TYPE_RX].reg;
 
-	for (i = 0; i < IDPF_NUM_DFLT_MBX_Q; i++) {
-		struct idpf_ctlq_create_info *ccq = cq + i;
+	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;
 
-		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;
-		}
-	}
+	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 d882c422ee1e..6e7d59a1b91a 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
@@ -202,25 +202,21 @@ static int idpf_add_flow_steer(struct net_device *netdev,
 		idpf_fsteer_fill_tcp(hdrs, fsp, true);
 		break;
 	default:
-		err = -EINVAL;
-		goto out;
+		kfree(rule);
+		return -EINVAL;
 	}
 
 	err = idpf_add_del_fsteer_filters(vport->adapter, rule,
 					  VIRTCHNL2_OP_ADD_FLOW_RULE);
 	if (err)
-		goto out;
+		return err;
 
-	if (info->status != cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS)) {
-		err = -EIO;
-		goto out;
-	}
+	if (info->status != cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS))
+		return -EIO;
 
 	fltr = kzalloc(sizeof(*fltr), GFP_KERNEL);
-	if (!fltr) {
-		err = -ENOMEM;
-		goto out;
-	}
+	if (!fltr)
+		return -ENOMEM;
 
 	fltr->loc = fsp->location;
 	fltr->q_index = q_index;
@@ -235,9 +231,7 @@ static int idpf_add_flow_steer(struct net_device *netdev,
 
 	user_config->num_fsteer_fltrs++;
 
-out:
-	kfree(rule);
-	return err;
+	return 0;
 }
 
 /**
@@ -279,12 +273,10 @@ 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;
+		return err;
 
-	if (info->status != cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS)) {
-		err = -EIO;
-		goto out;
-	}
+	if (info->status != cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS))
+		return -EIO;
 
 	list_for_each_entry_safe(f, iter,
 				 &user_config->flow_steer_list, list) {
@@ -292,14 +284,11 @@ static int idpf_del_flow_steer(struct net_device *netdev,
 			list_del(&f->list);
 			kfree(f);
 			user_config->num_fsteer_fltrs--;
-			goto out;
+			return 0;
 		}
 	}
-	err = -EINVAL;
 
-out:
-	kfree(rule);
-	return err;
+	return -EINVAL;
 }
 
 static int idpf_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index 68330b884967..500bff1091d9 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -1190,6 +1190,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);
@@ -1200,7 +1201,11 @@ void idpf_mbx_task(struct work_struct *work)
 		queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task,
 				   msecs_to_jiffies(300));
 
-	idpf_recv_mb_msg(adapter, adapter->hw.arq);
+	xn_params.xnm = adapter->xn_init_params.xnm;
+	xn_params.ctlq = adapter->arq;
+	xn_params.ctlq_msg_handler = idpf_recv_event_msg;
+
+	libie_ctlq_xn_recv(&xn_params);
 }
 
 /**
@@ -1757,7 +1762,6 @@ static int 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;
@@ -1825,7 +1829,7 @@ void idpf_vc_event_task(struct work_struct *work)
 	return;
 
 func_reset:
-	idpf_vc_xn_shutdown(adapter->vcxn_mngr);
+	idpf_deinit_dflt_mbx(adapter);
 drv_load:
 	set_bit(IDPF_HR_RESET_IN_PROG, adapter->flags);
 	idpf_init_hard_reset(adapter);
@@ -2324,40 +2328,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);
-
-	mem->va = dma_alloc_coherent(&adapter->pdev->dev, sz,
-				     &mem->pa, GFP_KERNEL);
-	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_coherent(&adapter->pdev->dev, mem->size,
-			  mem->va, mem->pa);
-	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 bb84b2871b84..7b732be1e2cf 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_main.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_main.c
@@ -47,7 +47,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;
@@ -81,8 +80,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);
@@ -104,7 +101,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);
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 b21a04fccf0f..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 wr32(a, reg, value)	writel((value), ((a)->hw_addr + (reg)))
-#define rd32(a, reg)		readl((a)->hw_addr + (reg))
-#define wr64(a, reg, value)	writeq((value), ((a)->hw_addr + (reg)))
-#define rd64(a, reg)		readq((a)->hw_addr + (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 fbe09413cdf6..14093dcb1c9c 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -241,7 +241,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 ee4907bd4f28..5df30b97f99d 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
- * @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_ctlq_create_info *cq)
+static void idpf_vf_ctlq_reg_init(struct libie_mmio_info *mmio,
+				  struct libie_ctlq_create_info *cci)
 {
-	int i;
+	struct libie_ctlq_reg *tx_reg = &cci[LIBIE_CTLQ_TYPE_TX].reg;
+	struct libie_ctlq_reg *rx_reg = &cci[LIBIE_CTLQ_TYPE_RX].reg;
 
-	for (i = 0; i < IDPF_NUM_DFLT_MBX_Q; i++) {
-		struct idpf_ctlq_create_info *ccq = cq + i;
+	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;
 
-		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;
-		}
-	}
+	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;
 }
 
 /**
@@ -148,11 +138,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 d8b62ca46f60..021fac3850ad 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -7,20 +7,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
@@ -81,79 +67,63 @@ 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
+ * idpf_mb_clean - cleanup the send mailbox queue entries
  * @adapter: driver specific private structure
  * @asq: send control queue info
  *
- * Reclaim the send mailbox queue entries to be used to send further messages
- *
- * Returns 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)
 {
-	u16 i, num_q_msg = IDPF_DFLT_MBX_Q_LEN;
-	struct idpf_ctlq_msg **q_msg;
-	struct idpf_dma_mem *dma_mem;
-	int err;
+	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,
+	};
 
-	q_msg = kcalloc(num_q_msg, sizeof(struct idpf_ctlq_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);
-
-	return err;
+	libie_ctlq_xn_send_clean(&clean_params);
 }
 
 #if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
@@ -187,7 +157,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.
@@ -195,527 +165,58 @@ static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,
 	if (!idpf_ptp_is_mb_msg(op) || !adapter->ptp->secondary_mbx.valid)
 		return;
 
-	ctlq_msg->opcode = idpf_mbq_opc_send_msg_to_peer_drv;
+	ctlq_msg->opcode = LIBIE_CTLQ_SEND_MSG_TO_PEER;
 	ctlq_msg->func_id = adapter->ptp->secondary_mbx.peer_mbx_q_id;
-	ctlq_msg->host_id = adapter->ptp->secondary_mbx.peer_id;
+	ctlq_msg->flags = FIELD_PREP(LIBIE_CTLQ_DESC_FLAG_HOST_ID,
+				     adapter->ptp->secondary_mbx.peer_id);
 }
 #else /* !CONFIG_PTP_1588_CLOCK */
 static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,
-				    struct idpf_ctlq_msg *ctlq_msg)
+				    struct libie_ctlq_msg *ctlq_msg)
 { }
 #endif /* CONFIG_PTP_1588_CLOCK */
 
 /**
- * idpf_send_mb_msg - Send message over mailbox
+ * idpf_send_mb_msg - send mailbox message to the device control plane
  * @adapter: driver specific private structure
- * @asq: control queue to send message to
- * @op: virtchnl opcode
- * @msg_size: size of the payload
- * @msg: pointer to buffer holding the payload
- * @cookie: unique SW generated cookie per message
+ * @xn_params: Xn send parameters to fill
+ * @send_buf: buffer to send
+ * @send_buf_size: size of the send buffer
  *
- * Will prepare the control queue message and initiates the send api
+ * Fill the Xn parameters with the required info to send a virtchnl message.
+ * The send buffer is DMA mapped in the libie to avoid memcpy.
  *
- * Returns 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(sizeof(*ctlq_msg), GFP_ATOMIC);
-	if (!ctlq_msg)
-		return -ENOMEM;
-
-	dma_mem = kzalloc(sizeof(*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).
+ * Cleanup the mailbox queue entries of the previously sent message to
+ * unmap and release the buffer.
  *
- * We are reusing the completion lock to serialize the accesses to the
- * transaction state for simplicity, but it could be its own separate synchro
- * as well. For now, this API is only used from within a workqueue context;
- * raw_spin_lock() is enough.
+ * Return: 0 if sending was successful or reset in detected,
+ *	   negative error code on failure.
  */
-/**
- * idpf_vc_xn_lock - Request exclusive access to vc transaction
- * @xn: struct idpf_vc_xn* to access
- */
-#define idpf_vc_xn_lock(xn)			\
-	raw_spin_lock(&(xn)->completed.wait.lock)
-
-/**
- * idpf_vc_xn_unlock - Release exclusive access to vc transaction
- * @xn: struct idpf_vc_xn* to access
- */
-#define idpf_vc_xn_unlock(xn)		\
-	raw_spin_unlock(&(xn)->completed.wait.lock)
-
-/**
- * idpf_vc_xn_release_bufs - Release reference to reply buffer(s) and
- * reset the transaction state.
- * @xn: struct idpf_vc_xn to update
- */
-static void idpf_vc_xn_release_bufs(struct idpf_vc_xn *xn)
+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)
 {
-	xn->reply.iov_base = NULL;
-	xn->reply.iov_len = 0;
+	struct libie_ctlq_msg ctlq_msg = {};
 
-	if (xn->state != IDPF_VC_XN_SHUTDOWN)
-		xn->state = IDPF_VC_XN_IDLE;
-}
+	if (idpf_is_reset_detected(adapter)) {
+		if (!libie_cp_can_send_onstack(send_buf_size))
+			kfree(send_buf);
 
-/**
- * idpf_vc_xn_init - Initialize virtchnl transaction object
- * @vcxn_mngr: pointer to vc transaction manager struct
- */
-static void idpf_vc_xn_init(struct idpf_vc_xn_manager *vcxn_mngr)
-{
-	int i;
-
-	spin_lock_init(&vcxn_mngr->xn_bm_lock);
-
-	for (i = 0; i < ARRAY_SIZE(vcxn_mngr->ring); i++) {
-		struct idpf_vc_xn *xn = &vcxn_mngr->ring[i];
-
-		xn->state = IDPF_VC_XN_IDLE;
-		xn->idx = i;
-		idpf_vc_xn_release_bufs(xn);
-		init_completion(&xn->completed);
+		return -EBUSY;
 	}
 
-	bitmap_fill(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN);
-}
+	idpf_prepare_ptp_mb_msg(adapter, xn_params->chnl_opcode, &ctlq_msg);
+	xn_params->ctlq_msg = ctlq_msg.opcode ? &ctlq_msg : NULL;
 
-/**
- * idpf_vc_xn_shutdown - Uninitialize virtchnl transaction object
- * @vcxn_mngr: pointer to vc transaction manager struct
- *
- * 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;
+	xn_params->send_buf.iov_base = send_buf;
+	xn_params->send_buf.iov_len = send_buf_size;
+	xn_params->xnm = adapter->xn_init_params.xnm;
+	xn_params->ctlq = xn_params->ctlq ? xn_params->ctlq : adapter->asq;
+	xn_params->rel_tx_buf = kfree;
 
-	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);
+	idpf_mb_clean(adapter, xn_params->ctlq);
 
-	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
- *
- * 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);
-	set_bit(xn->idx, vcxn_mngr->free_xn_bm);
-}
-
-/**
- * idpf_vc_xn_exec - Perform a send/recv virtchnl transaction
- * @adapter: driver specific private structure with vcxn_mngr
- * @params: parameters for this particular transaction including
- *   -vc_op: virtchannel operation to send
- *   -send_buf: kvec iov for send buf and len
- *   -recv_buf: kvec iov for recv buf and len (ignored if NULL)
- *   -timeout_ms: timeout waiting for a reply (milliseconds)
- *   -async: don't wait for message reply, will lose caller context
- *   -async_handler: callback to handle async replies
- *
- * @returns >= 0 for success, the size of the initial reply (may or may not be
- * >= @recv_buf.iov_len, but we never overflow @@recv_buf_iov_base). < 0 for
- * error.
- */
-ssize_t idpf_vc_xn_exec(struct idpf_adapter *adapter,
-			const struct idpf_vc_xn_params *params)
-{
-	const struct kvec *send_buf = &params->send_buf;
-	struct idpf_vc_xn *xn;
-	ssize_t retval;
-	u16 cookie;
-
-	xn = idpf_vc_xn_pop_free(adapter->vcxn_mngr);
-	/* no free transactions available */
-	if (!xn)
-		return -ENOSPC;
-
-	idpf_vc_xn_lock(xn);
-	if (xn->state == IDPF_VC_XN_SHUTDOWN) {
-		retval = -ENXIO;
-		goto only_unlock;
-	} else if (xn->state != IDPF_VC_XN_IDLE) {
-		/* We're just going to clobber this transaction even though
-		 * it's not IDLE. If we don't reuse it we could theoretically
-		 * eventually leak all the free transactions and not be able to
-		 * send any messages. At least this way we make an attempt to
-		 * remain functional even though something really bad is
-		 * happening that's corrupting what was supposed to be free
-		 * transactions.
-		 */
-		WARN_ONCE(1, "There should only be idle transactions in free list (idx %d op %d)\n",
-			  xn->idx, xn->vc_op);
-	}
-
-	xn->reply = params->recv_buf;
-	xn->reply_sz = 0;
-	xn->state = params->async ? IDPF_VC_XN_ASYNC : IDPF_VC_XN_WAITING;
-	xn->vc_op = params->vc_op;
-	xn->async_handler = params->async_handler;
-	idpf_vc_xn_unlock(xn);
-
-	if (!params->async)
-		reinit_completion(&xn->completed);
-	cookie = FIELD_PREP(IDPF_VC_XN_SALT_M, xn->salt) |
-		 FIELD_PREP(IDPF_VC_XN_IDX_M, xn->idx);
-
-	retval = idpf_send_mb_msg(adapter, adapter->hw.asq, params->vc_op,
-				  send_buf->iov_len, send_buf->iov_base,
-				  cookie);
-	if (retval) {
-		idpf_vc_xn_lock(xn);
-		goto release_and_unlock;
-	}
-
-	if (params->async)
-		return 0;
-
-	wait_for_completion_timeout(&xn->completed,
-				    msecs_to_jiffies(params->timeout_ms));
-
-	/* No need to check the return value; we check the final state of the
-	 * transaction below. It's possible the transaction actually gets more
-	 * timeout than specified if we get preempted here but after
-	 * wait_for_completion_timeout returns. This should be non-issue
-	 * however.
-	 */
-	idpf_vc_xn_lock(xn);
-	switch (xn->state) {
-	case IDPF_VC_XN_SHUTDOWN:
-		retval = -ENXIO;
-		goto only_unlock;
-	case IDPF_VC_XN_WAITING:
-		dev_notice_ratelimited(&adapter->pdev->dev,
-				       "Transaction timed-out (op:%d cookie:%04x vc_op:%d salt:%02x timeout:%dms)\n",
-				       params->vc_op, cookie, xn->vc_op,
-				       xn->salt, params->timeout_ms);
-		retval = -ETIME;
-		break;
-	case IDPF_VC_XN_COMPLETED_SUCCESS:
-		retval = xn->reply_sz;
-		break;
-	case IDPF_VC_XN_COMPLETED_FAILED:
-		dev_notice_ratelimited(&adapter->pdev->dev, "Transaction failed (op %d)\n",
-				       params->vc_op);
-		retval = -EIO;
-		break;
-	default:
-		/* Invalid state. */
-		WARN_ON_ONCE(1);
-		retval = -EIO;
-		break;
-	}
-
-release_and_unlock:
-	idpf_vc_xn_push_free(adapter->vcxn_mngr, xn);
-	/* If we receive a VC reply after here, it will be dropped. */
-only_unlock:
-	idpf_vc_xn_unlock(xn);
-
-	return retval;
-}
-
-/**
- * idpf_vc_xn_forward_async - Handle async reply receives
- * @adapter: private data struct
- * @xn: transaction to handle
- * @ctlq_msg: corresponding ctlq_msg
- *
- * For async sends we're going to lose the caller's context so, if an
- * async_handler was provided, it can deal with the reply, otherwise we'll just
- * check and report if there is an error.
- */
-static int
-idpf_vc_xn_forward_async(struct idpf_adapter *adapter, struct idpf_vc_xn *xn,
-			 const struct idpf_ctlq_msg *ctlq_msg)
-{
-	int err = 0;
-
-	if (ctlq_msg->cookie.mbx.chnl_opcode != xn->vc_op) {
-		dev_err_ratelimited(&adapter->pdev->dev, "Async message opcode does not match transaction opcode (msg: %d) (xn: %d)\n",
-				    ctlq_msg->cookie.mbx.chnl_opcode, xn->vc_op);
-		xn->reply_sz = 0;
-		err = -EINVAL;
-		goto release_bufs;
-	}
-
-	if (xn->async_handler) {
-		err = xn->async_handler(adapter, xn, ctlq_msg);
-		goto release_bufs;
-	}
-
-	if (ctlq_msg->cookie.mbx.chnl_retval) {
-		xn->reply_sz = 0;
-		dev_err_ratelimited(&adapter->pdev->dev, "Async message failure (op %d)\n",
-				    ctlq_msg->cookie.mbx.chnl_opcode);
-		err = -EINVAL;
-	}
-
-release_bufs:
-	idpf_vc_xn_push_free(adapter->vcxn_mngr, xn);
-
-	return err;
-}
-
-/**
- * idpf_vc_xn_forward_reply - copy a reply back to receiving thread
- * @adapter: driver specific private structure with vcxn_mngr
- * @ctlq_msg: controlq message to send back to receiving thread
- */
-static int
-idpf_vc_xn_forward_reply(struct idpf_adapter *adapter,
-			 const struct idpf_ctlq_msg *ctlq_msg)
-{
-	const void *payload = NULL;
-	size_t payload_size = 0;
-	struct idpf_vc_xn *xn;
-	u16 msg_info;
-	int err = 0;
-	u16 xn_idx;
-	u16 salt;
-
-	msg_info = ctlq_msg->ctx.sw_cookie.data;
-	xn_idx = FIELD_GET(IDPF_VC_XN_IDX_M, msg_info);
-	if (xn_idx >= ARRAY_SIZE(adapter->vcxn_mngr->ring)) {
-		dev_err_ratelimited(&adapter->pdev->dev, "Out of bounds cookie received: %02x\n",
-				    xn_idx);
-		return -EINVAL;
-	}
-	xn = &adapter->vcxn_mngr->ring[xn_idx];
-	idpf_vc_xn_lock(xn);
-	salt = FIELD_GET(IDPF_VC_XN_SALT_M, msg_info);
-	if (xn->salt != salt) {
-		dev_err_ratelimited(&adapter->pdev->dev, "Transaction salt does not match (exp:%d@%02x(%d) != got:%d@%02x)\n",
-				    xn->vc_op, xn->salt, xn->state,
-				    ctlq_msg->cookie.mbx.chnl_opcode, salt);
-		idpf_vc_xn_unlock(xn);
-		return -EINVAL;
-	}
-
-	switch (xn->state) {
-	case IDPF_VC_XN_WAITING:
-		/* success */
-		break;
-	case IDPF_VC_XN_IDLE:
-		dev_err_ratelimited(&adapter->pdev->dev, "Unexpected or belated VC reply (op %d)\n",
-				    ctlq_msg->cookie.mbx.chnl_opcode);
-		err = -EINVAL;
-		goto out_unlock;
-	case IDPF_VC_XN_SHUTDOWN:
-		/* ENXIO is a bit special here as the recv msg loop uses that
-		 * know if it should stop trying to clean the ring if we lost
-		 * the virtchnl. We need to stop playing with registers and
-		 * yield.
-		 */
-		err = -ENXIO;
-		goto out_unlock;
-	case IDPF_VC_XN_ASYNC:
-		err = idpf_vc_xn_forward_async(adapter, xn, ctlq_msg);
-		idpf_vc_xn_unlock(xn);
-		return err;
-	default:
-		dev_err_ratelimited(&adapter->pdev->dev, "Overwriting VC reply (op %d)\n",
-				    ctlq_msg->cookie.mbx.chnl_opcode);
-		err = -EBUSY;
-		goto out_unlock;
-	}
-
-	if (ctlq_msg->cookie.mbx.chnl_opcode != xn->vc_op) {
-		dev_err_ratelimited(&adapter->pdev->dev, "Message opcode does not match transaction opcode (msg: %d) (xn: %d)\n",
-				    ctlq_msg->cookie.mbx.chnl_opcode, xn->vc_op);
-		xn->reply_sz = 0;
-		xn->state = IDPF_VC_XN_COMPLETED_FAILED;
-		err = -EINVAL;
-		goto out_unlock;
-	}
-
-	if (ctlq_msg->cookie.mbx.chnl_retval) {
-		xn->reply_sz = 0;
-		xn->state = IDPF_VC_XN_COMPLETED_FAILED;
-		err = -EINVAL;
-		goto out_unlock;
-	}
-
-	if (ctlq_msg->data_len) {
-		payload = ctlq_msg->ctx.indirect.payload->va;
-		payload_size = ctlq_msg->data_len;
-	}
-
-	xn->reply_sz = payload_size;
-	xn->state = IDPF_VC_XN_COMPLETED_SUCCESS;
-
-	if (xn->reply.iov_base && xn->reply.iov_len && payload_size)
-		memcpy(xn->reply.iov_base, payload,
-		       min_t(size_t, xn->reply.iov_len, payload_size));
-
-out_unlock:
-	idpf_vc_xn_unlock(xn);
-	/* we _cannot_ hold lock while calling complete */
-	complete(&xn->completed);
-
-	return err;
-}
-
-/**
- * idpf_recv_mb_msg - Receive message over mailbox
- * @adapter: driver specific private structure
- * @arq: control queue to receive message from
- *
- * Will receive control queue message and posts the receive buffer. Returns 0
- * on success and negative on failure.
- */
-int idpf_recv_mb_msg(struct idpf_adapter *adapter, struct idpf_ctlq_info *arq)
-{
-	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;
-		}
-
-		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)
-				dmam_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;
-	}
-
-	return err;
+	return libie_ctlq_xn_send(xn_params);
 }
 
 /**
@@ -756,11 +257,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);
@@ -770,24 +274,18 @@ 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;
-
-	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 &&
@@ -805,6 +303,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;
 }
 
@@ -817,9 +318,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	|
@@ -877,18 +381,14 @@ 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;
+	memcpy(&adapter->caps, xn_params.recv_mem.iov_base,
+	       sizeof(adapter->caps));
+
+	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
 
 	return 0;
 }
@@ -909,23 +409,25 @@ int idpf_add_del_fsteer_filters(struct idpf_adapter *adapter,
 				enum virtchnl2_op opcode)
 {
 	int rule_count = le32_to_cpu(rule->count);
-	struct idpf_vc_xn_params xn_params = {};
-	ssize_t reply_sz;
+	struct libie_ctlq_xn_send_params xn_params = {
+		.chnl_opcode = opcode,
+		.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+	};
+	int ret;
 
 	if (opcode != VIRTCHNL2_OP_ADD_FLOW_RULE &&
-	    opcode != VIRTCHNL2_OP_DEL_FLOW_RULE)
+	    opcode != VIRTCHNL2_OP_DEL_FLOW_RULE) {
+		kfree(rule);
 		return -EINVAL;
+	}
 
-	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);
+	ret = idpf_send_mb_msg(adapter, &xn_params, rule,
+			       struct_size(rule, rule_info, rule_count));
+	if (ret)
+		return ret;
 
-	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
-	return reply_sz < 0 ? reply_sz : 0;
+	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+	return 0;
 }
 
 /**
@@ -1301,11 +803,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);
@@ -1332,33 +836,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(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);
 
@@ -1421,19 +921,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_MIN_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_MIN_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;
 }
 
 /**
@@ -1446,19 +949,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;
 }
 
 /**
@@ -1471,19 +977,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_MIN_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_MIN_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;
 }
 
 /**
@@ -1499,13 +1008,15 @@ static int idpf_send_config_tx_queues_msg(struct idpf_adapter *adapter,
 					  struct idpf_q_vec_rsrc *rsrc,
 					  u32 vport_id)
 {
-	struct virtchnl2_config_tx_queues *ctq __free(kfree) = NULL;
+	struct libie_ctlq_xn_send_params xn_params = {
+		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+		.chnl_opcode	= VIRTCHNL2_OP_CONFIG_TX_QUEUES,
+	};
 	struct virtchnl2_txq_info *qi __free(kfree) = NULL;
-	struct idpf_vc_xn_params xn_params = {};
+	struct virtchnl2_config_tx_queues *ctq;
 	u32 config_sz, chunk_sz, buf_sz;
 	int totqs, num_msgs, num_chunks;
-	ssize_t reply_sz;
-	int k = 0;
+	int k = 0, err = 0;
 
 	totqs = rsrc->num_txq + rsrc->num_complq;
 	qi = kcalloc(totqs, sizeof(struct virtchnl2_txq_info), GFP_KERNEL);
@@ -1579,34 +1090,37 @@ static int idpf_send_config_tx_queues_msg(struct idpf_adapter *adapter,
 			   totqs);
 	num_msgs = DIV_ROUND_UP(totqs, num_chunks);
 
-	buf_sz = struct_size(ctq, qinfo, num_chunks);
-	ctq = kzalloc(buf_sz, GFP_KERNEL);
-	if (!ctq)
-		return -ENOMEM;
-
-	xn_params.vc_op = VIRTCHNL2_OP_CONFIG_TX_QUEUES;
-	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
-
 	for (u16 i = 0, k = 0; i < num_msgs; i++) {
-		memset(ctq, 0, buf_sz);
+		buf_sz = struct_size(ctq, qinfo, num_chunks);
+		ctq = kzalloc(buf_sz, GFP_KERNEL);
+		if (!ctq)
+			return -ENOMEM;
+
 		ctq->vport_id = cpu_to_le32(vport_id);
 		ctq->num_qinfo = cpu_to_le16(num_chunks);
 		memcpy(ctq->qinfo, &qi[k], chunk_sz * num_chunks);
 
-		xn_params.send_buf.iov_base = ctq;
-		xn_params.send_buf.iov_len = buf_sz;
-		reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
-		if (reply_sz < 0)
-			return reply_sz;
+		err = idpf_send_mb_msg(adapter, &xn_params, ctq, buf_sz);
+		if (err)
+			goto rel_last_buf;
+
+		libie_ctlq_release_rx_buf(&xn_params.recv_mem);
 
 		k += num_chunks;
 		totqs -= num_chunks;
 		num_chunks = min(num_chunks, totqs);
-		/* Recalculate buffer size */
-		buf_sz = struct_size(ctq, qinfo, num_chunks);
 	}
 
-	return 0;
+rel_last_buf:
+	/* Only the last buffer might be of size LIBIE_CP_TX_COPYBREAK or less.
+	 * For buffers larger than LIBIE_CP_TX_COPYBREAK, are DMA mapped
+	 * and released on mailbox cleanup. Smaller buffers are memcopied into
+	 * the pre-allocated DMA buffers and are released here.
+	 */
+	if (num_msgs && libie_cp_can_send_onstack(buf_sz))
+		kfree(ctq);
+
+	return err;
 }
 
 /**
@@ -1623,13 +1137,15 @@ static int idpf_send_config_rx_queues_msg(struct idpf_adapter *adapter,
 					  struct idpf_q_vec_rsrc *rsrc,
 					  u32 vport_id, bool rsc_ena)
 {
-	struct virtchnl2_config_rx_queues *crq __free(kfree) = NULL;
+	struct libie_ctlq_xn_send_params xn_params = {
+		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+		.chnl_opcode	= VIRTCHNL2_OP_CONFIG_RX_QUEUES,
+	};
 	struct virtchnl2_rxq_info *qi __free(kfree) = NULL;
-	struct idpf_vc_xn_params xn_params = {};
+	struct virtchnl2_config_rx_queues *crq;
 	u32 config_sz, chunk_sz, buf_sz;
 	int totqs, num_msgs, num_chunks;
-	ssize_t reply_sz;
-	int k = 0;
+	int k = 0, err = 0;
 
 	totqs = rsrc->num_rxq + rsrc->num_bufq;
 	qi = kcalloc(totqs, sizeof(struct virtchnl2_rxq_info), GFP_KERNEL);
@@ -1735,34 +1251,32 @@ static int idpf_send_config_rx_queues_msg(struct idpf_adapter *adapter,
 			   totqs);
 	num_msgs = DIV_ROUND_UP(totqs, num_chunks);
 
-	buf_sz = struct_size(crq, qinfo, num_chunks);
-	crq = kzalloc(buf_sz, GFP_KERNEL);
-	if (!crq)
-		return -ENOMEM;
-
-	xn_params.vc_op = VIRTCHNL2_OP_CONFIG_RX_QUEUES;
-	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
-
 	for (u16 i = 0, k = 0; i < num_msgs; i++) {
-		memset(crq, 0, buf_sz);
+		buf_sz = struct_size(crq, qinfo, num_chunks);
+		crq = kzalloc(buf_sz, GFP_KERNEL);
+		if (!crq)
+			return -ENOMEM;
+
 		crq->vport_id = cpu_to_le32(vport_id);
 		crq->num_qinfo = cpu_to_le16(num_chunks);
 		memcpy(crq->qinfo, &qi[k], chunk_sz * num_chunks);
 
-		xn_params.send_buf.iov_base = crq;
-		xn_params.send_buf.iov_len = buf_sz;
-		reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
-		if (reply_sz < 0)
-			return reply_sz;
+		err = idpf_send_mb_msg(adapter, &xn_params, crq, buf_sz);
+		if (err)
+			goto rel_last_buf;
+
+		libie_ctlq_release_rx_buf(&xn_params.recv_mem);
 
 		k += num_chunks;
 		totqs -= num_chunks;
 		num_chunks = min(num_chunks, totqs);
-		/* Recalculate buffer size */
-		buf_sz = struct_size(crq, qinfo, num_chunks);
 	}
 
-	return 0;
+rel_last_buf:
+	if (num_msgs && libie_cp_can_send_onstack(buf_sz))
+		kfree(crq);
+
+	return err;
 }
 
 /**
@@ -1781,18 +1295,15 @@ static int idpf_send_ena_dis_queues_msg(struct idpf_adapter *adapter,
 					u32 vport_id,
 					bool ena)
 {
-	struct virtchnl2_del_ena_dis_queues *eq __free(kfree) = NULL;
-	struct idpf_vc_xn_params xn_params = {};
+	struct libie_ctlq_xn_send_params xn_params = {
+		.chnl_opcode = ena ? VIRTCHNL2_OP_ENABLE_QUEUES :
+				     VIRTCHNL2_OP_DISABLE_QUEUES,
+		.timeout_ms = ena ? IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC :
+				    IDPF_VC_XN_MIN_TIMEOUT_MSEC,
+	};
+	struct virtchnl2_del_ena_dis_queues *eq;
 	u32 num_chunks, buf_sz;
-	ssize_t reply_sz;
-
-	if (ena) {
-		xn_params.vc_op = VIRTCHNL2_OP_ENABLE_QUEUES;
-		xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
-	} else {
-		xn_params.vc_op = VIRTCHNL2_OP_DISABLE_QUEUES;
-		xn_params.timeout_ms = IDPF_VC_XN_MIN_TIMEOUT_MSEC;
-	}
+	int err = 0;
 
 	num_chunks = chunks->num_chunks;
 	buf_sz = struct_size(eq, chunks.chunks, num_chunks);
@@ -1806,11 +1317,16 @@ static int idpf_send_ena_dis_queues_msg(struct idpf_adapter *adapter,
 	idpf_convert_reg_to_queue_chunks(eq->chunks.chunks, chunks->queue_chunks,
 					 num_chunks);
 
-	xn_params.send_buf.iov_base = eq;
-	xn_params.send_buf.iov_len = buf_sz;
-	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
+	err = idpf_send_mb_msg(adapter, &xn_params, eq, buf_sz);
+	if (err)
+		goto rel_tx;
 
-	return reply_sz < 0 ? reply_sz : 0;
+	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+rel_tx:
+	if (libie_cp_can_send_onstack(buf_sz))
+		kfree(eq);
+
+	return err;
 }
 
 /**
@@ -1829,13 +1345,17 @@ int idpf_send_map_unmap_queue_vector_msg(struct idpf_adapter *adapter,
 					 u32 vport_id,
 					 bool map)
 {
-	struct virtchnl2_queue_vector_maps *vqvm __free(kfree) = NULL;
+	struct libie_ctlq_xn_send_params xn_params = {
+		.timeout_ms =	map ? IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC :
+				      IDPF_VC_XN_MIN_TIMEOUT_MSEC,
+		.chnl_opcode =	map ? VIRTCHNL2_OP_MAP_QUEUE_VECTOR :
+				      VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR,
+	};
 	struct virtchnl2_queue_vector *vqv __free(kfree) = NULL;
-	struct idpf_vc_xn_params xn_params = {};
+	struct virtchnl2_queue_vector_maps *vqvm;
 	u32 config_sz, chunk_sz, buf_sz;
 	u32 num_msgs, num_chunks, num_q;
-	ssize_t reply_sz;
-	int k = 0;
+	int k = 0, err = 0;
 
 	num_q = rsrc->num_txq + rsrc->num_rxq;
 
@@ -1910,39 +1430,33 @@ int idpf_send_map_unmap_queue_vector_msg(struct idpf_adapter *adapter,
 			   num_q);
 	num_msgs = DIV_ROUND_UP(num_q, num_chunks);
 
-	buf_sz = struct_size(vqvm, qv_maps, num_chunks);
-	vqvm = kzalloc(buf_sz, GFP_KERNEL);
-	if (!vqvm)
-		return -ENOMEM;
-
-	if (map) {
-		xn_params.vc_op = VIRTCHNL2_OP_MAP_QUEUE_VECTOR;
-		xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
-	} else {
-		xn_params.vc_op = VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR;
-		xn_params.timeout_ms = IDPF_VC_XN_MIN_TIMEOUT_MSEC;
-	}
-
 	for (u16 i = 0, k = 0; i < num_msgs; i++) {
-		memset(vqvm, 0, buf_sz);
-		xn_params.send_buf.iov_base = vqvm;
-		xn_params.send_buf.iov_len = buf_sz;
+		buf_sz = struct_size(vqvm, qv_maps, num_chunks);
+		vqvm = kzalloc(buf_sz, GFP_KERNEL);
+		if (!vqvm)
+			return -ENOMEM;
+
 		vqvm->vport_id = cpu_to_le32(vport_id);
 		vqvm->num_qv_maps = cpu_to_le16(num_chunks);
 		memcpy(vqvm->qv_maps, &vqv[k], chunk_sz * num_chunks);
 
-		reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
-		if (reply_sz < 0)
-			return reply_sz;
+		err = idpf_send_mb_msg(adapter, &xn_params, vqvm,
+				       buf_sz);
+		if (err)
+			goto rel_last_buf;
+
+		libie_ctlq_release_rx_buf(&xn_params.recv_mem);
 
 		k += num_chunks;
 		num_q -= num_chunks;
 		num_chunks = min(num_chunks, num_q);
-		/* Recalculate buffer size */
-		buf_sz = struct_size(vqvm, qv_maps, num_chunks);
 	}
 
-	return 0;
+rel_last_buf:
+	if (num_msgs && libie_cp_can_send_onstack(buf_sz))
+		kfree(vqvm);
+
+	return err;
 }
 
 /**
@@ -2008,11 +1522,13 @@ 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_MIN_TIMEOUT_MSEC,
+		.chnl_opcode	= VIRTCHNL2_OP_DEL_QUEUES,
+	};
+	struct virtchnl2_del_ena_dis_queues *eq;
+	int buf_size, err;
 	u16 num_chunks;
-	int buf_size;
 
 	num_chunks = chunks->num_chunks;
 	buf_size = struct_size(eq, chunks.chunks, num_chunks);
@@ -2027,13 +1543,17 @@ 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_MIN_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(adapter, &xn_params, eq, buf_size);
+	if (err)
+		goto rel_buf;
 
-	return reply_sz < 0 ? reply_sz : 0;
+	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
+rel_buf:
+	if (libie_cp_can_send_onstack(buf_size))
+		kfree(eq);
+
+	return err;
 }
 
 /**
@@ -2074,15 +1594,13 @@ 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;
+	int err;
 
 	aq.vport_id = cpu_to_le32(vport_id);
 	aq.num_tx_q = cpu_to_le16(rsrc->num_txq);
@@ -2090,29 +1608,27 @@ 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;
 
 	/* 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;
+	err = idpf_vport_init_queue_reg_chunks(vport_config, &vc_msg->chunks);
 
-	return idpf_vport_init_queue_reg_chunks(vport_config, &vc_msg->chunks);
+free_rx_buf:
+	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
+	return err;
 }
 
 /**
@@ -2124,49 +1640,52 @@ int idpf_send_add_queues_msg(struct idpf_adapter *adapter,
  */
 int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors)
 {
-	struct virtchnl2_alloc_vectors *rcvd_vec __free(kfree) = NULL;
-	struct idpf_vc_xn_params xn_params = {};
+	struct libie_ctlq_xn_send_params xn_params = {
+		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+		.chnl_opcode	= VIRTCHNL2_OP_ALLOC_VECTORS,
+	};
+	struct virtchnl2_alloc_vectors *rcvd_vec;
 	struct virtchnl2_alloc_vectors ac = {};
-	ssize_t reply_sz;
 	u16 num_vchunks;
-	int size;
+	int size, err;
 
 	ac.num_vectors = cpu_to_le16(num_vectors);
 
-	rcvd_vec = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
-	if (!rcvd_vec)
-		return -ENOMEM;
+	err = idpf_send_mb_msg(adapter, &xn_params, &ac, sizeof(ac));
+	if (err)
+		return err;
 
-	xn_params.vc_op = VIRTCHNL2_OP_ALLOC_VECTORS;
-	xn_params.send_buf.iov_base = &ac;
-	xn_params.send_buf.iov_len = sizeof(ac);
-	xn_params.recv_buf.iov_base = rcvd_vec;
-	xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
-	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
-	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
-	if (reply_sz < 0)
-		return reply_sz;
+	rcvd_vec = xn_params.recv_mem.iov_base;
 
 	num_vchunks = le16_to_cpu(rcvd_vec->vchunks.num_vchunks);
 	size = struct_size(rcvd_vec, vchunks.vchunks, num_vchunks);
-	if (reply_sz < size)
-		return -EIO;
+	if (xn_params.recv_mem.iov_len < size) {
+		err = -EIO;
+		goto free_rx_buf;
+	}
 
-	if (size > IDPF_CTLQ_MAX_BUF_LEN)
-		return -EINVAL;
+	if (size > LIBIE_CTLQ_MAX_BUF_LEN) {
+		err = -EINVAL;
+		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;
 }
 
 /**
@@ -2178,25 +1697,33 @@ 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_MIN_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_MIN_TIMEOUT_MSEC;
-	reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
-	if (reply_sz < 0)
-		return reply_sz;
+	err = idpf_send_mb_msg(adapter, &xn_params, vcs, buf_size);
+	if (err)
+		goto rel_buf;
 
 	kfree(adapter->req_vec_chunks);
 	adapter->req_vec_chunks = NULL;
 
-	return 0;
+	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
+rel_buf:
+	if (libie_cp_can_send_onstack(buf_size))
+		kfree(vcs);
+
+	return err;
 }
 
 /**
@@ -2219,18 +1746,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;
 }
 
 /**
@@ -2243,10 +1774,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 */
 	if (np->state <= __IDPF_VPORT_DOWN)
@@ -2254,37 +1789,40 @@ 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);
+	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_msg;
+	port_stats->vport_stats = *stats_recv;
 
 	spin_unlock_bh(&np->stats_lock);
 
+free_rx_buf:
+	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
 	return 0;
 }
 
@@ -2301,12 +1839,14 @@ 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;
-	ssize_t reply_sz;
-	int i;
+	int i, err;
 
 	buf_size = struct_size(rl, lut, rss_data->rss_lut_size);
 	rl = kzalloc(buf_size, GFP_KERNEL);
@@ -2314,36 +1854,30 @@ 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] = cpu_to_le32(rss_data->rss_lut[i]);
-
-		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(adapter, &xn_params, rl, buf_size);
+	if (err)
+		goto free_tx_buf;
+
 	if (!get)
-		return 0;
-	if (reply_sz < sizeof(struct virtchnl2_rss_lut))
-		return -EIO;
+		goto free_rx_buf;
+	if (xn_params.recv_mem.iov_len < sizeof(struct virtchnl2_rss_lut)) {
+		err = -EIO;
+		goto free_rx_buf;
+	}
+
+	recv_rl = xn_params.recv_mem.iov_base;
 
 	lut_buf_size = le16_to_cpu(recv_rl->lut_entries) * sizeof(u32);
-	if (reply_sz < lut_buf_size)
-		return -EIO;
+	if (xn_params.recv_mem.iov_len < lut_buf_size) {
+		err = -EIO;
+		goto free_rx_buf;
+	}
 
 	/* size didn't change, we can reuse existing lut buf */
 	if (rss_data->rss_lut_size == le16_to_cpu(recv_rl->lut_entries))
@@ -2355,13 +1889,19 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_adapter *adapter,
 	rss_data->rss_lut = kzalloc(lut_buf_size, GFP_KERNEL);
 	if (!rss_data->rss_lut) {
 		rss_data->rss_lut_size = 0;
-		return -ENOMEM;
+		err = -ENOMEM;
+		goto free_rx_buf;
 	}
 
 do_memcpy:
 	memcpy(rss_data->rss_lut, recv_rl->lut, rss_data->rss_lut_size);
+free_rx_buf:
+	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+free_tx_buf:
+	if (libie_cp_can_send_onstack(buf_size))
+		kfree(rl);
 
-	return 0;
+	return err;
 }
 
 /**
@@ -2377,12 +1917,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);
@@ -2390,37 +1932,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;
-	if (!get)
-		return 0;
-	if (reply_sz < sizeof(struct virtchnl2_rss_key))
-		return -EIO;
+	err = idpf_send_mb_msg(adapter, &xn_params, rk, buf_size);
+	if (err)
+		goto free_tx_buf;
 
+	if (!get)
+		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)
@@ -2431,13 +1968,19 @@ 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);
+free_tx_buf:
+	if (libie_cp_can_send_onstack(buf_size))
+		kfree(rk);
 
-	return 0;
+	return err;
 }
 
 /**
@@ -2614,15 +2157,19 @@ 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 libie_ctlq_xn_send_params xn_params = {
+		.timeout_ms	= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+		.chnl_opcode	= VIRTCHNL2_OP_GET_PTYPE_INFO,
+	};
 	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 virtchnl2_get_ptype_info *get_ptype_info;
+	struct virtchnl2_get_ptype_info *ptype_info;
+	int buf_size = sizeof(*get_ptype_info);
 	int ptypes_recvd = 0, ptype_offset;
-	u32 max_ptype = IDPF_RX_MAX_PTYPE;
+	int max_ptype = IDPF_RX_MAX_PTYPE;
 	u16 next_ptype_id = 0;
-	ssize_t reply_sz;
+	int err = 0;
 
 	singleq_pt_lkup = kcalloc(IDPF_RX_MAX_BASE_PTYPE,
 				  sizeof(*singleq_pt_lkup), GFP_KERNEL);
@@ -2633,22 +2180,11 @@ static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)
 	if (!splitq_pt_lkup)
 		return -ENOMEM;
 
-	get_ptype_info = kzalloc(sizeof(*get_ptype_info), GFP_KERNEL);
-	if (!get_ptype_info)
-		return -ENOMEM;
-
-	ptype_info = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
-	if (!ptype_info)
-		return -ENOMEM;
-
-	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;
-
 	while (next_ptype_id < max_ptype) {
+		get_ptype_info = kzalloc(buf_size, GFP_KERNEL);
+		if (!get_ptype_info)
+			return -ENOMEM;
+
 		get_ptype_info->start_ptype_id = cpu_to_le16(next_ptype_id);
 
 		if ((next_ptype_id + IDPF_RX_MAX_PTYPES_PER_BUF) > max_ptype)
@@ -2658,13 +2194,17 @@ static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)
 			get_ptype_info->num_ptypes =
 				cpu_to_le16(IDPF_RX_MAX_PTYPES_PER_BUF);
 
-		reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
-		if (reply_sz < 0)
-			return reply_sz;
+		err = idpf_send_mb_msg(adapter, &xn_params, get_ptype_info,
+				       buf_size);
+		if (err)
+			goto free_tx_buf;
 
+		ptype_info = xn_params.recv_mem.iov_base;
 		ptypes_recvd += le16_to_cpu(ptype_info->num_ptypes);
-		if (ptypes_recvd > max_ptype)
-			return -EINVAL;
+		if (ptypes_recvd > max_ptype) {
+			err = -EINVAL;
+			goto free_rx_buf;
+		}
 
 		next_ptype_id = le16_to_cpu(get_ptype_info->start_ptype_id) +
 				le16_to_cpu(get_ptype_info->num_ptypes);
@@ -2683,8 +2223,10 @@ 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)
@@ -2702,6 +2244,10 @@ 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);
+		if (libie_cp_can_send_onstack(buf_size))
+			kfree(get_ptype_info);
 	}
 
 out:
@@ -2709,6 +2255,14 @@ static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)
 	adapter->singleq_pt_lkup = no_free_ptr(singleq_pt_lkup);
 
 	return 0;
+
+free_rx_buf:
+	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+free_tx_buf:
+	if (libie_cp_can_send_onstack(buf_size))
+		kfree(get_ptype_info);
+
+	return err;
 }
 
 /**
@@ -2736,40 +2290,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);
+	err = idpf_send_mb_msg(adapter, &xn_params, &loopback,
+			       sizeof(loopback));
+	if (err)
+		return err;
 
-	return reply_sz < 0 ? reply_sz : 0;
-}
+	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
 
-/**
- * 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;
-
-	list_for_each_entry_safe(cq, tmp, &hw->cq_list_head, cq_list)
-		if (cq->q_id == id && cq->cq_type == type)
-			return cq;
-
-	return NULL;
+	return 0;
 }
 
 /**
@@ -2780,40 +2318,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(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->xn_init_params.xnm = params.xnm;
 	adapter->state = __IDPF_VER_CHECK;
 
 	return 0;
@@ -2825,12 +2366,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);
+		libie_ctlq_xn_deinit(adapter->xn_init_params.xnm,
+				     &adapter->ctlq_ctx);
 	}
-	adapter->hw.arq = NULL;
-	adapter->hw.asq = NULL;
+	adapter->arq = NULL;
+	adapter->asq = NULL;
 }
 
 /**
@@ -2903,15 +2445,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(sizeof(*adapter->vcxn_mngr), GFP_KERNEL);
-		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:
@@ -3038,8 +2571,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));
@@ -3062,7 +2594,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);
@@ -3070,7 +2602,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);
@@ -3586,9 +3118,9 @@ u32 idpf_get_vport_id(struct idpf_vport *vport)
 
 /**
  * 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
@@ -3596,13 +3128,14 @@ u32 idpf_get_vport_id(struct idpf_vport *vport)
  * 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;
@@ -3610,18 +3143,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)
+		goto free_mem;
 
+	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));
@@ -3641,16 +3174,15 @@ 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);
+	goto free_mem;
 
 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);
+free_mem:
+	libie_ctlq_release_rx_buf(buff);
 }
 
 /**
@@ -3667,19 +3199,22 @@ int idpf_add_del_mac_filters(struct idpf_adapter *adapter,
 			     struct idpf_vport_config *vport_config,
 			     u32 vport_id, bool add, bool async)
 {
-	struct virtchnl2_mac_addr_list *ma_list __free(kfree) = NULL;
+	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 *mac_addr __free(kfree) = NULL;
-	struct idpf_vc_xn_params xn_params = {};
+	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, k, err = 0;
+	u32 buf_size;
 
-	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);
 
@@ -3733,37 +3268,59 @@ 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;
+		u32 entries_size, num_entries;
 
 		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_KERNEL);
+		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(adapter, &xn_params, ma_list, buf_size);
+		if (err)
+			goto free_tx_buf;
+
+		if (!async)
+			libie_ctlq_release_rx_buf(&xn_params.recv_mem);
 
 		k += num_entries;
 		total_filters -= num_entries;
 	}
 
-	return 0;
+free_tx_buf:
+	if (num_msgs && libie_cp_can_send_onstack(buf_size))
+		kfree(ma_list);
+
+	return err;
+}
+
+/**
+ * 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);
+
+	libie_ctlq_release_rx_buf(buff);
 }
 
 /**
@@ -3780,9 +3337,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))
@@ -3793,13 +3354,5 @@ 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));
 }
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
index cecb95f37645..dfe1ba223bf0 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
@@ -6,85 +6,6 @@
 
 #define IDPF_VC_XN_MIN_TIMEOUT_MSEC	2000
 #define IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC	(60 * 1000)
-#define IDPF_VC_XN_IDX_M		GENMASK(7, 0)
-#define IDPF_VC_XN_SALT_M		GENMASK(15, 8)
-#define IDPF_VC_XN_RING_LEN		U8_MAX
-
-/**
- * enum idpf_vc_xn_state - Virtchnl transaction status
- * @IDPF_VC_XN_IDLE: not expecting a reply, ready to be used
- * @IDPF_VC_XN_WAITING: expecting a reply, not yet received
- * @IDPF_VC_XN_COMPLETED_SUCCESS: a reply was expected and received, buffer
- *				  updated
- * @IDPF_VC_XN_COMPLETED_FAILED: a reply was expected and received, but there
- *				 was an error, buffer not updated
- * @IDPF_VC_XN_SHUTDOWN: transaction object cannot be used, VC torn down
- * @IDPF_VC_XN_ASYNC: transaction sent asynchronously and doesn't have the
- *		      return context; a callback may be provided to handle
- *		      return
- */
-enum idpf_vc_xn_state {
-	IDPF_VC_XN_IDLE = 1,
-	IDPF_VC_XN_WAITING,
-	IDPF_VC_XN_COMPLETED_SUCCESS,
-	IDPF_VC_XN_COMPLETED_FAILED,
-	IDPF_VC_XN_SHUTDOWN,
-	IDPF_VC_XN_ASYNC,
-};
-
-struct idpf_vc_xn;
-/* Callback for asynchronous messages */
-typedef int (*async_vc_cb) (struct idpf_adapter *, struct idpf_vc_xn *,
-			    const struct idpf_ctlq_msg *);
-
-/**
- * struct idpf_vc_xn - Data structure representing virtchnl transactions
- * @completed: virtchnl event loop uses that to signal when a reply is
- *	       available, uses kernel completion API
- * @state: virtchnl event loop stores the data below, protected by the
- *	   completion's lock.
- * @reply_sz: Original size of reply, may be > reply_buf.iov_len; it will be
- *	      truncated on its way to the receiver thread according to
- *	      reply_buf.iov_len.
- * @reply: Reference to the buffer(s) where the reply data should be written
- *	   to. May be 0-length (then NULL address permitted) if the reply data
- *	   should be ignored.
- * @async_handler: if sent asynchronously, a callback can be provided to handle
- *		   the reply when it's received
- * @vc_op: corresponding opcode sent with this transaction
- * @idx: index used as retrieval on reply receive, used for cookie
- * @salt: changed every message to make unique, used for cookie
- */
-struct idpf_vc_xn {
-	struct completion completed;
-	enum idpf_vc_xn_state state;
-	size_t reply_sz;
-	struct kvec reply;
-	async_vc_cb async_handler;
-	u32 vc_op;
-	u8 idx;
-	u8 salt;
-};
-
-/**
- * struct idpf_vc_xn_params - Parameters for executing transaction
- * @send_buf: kvec for send buffer
- * @recv_buf: kvec for recv buffer, may be NULL, must then have zero length
- * @timeout_ms: timeout to wait for reply
- * @async: send message asynchronously, will not wait on completion
- * @async_handler: If sent asynchronously, optional callback handler. The user
- *		   must be careful when using async handlers as the memory for
- *		   the recv_buf _cannot_ be on stack if this is async.
- * @vc_op: virtchnl op to send
- */
-struct idpf_vc_xn_params {
-	struct kvec send_buf;
-	struct kvec recv_buf;
-	int timeout_ms;
-	bool async;
-	async_vc_cb async_handler;
-	u32 vc_op;
-};
 
 struct idpf_adapter;
 struct idpf_netdev_priv;
@@ -93,8 +14,6 @@ struct idpf_vport;
 struct idpf_vport_max_q;
 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);
@@ -115,9 +34,11 @@ 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_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q);
 u32 idpf_get_vport_id(struct idpf_vport *vport);
@@ -179,6 +100,5 @@ 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);
 
 #endif /* _IDPF_VIRTCHNL_H_ */
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c
index f9b23e98e55f..7dee41953c92 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,10 +23,9 @@ 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 virtchnl2_ptp_get_caps *recv_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 libie_mmio_info	*mmio_info = &adapter->ctlq_ctx.mmio_info;
@@ -37,21 +35,21 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)
 	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(sizeof(struct virtchnl2_ptp_get_caps),
-				    GFP_KERNEL);
-	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);
@@ -95,7 +93,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;
 
@@ -133,7 +131,9 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)
 	ptp->dev_clk_regs.phy_shadj_h =
 		libie_pci_get_mmio_addr(mmio_info, temp_offset);
 
-	return 0;
+free_resp:
+	libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+	return err;
 }
 
 /**
@@ -148,28 +148,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;
 }
 
 /**
@@ -186,23 +192,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;
 }
 
 /**
@@ -219,23 +220,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;
 }
 
 /**
@@ -253,23 +249,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;
 }
 
 /**
@@ -288,18 +279,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)
@@ -311,19 +300,15 @@ int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport)
 	    get_dev_clk_access == IDPF_PTP_NONE)
 		return -EOPNOTSUPP;
 
-	rcv_tx_tstamp_caps = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
-	if (!rcv_tx_tstamp_caps)
-		return -ENOMEM;
-
 	send_tx_tstamp_caps.vport_id = cpu_to_le32(vport->vport_id);
-	xn_params.recv_buf.iov_base = rcv_tx_tstamp_caps;
 
-	reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
-	if (reply_sz < 0) {
-		err = reply_sz;
-		goto get_tstamp_caps_out;
-	}
+	err = idpf_send_mb_msg(vport->adapter, &xn_params, &send_tx_tstamp_caps,
+			       sizeof(send_tx_tstamp_caps));
+	if (err)
+		return err;
 
+	rcv_tx_tstamp_caps = xn_params.recv_mem.iov_base;
+	reply_sz = xn_params.recv_mem.iov_len;
 	num_latches = le16_to_cpu(rcv_tx_tstamp_caps->num_latches);
 	size = struct_size(rcv_tx_tstamp_caps, tstamp_latches, num_latches);
 	if (reply_sz != size) {
@@ -378,7 +363,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;
 
@@ -391,7 +376,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;
 }
@@ -483,9 +468,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
@@ -493,22 +478,21 @@ 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;
+	recv_tx_tstamp_msg = mem->iov_base;
 	vport_id = le32_to_cpu(recv_tx_tstamp_msg->vport_id);
 
 	idpf_for_each_vport(adapter, vport) {
@@ -522,7 +506,7 @@ idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,
 	}
 
 	if (!tstamp_vport || !tstamp_vport->tx_tstamp_caps)
-		return -EINVAL;
+		goto free_resp;
 
 	tx_tstamp_caps = tstamp_vport->tx_tstamp_caps;
 	num_latches = le16_to_cpu(recv_tx_tstamp_msg->num_latches);
@@ -557,8 +541,8 @@ idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,
 
 unlock:
 	spin_unlock_bh(&tx_tstamp_caps->latches_lock);
-
-	return err;
+free_resp:
+	libie_ctlq_release_rx_buf(mem);
 }
 
 /**
@@ -574,15 +558,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;
 
@@ -615,11 +599,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(vport->adapter, &xn_params, send_tx_tstamp_msg,
+				msg_size);
 }
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 10/15] idpf: make mbx_task queueing and cancelling more consistent
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
                   ` (8 preceding siblings ...)
  2025-05-16 14:58 ` [PATCH iwl-next v4 09/15] idpf: refactor idpf to use libie control queues Larysa Zaremba
@ 2025-05-16 14:58 ` Larysa Zaremba
  2025-06-10 21:51   ` [Intel-wired-lan] " Salin, Samuel
  2025-05-16 14:58 ` [PATCH iwl-next v4 11/15] idpf: print a debug message and bail in case of non-event ctlq message Larysa Zaremba
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:58 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali, Michal Kubiak

As a consequence of refactoring idpf code to use libeth APIs,
idpf_vc_xn_shutdown was merged with and replaced by idpf_deinit_dflt_mbx.
This does not affect the Tx path, as it checked for a presence of an xn
manager anyway. Rx processing is handled by the mbx_task that is not always
cancelled before calling the new consolidated mailbox deinit function.
Moreover, in the reset path idpf_intr_rel() reschedules it after the deinit
is done. This leads to mbx_task referencing the freed mailbox and causing
KASAN warnings.

To remedy this, in the init path, do the first queueing of mbx_task in
idpf_init_dflt_mbx(), in deinit and reset, always cancel the task in
idpf_deinit_dflt_mbx() and in every flow first call idpf_mb_intr_rel_irq().

Reviewed-by: Michal Kubiak <michal.kubiak@intel.com>
Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
---
 drivers/net/ethernet/intel/idpf/idpf.h          | 1 +
 drivers/net/ethernet/intel/idpf/idpf_lib.c      | 9 ++++-----
 drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 6 +++++-
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index ff69d920d7d3..e84881307b99 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -880,6 +880,7 @@ void idpf_vc_event_task(struct work_struct *work);
 void idpf_dev_ops_init(struct idpf_adapter *adapter);
 void idpf_vf_dev_ops_init(struct idpf_adapter *adapter);
 int idpf_intr_req(struct idpf_adapter *adapter);
+void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter);
 void idpf_intr_rel(struct idpf_adapter *adapter);
 u16 idpf_get_max_tx_hdr_size(struct idpf_adapter *adapter);
 int idpf_initiate_soft_reset(struct idpf_vport *vport,
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index 500bff1091d9..f8a025cecac5 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -66,9 +66,11 @@ static void idpf_deinit_vector_stack(struct idpf_adapter *adapter)
  * This will also disable interrupt mode and queue up mailbox task. Mailbox
  * task will reschedule itself if not in interrupt mode.
  */
-static void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter)
+void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter)
 {
-	clear_bit(IDPF_MB_INTR_MODE, adapter->flags);
+	if (!test_and_clear_bit(IDPF_MB_INTR_MODE, adapter->flags))
+		return;
+
 	kfree(free_irq(adapter->msix_entries[0].vector, adapter));
 	queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task, 0);
 }
@@ -1783,14 +1785,11 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter)
 		goto unlock_mutex;
 	}
 
-	queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task, 0);
-
 	/* Initialize the state machine, also allocate memory and request
 	 * resources
 	 */
 	err = idpf_vc_core_init(adapter);
 	if (err) {
-		cancel_delayed_work_sync(&adapter->mbx_task);
 		idpf_deinit_dflt_mbx(adapter);
 		goto unlock_mutex;
 	}
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 021fac3850ad..31c7e1984f6c 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -2357,6 +2357,8 @@ int idpf_init_dflt_mbx(struct idpf_adapter *adapter)
 	adapter->xn_init_params.xnm = params.xnm;
 	adapter->state = __IDPF_VER_CHECK;
 
+	queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task, 0);
+
 	return 0;
 }
 
@@ -2366,6 +2368,9 @@ int idpf_init_dflt_mbx(struct idpf_adapter *adapter)
  */
 void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter)
 {
+	idpf_mb_intr_rel_irq(adapter);
+	cancel_delayed_work_sync(&adapter->mbx_task);
+
 	if (adapter->arq && adapter->asq) {
 		idpf_mb_clean(adapter, adapter->asq);
 		libie_ctlq_xn_deinit(adapter->xn_init_params.xnm,
@@ -2605,7 +2610,6 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)
 		idpf_deinit_dflt_mbx(adapter);
 
 	cancel_delayed_work_sync(&adapter->serv_task);
-	cancel_delayed_work_sync(&adapter->mbx_task);
 
 	idpf_vport_params_buf_rel(adapter);
 
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 11/15] idpf: print a debug message and bail in case of non-event ctlq message
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
                   ` (9 preceding siblings ...)
  2025-05-16 14:58 ` [PATCH iwl-next v4 10/15] idpf: make mbx_task queueing and cancelling more consistent Larysa Zaremba
@ 2025-05-16 14:58 ` Larysa Zaremba
  2025-06-10 21:53   ` [Intel-wired-lan] " Salin, Samuel
  2025-05-16 14:58 ` [PATCH iwl-next v4 12/15] ixd: add basic driver framework for Intel(R) Control Plane Function Larysa Zaremba
                   ` (3 subsequent siblings)
  14 siblings, 1 reply; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:58 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali, Michal Kubiak

Unlike previous internal idpf ctlq implementation, idpf calls the default
message handler for all received messages that do not have a matching xn
transaction, not only for VIRTCHNL2_OP_EVENT. This leads to many error
messages printing garbage, because the parsing expected a valid event
message, but got e.g. a delayed response for a timed-out transaction.

The information about timed-out transactions and otherwise unhandleable
messages can still be valuable for developers, so print the information
with dynamic debug and exit the function, so the following functions can
parse valid events in peace.

Reviewed-by: Michal Kubiak <michal.kubiak@intel.com>
Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
---
 drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 31c7e1984f6c..d2bf5226b31d 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -82,6 +82,13 @@ void idpf_recv_event_msg(struct libie_ctlq_ctx *ctx,
 	u32 event;
 
 	adapter = container_of(ctx, struct idpf_adapter, ctlq_ctx);
+	if (ctlq_msg->chnl_opcode != VIRTCHNL2_OP_EVENT) {
+		dev_dbg(&adapter->pdev->dev,
+			"Unhandled message with opcode %u from CP\n",
+			ctlq_msg->chnl_opcode);
+		goto free_rx_buf;
+	}
+
 	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->chnl_opcode,
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 12/15] ixd: add basic driver framework for Intel(R) Control Plane Function
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
                   ` (10 preceding siblings ...)
  2025-05-16 14:58 ` [PATCH iwl-next v4 11/15] idpf: print a debug message and bail in case of non-event ctlq message Larysa Zaremba
@ 2025-05-16 14:58 ` Larysa Zaremba
  2025-05-16 14:58 ` [PATCH iwl-next v4 13/15] ixd: add reset checks and initialize the mailbox Larysa Zaremba
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:58 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali

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.

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>
---
 .../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     | 122 ++++++++++++++++++
 9 files changed, 242 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 f9ed93c1da35..62c30e866a90 100644
--- a/Documentation/networking/device_drivers/ethernet/index.rst
+++ b/Documentation/networking/device_drivers/ethernet/index.rst
@@ -37,6 +37,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 b05cc0d7a15d..4fd6d0ea1553 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -395,4 +395,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 04c844ef4964..8de2222a0333 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..a991eaa8a2aa
--- /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			0x1453
+
+/* 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..5b8b8258fec8
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_main.c
@@ -0,0 +1,122 @@
+// 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);
+	libie_pci_deinit_dev(pdev);
+}
+
+/**
+ * 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);
+
+	err = ixd_iomap_regions(adapter);
+	if (err)
+		goto deinit_dev;
+
+	return 0;
+
+deinit_dev:
+	libie_pci_deinit_dev(pdev);
+
+	return err;
+}
+
+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.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 13/15] ixd: add reset checks and initialize the mailbox
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
                   ` (11 preceding siblings ...)
  2025-05-16 14:58 ` [PATCH iwl-next v4 12/15] ixd: add basic driver framework for Intel(R) Control Plane Function Larysa Zaremba
@ 2025-05-16 14:58 ` Larysa Zaremba
  2025-05-16 14:58 ` [PATCH iwl-next v4 14/15] ixd: add the core initialization Larysa Zaremba
  2025-05-16 14:58 ` [PATCH iwl-next v4 15/15] ixd: add devlink support Larysa Zaremba
  14 siblings, 0 replies; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:58 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali

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.

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>
---
 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     |  26 +++-
 7 files changed, 321 insertions(+), 8 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..6c41a820eecc
--- /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 != 0xFFFFFFFF &&
+	    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 a991eaa8a2aa..26b1e3cfcf20 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..b8dd5c4de7b2
--- /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 == VIRTCHNL2_QUEUE_TYPE_RX)
+			adapter->arq = cq;
+		else if (cq->type == VIRTCHNL2_QUEUE_TYPE_TX)
+			adapter->asq = cq;
+	}
+}
+
+/**
+ * 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], VIRTCHNL2_QUEUE_TYPE_TX,
+				  &ctlq_reg_tx);
+	ixd_init_ctlq_create_info(&ctlqs_info[1], VIRTCHNL2_QUEUE_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) {
+		libie_ctlq_xn_deinit(adapter->xnm, &adapter->cp_ctx);
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+/**
+ * ixd_deinit_dflt_mbx - Deinitialize default mailbox
+ * @adapter: adapter info struct
+ */
+void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter)
+{
+	if (adapter->arq || adapter->asq)
+		libie_ctlq_xn_deinit(adapter->xnm, &adapter->cp_ctx);
+
+	adapter->arq = NULL;
+	adapter->asq = NULL;
+	adapter->xnm = NULL;
+}
+
+/**
+ * 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 5b8b8258fec8..71b216fd40cc 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);
 	libie_pci_deinit_dev(pdev);
 }
 
@@ -52,7 +59,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,
@@ -82,11 +89,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)
@@ -98,6 +109,13 @@ static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (err)
 		goto deinit_dev;
 
+	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;
 
 deinit_dev:
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 14/15] ixd: add the core initialization
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
                   ` (12 preceding siblings ...)
  2025-05-16 14:58 ` [PATCH iwl-next v4 13/15] ixd: add reset checks and initialize the mailbox Larysa Zaremba
@ 2025-05-16 14:58 ` Larysa Zaremba
  2025-05-16 14:58 ` [PATCH iwl-next v4 15/15] ixd: add devlink support Larysa Zaremba
  14 siblings, 0 replies; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:58 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali

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.

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>
---
 drivers/net/ethernet/intel/ixd/Makefile       |   2 +
 drivers/net/ethernet/intel/ixd/ixd.h          |  10 +
 drivers/net/ethernet/intel/ixd/ixd_ctlq.c     | 148 +++++++++++++++
 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, 410 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..d8347932a68f
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
@@ -0,0 +1,148 @@
+// 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,
+	};
+
+	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..f450a3a0828f
--- /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 b8dd5c4de7b2..34ba987866b1 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
 
@@ -94,6 +95,8 @@ int ixd_init_dflt_mbx(struct ixd_adapter *adapter)
 		return -ENOENT;
 	}
 
+	queue_delayed_work(system_unbound_wq, &adapter->mbx_task, 0);
+
 	return 0;
 }
 
@@ -103,6 +106,8 @@ int ixd_init_dflt_mbx(struct ixd_adapter *adapter)
  */
 void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter)
 {
+	cancel_delayed_work_sync(&adapter->mbx_task);
+
 	if (adapter->arq || adapter->asq)
 		libie_ctlq_xn_deinit(adapter->xnm, &adapter->cp_ctx);
 
@@ -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 71b216fd40cc..c6dd6b3f14bb 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);
@@ -111,6 +113,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.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH iwl-next v4 15/15] ixd: add devlink support
  2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
                   ` (13 preceding siblings ...)
  2025-05-16 14:58 ` [PATCH iwl-next v4 14/15] ixd: add the core initialization Larysa Zaremba
@ 2025-05-16 14:58 ` Larysa Zaremba
  14 siblings, 0 replies; 24+ messages in thread
From: Larysa Zaremba @ 2025-05-16 14:58 UTC (permalink / raw)
  To: intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Larysa Zaremba, Sridhar Samudrala,
	Jacob Keller, Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki,
	netdev, linux-doc, linux-kernel, Karlsson, Magnus, Emil Tantilov,
	Madhu Chittim, Josh Hay, Milena Olech, pavan.kumar.linga,
	Singhai, Anjali

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.

$ 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:
        cp 0.0
        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>
---
 Documentation/networking/devlink/index.rst   |   1 +
 Documentation/networking/devlink/ixd.rst     |  35 +++++++
 drivers/net/ethernet/intel/ixd/Kconfig       |   1 +
 drivers/net/ethernet/intel/ixd/Makefile      |   1 +
 drivers/net/ethernet/intel/ixd/ixd_devlink.c | 105 +++++++++++++++++++
 drivers/net/ethernet/intel/ixd/ixd_devlink.h |  44 ++++++++
 drivers/net/ethernet/intel/ixd/ixd_main.c    |  13 ++-
 7 files changed, 197 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 8319f43b5933..ee9d89429fa2 100644
--- a/Documentation/networking/devlink/index.rst
+++ b/Documentation/networking/devlink/index.rst
@@ -85,6 +85,7 @@ parameters, info versions, and other features it supports.
    ionic
    ice
    ixgbe
+   ixd
    mlx4
    mlx5
    mlxsw
diff --git a/Documentation/networking/devlink/ixd.rst b/Documentation/networking/devlink/ixd.rst
new file mode 100644
index 000000000000..81b28ffb00f6
--- /dev/null
+++ b/Documentation/networking/devlink/ixd.rst
@@ -0,0 +1,35 @@
+.. 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
+    * - ``cp``
+      - running
+      - 0.0
+      - Version number (major.minor) of the Control Plane software
+        running on the 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..6f60cfe4fab2
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_devlink.c
@@ -0,0 +1,105 @@
+// 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 == 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",
+		 le16_to_cpu(adapter->caps.cp_ver_major),
+		 le16_to_cpu(adapter->caps.cp_ver_minor));
+
+	err = devlink_info_version_running_put(req, "cp", 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 c6dd6b3f14bb..d58b49bb3953 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,12 +22,15 @@ 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);
 	libie_pci_deinit_dev(pdev);
+	ixd_devlink_free(adapter);
 }
 
 /**
@@ -94,7 +98,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;
 
@@ -103,7 +107,7 @@ 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);
 
@@ -119,11 +123,14 @@ 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;
 
 deinit_dev:
 	libie_pci_deinit_dev(pdev);
-
+free_adapter:
+	ixd_devlink_free(adapter);
 	return err;
 }
 
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* RE: [Intel-wired-lan] [PATCH iwl-next v4 07/15] idpf: remove 'vport_params_reqd' field
  2025-05-16 14:58 ` [PATCH iwl-next v4 07/15] idpf: remove 'vport_params_reqd' field Larysa Zaremba
@ 2025-06-10 21:50   ` Salin, Samuel
  0 siblings, 0 replies; 24+ messages in thread
From: Salin, Samuel @ 2025-06-10 21:50 UTC (permalink / raw)
  To: Zaremba, Larysa, intel-wired-lan@lists.osuosl.org,
	Nguyen, Anthony L
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Kitszel, Przemyslaw, Jiri Pirko,
	Nikolova, Tatyana E, Andrew Lunn, Lobakin, Aleksander,
	Michael Ellerman, Fijalkowski, Maciej, Lee Trager,
	Madhavan Srinivasan, Zaremba, Larysa, Samudrala, Sridhar,
	Keller, Jacob E, Michal Swiatkowski, Polchlopek, Mateusz,
	Zaki, Ahmed, netdev@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, Karlsson, Magnus, Tantilov, Emil S,
	Chittim, Madhu, Hay, Joshua A, Olech, Milena, Linga, Pavan Kumar,
	Singhai, Anjali



> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf Of
> Larysa Zaremba
> Sent: Friday, May 16, 2025 7:58 AM
> To: intel-wired-lan@lists.osuosl.org; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>
> Cc: David S. Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@google.com>; Jakub Kicinski <kuba@kernel.org>; Paolo Abeni
> <pabeni@redhat.com>; Simon Horman <horms@kernel.org>; Jonathan
> Corbet <corbet@lwn.net>; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Jiri Pirko <jiri@resnulli.us>; Nikolova, Tatyana
> E <tatyana.e.nikolova@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
> Lobakin, Aleksander <aleksander.lobakin@intel.com>; Michael Ellerman
> <mpe@ellerman.id.au>; Fijalkowski, Maciej <maciej.fijalkowski@intel.com>;
> Lee Trager <lee@trager.us>; Madhavan Srinivasan <maddy@linux.ibm.com>;
> Zaremba, Larysa <larysa.zaremba@intel.com>; Samudrala, Sridhar
> <sridhar.samudrala@intel.com>; Keller, Jacob E <jacob.e.keller@intel.com>;
> Michal Swiatkowski <michal.swiatkowski@linux.intel.com>; Polchlopek,
> Mateusz <mateusz.polchlopek@intel.com>; Zaki, Ahmed
> <ahmed.zaki@intel.com>; netdev@vger.kernel.org; linux-
> doc@vger.kernel.org; linux-kernel@vger.kernel.org; Karlsson, Magnus
> <magnus.karlsson@intel.com>; Tantilov, Emil S <emil.s.tantilov@intel.com>;
> Chittim, Madhu <madhu.chittim@intel.com>; Hay, Joshua A
> <joshua.a.hay@intel.com>; Olech, Milena <milena.olech@intel.com>; Linga,
> Pavan Kumar <pavan.kumar.linga@intel.com>; Singhai, Anjali
> <anjali.singhai@intel.com>
> Subject: [Intel-wired-lan] [PATCH iwl-next v4 07/15] idpf: remove
> 'vport_params_reqd' field
> 
> From: Pavan Kumar Linga <pavan.kumar.linga@intel.com>
> 
> While sending a create vport message to the device control plane, a create
> vport virtchnl message is prepared with all the required info to initialize the
> vport. This info is stored in the adapter struct but never used thereafter. So,
> remove the said field.
> 
> Signed-off-by: Pavan Kumar Linga <pavan.kumar.linga@intel.com>
> Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
> ---
> 2.47.0

Tested-by: Samuel Salin <Samuel.salin@intel.com>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [Intel-wired-lan] [PATCH iwl-next v4 08/15] idpf: refactor idpf to use libie_pci APIs
  2025-05-16 14:58 ` [PATCH iwl-next v4 08/15] idpf: refactor idpf to use libie_pci APIs Larysa Zaremba
@ 2025-06-10 21:51   ` Salin, Samuel
  0 siblings, 0 replies; 24+ messages in thread
From: Salin, Samuel @ 2025-06-10 21:51 UTC (permalink / raw)
  To: Zaremba, Larysa, intel-wired-lan@lists.osuosl.org,
	Nguyen, Anthony L
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Kitszel, Przemyslaw, Jiri Pirko,
	Nikolova, Tatyana E, Andrew Lunn, Lobakin, Aleksander,
	Michael Ellerman, Fijalkowski, Maciej, Lee Trager,
	Madhavan Srinivasan, Zaremba, Larysa, Samudrala, Sridhar,
	Keller, Jacob E, Michal Swiatkowski, Polchlopek, Mateusz,
	Zaki, Ahmed, netdev@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, Karlsson, Magnus, Tantilov, Emil S,
	Chittim, Madhu, Hay, Joshua A, Olech, Milena, Linga, Pavan Kumar,
	Singhai, Anjali, Kubiak, Michal



> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf Of
> Larysa Zaremba
> Sent: Friday, May 16, 2025 7:58 AM
> To: intel-wired-lan@lists.osuosl.org; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>
> Cc: David S. Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@google.com>; Jakub Kicinski <kuba@kernel.org>; Paolo Abeni
> <pabeni@redhat.com>; Simon Horman <horms@kernel.org>; Jonathan
> Corbet <corbet@lwn.net>; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Jiri Pirko <jiri@resnulli.us>; Nikolova, Tatyana
> E <tatyana.e.nikolova@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
> Lobakin, Aleksander <aleksander.lobakin@intel.com>; Michael Ellerman
> <mpe@ellerman.id.au>; Fijalkowski, Maciej <maciej.fijalkowski@intel.com>;
> Lee Trager <lee@trager.us>; Madhavan Srinivasan <maddy@linux.ibm.com>;
> Zaremba, Larysa <larysa.zaremba@intel.com>; Samudrala, Sridhar
> <sridhar.samudrala@intel.com>; Keller, Jacob E <jacob.e.keller@intel.com>;
> Michal Swiatkowski <michal.swiatkowski@linux.intel.com>; Polchlopek,
> Mateusz <mateusz.polchlopek@intel.com>; Zaki, Ahmed
> <ahmed.zaki@intel.com>; netdev@vger.kernel.org; linux-
> doc@vger.kernel.org; linux-kernel@vger.kernel.org; Karlsson, Magnus
> <magnus.karlsson@intel.com>; Tantilov, Emil S <emil.s.tantilov@intel.com>;
> Chittim, Madhu <madhu.chittim@intel.com>; Hay, Joshua A
> <joshua.a.hay@intel.com>; Olech, Milena <milena.olech@intel.com>; Linga,
> Pavan Kumar <pavan.kumar.linga@intel.com>; Singhai, Anjali
> <anjali.singhai@intel.com>; Kubiak, Michal <michal.kubiak@intel.com>
> Subject: [Intel-wired-lan] [PATCH iwl-next v4 08/15] idpf: refactor idpf to use
> libie_pci APIs
> 
> From: Pavan Kumar Linga <pavan.kumar.linga@intel.com>
> 
> Use libie_pci init and MMIO APIs where possible, struct idpf_hw cannot be
> deleted for now as it also houses control queues that will be refactored later.
> Use libie_cp header for libie_ctlq_ctx that contains mmio info from the start in
> order to not increase the diff later.
> 
> Reviewed-by: Michal Kubiak <michal.kubiak@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>
> ---
> 2.47.0

Tested-by: Samuel Salin <Samuel.salin@intel.com>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [Intel-wired-lan] [PATCH iwl-next v4 09/15] idpf: refactor idpf to use libie control queues
  2025-05-16 14:58 ` [PATCH iwl-next v4 09/15] idpf: refactor idpf to use libie control queues Larysa Zaremba
@ 2025-06-10 21:51   ` Salin, Samuel
  2025-06-18  0:04   ` Tantilov, Emil S
  1 sibling, 0 replies; 24+ messages in thread
From: Salin, Samuel @ 2025-06-10 21:51 UTC (permalink / raw)
  To: Zaremba, Larysa, intel-wired-lan@lists.osuosl.org,
	Nguyen, Anthony L
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Kitszel, Przemyslaw, Jiri Pirko,
	Nikolova, Tatyana E, Andrew Lunn, Lobakin, Aleksander,
	Michael Ellerman, Fijalkowski, Maciej, Lee Trager,
	Madhavan Srinivasan, Zaremba, Larysa, Samudrala, Sridhar,
	Keller, Jacob E, Michal Swiatkowski, Polchlopek, Mateusz,
	Zaki, Ahmed, netdev@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, Karlsson, Magnus, Tantilov, Emil S,
	Chittim, Madhu, Hay, Joshua A, Olech, Milena, Linga, Pavan Kumar,
	Singhai, Anjali, Kubiak, Michal



> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf Of
> Larysa Zaremba
> Sent: Friday, May 16, 2025 7:58 AM
> To: intel-wired-lan@lists.osuosl.org; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>
> Cc: David S. Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@google.com>; Jakub Kicinski <kuba@kernel.org>; Paolo Abeni
> <pabeni@redhat.com>; Simon Horman <horms@kernel.org>; Jonathan
> Corbet <corbet@lwn.net>; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Jiri Pirko <jiri@resnulli.us>; Nikolova, Tatyana
> E <tatyana.e.nikolova@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
> Lobakin, Aleksander <aleksander.lobakin@intel.com>; Michael Ellerman
> <mpe@ellerman.id.au>; Fijalkowski, Maciej <maciej.fijalkowski@intel.com>;
> Lee Trager <lee@trager.us>; Madhavan Srinivasan <maddy@linux.ibm.com>;
> Zaremba, Larysa <larysa.zaremba@intel.com>; Samudrala, Sridhar
> <sridhar.samudrala@intel.com>; Keller, Jacob E <jacob.e.keller@intel.com>;
> Michal Swiatkowski <michal.swiatkowski@linux.intel.com>; Polchlopek,
> Mateusz <mateusz.polchlopek@intel.com>; Zaki, Ahmed
> <ahmed.zaki@intel.com>; netdev@vger.kernel.org; linux-
> doc@vger.kernel.org; linux-kernel@vger.kernel.org; Karlsson, Magnus
> <magnus.karlsson@intel.com>; Tantilov, Emil S <emil.s.tantilov@intel.com>;
> Chittim, Madhu <madhu.chittim@intel.com>; Hay, Joshua A
> <joshua.a.hay@intel.com>; Olech, Milena <milena.olech@intel.com>; Linga,
> Pavan Kumar <pavan.kumar.linga@intel.com>; Singhai, Anjali
> <anjali.singhai@intel.com>; Kubiak, Michal <michal.kubiak@intel.com>
> Subject: [Intel-wired-lan] [PATCH iwl-next v4 09/15] idpf: refactor idpf to use
> libie control queues
> 
> From: Pavan Kumar Linga <pavan.kumar.linga@intel.com>
> 
> Support to initialize and configure controlqs, and manage their
> transactions was introduced in libie. As part of it, most of the existing
> controlq structures are renamed and modified. Use those APIs in idpf and
> make all the necessary changes.
> 
> Previously for the send and receive virtchnl messages, there used to be a
> memcpy involved in controlq code to copy the buffer info passed by the send
> function into the controlq specific buffers. There was no restriction to
> use automatic memory in that case. The new implementation in libie removed
> copying of the send buffer info and introduced DMA mapping of the send
> buffer itself. To accommodate it, use dynamic memory for the larger send
> buffers. For smaller ones (<= 128 bytes) libie still can copy them into the
> pre-allocated message memory.
> 
> In case of receive, idpf receives a page pool buffer allocated by the libie
> and care should be taken to release it after use in the idpf.
> 
> The changes are fairly trivial and localized, with a notable exception
> being the consolidation of idpf_vc_xn_shutdown and idpf_deinit_dflt_mbx
> under the latter name. This has some additional consequences that are
> addressed in the following patches.
> 
> This refactoring introduces roughly additional 40KB of module storage used
> for systems that only run idpf, so idpf + libie_cp + libie_pci takes about
> 7% more storage than just idpf before refactoring.
> 
> 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: Michal Kubiak <michal.kubiak@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>
> ---
> 2.47.0

Tested-by: Samuel Salin <Samuel.salin@intel.com>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [Intel-wired-lan] [PATCH iwl-next v4 10/15] idpf: make mbx_task queueing and cancelling more consistent
  2025-05-16 14:58 ` [PATCH iwl-next v4 10/15] idpf: make mbx_task queueing and cancelling more consistent Larysa Zaremba
@ 2025-06-10 21:51   ` Salin, Samuel
  0 siblings, 0 replies; 24+ messages in thread
From: Salin, Samuel @ 2025-06-10 21:51 UTC (permalink / raw)
  To: Zaremba, Larysa, intel-wired-lan@lists.osuosl.org,
	Nguyen, Anthony L
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Kitszel, Przemyslaw, Jiri Pirko,
	Nikolova, Tatyana E, Andrew Lunn, Lobakin, Aleksander,
	Michael Ellerman, Fijalkowski, Maciej, Lee Trager,
	Madhavan Srinivasan, Zaremba, Larysa, Samudrala, Sridhar,
	Keller, Jacob E, Michal Swiatkowski, Polchlopek, Mateusz,
	Zaki, Ahmed, netdev@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, Karlsson, Magnus, Tantilov, Emil S,
	Chittim, Madhu, Hay, Joshua A, Olech, Milena, Linga, Pavan Kumar,
	Singhai, Anjali, Kubiak, Michal



> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf Of
> Larysa Zaremba
> Sent: Friday, May 16, 2025 7:58 AM
> To: intel-wired-lan@lists.osuosl.org; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>
> Cc: David S. Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@google.com>; Jakub Kicinski <kuba@kernel.org>; Paolo Abeni
> <pabeni@redhat.com>; Simon Horman <horms@kernel.org>; Jonathan
> Corbet <corbet@lwn.net>; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Jiri Pirko <jiri@resnulli.us>; Nikolova, Tatyana
> E <tatyana.e.nikolova@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
> Lobakin, Aleksander <aleksander.lobakin@intel.com>; Michael Ellerman
> <mpe@ellerman.id.au>; Fijalkowski, Maciej <maciej.fijalkowski@intel.com>;
> Lee Trager <lee@trager.us>; Madhavan Srinivasan <maddy@linux.ibm.com>;
> Zaremba, Larysa <larysa.zaremba@intel.com>; Samudrala, Sridhar
> <sridhar.samudrala@intel.com>; Keller, Jacob E <jacob.e.keller@intel.com>;
> Michal Swiatkowski <michal.swiatkowski@linux.intel.com>; Polchlopek,
> Mateusz <mateusz.polchlopek@intel.com>; Zaki, Ahmed
> <ahmed.zaki@intel.com>; netdev@vger.kernel.org; linux-
> doc@vger.kernel.org; linux-kernel@vger.kernel.org; Karlsson, Magnus
> <magnus.karlsson@intel.com>; Tantilov, Emil S <emil.s.tantilov@intel.com>;
> Chittim, Madhu <madhu.chittim@intel.com>; Hay, Joshua A
> <joshua.a.hay@intel.com>; Olech, Milena <milena.olech@intel.com>; Linga,
> Pavan Kumar <pavan.kumar.linga@intel.com>; Singhai, Anjali
> <anjali.singhai@intel.com>; Kubiak, Michal <michal.kubiak@intel.com>
> Subject: [Intel-wired-lan] [PATCH iwl-next v4 10/15] idpf: make mbx_task
> queueing and cancelling more consistent
> 
> As a consequence of refactoring idpf code to use libeth APIs,
> idpf_vc_xn_shutdown was merged with and replaced by
> idpf_deinit_dflt_mbx.
> This does not affect the Tx path, as it checked for a presence of an xn manager
> anyway. Rx processing is handled by the mbx_task that is not always cancelled
> before calling the new consolidated mailbox deinit function.
> Moreover, in the reset path idpf_intr_rel() reschedules it after the deinit is
> done. This leads to mbx_task referencing the freed mailbox and causing
> KASAN warnings.
> 
> To remedy this, in the init path, do the first queueing of mbx_task in
> idpf_init_dflt_mbx(), in deinit and reset, always cancel the task in
> idpf_deinit_dflt_mbx() and in every flow first call idpf_mb_intr_rel_irq().
> 
> Reviewed-by: Michal Kubiak <michal.kubiak@intel.com>
> Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
> ---
> 2.47.0

Tested-by: Samuel Salin <Samuel.salin@intel.com>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [Intel-wired-lan] [PATCH iwl-next v4 11/15] idpf: print a debug message and bail in case of non-event ctlq message
  2025-05-16 14:58 ` [PATCH iwl-next v4 11/15] idpf: print a debug message and bail in case of non-event ctlq message Larysa Zaremba
@ 2025-06-10 21:53   ` Salin, Samuel
  0 siblings, 0 replies; 24+ messages in thread
From: Salin, Samuel @ 2025-06-10 21:53 UTC (permalink / raw)
  To: Zaremba, Larysa, intel-wired-lan@lists.osuosl.org,
	Nguyen, Anthony L
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Kitszel, Przemyslaw, Jiri Pirko,
	Nikolova, Tatyana E, Andrew Lunn, Lobakin, Aleksander,
	Michael Ellerman, Fijalkowski, Maciej, Lee Trager,
	Madhavan Srinivasan, Zaremba, Larysa, Samudrala, Sridhar,
	Keller, Jacob E, Michal Swiatkowski, Polchlopek, Mateusz,
	Zaki, Ahmed, netdev@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, Karlsson, Magnus, Tantilov, Emil S,
	Chittim, Madhu, Hay, Joshua A, Olech, Milena, Linga, Pavan Kumar,
	Singhai, Anjali, Kubiak, Michal



> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf Of
> Larysa Zaremba
> Sent: Friday, May 16, 2025 7:58 AM
> To: intel-wired-lan@lists.osuosl.org; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>
> Cc: David S. Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@google.com>; Jakub Kicinski <kuba@kernel.org>; Paolo Abeni
> <pabeni@redhat.com>; Simon Horman <horms@kernel.org>; Jonathan
> Corbet <corbet@lwn.net>; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Jiri Pirko <jiri@resnulli.us>; Nikolova, Tatyana
> E <tatyana.e.nikolova@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
> Lobakin, Aleksander <aleksander.lobakin@intel.com>; Michael Ellerman
> <mpe@ellerman.id.au>; Fijalkowski, Maciej <maciej.fijalkowski@intel.com>;
> Lee Trager <lee@trager.us>; Madhavan Srinivasan <maddy@linux.ibm.com>;
> Zaremba, Larysa <larysa.zaremba@intel.com>; Samudrala, Sridhar
> <sridhar.samudrala@intel.com>; Keller, Jacob E <jacob.e.keller@intel.com>;
> Michal Swiatkowski <michal.swiatkowski@linux.intel.com>; Polchlopek,
> Mateusz <mateusz.polchlopek@intel.com>; Zaki, Ahmed
> <ahmed.zaki@intel.com>; netdev@vger.kernel.org; linux-
> doc@vger.kernel.org; linux-kernel@vger.kernel.org; Karlsson, Magnus
> <magnus.karlsson@intel.com>; Tantilov, Emil S <emil.s.tantilov@intel.com>;
> Chittim, Madhu <madhu.chittim@intel.com>; Hay, Joshua A
> <joshua.a.hay@intel.com>; Olech, Milena <milena.olech@intel.com>; Linga,
> Pavan Kumar <pavan.kumar.linga@intel.com>; Singhai, Anjali
> <anjali.singhai@intel.com>; Kubiak, Michal <michal.kubiak@intel.com>
> Subject: [Intel-wired-lan] [PATCH iwl-next v4 11/15] idpf: print a debug
> message and bail in case of non-event ctlq message
> 
> Unlike previous internal idpf ctlq implementation, idpf calls the default
> message handler for all received messages that do not have a matching xn
> transaction, not only for VIRTCHNL2_OP_EVENT. This leads to many error
> messages printing garbage, because the parsing expected a valid event
> message, but got e.g. a delayed response for a timed-out transaction.
> 
> The information about timed-out transactions and otherwise unhandleable
> messages can still be valuable for developers, so print the information with
> dynamic debug and exit the function, so the following functions can parse
> valid events in peace.
> 
> Reviewed-by: Michal Kubiak <michal.kubiak@intel.com>
> Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
> ---
> 2.47.0

Tested-by: Samuel Salin <Samuel.salin@intel.com>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH iwl-next v4 09/15] idpf: refactor idpf to use libie control queues
  2025-05-16 14:58 ` [PATCH iwl-next v4 09/15] idpf: refactor idpf to use libie control queues Larysa Zaremba
  2025-06-10 21:51   ` [Intel-wired-lan] " Salin, Samuel
@ 2025-06-18  0:04   ` Tantilov, Emil S
  2025-06-18  7:54     ` Larysa Zaremba
  1 sibling, 1 reply; 24+ messages in thread
From: Tantilov, Emil S @ 2025-06-18  0:04 UTC (permalink / raw)
  To: Larysa Zaremba, intel-wired-lan, Tony Nguyen
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Przemek Kitszel, Jiri Pirko,
	Tatyana Nikolova, Andrew Lunn, Alexander Lobakin,
	Michael Ellerman, Maciej Fijalkowski, Lee Trager,
	Madhavan Srinivasan, Sridhar Samudrala, Jacob Keller,
	Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki, netdev,
	linux-doc, linux-kernel, Karlsson, Magnus, Madhu Chittim,
	Josh Hay, Milena Olech, pavan.kumar.linga, Singhai, Anjali,
	Michal Kubiak



On 5/16/2025 7:58 AM, Larysa Zaremba 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.
> 
> 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.

There is an issue with this approach that impacts the ability of the 
driver to force a reset. See below ...

> 
> 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: Michal Kubiak <michal.kubiak@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>
> ---
>   drivers/net/ethernet/intel/idpf/Kconfig       |    2 +-
>   drivers/net/ethernet/intel/idpf/Makefile      |    2 -
>   drivers/net/ethernet/intel/idpf/idpf.h        |   27 +-
>   .../net/ethernet/intel/idpf/idpf_controlq.c   |  624 -------
>   .../net/ethernet/intel/idpf/idpf_controlq.h   |  130 --
>   .../ethernet/intel/idpf/idpf_controlq_api.h   |  177 --
>   .../ethernet/intel/idpf/idpf_controlq_setup.c |  171 --
>   drivers/net/ethernet/intel/idpf/idpf_dev.c    |   54 +-
>   .../net/ethernet/intel/idpf/idpf_ethtool.c    |   37 +-
>   drivers/net/ethernet/intel/idpf/idpf_lib.c    |   44 +-
>   drivers/net/ethernet/intel/idpf/idpf_main.c   |    4 -
>   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 |   60 +-
>   .../net/ethernet/intel/idpf/idpf_virtchnl.c   | 1617 ++++++-----------
>   .../net/ethernet/intel/idpf/idpf_virtchnl.h   |   90 +-
>   .../ethernet/intel/idpf/idpf_virtchnl_ptp.c   |  204 +--
>   17 files changed, 765 insertions(+), 2500 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
> 

<snip>

> diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
> index 68330b884967..500bff1091d9 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
> @@ -1190,6 +1190,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);
> @@ -1200,7 +1201,11 @@ void idpf_mbx_task(struct work_struct *work)
>   		queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task,
>   				   msecs_to_jiffies(300));
>   
> -	idpf_recv_mb_msg(adapter, adapter->hw.arq);
> +	xn_params.xnm = adapter->xn_init_params.xnm;
> +	xn_params.ctlq = adapter->arq;
> +	xn_params.ctlq_msg_handler = idpf_recv_event_msg;
> +
> +	libie_ctlq_xn_recv(&xn_params);
>   }
>   
>   /**
> @@ -1757,7 +1762,6 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter)
>   		idpf_vc_core_deinit(adapter);
>   		if (!is_reset)

Since one of the checks in idpf_is_reset_detected() is !adapter->arq, 
this will never be possible through the event task. I think we may be 
able to remove this check altogether, but as-is this patch introduces 
large delays in the Tx hang recovery and depending on the cause may not 
recover at all.

>   			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;
> @@ -1825,7 +1829,7 @@ void idpf_vc_event_task(struct work_struct *work)
>   	return;
>   
>   func_reset:
> -	idpf_vc_xn_shutdown(adapter->vcxn_mngr);
> +	idpf_deinit_dflt_mbx(adapter);

This is not a straightforward swap, whereas previously we just discard 
messages knowing that we cannot communicate with the CP in a reset, this 
goes much further as it dismantles the MBX resources, and as a result 
the check `if (!is_reset)` in idpf_init_hard_reset() will never be true.

<snip>

Thanks,
Emil


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH iwl-next v4 09/15] idpf: refactor idpf to use libie control queues
  2025-06-18  0:04   ` Tantilov, Emil S
@ 2025-06-18  7:54     ` Larysa Zaremba
  2025-06-19  2:57       ` Tantilov, Emil S
  0 siblings, 1 reply; 24+ messages in thread
From: Larysa Zaremba @ 2025-06-18  7:54 UTC (permalink / raw)
  To: Tantilov, Emil S
  Cc: intel-wired-lan, Tony Nguyen, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
	Przemek Kitszel, Jiri Pirko, Tatyana Nikolova, Andrew Lunn,
	Alexander Lobakin, Michael Ellerman, Maciej Fijalkowski,
	Lee Trager, Madhavan Srinivasan, Sridhar Samudrala, Jacob Keller,
	Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki, netdev,
	linux-doc, linux-kernel, Karlsson, Magnus, Madhu Chittim,
	Josh Hay, Milena Olech, pavan.kumar.linga, Singhai, Anjali,
	Michal Kubiak

On Tue, Jun 17, 2025 at 05:04:55PM -0700, Tantilov, Emil S wrote:
> 
> 
> On 5/16/2025 7:58 AM, Larysa Zaremba 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.
> > 
> > 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.
> 
> There is an issue with this approach that impacts the ability of the driver
> to force a reset. See below ...
> 
> > 
> > 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: Michal Kubiak <michal.kubiak@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>
> > ---
> >   drivers/net/ethernet/intel/idpf/Kconfig       |    2 +-
> >   drivers/net/ethernet/intel/idpf/Makefile      |    2 -
> >   drivers/net/ethernet/intel/idpf/idpf.h        |   27 +-
> >   .../net/ethernet/intel/idpf/idpf_controlq.c   |  624 -------
> >   .../net/ethernet/intel/idpf/idpf_controlq.h   |  130 --
> >   .../ethernet/intel/idpf/idpf_controlq_api.h   |  177 --
> >   .../ethernet/intel/idpf/idpf_controlq_setup.c |  171 --
> >   drivers/net/ethernet/intel/idpf/idpf_dev.c    |   54 +-
> >   .../net/ethernet/intel/idpf/idpf_ethtool.c    |   37 +-
> >   drivers/net/ethernet/intel/idpf/idpf_lib.c    |   44 +-
> >   drivers/net/ethernet/intel/idpf/idpf_main.c   |    4 -
> >   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 |   60 +-
> >   .../net/ethernet/intel/idpf/idpf_virtchnl.c   | 1617 ++++++-----------
> >   .../net/ethernet/intel/idpf/idpf_virtchnl.h   |   90 +-
> >   .../ethernet/intel/idpf/idpf_virtchnl_ptp.c   |  204 +--
> >   17 files changed, 765 insertions(+), 2500 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
> > 
> 
> <snip>
> 
> > diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
> > index 68330b884967..500bff1091d9 100644
> > --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
> > +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
> > @@ -1190,6 +1190,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);
> > @@ -1200,7 +1201,11 @@ void idpf_mbx_task(struct work_struct *work)
> >   		queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task,
> >   				   msecs_to_jiffies(300));
> > -	idpf_recv_mb_msg(adapter, adapter->hw.arq);
> > +	xn_params.xnm = adapter->xn_init_params.xnm;
> > +	xn_params.ctlq = adapter->arq;
> > +	xn_params.ctlq_msg_handler = idpf_recv_event_msg;
> > +
> > +	libie_ctlq_xn_recv(&xn_params);
> >   }
> >   /**
> > @@ -1757,7 +1762,6 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter)
> >   		idpf_vc_core_deinit(adapter);
> >   		if (!is_reset)
> 
> Since one of the checks in idpf_is_reset_detected() is !adapter->arq, this
> will never be possible through the event task. I think we may be able to
> remove this check altogether, but as-is this patch introduces large delays
> in the Tx hang recovery and depending on the cause may not recover at all.
> 
> >   			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;
> > @@ -1825,7 +1829,7 @@ void idpf_vc_event_task(struct work_struct *work)
> >   	return;
> >   func_reset:
> > -	idpf_vc_xn_shutdown(adapter->vcxn_mngr);
> > +	idpf_deinit_dflt_mbx(adapter);
> 
> This is not a straightforward swap, whereas previously we just discard
> messages knowing that we cannot communicate with the CP in a reset, this
> goes much further as it dismantles the MBX resources, and as a result the
> check `if (!is_reset)` in idpf_init_hard_reset() will never be true.
>

Thanks for finding this!

Given the problem seems to only relate to idpf_vc_event_task() in case of 
IDPF_HR_FUNC_RESET and the following call sequence:

	idpf_deinit_dflt_mbx(adapter);
	set_bit(IDPF_HR_RESET_IN_PROG, adapter->flags);
	idpf_init_hard_reset(adapter);
		netif_carrier_off();
		netif_tx_disable();
		is_reset = idpf_is_reset_detected(adapter);
		idpf_set_vport_state(adapter);
		idpf_vc_core_deinit(adapter);
			idpf_deinit_dflt_mbx(adapter);
			...
		...

I think, it is safe to remove idpf_deinit_dflt_mbx() from idpf_vc_event_task(), 
given no mailbox communication is attempted in between it and 
idpf_vc_core_deinit(). Anything going on in parallel also should not suffer from 
having mailbox available just a little bit longer.

What do you think?

> <snip>
> 
> Thanks,
> Emil
> 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH iwl-next v4 09/15] idpf: refactor idpf to use libie control queues
  2025-06-18  7:54     ` Larysa Zaremba
@ 2025-06-19  2:57       ` Tantilov, Emil S
  0 siblings, 0 replies; 24+ messages in thread
From: Tantilov, Emil S @ 2025-06-19  2:57 UTC (permalink / raw)
  To: Larysa Zaremba
  Cc: intel-wired-lan, Tony Nguyen, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
	Przemek Kitszel, Jiri Pirko, Tatyana Nikolova, Andrew Lunn,
	Alexander Lobakin, Michael Ellerman, Maciej Fijalkowski,
	Lee Trager, Madhavan Srinivasan, Sridhar Samudrala, Jacob Keller,
	Michal Swiatkowski, Mateusz Polchlopek, Ahmed Zaki, netdev,
	linux-doc, linux-kernel, Karlsson, Magnus, Madhu Chittim,
	Josh Hay, Milena Olech, pavan.kumar.linga, Singhai, Anjali,
	Michal Kubiak



On 6/18/2025 12:54 AM, Larysa Zaremba wrote:
> On Tue, Jun 17, 2025 at 05:04:55PM -0700, Tantilov, Emil S wrote:
>>
>>
>> On 5/16/2025 7:58 AM, Larysa Zaremba 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.
>>>
>>> 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.
>>
>> There is an issue with this approach that impacts the ability of the driver
>> to force a reset. See below ...
>>
>>>
>>> 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: Michal Kubiak <michal.kubiak@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>
>>> ---
>>>    drivers/net/ethernet/intel/idpf/Kconfig       |    2 +-
>>>    drivers/net/ethernet/intel/idpf/Makefile      |    2 -
>>>    drivers/net/ethernet/intel/idpf/idpf.h        |   27 +-
>>>    .../net/ethernet/intel/idpf/idpf_controlq.c   |  624 -------
>>>    .../net/ethernet/intel/idpf/idpf_controlq.h   |  130 --
>>>    .../ethernet/intel/idpf/idpf_controlq_api.h   |  177 --
>>>    .../ethernet/intel/idpf/idpf_controlq_setup.c |  171 --
>>>    drivers/net/ethernet/intel/idpf/idpf_dev.c    |   54 +-
>>>    .../net/ethernet/intel/idpf/idpf_ethtool.c    |   37 +-
>>>    drivers/net/ethernet/intel/idpf/idpf_lib.c    |   44 +-
>>>    drivers/net/ethernet/intel/idpf/idpf_main.c   |    4 -
>>>    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 |   60 +-
>>>    .../net/ethernet/intel/idpf/idpf_virtchnl.c   | 1617 ++++++-----------
>>>    .../net/ethernet/intel/idpf/idpf_virtchnl.h   |   90 +-
>>>    .../ethernet/intel/idpf/idpf_virtchnl_ptp.c   |  204 +--
>>>    17 files changed, 765 insertions(+), 2500 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
>>>
>>
>> <snip>
>>
>>> diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
>>> index 68330b884967..500bff1091d9 100644
>>> --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
>>> +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
>>> @@ -1190,6 +1190,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);
>>> @@ -1200,7 +1201,11 @@ void idpf_mbx_task(struct work_struct *work)
>>>    		queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task,
>>>    				   msecs_to_jiffies(300));
>>> -	idpf_recv_mb_msg(adapter, adapter->hw.arq);
>>> +	xn_params.xnm = adapter->xn_init_params.xnm;
>>> +	xn_params.ctlq = adapter->arq;
>>> +	xn_params.ctlq_msg_handler = idpf_recv_event_msg;
>>> +
>>> +	libie_ctlq_xn_recv(&xn_params);
>>>    }
>>>    /**
>>> @@ -1757,7 +1762,6 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter)
>>>    		idpf_vc_core_deinit(adapter);
>>>    		if (!is_reset)
>>
>> Since one of the checks in idpf_is_reset_detected() is !adapter->arq, this
>> will never be possible through the event task. I think we may be able to
>> remove this check altogether, but as-is this patch introduces large delays
>> in the Tx hang recovery and depending on the cause may not recover at all.
>>
>>>    			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;
>>> @@ -1825,7 +1829,7 @@ void idpf_vc_event_task(struct work_struct *work)
>>>    	return;
>>>    func_reset:
>>> -	idpf_vc_xn_shutdown(adapter->vcxn_mngr);
>>> +	idpf_deinit_dflt_mbx(adapter);
>>
>> This is not a straightforward swap, whereas previously we just discard
>> messages knowing that we cannot communicate with the CP in a reset, this
>> goes much further as it dismantles the MBX resources, and as a result the
>> check `if (!is_reset)` in idpf_init_hard_reset() will never be true.
>>
> 
> Thanks for finding this!
> 
> Given the problem seems to only relate to idpf_vc_event_task() in case of
> IDPF_HR_FUNC_RESET and the following call sequence:
> 
> 	idpf_deinit_dflt_mbx(adapter);
> 	set_bit(IDPF_HR_RESET_IN_PROG, adapter->flags);
> 	idpf_init_hard_reset(adapter);
> 		netif_carrier_off();
> 		netif_tx_disable();
> 		is_reset = idpf_is_reset_detected(adapter);
> 		idpf_set_vport_state(adapter);
> 		idpf_vc_core_deinit(adapter);
> 			idpf_deinit_dflt_mbx(adapter);
> 			...
> 		...
> 
> I think, it is safe to remove idpf_deinit_dflt_mbx() from idpf_vc_event_task(),
> given no mailbox communication is attempted in between it and
> idpf_vc_core_deinit(). Anything going on in parallel also should not suffer from
> having mailbox available just a little bit longer.
> 
> What do you think?

I think this will work. The small difference here is that the MBX will 
be disabled a bit later than before. Say there were already messages in 
flight when the reset happened. Previously we flush the MBX and then 
begin to handle the reset. If we remove idpf_deinit_dflt_mbx() from the 
event task the MBX will be disabled as part of the reset handling. FWIW 
I ran a few tests with the change you propose and did not see any issues 
as a result.

Thanks,
Emil

> 
>> <snip>
>>
>> Thanks,
>> Emil
>>


^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2025-06-19  2:57 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-16 14:57 [PATCH iwl-next v4 00/15] Introduce iXD driver Larysa Zaremba
2025-05-16 14:57 ` [PATCH iwl-next v4 01/15] virtchnl: create 'include/linux/intel' and move necessary header files Larysa Zaremba
2025-05-16 14:57 ` [PATCH iwl-next v4 02/15] virtchnl: introduce control plane version fields Larysa Zaremba
2025-05-16 14:58 ` [PATCH iwl-next v4 03/15] libie: add PCI device initialization helpers to libie Larysa Zaremba
2025-05-16 14:58 ` [PATCH iwl-next v4 04/15] libeth: allow to create fill queues without NAPI Larysa Zaremba
2025-05-16 14:58 ` [PATCH iwl-next v4 05/15] libie: add control queue support Larysa Zaremba
2025-05-16 14:58 ` [PATCH iwl-next v4 06/15] libie: add bookkeeping support for control queue messages Larysa Zaremba
2025-05-16 14:58 ` [PATCH iwl-next v4 07/15] idpf: remove 'vport_params_reqd' field Larysa Zaremba
2025-06-10 21:50   ` [Intel-wired-lan] " Salin, Samuel
2025-05-16 14:58 ` [PATCH iwl-next v4 08/15] idpf: refactor idpf to use libie_pci APIs Larysa Zaremba
2025-06-10 21:51   ` [Intel-wired-lan] " Salin, Samuel
2025-05-16 14:58 ` [PATCH iwl-next v4 09/15] idpf: refactor idpf to use libie control queues Larysa Zaremba
2025-06-10 21:51   ` [Intel-wired-lan] " Salin, Samuel
2025-06-18  0:04   ` Tantilov, Emil S
2025-06-18  7:54     ` Larysa Zaremba
2025-06-19  2:57       ` Tantilov, Emil S
2025-05-16 14:58 ` [PATCH iwl-next v4 10/15] idpf: make mbx_task queueing and cancelling more consistent Larysa Zaremba
2025-06-10 21:51   ` [Intel-wired-lan] " Salin, Samuel
2025-05-16 14:58 ` [PATCH iwl-next v4 11/15] idpf: print a debug message and bail in case of non-event ctlq message Larysa Zaremba
2025-06-10 21:53   ` [Intel-wired-lan] " Salin, Samuel
2025-05-16 14:58 ` [PATCH iwl-next v4 12/15] ixd: add basic driver framework for Intel(R) Control Plane Function Larysa Zaremba
2025-05-16 14:58 ` [PATCH iwl-next v4 13/15] ixd: add reset checks and initialize the mailbox Larysa Zaremba
2025-05-16 14:58 ` [PATCH iwl-next v4 14/15] ixd: add the core initialization Larysa Zaremba
2025-05-16 14:58 ` [PATCH iwl-next v4 15/15] ixd: add devlink support Larysa Zaremba

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).