| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/08/12 21:56 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"KMSANReasoning": "",
"NeedsKMSAN": false,
"Reasoning": "The patch introduces a new driver `ixd` for Intel Control Plane Function and refactors the `idpf` driver (Intel Infrastructure Data Path Function) to use common helper modules `libie_cp` and `libie_pci`. Both `ixd` and `idpf` are vendor-specific SmartNIC (Intel IPU) drivers that require physical PCIe hardware cards not emulated in standard QEMU. The changes to other drivers (`i40e`, `iavf`, `ice`) are purely `#include` path updates. Therefore, the functional changes are not reachable in virtualized environments.",
"WorthFuzzing": false
} |
| 1/1 | 2026/08/12 21:56 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 70c3f5eae95ebe97c3f413cd4b978c15b52b382f\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Wed Aug 12 21:56:24 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/Documentation/networking/device_drivers/ethernet/index.rst b/Documentation/networking/device_drivers/ethernet/index.rst\nindex 786a23c84b901..d9980c84487a5 100644\n--- a/Documentation/networking/device_drivers/ethernet/index.rst\n+++ b/Documentation/networking/device_drivers/ethernet/index.rst\n@@ -35,6 +35,7 @@ Contents:\n intel/idpf\n intel/igb\n intel/igbvf\n+ intel/ixd\n intel/ixgbe\n intel/ixgbevf\n intel/i40e\ndiff --git a/Documentation/networking/device_drivers/ethernet/intel/ixd.rst b/Documentation/networking/device_drivers/ethernet/intel/ixd.rst\nnew file mode 100644\nindex 0000000000000..1387626e5d20d\n--- /dev/null\n+++ b/Documentation/networking/device_drivers/ethernet/intel/ixd.rst\n@@ -0,0 +1,39 @@\n+.. SPDX-License-Identifier: GPL-2.0+\n+\n+==========================================================================\n+iXD Linux* Base Driver for the Intel(R) Control Plane Function\n+==========================================================================\n+\n+Intel iXD Linux driver.\n+Copyright(C) 2025 Intel Corporation.\n+\n+.. contents::\n+\n+For questions related to hardware requirements, refer to the documentation\n+supplied with your Intel adapter. All hardware requirements listed apply to use\n+with Linux.\n+\n+\n+Identifying Your Adapter\n+========================\n+For information on how to identify your adapter, and for the latest Intel\n+network drivers, refer to the Intel Support website:\n+http://www.intel.com/support\n+\n+\n+Support\n+=======\n+For general information, go to the Intel support website at:\n+http://www.intel.com/support/\n+\n+If an issue is identified with the released source code on a supported kernel\n+with a supported adapter, email the specific information related to the issue\n+to intel-wired-lan@lists.osuosl.org.\n+\n+\n+Trademarks\n+==========\n+Intel is a trademark or registered trademark of Intel Corporation or its\n+subsidiaries in the United States and/or other countries.\n+\n+* Other names and brands may be claimed as the property of others.\ndiff --git a/Documentation/networking/devlink/index.rst b/Documentation/networking/devlink/index.rst\nindex 4745148fecf4f..d4a83fdcff7fe 100644\n--- a/Documentation/networking/devlink/index.rst\n+++ b/Documentation/networking/devlink/index.rst\n@@ -87,6 +87,7 @@ parameters, info versions, and other features it supports.\n ice\n ionic\n iosm\n+ ixd\n ixgbe\n kvaser_pciefd\n kvaser_usb\ndiff --git a/Documentation/networking/devlink/ixd.rst b/Documentation/networking/devlink/ixd.rst\nnew file mode 100644\nindex 0000000000000..cba4f6f650132\n--- /dev/null\n+++ b/Documentation/networking/devlink/ixd.rst\n@@ -0,0 +1,30 @@\n+.. SPDX-License-Identifier: GPL-2.0\n+\n+===================\n+ixd devlink support\n+===================\n+\n+This document describes the devlink features implemented by the ``ixd``\n+device driver.\n+\n+Info versions\n+=============\n+\n+The ``ixd`` driver reports the following versions\n+\n+.. list-table:: devlink info versions implemented\n+ :widths: 5 5 5 90\n+\n+ * - Name\n+ - Type\n+ - Example\n+ - Description\n+ * - ``device.type``\n+ - fixed\n+ - MEV\n+ - The hardware type for this device\n+ * - ``fw.mgmt.api``\n+ - running\n+ - 2.0\n+ - 2-digit version number (major.minor) of the communication channel\n+ (virtchnl) used by the device.\ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex e0e7fae5b92fb..0f29ea109db5d 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -13033,8 +13033,7 @@ T:\tgit git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue.git\n F:\tDocumentation/networking/device_drivers/ethernet/intel/\n F:\tdrivers/net/ethernet/intel/\n F:\tdrivers/net/ethernet/intel/*/\n-F:\tinclude/linux/avf/virtchnl.h\n-F:\tinclude/linux/net/intel/*/\n+F:\tinclude/linux/net/intel/\n \n INTEL ETHERNET PROTOCOL DRIVER FOR RDMA\n M:\tTatyana Nikolova \u003ctatyana.e.nikolova@intel.com\u003e\ndiff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig\nindex 288fa8ce53af0..780f113986ea8 100644\n--- a/drivers/net/ethernet/intel/Kconfig\n+++ b/drivers/net/ethernet/intel/Kconfig\n@@ -398,4 +398,6 @@ config IGC_LEDS\n \n source \"drivers/net/ethernet/intel/idpf/Kconfig\"\n \n+source \"drivers/net/ethernet/intel/ixd/Kconfig\"\n+\n endif # NET_VENDOR_INTEL\ndiff --git a/drivers/net/ethernet/intel/Makefile b/drivers/net/ethernet/intel/Makefile\nindex 9a37dc76aef0b..08b29f3b68011 100644\n--- a/drivers/net/ethernet/intel/Makefile\n+++ b/drivers/net/ethernet/intel/Makefile\n@@ -19,3 +19,4 @@ obj-$(CONFIG_IAVF) += iavf/\n obj-$(CONFIG_FM10K) += fm10k/\n obj-$(CONFIG_ICE) += ice/\n obj-$(CONFIG_IDPF) += idpf/\n+obj-$(CONFIG_IXD) += ixd/\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h\nindex 83e780919ac97..1b6a8fbaa6485 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e.h\n+++ b/drivers/net/ethernet/intel/i40e/i40e.h\n@@ -8,8 +8,8 @@\n #include \u003clinux/pci.h\u003e\n #include \u003clinux/ptp_clock_kernel.h\u003e\n #include \u003clinux/types.h\u003e\n-#include \u003clinux/avf/virtchnl.h\u003e\n #include \u003clinux/net/intel/i40e_client.h\u003e\n+#include \u003clinux/net/intel/virtchnl.h\u003e\n #include \u003cnet/devlink.h\u003e\n #include \u003cnet/pkt_cls.h\u003e\n #include \u003cnet/udp_tunnel.h\u003e\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c\nindex 59f5c1e810eb0..8dadfef2c09f6 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_common.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c\n@@ -1,10 +1,10 @@\n // SPDX-License-Identifier: GPL-2.0\n /* Copyright(c) 2013 - 2021 Intel Corporation. */\n \n-#include \u003clinux/avf/virtchnl.h\u003e\n #include \u003clinux/bitfield.h\u003e\n #include \u003clinux/delay.h\u003e\n #include \u003clinux/etherdevice.h\u003e\n+#include \u003clinux/net/intel/virtchnl.h\u003e\n #include \u003clinux/pci.h\u003e\n #include \"i40e_adminq_cmd.h\"\n #include \"i40e_devids.h\"\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h\nindex 26bb7bffe3610..e3d57550090ec 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n+++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n@@ -5,7 +5,7 @@\n #define _I40E_PROTOTYPE_H_\n \n #include \u003clinux/ethtool.h\u003e\n-#include \u003clinux/avf/virtchnl.h\u003e\n+#include \u003clinux/net/intel/virtchnl.h\u003e\n #include \"i40e_debug.h\"\n #include \"i40e_type.h\"\n \ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h\nindex f558b45725c81..4e119c0502f34 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h\n+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h\n@@ -4,7 +4,7 @@\n #ifndef _I40E_VIRTCHNL_PF_H_\n #define _I40E_VIRTCHNL_PF_H_\n \n-#include \u003clinux/avf/virtchnl.h\u003e\n+#include \u003clinux/net/intel/virtchnl.h\u003e\n #include \u003clinux/netdevice.h\u003e\n #include \"i40e_type.h\"\n \ndiff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h\nindex 050f8241ef5e6..dc31202b2a946 100644\n--- a/drivers/net/ethernet/intel/iavf/iavf.h\n+++ b/drivers/net/ethernet/intel/iavf/iavf.h\n@@ -27,6 +27,7 @@\n #include \u003clinux/etherdevice.h\u003e\n #include \u003clinux/socket.h\u003e\n #include \u003clinux/jiffies.h\u003e\n+#include \u003clinux/net/intel/virtchnl.h\u003e\n #include \u003cnet/ip6_checksum.h\u003e\n #include \u003cnet/pkt_cls.h\u003e\n #include \u003cnet/pkt_sched.h\u003e\n@@ -37,7 +38,6 @@\n #include \u003cnet/net_shaper.h\u003e\n \n #include \"iavf_type.h\"\n-#include \u003clinux/avf/virtchnl.h\u003e\n #include \"iavf_txrx.h\"\n #include \"iavf_fdir.h\"\n #include \"iavf_adv_rss.h\"\ndiff --git a/drivers/net/ethernet/intel/iavf/iavf_common.c b/drivers/net/ethernet/intel/iavf/iavf_common.c\nindex 614a886bca99b..277193a97d910 100644\n--- a/drivers/net/ethernet/intel/iavf/iavf_common.c\n+++ b/drivers/net/ethernet/intel/iavf/iavf_common.c\n@@ -1,7 +1,7 @@\n // SPDX-License-Identifier: GPL-2.0\n /* Copyright(c) 2013 - 2018 Intel Corporation. */\n \n-#include \u003clinux/avf/virtchnl.h\u003e\n+#include \u003clinux/net/intel/virtchnl.h\u003e\n #include \u003clinux/bitfield.h\u003e\n #include \"iavf_type.h\"\n #include \"iavf_adminq.h\"\ndiff --git a/drivers/net/ethernet/intel/iavf/iavf_prototype.h b/drivers/net/ethernet/intel/iavf/iavf_prototype.h\nindex 7f9f9dbf959ac..1b1f6ede39208 100644\n--- a/drivers/net/ethernet/intel/iavf/iavf_prototype.h\n+++ b/drivers/net/ethernet/intel/iavf/iavf_prototype.h\n@@ -4,9 +4,10 @@\n #ifndef _IAVF_PROTOTYPE_H_\n #define _IAVF_PROTOTYPE_H_\n \n+#include \u003clinux/net/intel/virtchnl.h\u003e\n+\n #include \"iavf_type.h\"\n #include \"iavf_alloc.h\"\n-#include \u003clinux/avf/virtchnl.h\u003e\n \n /* Prototypes for shared code functions that are not in\n * the standard function pointer structures. These are\ndiff --git a/drivers/net/ethernet/intel/iavf/iavf_types.h b/drivers/net/ethernet/intel/iavf/iavf_types.h\nindex a095855122bf2..35d6d8fcca044 100644\n--- a/drivers/net/ethernet/intel/iavf/iavf_types.h\n+++ b/drivers/net/ethernet/intel/iavf/iavf_types.h\n@@ -4,9 +4,7 @@\n #ifndef _IAVF_TYPES_H_\n #define _IAVF_TYPES_H_\n \n-#include \"iavf_types.h\"\n-\n-#include \u003clinux/avf/virtchnl.h\u003e\n+#include \u003clinux/net/intel/virtchnl.h\u003e\n #include \u003clinux/ptp_clock_kernel.h\u003e\n \n /* structure used to queue PTP commands for processing */\ndiff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h\nindex fc91b6665f905..db3c7015c56c4 100644\n--- a/drivers/net/ethernet/intel/ice/ice.h\n+++ b/drivers/net/ethernet/intel/ice/ice.h\n@@ -36,7 +36,7 @@\n #include \u003clinux/bpf.h\u003e\n #include \u003clinux/btf.h\u003e\n #include \u003clinux/auxiliary_bus.h\u003e\n-#include \u003clinux/avf/virtchnl.h\u003e\n+#include \u003clinux/net/intel/virtchnl.h\u003e\n #include \u003clinux/cpu_rmap.h\u003e\n #include \u003clinux/dim.h\u003e\n #include \u003clinux/gnss.h\u003e\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h\nindex 9f53442121955..d1d674ca644f6 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.h\n+++ b/drivers/net/ethernet/intel/ice/ice_common.h\n@@ -5,13 +5,13 @@\n #define _ICE_COMMON_H_\n \n #include \u003clinux/bitfield.h\u003e\n+#include \u003clinux/net/intel/virtchnl.h\u003e\n \n #include \"ice.h\"\n #include \"ice_type.h\"\n #include \"ice_nvm.h\"\n #include \"ice_flex_pipe.h\"\n #include \"ice_parser.h\"\n-#include \u003clinux/avf/virtchnl.h\u003e\n #include \"ice_switch.h\"\n #include \"ice_fdir.h\"\n \ndiff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h\nindex 7a9c75d1d07cb..fa436b3b1eac2 100644\n--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h\n+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h\n@@ -8,9 +8,9 @@\n #include \u003clinux/hashtable.h\u003e\n #include \u003clinux/bitmap.h\u003e\n #include \u003clinux/mutex.h\u003e\n+#include \u003clinux/net/intel/virtchnl.h\u003e\n #include \u003clinux/pci.h\u003e\n #include \u003cnet/devlink.h\u003e\n-#include \u003clinux/avf/virtchnl.h\u003e\n #include \"ice_type.h\"\n #include \"ice_flow.h\"\n #include \"virt/fdir.h\"\ndiff --git a/drivers/net/ethernet/intel/ice/virt/virtchnl.h b/drivers/net/ethernet/intel/ice/virt/virtchnl.h\nindex 71bb456e2d71a..d11789b3ae1f0 100644\n--- a/drivers/net/ethernet/intel/ice/virt/virtchnl.h\n+++ b/drivers/net/ethernet/intel/ice/virt/virtchnl.h\n@@ -7,7 +7,7 @@\n #include \u003clinux/types.h\u003e\n #include \u003clinux/bitops.h\u003e\n #include \u003clinux/if_ether.h\u003e\n-#include \u003clinux/avf/virtchnl.h\u003e\n+#include \u003clinux/net/intel/virtchnl.h\u003e\n #include \"ice_vf_lib.h\"\n \n /* Restrict number of MAC Addr and VLAN that non-trusted VF can programmed */\ndiff --git a/drivers/net/ethernet/intel/idpf/Kconfig b/drivers/net/ethernet/intel/idpf/Kconfig\nindex adab2154125ba..586df3a4afe90 100644\n--- a/drivers/net/ethernet/intel/idpf/Kconfig\n+++ b/drivers/net/ethernet/intel/idpf/Kconfig\n@@ -6,6 +6,7 @@ config IDPF\n \tdepends on PCI_MSI\n \tdepends on PTP_1588_CLOCK_OPTIONAL\n \tselect DIMLIB\n+\tselect LIBIE_CP\n \tselect LIBETH_XDP\n \thelp\n \t This driver supports Intel(R) Infrastructure Data Path Function\ndiff --git a/drivers/net/ethernet/intel/idpf/Makefile b/drivers/net/ethernet/intel/idpf/Makefile\nindex 651ddee942bd8..4aaafa175ec37 100644\n--- a/drivers/net/ethernet/intel/idpf/Makefile\n+++ b/drivers/net/ethernet/intel/idpf/Makefile\n@@ -6,8 +6,6 @@\n obj-$(CONFIG_IDPF) += idpf.o\n \n idpf-y := \\\n-\tidpf_controlq.o\t\t\\\n-\tidpf_controlq_setup.o\t\\\n \tidpf_dev.o\t\t\\\n \tidpf_ethtool.o\t\t\\\n \tidpf_idc.o\t\t\\\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h\nindex ec1b75f039bb2..470bc23c844c1 100644\n--- a/drivers/net/ethernet/intel/idpf/idpf.h\n+++ b/drivers/net/ethernet/intel/idpf/idpf.h\n@@ -23,10 +23,10 @@ struct idpf_rss_data;\n \n #include \u003clinux/net/intel/iidc_rdma.h\u003e\n #include \u003clinux/net/intel/iidc_rdma_idpf.h\u003e\n+#include \u003clinux/net/intel/libie/controlq.h\u003e\n+#include \u003clinux/net/intel/virtchnl2.h\u003e\n \n-#include \"virtchnl2.h\"\n #include \"idpf_txrx.h\"\n-#include \"idpf_controlq.h\"\n \n #define GETMAXVAL(num_bits)\t\tGENMASK((num_bits) - 1, 0)\n \n@@ -36,11 +36,10 @@ struct idpf_rss_data;\n #define IDPF_NUM_FILTERS_PER_MSG\t20\n #define IDPF_NUM_DFLT_MBX_Q\t\t2\t/* includes both TX and RX */\n #define IDPF_DFLT_MBX_Q_LEN\t\t64\n-#define IDPF_DFLT_MBX_ID\t\t-1\n /* maximum number of times to try before resetting mailbox */\n #define IDPF_MB_MAX_ERR\t\t\t20\n #define IDPF_NUM_CHUNKS_PER_MSG(struct_sz, chunk_sz)\t\\\n-\t((IDPF_CTLQ_MAX_BUF_LEN - (struct_sz)) / (chunk_sz))\n+\t((LIBIE_CTLQ_MAX_BUF_LEN - (struct_sz)) / (chunk_sz))\n \n #define IDPF_WAIT_FOR_MARKER_TIMEO\t500\n #define IDPF_MAX_WAIT\t\t\t500\n@@ -201,8 +200,8 @@ struct idpf_vport_max_q {\n * @ptp_reg_init: PTP register initialization\n */\n struct idpf_reg_ops {\n-\tvoid (*ctlq_reg_init)(struct idpf_adapter *adapter,\n-\t\t\t struct idpf_ctlq_create_info *cq);\n+\tvoid (*ctlq_reg_init)(struct libie_mmio_info *mmio,\n+\t\t\t struct libie_ctlq_create_info *cctlq_info);\n \tint (*intr_reg_init)(struct idpf_vport *vport,\n \t\t\t struct idpf_q_vec_rsrc *rsrc);\n \tvoid (*mb_intr_reg_init)(struct idpf_adapter *adapter);\n@@ -605,8 +604,6 @@ struct idpf_vport_config {\n \tDECLARE_BITMAP(flags, IDPF_VPORT_CONFIG_FLAGS_NBITS);\n };\n \n-struct idpf_vc_xn_manager;\n-\n #define idpf_for_each_vport(adapter, iter) \\\n \tfor (struct idpf_vport **__##iter = \u0026(adapter)-\u003evports[0], \\\n \t *iter = (adapter)-\u003emax_vports ? *__##iter : NULL; \\\n@@ -624,7 +621,10 @@ struct idpf_vc_xn_manager;\n * @state: Init state machine\n * @flags: See enum idpf_flags\n * @reset_reg: See struct idpf_reset_reg\n- * @hw: Device access data\n+ * @ctlq_ctx: controlq context\n+ * @asq: Send control queue info\n+ * @arq: Receive control queue info\n+ * @xnm: Xn transaction manager\n * @num_avail_msix: Available number of MSIX vectors\n * @num_msix_entries: Number of entries in MSIX table\n * @msix_entries: MSIX table\n@@ -638,7 +638,6 @@ struct idpf_vc_xn_manager;\n * @avail_queues: Device given queue limits\n * @vports: Array to store vports created by the driver\n * @netdevs: Associated Vport netdevs\n- * @vport_params_reqd: Vport params requested\n * @vport_params_recvd: Vport params received\n * @vport_ids: Array of device given vport identifiers\n * @singleq_pt_lkup: Lookup table for singleq RX ptypes\n@@ -658,7 +657,6 @@ struct idpf_vc_xn_manager;\n * @stats_task: Periodic statistics retrieval task\n * @stats_wq: Workqueue for statistics task\n * @caps: Negotiated capabilities with device\n- * @vcxn_mngr: Virtchnl transaction manager\n * @dev_ops: See idpf_dev_ops\n * @cdev_info: IDC core device info pointer\n * @num_vfs: Number of allocated VFs through sysfs. PF does not directly talk\n@@ -682,7 +680,10 @@ struct idpf_adapter {\n \tenum idpf_state state;\n \tDECLARE_BITMAP(flags, IDPF_FLAGS_NBITS);\n \tstruct idpf_reset_reg reset_reg;\n-\tstruct idpf_hw hw;\n+\tstruct libie_ctlq_ctx ctlq_ctx;\n+\tstruct libie_ctlq_info *asq;\n+\tstruct libie_ctlq_info *arq;\n+\tstruct libie_ctlq_xn_manager *xnm;\n \tu16 num_avail_msix;\n \tu16 num_msix_entries;\n \tstruct msix_entry *msix_entries;\n@@ -697,7 +698,6 @@ struct idpf_adapter {\n \tstruct idpf_avail_queue_info avail_queues;\n \tstruct idpf_vport **vports;\n \tstruct net_device **netdevs;\n-\tstruct virtchnl2_create_vport **vport_params_reqd;\n \tstruct virtchnl2_create_vport **vport_params_recvd;\n \tu32 *vport_ids;\n \n@@ -720,7 +720,6 @@ struct idpf_adapter {\n \tstruct delayed_work stats_task;\n \tstruct workqueue_struct *stats_wq;\n \tstruct virtchnl2_get_capabilities caps;\n-\tstruct idpf_vc_xn_manager *vcxn_mngr;\n \n \tstruct idpf_dev_ops dev_ops;\n \tstruct iidc_rdma_core_dev_info *cdev_info;\n@@ -872,70 +871,6 @@ static inline u8 idpf_get_min_tx_pkt_len(struct idpf_adapter *adapter)\n \treturn pkt_len ? pkt_len : IDPF_TX_MIN_PKT_LEN;\n }\n \n-/**\n- * idpf_get_mbx_reg_addr - Get BAR0 mailbox register address\n- * @adapter: private data struct\n- * @reg_offset: register offset value\n- *\n- * Return: BAR0 mailbox register address based on register offset.\n- */\n-static inline void __iomem *idpf_get_mbx_reg_addr(struct idpf_adapter *adapter,\n-\t\t\t\t\t\t resource_size_t reg_offset)\n-{\n-\treturn adapter-\u003ehw.mbx.vaddr + reg_offset;\n-}\n-\n-/**\n- * idpf_get_rstat_reg_addr - Get BAR0 rstat register address\n- * @adapter: private data struct\n- * @reg_offset: register offset value\n- *\n- * Return: BAR0 rstat register address based on register offset.\n- */\n-static inline void __iomem *idpf_get_rstat_reg_addr(struct idpf_adapter *adapter,\n-\t\t\t\t\t\t resource_size_t reg_offset)\n-{\n-\treg_offset -= adapter-\u003edev_ops.static_reg_info[1].start;\n-\n-\treturn adapter-\u003ehw.rstat.vaddr + reg_offset;\n-}\n-\n-/**\n- * idpf_get_reg_addr - Get BAR0 register address\n- * @adapter: private data struct\n- * @reg_offset: register offset value\n- *\n- * Based on the register offset, return the actual BAR0 register address\n- */\n-static inline void __iomem *idpf_get_reg_addr(struct idpf_adapter *adapter,\n-\t\t\t\t\t resource_size_t reg_offset)\n-{\n-\tstruct idpf_hw *hw = \u0026adapter-\u003ehw;\n-\n-\tfor (int i = 0; i \u003c hw-\u003enum_lan_regs; i++) {\n-\t\tstruct idpf_mmio_reg *region = \u0026hw-\u003elan_regs[i];\n-\n-\t\tif (reg_offset \u003e= region-\u003eaddr_start \u0026\u0026\n-\t\t reg_offset \u003c (region-\u003eaddr_start + region-\u003eaddr_len)) {\n-\t\t\t/* Convert the offset so that it is relative to the\n-\t\t\t * start of the region. Then add the base address of\n-\t\t\t * the region to get the final address.\n-\t\t\t */\n-\t\t\treg_offset -= region-\u003eaddr_start;\n-\n-\t\t\treturn region-\u003evaddr + reg_offset;\n-\t\t}\n-\t}\n-\n-\t/* It's impossible to hit this case with offsets from the CP. But if we\n-\t * do for any other reason, the kernel will panic on that register\n-\t * access. Might as well do it here to make it clear what's happening.\n-\t */\n-\tBUG();\n-\n-\treturn NULL;\n-}\n-\n /**\n * idpf_is_reset_detected - check if we were reset at some point\n * @adapter: driver specific private structure\n@@ -944,11 +879,12 @@ static inline void __iomem *idpf_get_reg_addr(struct idpf_adapter *adapter,\n */\n static inline bool idpf_is_reset_detected(struct idpf_adapter *adapter)\n {\n-\tif (!adapter-\u003ehw.arq)\n+\tstruct libie_ctlq_info *arq = adapter-\u003earq;\n+\n+\tif (!arq)\n \t\treturn true;\n \n-\treturn !(readl(idpf_get_mbx_reg_addr(adapter, adapter-\u003ehw.arq-\u003ereg.len)) \u0026\n-\t\t adapter-\u003ehw.arq-\u003ereg.len_mask);\n+\treturn !(readl(arq-\u003ereg.len) \u0026 arq-\u003ereg.len_mask);\n }\n \n /**\n@@ -1048,6 +984,7 @@ void idpf_vc_event_task(struct work_struct *work);\n void idpf_dev_ops_init(struct idpf_adapter *adapter);\n void idpf_vf_dev_ops_init(struct idpf_adapter *adapter);\n int idpf_intr_req(struct idpf_adapter *adapter);\n+void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter);\n void idpf_intr_rel(struct idpf_adapter *adapter);\n u16 idpf_get_max_tx_hdr_size(struct idpf_adapter *adapter);\n int idpf_initiate_soft_reset(struct idpf_vport *vport,\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq.c b/drivers/net/ethernet/intel/idpf/idpf_controlq.c\ndeleted file mode 100644\nindex d2dde43269e9e..0000000000000\n--- a/drivers/net/ethernet/intel/idpf/idpf_controlq.c\n+++ /dev/null\n@@ -1,621 +0,0 @@\n-// SPDX-License-Identifier: GPL-2.0-only\n-/* Copyright (C) 2023 Intel Corporation */\n-\n-#include \"idpf_controlq.h\"\n-\n-/**\n- * idpf_ctlq_setup_regs - initialize control queue registers\n- * @cq: pointer to the specific control queue\n- * @q_create_info: structs containing info for each queue to be initialized\n- */\n-static void idpf_ctlq_setup_regs(struct idpf_ctlq_info *cq,\n-\t\t\t\t struct idpf_ctlq_create_info *q_create_info)\n-{\n-\t/* set control queue registers in our local struct */\n-\tcq-\u003ereg.head = q_create_info-\u003ereg.head;\n-\tcq-\u003ereg.tail = q_create_info-\u003ereg.tail;\n-\tcq-\u003ereg.len = q_create_info-\u003ereg.len;\n-\tcq-\u003ereg.bah = q_create_info-\u003ereg.bah;\n-\tcq-\u003ereg.bal = q_create_info-\u003ereg.bal;\n-\tcq-\u003ereg.len_mask = q_create_info-\u003ereg.len_mask;\n-\tcq-\u003ereg.len_ena_mask = q_create_info-\u003ereg.len_ena_mask;\n-\tcq-\u003ereg.head_mask = q_create_info-\u003ereg.head_mask;\n-}\n-\n-/**\n- * idpf_ctlq_init_regs - Initialize control queue registers\n- * @hw: pointer to hw struct\n- * @cq: pointer to the specific Control queue\n- * @is_rxq: true if receive control queue, false otherwise\n- *\n- * Initialize registers. The caller is expected to have already initialized the\n- * descriptor ring memory and buffer memory\n- */\n-static void idpf_ctlq_init_regs(struct idpf_hw *hw, struct idpf_ctlq_info *cq,\n-\t\t\t\tbool is_rxq)\n-{\n-\t/* Update tail to post pre-allocated buffers for rx queues */\n-\tif (is_rxq)\n-\t\tidpf_mbx_wr32(hw, cq-\u003ereg.tail, (u32)(cq-\u003ering_size - 1));\n-\n-\t/* For non-Mailbox control queues only TAIL need to be set */\n-\tif (cq-\u003eq_id != -1)\n-\t\treturn;\n-\n-\t/* Clear Head for both send or receive */\n-\tidpf_mbx_wr32(hw, cq-\u003ereg.head, 0);\n-\n-\t/* set starting point */\n-\tidpf_mbx_wr32(hw, cq-\u003ereg.bal, lower_32_bits(cq-\u003edesc_ring.pa));\n-\tidpf_mbx_wr32(hw, cq-\u003ereg.bah, upper_32_bits(cq-\u003edesc_ring.pa));\n-\tidpf_mbx_wr32(hw, cq-\u003ereg.len, (cq-\u003ering_size | cq-\u003ereg.len_ena_mask));\n-}\n-\n-/**\n- * idpf_ctlq_init_rxq_bufs - populate receive queue descriptors with buf\n- * @cq: pointer to the specific Control queue\n- *\n- * Record the address of the receive queue DMA buffers in the descriptors.\n- * The buffers must have been previously allocated.\n- */\n-static void idpf_ctlq_init_rxq_bufs(struct idpf_ctlq_info *cq)\n-{\n-\tint i;\n-\n-\tfor (i = 0; i \u003c cq-\u003ering_size; i++) {\n-\t\tstruct idpf_ctlq_desc *desc = IDPF_CTLQ_DESC(cq, i);\n-\t\tstruct idpf_dma_mem *bi = cq-\u003ebi.rx_buff[i];\n-\n-\t\t/* No buffer to post to descriptor, continue */\n-\t\tif (!bi)\n-\t\t\tcontinue;\n-\n-\t\tdesc-\u003eflags =\n-\t\t\tcpu_to_le16(IDPF_CTLQ_FLAG_BUF | IDPF_CTLQ_FLAG_RD);\n-\t\tdesc-\u003eopcode = 0;\n-\t\tdesc-\u003edatalen = cpu_to_le16(bi-\u003esize);\n-\t\tdesc-\u003eret_val = 0;\n-\t\tdesc-\u003ev_opcode_dtype = 0;\n-\t\tdesc-\u003ev_retval = 0;\n-\t\tdesc-\u003eparams.indirect.addr_high =\n-\t\t\tcpu_to_le32(upper_32_bits(bi-\u003epa));\n-\t\tdesc-\u003eparams.indirect.addr_low =\n-\t\t\tcpu_to_le32(lower_32_bits(bi-\u003epa));\n-\t\tdesc-\u003eparams.indirect.param0 = 0;\n-\t\tdesc-\u003eparams.indirect.sw_cookie = 0;\n-\t\tdesc-\u003eparams.indirect.v_flags = 0;\n-\t}\n-}\n-\n-/**\n- * idpf_ctlq_shutdown - shutdown the CQ\n- * @hw: pointer to hw struct\n- * @cq: pointer to the specific Control queue\n- *\n- * The main shutdown routine for any controq queue\n- */\n-static void idpf_ctlq_shutdown(struct idpf_hw *hw, struct idpf_ctlq_info *cq)\n-{\n-\tspin_lock(\u0026cq-\u003ecq_lock);\n-\n-\t/* free ring buffers and the ring itself */\n-\tidpf_ctlq_dealloc_ring_res(hw, cq);\n-\n-\t/* Set ring_size to 0 to indicate uninitialized queue */\n-\tcq-\u003ering_size = 0;\n-\n-\tspin_unlock(\u0026cq-\u003ecq_lock);\n-}\n-\n-/**\n- * idpf_ctlq_add - add one control queue\n- * @hw: pointer to hardware struct\n- * @qinfo: info for queue to be created\n- * @cq_out: (output) double pointer to control queue to be created\n- *\n- * Allocate and initialize a control queue and add it to the control queue list.\n- * The cq parameter will be allocated/initialized and passed back to the caller\n- * if no errors occur.\n- *\n- * Note: idpf_ctlq_init must be called prior to any calls to idpf_ctlq_add\n- */\n-int idpf_ctlq_add(struct idpf_hw *hw,\n-\t\t struct idpf_ctlq_create_info *qinfo,\n-\t\t struct idpf_ctlq_info **cq_out)\n-{\n-\tstruct idpf_ctlq_info *cq;\n-\tbool is_rxq = false;\n-\tint err;\n-\n-\tcq = kzalloc_obj(*cq);\n-\tif (!cq)\n-\t\treturn -ENOMEM;\n-\n-\tcq-\u003ecq_type = qinfo-\u003etype;\n-\tcq-\u003eq_id = qinfo-\u003eid;\n-\tcq-\u003ebuf_size = qinfo-\u003ebuf_size;\n-\tcq-\u003ering_size = qinfo-\u003elen;\n-\n-\tcq-\u003enext_to_use = 0;\n-\tcq-\u003enext_to_clean = 0;\n-\tcq-\u003enext_to_post = cq-\u003ering_size - 1;\n-\n-\tswitch (qinfo-\u003etype) {\n-\tcase IDPF_CTLQ_TYPE_MAILBOX_RX:\n-\t\tis_rxq = true;\n-\t\tfallthrough;\n-\tcase IDPF_CTLQ_TYPE_MAILBOX_TX:\n-\t\terr = idpf_ctlq_alloc_ring_res(hw, cq);\n-\t\tbreak;\n-\tdefault:\n-\t\terr = -EBADR;\n-\t\tbreak;\n-\t}\n-\n-\tif (err)\n-\t\tgoto init_free_q;\n-\n-\tif (is_rxq) {\n-\t\tidpf_ctlq_init_rxq_bufs(cq);\n-\t} else {\n-\t\t/* Allocate the array of msg pointers for TX queues */\n-\t\tcq-\u003ebi.tx_msg = kzalloc_objs(struct idpf_ctlq_msg *, qinfo-\u003elen);\n-\t\tif (!cq-\u003ebi.tx_msg) {\n-\t\t\terr = -ENOMEM;\n-\t\t\tgoto init_dealloc_q_mem;\n-\t\t}\n-\t}\n-\n-\tidpf_ctlq_setup_regs(cq, qinfo);\n-\n-\tidpf_ctlq_init_regs(hw, cq, is_rxq);\n-\n-\tspin_lock_init(\u0026cq-\u003ecq_lock);\n-\n-\tlist_add(\u0026cq-\u003ecq_list, \u0026hw-\u003ecq_list_head);\n-\n-\t*cq_out = cq;\n-\n-\treturn 0;\n-\n-init_dealloc_q_mem:\n-\t/* free ring buffers and the ring itself */\n-\tidpf_ctlq_dealloc_ring_res(hw, cq);\n-init_free_q:\n-\tkfree(cq);\n-\n-\treturn err;\n-}\n-\n-/**\n- * idpf_ctlq_remove - deallocate and remove specified control queue\n- * @hw: pointer to hardware struct\n- * @cq: pointer to control queue to be removed\n- */\n-void idpf_ctlq_remove(struct idpf_hw *hw,\n-\t\t struct idpf_ctlq_info *cq)\n-{\n-\tlist_del(\u0026cq-\u003ecq_list);\n-\tidpf_ctlq_shutdown(hw, cq);\n-\tkfree(cq);\n-}\n-\n-/**\n- * idpf_ctlq_init - main initialization routine for all control queues\n- * @hw: pointer to hardware struct\n- * @num_q: number of queues to initialize\n- * @q_info: array of structs containing info for each queue to be initialized\n- *\n- * This initializes any number and any type of control queues. This is an all\n- * or nothing routine; if one fails, all previously allocated queues will be\n- * destroyed. This must be called prior to using the individual add/remove\n- * APIs.\n- */\n-int idpf_ctlq_init(struct idpf_hw *hw, u8 num_q,\n-\t\t struct idpf_ctlq_create_info *q_info)\n-{\n-\tstruct idpf_ctlq_info *cq, *tmp;\n-\tint err;\n-\tint i;\n-\n-\tINIT_LIST_HEAD(\u0026hw-\u003ecq_list_head);\n-\n-\tfor (i = 0; i \u003c num_q; i++) {\n-\t\tstruct idpf_ctlq_create_info *qinfo = q_info + i;\n-\n-\t\terr = idpf_ctlq_add(hw, qinfo, \u0026cq);\n-\t\tif (err)\n-\t\t\tgoto init_destroy_qs;\n-\t}\n-\n-\treturn 0;\n-\n-init_destroy_qs:\n-\tlist_for_each_entry_safe(cq, tmp, \u0026hw-\u003ecq_list_head, cq_list)\n-\t\tidpf_ctlq_remove(hw, cq);\n-\n-\treturn err;\n-}\n-\n-/**\n- * idpf_ctlq_deinit - destroy all control queues\n- * @hw: pointer to hw struct\n- */\n-void idpf_ctlq_deinit(struct idpf_hw *hw)\n-{\n-\tstruct idpf_ctlq_info *cq, *tmp;\n-\n-\tlist_for_each_entry_safe(cq, tmp, \u0026hw-\u003ecq_list_head, cq_list)\n-\t\tidpf_ctlq_remove(hw, cq);\n-}\n-\n-/**\n- * idpf_ctlq_send - send command to Control Queue (CTQ)\n- * @hw: pointer to hw struct\n- * @cq: handle to control queue struct to send on\n- * @num_q_msg: number of messages to send on control queue\n- * @q_msg: pointer to array of queue messages to be sent\n- *\n- * The caller is expected to allocate DMAable buffers and pass them to the\n- * send routine via the q_msg struct / control queue specific data struct.\n- * The control queue will hold a reference to each send message until\n- * the completion for that message has been cleaned.\n- */\n-int idpf_ctlq_send(struct idpf_hw *hw, struct idpf_ctlq_info *cq,\n-\t\t u16 num_q_msg, struct idpf_ctlq_msg q_msg[])\n-{\n-\tstruct idpf_ctlq_desc *desc;\n-\tint num_desc_avail;\n-\tint err = 0;\n-\tint i;\n-\n-\tspin_lock(\u0026cq-\u003ecq_lock);\n-\n-\t/* Ensure there are enough descriptors to send all messages */\n-\tnum_desc_avail = IDPF_CTLQ_DESC_UNUSED(cq);\n-\tif (num_desc_avail == 0 || num_desc_avail \u003c num_q_msg) {\n-\t\terr = -ENOSPC;\n-\t\tgoto err_unlock;\n-\t}\n-\n-\tfor (i = 0; i \u003c num_q_msg; i++) {\n-\t\tstruct idpf_ctlq_msg *msg = \u0026q_msg[i];\n-\n-\t\tdesc = IDPF_CTLQ_DESC(cq, cq-\u003enext_to_use);\n-\n-\t\tdesc-\u003eopcode = cpu_to_le16(msg-\u003eopcode);\n-\t\tdesc-\u003epfid_vfid = cpu_to_le16(msg-\u003efunc_id);\n-\n-\t\tdesc-\u003ev_opcode_dtype = cpu_to_le32(msg-\u003ecookie.mbx.chnl_opcode);\n-\t\tdesc-\u003ev_retval = cpu_to_le32(msg-\u003ecookie.mbx.chnl_retval);\n-\n-\t\tdesc-\u003eflags = cpu_to_le16((msg-\u003ehost_id \u0026 IDPF_HOST_ID_MASK) \u003c\u003c\n-\t\t\t\t\t IDPF_CTLQ_FLAG_HOST_ID_S);\n-\t\tif (msg-\u003edata_len) {\n-\t\t\tstruct idpf_dma_mem *buff = msg-\u003ectx.indirect.payload;\n-\n-\t\t\tdesc-\u003edatalen |= cpu_to_le16(msg-\u003edata_len);\n-\t\t\tdesc-\u003eflags |= cpu_to_le16(IDPF_CTLQ_FLAG_BUF);\n-\t\t\tdesc-\u003eflags |= cpu_to_le16(IDPF_CTLQ_FLAG_RD);\n-\n-\t\t\t/* Update the address values in the desc with the pa\n-\t\t\t * value for respective buffer\n-\t\t\t */\n-\t\t\tdesc-\u003eparams.indirect.addr_high =\n-\t\t\t\tcpu_to_le32(upper_32_bits(buff-\u003epa));\n-\t\t\tdesc-\u003eparams.indirect.addr_low =\n-\t\t\t\tcpu_to_le32(lower_32_bits(buff-\u003epa));\n-\n-\t\t\tmemcpy(\u0026desc-\u003eparams, msg-\u003ectx.indirect.context,\n-\t\t\t IDPF_INDIRECT_CTX_SIZE);\n-\t\t} else {\n-\t\t\tmemcpy(\u0026desc-\u003eparams, msg-\u003ectx.direct,\n-\t\t\t IDPF_DIRECT_CTX_SIZE);\n-\t\t}\n-\n-\t\t/* Store buffer info */\n-\t\tcq-\u003ebi.tx_msg[cq-\u003enext_to_use] = msg;\n-\n-\t\t(cq-\u003enext_to_use)++;\n-\t\tif (cq-\u003enext_to_use == cq-\u003ering_size)\n-\t\t\tcq-\u003enext_to_use = 0;\n-\t}\n-\n-\t/* Force memory write to complete before letting hardware\n-\t * know that there are new descriptors to fetch.\n-\t */\n-\tdma_wmb();\n-\n-\tidpf_mbx_wr32(hw, cq-\u003ereg.tail, cq-\u003enext_to_use);\n-\n-err_unlock:\n-\tspin_unlock(\u0026cq-\u003ecq_lock);\n-\n-\treturn err;\n-}\n-\n-/**\n- * idpf_ctlq_clean_sq - reclaim send descriptors on HW write back for the\n- * requested queue\n- * @cq: pointer to the specific Control queue\n- * @clean_count: (input|output) number of descriptors to clean as input, and\n- * number of descriptors actually cleaned as output\n- * @msg_status: (output) pointer to msg pointer array to be populated; needs\n- * to be allocated by caller\n- *\n- * Returns an array of message pointers associated with the cleaned\n- * descriptors. The pointers are to the original ctlq_msgs sent on the cleaned\n- * descriptors. The status will be returned for each; any messages that failed\n- * to send will have a non-zero status. The caller is expected to free original\n- * ctlq_msgs and free or reuse the DMA buffers.\n- */\n-int idpf_ctlq_clean_sq(struct idpf_ctlq_info *cq, u16 *clean_count,\n-\t\t struct idpf_ctlq_msg *msg_status[])\n-{\n-\tstruct idpf_ctlq_desc *desc;\n-\tu16 i, num_to_clean;\n-\tu16 ntc, desc_err;\n-\n-\tif (*clean_count == 0)\n-\t\treturn 0;\n-\tif (*clean_count \u003e cq-\u003ering_size)\n-\t\treturn -EBADR;\n-\n-\tspin_lock(\u0026cq-\u003ecq_lock);\n-\n-\tntc = cq-\u003enext_to_clean;\n-\n-\tnum_to_clean = *clean_count;\n-\n-\tfor (i = 0; i \u003c num_to_clean; i++) {\n-\t\t/* Fetch next descriptor and check if marked as done */\n-\t\tdesc = IDPF_CTLQ_DESC(cq, ntc);\n-\t\tif (!(le16_to_cpu(desc-\u003eflags) \u0026 IDPF_CTLQ_FLAG_DD))\n-\t\t\tbreak;\n-\n-\t\t/* Ensure no other fields are read until DD flag is checked */\n-\t\tdma_rmb();\n-\n-\t\t/* strip off FW internal code */\n-\t\tdesc_err = le16_to_cpu(desc-\u003eret_val) \u0026 0xff;\n-\n-\t\tmsg_status[i] = cq-\u003ebi.tx_msg[ntc];\n-\t\tmsg_status[i]-\u003estatus = desc_err;\n-\n-\t\tcq-\u003ebi.tx_msg[ntc] = NULL;\n-\n-\t\t/* Zero out any stale data */\n-\t\tmemset(desc, 0, sizeof(*desc));\n-\n-\t\tntc++;\n-\t\tif (ntc == cq-\u003ering_size)\n-\t\t\tntc = 0;\n-\t}\n-\n-\tcq-\u003enext_to_clean = ntc;\n-\n-\tspin_unlock(\u0026cq-\u003ecq_lock);\n-\n-\t/* Return number of descriptors actually cleaned */\n-\t*clean_count = i;\n-\n-\treturn 0;\n-}\n-\n-/**\n- * idpf_ctlq_post_rx_buffs - post buffers to descriptor ring\n- * @hw: pointer to hw struct\n- * @cq: pointer to control queue handle\n- * @buff_count: (input|output) input is number of buffers caller is trying to\n- * return; output is number of buffers that were not posted\n- * @buffs: array of pointers to dma mem structs to be given to hardware\n- *\n- * Caller uses this function to return DMA buffers to the descriptor ring after\n- * consuming them; buff_count will be the number of buffers.\n- *\n- * Note: this function needs to be called after a receive call even\n- * if there are no DMA buffers to be returned, i.e. buff_count = 0,\n- * buffs = NULL to support direct commands\n- */\n-int idpf_ctlq_post_rx_buffs(struct idpf_hw *hw, struct idpf_ctlq_info *cq,\n-\t\t\t u16 *buff_count, struct idpf_dma_mem **buffs)\n-{\n-\tstruct idpf_ctlq_desc *desc;\n-\tu16 ntp = cq-\u003enext_to_post;\n-\tbool buffs_avail = false;\n-\tu16 tbp = ntp + 1;\n-\tint i = 0;\n-\n-\tif (*buff_count \u003e cq-\u003ering_size)\n-\t\treturn -EBADR;\n-\n-\tif (*buff_count \u003e 0)\n-\t\tbuffs_avail = true;\n-\n-\tspin_lock(\u0026cq-\u003ecq_lock);\n-\n-\tif (tbp \u003e= cq-\u003ering_size)\n-\t\ttbp = 0;\n-\n-\tif (tbp == cq-\u003enext_to_clean)\n-\t\t/* Nothing to do */\n-\t\tgoto post_buffs_out;\n-\n-\t/* Post buffers for as many as provided or up until the last one used */\n-\twhile (ntp != cq-\u003enext_to_clean) {\n-\t\tdesc = IDPF_CTLQ_DESC(cq, ntp);\n-\n-\t\tif (cq-\u003ebi.rx_buff[ntp])\n-\t\t\tgoto fill_desc;\n-\t\tif (!buffs_avail) {\n-\t\t\t/* If the caller hasn't given us any buffers or\n-\t\t\t * there are none left, search the ring itself\n-\t\t\t * for an available buffer to move to this\n-\t\t\t * entry starting at the next entry in the ring\n-\t\t\t */\n-\t\t\ttbp = ntp + 1;\n-\n-\t\t\t/* Wrap ring if necessary */\n-\t\t\tif (tbp \u003e= cq-\u003ering_size)\n-\t\t\t\ttbp = 0;\n-\n-\t\t\twhile (tbp != cq-\u003enext_to_clean) {\n-\t\t\t\tif (cq-\u003ebi.rx_buff[tbp]) {\n-\t\t\t\t\tcq-\u003ebi.rx_buff[ntp] =\n-\t\t\t\t\t\tcq-\u003ebi.rx_buff[tbp];\n-\t\t\t\t\tcq-\u003ebi.rx_buff[tbp] = NULL;\n-\n-\t\t\t\t\t/* Found a buffer, no need to\n-\t\t\t\t\t * search anymore\n-\t\t\t\t\t */\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\n-\t\t\t\t/* Wrap ring if necessary */\n-\t\t\t\ttbp++;\n-\t\t\t\tif (tbp \u003e= cq-\u003ering_size)\n-\t\t\t\t\ttbp = 0;\n-\t\t\t}\n-\n-\t\t\tif (tbp == cq-\u003enext_to_clean)\n-\t\t\t\tgoto post_buffs_out;\n-\t\t} else {\n-\t\t\t/* Give back pointer to DMA buffer */\n-\t\t\tcq-\u003ebi.rx_buff[ntp] = buffs[i];\n-\t\t\ti++;\n-\n-\t\t\tif (i \u003e= *buff_count)\n-\t\t\t\tbuffs_avail = false;\n-\t\t}\n-\n-fill_desc:\n-\t\tdesc-\u003eflags =\n-\t\t\tcpu_to_le16(IDPF_CTLQ_FLAG_BUF | IDPF_CTLQ_FLAG_RD);\n-\n-\t\t/* Post buffers to descriptor */\n-\t\tdesc-\u003edatalen = cpu_to_le16(cq-\u003ebi.rx_buff[ntp]-\u003esize);\n-\t\tdesc-\u003eparams.indirect.addr_high =\n-\t\t\tcpu_to_le32(upper_32_bits(cq-\u003ebi.rx_buff[ntp]-\u003epa));\n-\t\tdesc-\u003eparams.indirect.addr_low =\n-\t\t\tcpu_to_le32(lower_32_bits(cq-\u003ebi.rx_buff[ntp]-\u003epa));\n-\n-\t\tntp++;\n-\t\tif (ntp == cq-\u003ering_size)\n-\t\t\tntp = 0;\n-\t}\n-\n-post_buffs_out:\n-\t/* Only update tail if buffers were actually posted */\n-\tif (cq-\u003enext_to_post != ntp) {\n-\t\tif (ntp)\n-\t\t\t/* Update next_to_post to ntp - 1 since current ntp\n-\t\t\t * will not have a buffer\n-\t\t\t */\n-\t\t\tcq-\u003enext_to_post = ntp - 1;\n-\t\telse\n-\t\t\t/* Wrap to end of end ring since current ntp is 0 */\n-\t\t\tcq-\u003enext_to_post = cq-\u003ering_size - 1;\n-\n-\t\tdma_wmb();\n-\n-\t\tidpf_mbx_wr32(hw, cq-\u003ereg.tail, cq-\u003enext_to_post);\n-\t}\n-\n-\tspin_unlock(\u0026cq-\u003ecq_lock);\n-\n-\t/* return the number of buffers that were not posted */\n-\t*buff_count = *buff_count - i;\n-\n-\treturn 0;\n-}\n-\n-/**\n- * idpf_ctlq_recv - receive control queue message call back\n- * @cq: pointer to control queue handle to receive on\n- * @num_q_msg: (input|output) input number of messages that should be received;\n- * output number of messages actually received\n- * @q_msg: (output) array of received control queue messages on this q;\n- * needs to be pre-allocated by caller for as many messages as requested\n- *\n- * Called by interrupt handler or polling mechanism. Caller is expected\n- * to free buffers\n- */\n-int idpf_ctlq_recv(struct idpf_ctlq_info *cq, u16 *num_q_msg,\n-\t\t struct idpf_ctlq_msg *q_msg)\n-{\n-\tu16 num_to_clean, ntc, flags;\n-\tstruct idpf_ctlq_desc *desc;\n-\tint err = 0;\n-\tu16 i;\n-\n-\t/* take the lock before we start messing with the ring */\n-\tspin_lock(\u0026cq-\u003ecq_lock);\n-\n-\tntc = cq-\u003enext_to_clean;\n-\n-\tnum_to_clean = *num_q_msg;\n-\n-\tfor (i = 0; i \u003c num_to_clean; i++) {\n-\t\t/* Fetch next descriptor and check if marked as done */\n-\t\tdesc = IDPF_CTLQ_DESC(cq, ntc);\n-\t\tflags = le16_to_cpu(desc-\u003eflags);\n-\n-\t\tif (!(flags \u0026 IDPF_CTLQ_FLAG_DD))\n-\t\t\tbreak;\n-\n-\t\t/* Ensure no other fields are read until DD flag is checked */\n-\t\tdma_rmb();\n-\n-\t\tq_msg[i].vmvf_type = (flags \u0026\n-\t\t\t\t (IDPF_CTLQ_FLAG_FTYPE_VM |\n-\t\t\t\t IDPF_CTLQ_FLAG_FTYPE_PF)) \u003e\u003e\n-\t\t\t\t IDPF_CTLQ_FLAG_FTYPE_S;\n-\n-\t\tif (flags \u0026 IDPF_CTLQ_FLAG_ERR)\n-\t\t\terr = -EBADMSG;\n-\n-\t\tq_msg[i].cookie.mbx.chnl_opcode =\n-\t\t\t\tle32_to_cpu(desc-\u003ev_opcode_dtype);\n-\t\tq_msg[i].cookie.mbx.chnl_retval =\n-\t\t\t\tle32_to_cpu(desc-\u003ev_retval);\n-\n-\t\tq_msg[i].opcode = le16_to_cpu(desc-\u003eopcode);\n-\t\tq_msg[i].data_len = le16_to_cpu(desc-\u003edatalen);\n-\t\tq_msg[i].status = le16_to_cpu(desc-\u003eret_val);\n-\n-\t\tif (desc-\u003edatalen) {\n-\t\t\tmemcpy(q_msg[i].ctx.indirect.context,\n-\t\t\t \u0026desc-\u003eparams.indirect, IDPF_INDIRECT_CTX_SIZE);\n-\n-\t\t\t/* Assign pointer to dma buffer to ctlq_msg array\n-\t\t\t * to be given to upper layer\n-\t\t\t */\n-\t\t\tq_msg[i].ctx.indirect.payload = cq-\u003ebi.rx_buff[ntc];\n-\n-\t\t\t/* Zero out pointer to DMA buffer info;\n-\t\t\t * will be repopulated by post buffers API\n-\t\t\t */\n-\t\t\tcq-\u003ebi.rx_buff[ntc] = NULL;\n-\t\t} else {\n-\t\t\tmemcpy(q_msg[i].ctx.direct, desc-\u003eparams.raw,\n-\t\t\t IDPF_DIRECT_CTX_SIZE);\n-\t\t}\n-\n-\t\t/* Zero out stale data in descriptor */\n-\t\tmemset(desc, 0, sizeof(struct idpf_ctlq_desc));\n-\n-\t\tntc++;\n-\t\tif (ntc == cq-\u003ering_size)\n-\t\t\tntc = 0;\n-\t}\n-\n-\tcq-\u003enext_to_clean = ntc;\n-\n-\tspin_unlock(\u0026cq-\u003ecq_lock);\n-\n-\t*num_q_msg = i;\n-\tif (*num_q_msg == 0)\n-\t\terr = -ENOMSG;\n-\n-\treturn err;\n-}\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq.h b/drivers/net/ethernet/intel/idpf/idpf_controlq.h\ndeleted file mode 100644\nindex de4ece40c2ff3..0000000000000\n--- a/drivers/net/ethernet/intel/idpf/idpf_controlq.h\n+++ /dev/null\n@@ -1,144 +0,0 @@\n-/* SPDX-License-Identifier: GPL-2.0-only */\n-/* Copyright (C) 2023 Intel Corporation */\n-\n-#ifndef _IDPF_CONTROLQ_H_\n-#define _IDPF_CONTROLQ_H_\n-\n-#include \u003clinux/slab.h\u003e\n-\n-#include \"idpf_controlq_api.h\"\n-\n-/* Maximum buffer length for all control queue types */\n-#define IDPF_CTLQ_MAX_BUF_LEN\t4096\n-\n-#define IDPF_CTLQ_DESC(R, i) \\\n-\t(\u0026(((struct idpf_ctlq_desc *)((R)-\u003edesc_ring.va))[i]))\n-\n-#define IDPF_CTLQ_DESC_UNUSED(R) \\\n-\t((u16)((((R)-\u003enext_to_clean \u003e (R)-\u003enext_to_use) ? 0 : (R)-\u003ering_size) + \\\n-\t (R)-\u003enext_to_clean - (R)-\u003enext_to_use - 1))\n-\n-/* Control Queue default settings */\n-#define IDPF_CTRL_SQ_CMD_TIMEOUT\t250 /* msecs */\n-\n-struct idpf_ctlq_desc {\n-\t/* Control queue descriptor flags */\n-\t__le16 flags;\n-\t/* Control queue message opcode */\n-\t__le16 opcode;\n-\t__le16 datalen;\t\t/* 0 for direct commands */\n-\tunion {\n-\t\t__le16 ret_val;\n-\t\t__le16 pfid_vfid;\n-#define IDPF_CTLQ_DESC_VF_ID_S\t0\n-#define IDPF_CTLQ_DESC_VF_ID_M\t(0x7FF \u003c\u003c IDPF_CTLQ_DESC_VF_ID_S)\n-#define IDPF_CTLQ_DESC_PF_ID_S\t11\n-#define IDPF_CTLQ_DESC_PF_ID_M\t(0x1F \u003c\u003c IDPF_CTLQ_DESC_PF_ID_S)\n-\t};\n-\n-\t/* Virtchnl message opcode and virtchnl descriptor type\n-\t * v_opcode=[27:0], v_dtype=[31:28]\n-\t */\n-\t__le32 v_opcode_dtype;\n-\t/* Virtchnl return value */\n-\t__le32 v_retval;\n-\tunion {\n-\t\tstruct {\n-\t\t\t__le32 param0;\n-\t\t\t__le32 param1;\n-\t\t\t__le32 param2;\n-\t\t\t__le32 param3;\n-\t\t} direct;\n-\t\tstruct {\n-\t\t\t__le32 param0;\n-\t\t\t__le16 sw_cookie;\n-\t\t\t/* Virtchnl flags */\n-\t\t\t__le16 v_flags;\n-\t\t\t__le32 addr_high;\n-\t\t\t__le32 addr_low;\n-\t\t} indirect;\n-\t\tu8 raw[16];\n-\t} params;\n-};\n-\n-/* Flags sub-structure\n- * |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10 |11 |12 |13 |14 |15 |\n- * |DD |CMP|ERR| * RSV * |FTYPE | *RSV* |RD |VFC|BUF| HOST_ID |\n- */\n-/* command flags and offsets */\n-#define IDPF_CTLQ_FLAG_DD_S\t\t0\n-#define IDPF_CTLQ_FLAG_CMP_S\t\t1\n-#define IDPF_CTLQ_FLAG_ERR_S\t\t2\n-#define IDPF_CTLQ_FLAG_FTYPE_S\t\t6\n-#define IDPF_CTLQ_FLAG_RD_S\t\t10\n-#define IDPF_CTLQ_FLAG_VFC_S\t\t11\n-#define IDPF_CTLQ_FLAG_BUF_S\t\t12\n-#define IDPF_CTLQ_FLAG_HOST_ID_S\t13\n-\n-#define IDPF_CTLQ_FLAG_DD\tBIT(IDPF_CTLQ_FLAG_DD_S)\t/* 0x1\t */\n-#define IDPF_CTLQ_FLAG_CMP\tBIT(IDPF_CTLQ_FLAG_CMP_S)\t/* 0x2\t */\n-#define IDPF_CTLQ_FLAG_ERR\tBIT(IDPF_CTLQ_FLAG_ERR_S)\t/* 0x4\t */\n-#define IDPF_CTLQ_FLAG_FTYPE_VM\tBIT(IDPF_CTLQ_FLAG_FTYPE_S)\t/* 0x40\t */\n-#define IDPF_CTLQ_FLAG_FTYPE_PF\tBIT(IDPF_CTLQ_FLAG_FTYPE_S + 1)\t/* 0x80 */\n-#define IDPF_CTLQ_FLAG_RD\tBIT(IDPF_CTLQ_FLAG_RD_S)\t/* 0x400 */\n-#define IDPF_CTLQ_FLAG_VFC\tBIT(IDPF_CTLQ_FLAG_VFC_S)\t/* 0x800 */\n-#define IDPF_CTLQ_FLAG_BUF\tBIT(IDPF_CTLQ_FLAG_BUF_S)\t/* 0x1000 */\n-\n-/* Host ID is a special field that has 3b and not a 1b flag */\n-#define IDPF_CTLQ_FLAG_HOST_ID_M MAKE_MASK(0x7000UL, IDPF_CTLQ_FLAG_HOST_ID_S)\n-\n-struct idpf_mbxq_desc {\n-\tu8 pad[8];\t\t/* CTLQ flags/opcode/len/retval fields */\n-\tu32 chnl_opcode;\t/* avoid confusion with desc-\u003eopcode */\n-\tu32 chnl_retval;\t/* ditto for desc-\u003eretval */\n-\tu32 pf_vf_id;\t\t/* used by CP when sending to PF */\n-};\n-\n-/* Max number of MMIO regions not including the mailbox and rstat regions in\n- * the fallback case when the whole bar is mapped.\n- */\n-#define IDPF_MMIO_MAP_FALLBACK_MAX_REMAINING\t\t3\n-\n-struct idpf_mmio_reg {\n-\tvoid __iomem *vaddr;\n-\tresource_size_t addr_start;\n-\tresource_size_t addr_len;\n-};\n-\n-/* Define the driver hardware struct to replace other control structs as needed\n- * Align to ctlq_hw_info\n- */\n-struct idpf_hw {\n-\tstruct idpf_mmio_reg mbx;\n-\tstruct idpf_mmio_reg rstat;\n-\t/* Array of remaining LAN BAR regions */\n-\tint num_lan_regs;\n-\tstruct idpf_mmio_reg *lan_regs;\n-\n-\tstruct idpf_adapter *back;\n-\n-\t/* control queue - send and receive */\n-\tstruct idpf_ctlq_info *asq;\n-\tstruct idpf_ctlq_info *arq;\n-\n-\t/* pci info */\n-\tu16 device_id;\n-\tu16 vendor_id;\n-\tu16 subsystem_device_id;\n-\tu16 subsystem_vendor_id;\n-\tu8 revision_id;\n-\tbool adapter_stopped;\n-\n-\tstruct list_head cq_list_head;\n-};\n-\n-int idpf_ctlq_alloc_ring_res(struct idpf_hw *hw,\n-\t\t\t struct idpf_ctlq_info *cq);\n-\n-void idpf_ctlq_dealloc_ring_res(struct idpf_hw *hw, struct idpf_ctlq_info *cq);\n-\n-/* prototype for functions used for dynamic memory allocation */\n-void *idpf_alloc_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem,\n-\t\t\t u64 size);\n-void idpf_free_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem);\n-#endif /* _IDPF_CONTROLQ_H_ */\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h b/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h\ndeleted file mode 100644\nindex 3414c5f9a8319..0000000000000\n--- a/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h\n+++ /dev/null\n@@ -1,177 +0,0 @@\n-/* SPDX-License-Identifier: GPL-2.0-only */\n-/* Copyright (C) 2023 Intel Corporation */\n-\n-#ifndef _IDPF_CONTROLQ_API_H_\n-#define _IDPF_CONTROLQ_API_H_\n-\n-#include \"idpf_mem.h\"\n-\n-struct idpf_hw;\n-\n-/* Used for queue init, response and events */\n-enum idpf_ctlq_type {\n-\tIDPF_CTLQ_TYPE_MAILBOX_TX\t= 0,\n-\tIDPF_CTLQ_TYPE_MAILBOX_RX\t= 1,\n-\tIDPF_CTLQ_TYPE_CONFIG_TX\t= 2,\n-\tIDPF_CTLQ_TYPE_CONFIG_RX\t= 3,\n-\tIDPF_CTLQ_TYPE_EVENT_RX\t\t= 4,\n-\tIDPF_CTLQ_TYPE_RDMA_TX\t\t= 5,\n-\tIDPF_CTLQ_TYPE_RDMA_RX\t\t= 6,\n-\tIDPF_CTLQ_TYPE_RDMA_COMPL\t= 7\n-};\n-\n-/* Generic Control Queue Structures */\n-struct idpf_ctlq_reg {\n-\t/* used for queue tracking */\n-\tu32 head;\n-\tu32 tail;\n-\t/* Below applies only to default mb (if present) */\n-\tu32 len;\n-\tu32 bah;\n-\tu32 bal;\n-\tu32 len_mask;\n-\tu32 len_ena_mask;\n-\tu32 head_mask;\n-};\n-\n-/* Generic queue msg structure */\n-struct idpf_ctlq_msg {\n-\tu8 vmvf_type; /* represents the source of the message on recv */\n-#define IDPF_VMVF_TYPE_VF 0\n-#define IDPF_VMVF_TYPE_VM 1\n-#define IDPF_VMVF_TYPE_PF 2\n-\tu8 host_id;\n-\t/* 3b field used only when sending a message to CP - to be used in\n-\t * combination with target func_id to route the message\n-\t */\n-#define IDPF_HOST_ID_MASK 0x7\n-\n-\tu16 opcode;\n-\tu16 data_len;\t/* data_len = 0 when no payload is attached */\n-\tunion {\n-\t\tu16 func_id;\t/* when sending a message */\n-\t\tu16 status;\t/* when receiving a message */\n-\t};\n-\tunion {\n-\t\tstruct {\n-\t\t\tu32 chnl_opcode;\n-\t\t\tu32 chnl_retval;\n-\t\t} mbx;\n-\t} cookie;\n-\tunion {\n-#define IDPF_DIRECT_CTX_SIZE\t16\n-#define IDPF_INDIRECT_CTX_SIZE\t8\n-\t\t/* 16 bytes of context can be provided or 8 bytes of context\n-\t\t * plus the address of a DMA buffer\n-\t\t */\n-\t\tu8 direct[IDPF_DIRECT_CTX_SIZE];\n-\t\tstruct {\n-\t\t\tu8 context[IDPF_INDIRECT_CTX_SIZE];\n-\t\t\tstruct idpf_dma_mem *payload;\n-\t\t} indirect;\n-\t\tstruct {\n-\t\t\tu32 rsvd;\n-\t\t\tu16 data;\n-\t\t\tu16 flags;\n-\t\t} sw_cookie;\n-\t} ctx;\n-};\n-\n-/* Generic queue info structures */\n-/* MB, CONFIG and EVENT q do not have extended info */\n-struct idpf_ctlq_create_info {\n-\tenum idpf_ctlq_type type;\n-\tint id; /* absolute queue offset passed as input\n-\t\t * -1 for default mailbox if present\n-\t\t */\n-\tu16 len; /* Queue length passed as input */\n-\tu16 buf_size; /* buffer size passed as input */\n-\tu64 base_address; /* output, HPA of the Queue start */\n-\tstruct idpf_ctlq_reg reg; /* registers accessed by ctlqs */\n-\n-\tint ext_info_size;\n-\tvoid *ext_info; /* Specific to q type */\n-};\n-\n-/* Control Queue information */\n-struct idpf_ctlq_info {\n-\tstruct list_head cq_list;\n-\n-\tenum idpf_ctlq_type cq_type;\n-\tint q_id;\n-\tspinlock_t cq_lock;\t\t/* control queue lock */\n-\t/* used for interrupt processing */\n-\tu16 next_to_use;\n-\tu16 next_to_clean;\n-\tu16 next_to_post;\t\t/* starting descriptor to post buffers\n-\t\t\t\t\t * to after recev\n-\t\t\t\t\t */\n-\n-\tstruct idpf_dma_mem desc_ring;\t/* descriptor ring memory\n-\t\t\t\t\t * idpf_dma_mem is defined in OSdep.h\n-\t\t\t\t\t */\n-\tunion {\n-\t\tstruct idpf_dma_mem **rx_buff;\n-\t\tstruct idpf_ctlq_msg **tx_msg;\n-\t} bi;\n-\n-\tu16 buf_size;\t\t\t/* queue buffer size */\n-\tu16 ring_size;\t\t\t/* Number of descriptors */\n-\tstruct idpf_ctlq_reg reg;\t/* registers accessed by ctlqs */\n-};\n-\n-/**\n- * enum idpf_mbx_opc - PF/VF mailbox commands\n- * @idpf_mbq_opc_send_msg_to_cp: used by PF or VF to send a message to its CP\n- * @idpf_mbq_opc_send_msg_to_peer_drv: used by PF or VF to send a message to\n- *\t\t\t\t any peer driver\n- */\n-enum idpf_mbx_opc {\n-\tidpf_mbq_opc_send_msg_to_cp\t\t= 0x0801,\n-\tidpf_mbq_opc_send_msg_to_peer_drv\t= 0x0804,\n-};\n-\n-/* API supported for control queue management */\n-/* Will init all required q including default mb. \"q_info\" is an array of\n- * create_info structs equal to the number of control queues to be created.\n- */\n-int idpf_ctlq_init(struct idpf_hw *hw, u8 num_q,\n-\t\t struct idpf_ctlq_create_info *q_info);\n-\n-/* Allocate and initialize a single control queue, which will be added to the\n- * control queue list; returns a handle to the created control queue\n- */\n-int idpf_ctlq_add(struct idpf_hw *hw,\n-\t\t struct idpf_ctlq_create_info *qinfo,\n-\t\t struct idpf_ctlq_info **cq);\n-\n-/* Deinitialize and deallocate a single control queue */\n-void idpf_ctlq_remove(struct idpf_hw *hw,\n-\t\t struct idpf_ctlq_info *cq);\n-\n-/* Sends messages to HW and will also free the buffer*/\n-int idpf_ctlq_send(struct idpf_hw *hw,\n-\t\t struct idpf_ctlq_info *cq,\n-\t\t u16 num_q_msg,\n-\t\t struct idpf_ctlq_msg q_msg[]);\n-\n-/* Receives messages and called by interrupt handler/polling\n- * initiated by app/process. Also caller is supposed to free the buffers\n- */\n-int idpf_ctlq_recv(struct idpf_ctlq_info *cq, u16 *num_q_msg,\n-\t\t struct idpf_ctlq_msg *q_msg);\n-\n-/* Reclaims send descriptors on HW write back */\n-int idpf_ctlq_clean_sq(struct idpf_ctlq_info *cq, u16 *clean_count,\n-\t\t struct idpf_ctlq_msg *msg_status[]);\n-\n-/* Indicate RX buffers are done being processed */\n-int idpf_ctlq_post_rx_buffs(struct idpf_hw *hw,\n-\t\t\t struct idpf_ctlq_info *cq,\n-\t\t\t u16 *buff_count,\n-\t\t\t struct idpf_dma_mem **buffs);\n-\n-/* Will destroy all q including the default mb */\n-void idpf_ctlq_deinit(struct idpf_hw *hw);\n-\n-#endif /* _IDPF_CONTROLQ_API_H_ */\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c b/drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c\ndeleted file mode 100644\nindex d4d488c7cfd60..0000000000000\n--- a/drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c\n+++ /dev/null\n@@ -1,169 +0,0 @@\n-// SPDX-License-Identifier: GPL-2.0-only\n-/* Copyright (C) 2023 Intel Corporation */\n-\n-#include \"idpf_controlq.h\"\n-\n-/**\n- * idpf_ctlq_alloc_desc_ring - Allocate Control Queue (CQ) rings\n- * @hw: pointer to hw struct\n- * @cq: pointer to the specific Control queue\n- */\n-static int idpf_ctlq_alloc_desc_ring(struct idpf_hw *hw,\n-\t\t\t\t struct idpf_ctlq_info *cq)\n-{\n-\tsize_t size = cq-\u003ering_size * sizeof(struct idpf_ctlq_desc);\n-\n-\tcq-\u003edesc_ring.va = idpf_alloc_dma_mem(hw, \u0026cq-\u003edesc_ring, size);\n-\tif (!cq-\u003edesc_ring.va)\n-\t\treturn -ENOMEM;\n-\n-\treturn 0;\n-}\n-\n-/**\n- * idpf_ctlq_alloc_bufs - Allocate Control Queue (CQ) buffers\n- * @hw: pointer to hw struct\n- * @cq: pointer to the specific Control queue\n- *\n- * Allocate the buffer head for all control queues, and if it's a receive\n- * queue, allocate DMA buffers\n- */\n-static int idpf_ctlq_alloc_bufs(struct idpf_hw *hw,\n-\t\t\t\tstruct idpf_ctlq_info *cq)\n-{\n-\tint i;\n-\n-\t/* Do not allocate DMA buffers for transmit queues */\n-\tif (cq-\u003ecq_type == IDPF_CTLQ_TYPE_MAILBOX_TX)\n-\t\treturn 0;\n-\n-\t/* We'll be allocating the buffer info memory first, then we can\n-\t * allocate the mapped buffers for the event processing\n-\t */\n-\tcq-\u003ebi.rx_buff = kzalloc_objs(struct idpf_dma_mem *, cq-\u003ering_size);\n-\tif (!cq-\u003ebi.rx_buff)\n-\t\treturn -ENOMEM;\n-\n-\t/* allocate the mapped buffers (except for the last one) */\n-\tfor (i = 0; i \u003c cq-\u003ering_size - 1; i++) {\n-\t\tstruct idpf_dma_mem *bi;\n-\t\tint num = 1; /* number of idpf_dma_mem to be allocated */\n-\n-\t\tcq-\u003ebi.rx_buff[i] = kzalloc_objs(struct idpf_dma_mem, num);\n-\t\tif (!cq-\u003ebi.rx_buff[i])\n-\t\t\tgoto unwind_alloc_cq_bufs;\n-\n-\t\tbi = cq-\u003ebi.rx_buff[i];\n-\n-\t\tbi-\u003eva = idpf_alloc_dma_mem(hw, bi, cq-\u003ebuf_size);\n-\t\tif (!bi-\u003eva) {\n-\t\t\t/* unwind will not free the failed entry */\n-\t\t\tkfree(cq-\u003ebi.rx_buff[i]);\n-\t\t\tgoto unwind_alloc_cq_bufs;\n-\t\t}\n-\t}\n-\n-\treturn 0;\n-\n-unwind_alloc_cq_bufs:\n-\t/* don't try to free the one that failed... */\n-\ti--;\n-\tfor (; i \u003e= 0; i--) {\n-\t\tidpf_free_dma_mem(hw, cq-\u003ebi.rx_buff[i]);\n-\t\tkfree(cq-\u003ebi.rx_buff[i]);\n-\t}\n-\tkfree(cq-\u003ebi.rx_buff);\n-\n-\treturn -ENOMEM;\n-}\n-\n-/**\n- * idpf_ctlq_free_desc_ring - Free Control Queue (CQ) rings\n- * @hw: pointer to hw struct\n- * @cq: pointer to the specific Control queue\n- *\n- * This assumes the posted send buffers have already been cleaned\n- * and de-allocated\n- */\n-static void idpf_ctlq_free_desc_ring(struct idpf_hw *hw,\n-\t\t\t\t struct idpf_ctlq_info *cq)\n-{\n-\tidpf_free_dma_mem(hw, \u0026cq-\u003edesc_ring);\n-}\n-\n-/**\n- * idpf_ctlq_free_bufs - Free CQ buffer info elements\n- * @hw: pointer to hw struct\n- * @cq: pointer to the specific Control queue\n- *\n- * Free the DMA buffers for RX queues, and DMA buffer header for both RX and TX\n- * queues. The upper layers are expected to manage freeing of TX DMA buffers\n- */\n-static void idpf_ctlq_free_bufs(struct idpf_hw *hw, struct idpf_ctlq_info *cq)\n-{\n-\tvoid *bi;\n-\n-\tif (cq-\u003ecq_type == IDPF_CTLQ_TYPE_MAILBOX_RX) {\n-\t\tint i;\n-\n-\t\t/* free DMA buffers for rx queues*/\n-\t\tfor (i = 0; i \u003c cq-\u003ering_size; i++) {\n-\t\t\tif (cq-\u003ebi.rx_buff[i]) {\n-\t\t\t\tidpf_free_dma_mem(hw, cq-\u003ebi.rx_buff[i]);\n-\t\t\t\tkfree(cq-\u003ebi.rx_buff[i]);\n-\t\t\t}\n-\t\t}\n-\n-\t\tbi = (void *)cq-\u003ebi.rx_buff;\n-\t} else {\n-\t\tbi = (void *)cq-\u003ebi.tx_msg;\n-\t}\n-\n-\t/* free the buffer header */\n-\tkfree(bi);\n-}\n-\n-/**\n- * idpf_ctlq_dealloc_ring_res - Free memory allocated for control queue\n- * @hw: pointer to hw struct\n- * @cq: pointer to the specific Control queue\n- *\n- * Free the memory used by the ring, buffers and other related structures\n- */\n-void idpf_ctlq_dealloc_ring_res(struct idpf_hw *hw, struct idpf_ctlq_info *cq)\n-{\n-\t/* free ring buffers and the ring itself */\n-\tidpf_ctlq_free_bufs(hw, cq);\n-\tidpf_ctlq_free_desc_ring(hw, cq);\n-}\n-\n-/**\n- * idpf_ctlq_alloc_ring_res - allocate memory for descriptor ring and bufs\n- * @hw: pointer to hw struct\n- * @cq: pointer to control queue struct\n- *\n- * Do *NOT* hold cq_lock when calling this as the memory allocation routines\n- * called are not going to be atomic context safe\n- */\n-int idpf_ctlq_alloc_ring_res(struct idpf_hw *hw, struct idpf_ctlq_info *cq)\n-{\n-\tint err;\n-\n-\t/* allocate the ring memory */\n-\terr = idpf_ctlq_alloc_desc_ring(hw, cq);\n-\tif (err)\n-\t\treturn err;\n-\n-\t/* allocate buffers in the rings */\n-\terr = idpf_ctlq_alloc_bufs(hw, cq);\n-\tif (err)\n-\t\tgoto idpf_init_cq_free_ring;\n-\n-\t/* success! */\n-\treturn 0;\n-\n-idpf_init_cq_free_ring:\n-\tidpf_free_dma_mem(hw, \u0026cq-\u003edesc_ring);\n-\n-\treturn err;\n-}\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c\nindex 4079a787657f1..083cf6319d262 100644\n--- a/drivers/net/ethernet/intel/idpf/idpf_dev.c\n+++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c\n@@ -10,45 +10,32 @@\n \n /**\n * idpf_ctlq_reg_init - initialize default mailbox registers\n- * @adapter: adapter structure\n- * @cq: pointer to the array of create control queues\n+ * @mmio: struct that contains MMIO region info\n+ * @cci: struct where the register offset pointer to be copied to\n */\n-static void idpf_ctlq_reg_init(struct idpf_adapter *adapter,\n-\t\t\t struct idpf_ctlq_create_info *cq)\n+static void idpf_ctlq_reg_init(struct libie_mmio_info *mmio,\n+\t\t\t struct libie_ctlq_create_info *cci)\n {\n-\tresource_size_t mbx_start = adapter-\u003edev_ops.static_reg_info[0].start;\n-\tint i;\n-\n-\tfor (i = 0; i \u003c IDPF_NUM_DFLT_MBX_Q; i++) {\n-\t\tstruct idpf_ctlq_create_info *ccq = cq + i;\n-\n-\t\tswitch (ccq-\u003etype) {\n-\t\tcase IDPF_CTLQ_TYPE_MAILBOX_TX:\n-\t\t\t/* set head and tail registers in our local struct */\n-\t\t\tccq-\u003ereg.head = PF_FW_ATQH - mbx_start;\n-\t\t\tccq-\u003ereg.tail = PF_FW_ATQT - mbx_start;\n-\t\t\tccq-\u003ereg.len = PF_FW_ATQLEN - mbx_start;\n-\t\t\tccq-\u003ereg.bah = PF_FW_ATQBAH - mbx_start;\n-\t\t\tccq-\u003ereg.bal = PF_FW_ATQBAL - mbx_start;\n-\t\t\tccq-\u003ereg.len_mask = PF_FW_ATQLEN_ATQLEN_M;\n-\t\t\tccq-\u003ereg.len_ena_mask = PF_FW_ATQLEN_ATQENABLE_M;\n-\t\t\tccq-\u003ereg.head_mask = PF_FW_ATQH_ATQH_M;\n-\t\t\tbreak;\n-\t\tcase IDPF_CTLQ_TYPE_MAILBOX_RX:\n-\t\t\t/* set head and tail registers in our local struct */\n-\t\t\tccq-\u003ereg.head = PF_FW_ARQH - mbx_start;\n-\t\t\tccq-\u003ereg.tail = PF_FW_ARQT - mbx_start;\n-\t\t\tccq-\u003ereg.len = PF_FW_ARQLEN - mbx_start;\n-\t\t\tccq-\u003ereg.bah = PF_FW_ARQBAH - mbx_start;\n-\t\t\tccq-\u003ereg.bal = PF_FW_ARQBAL - mbx_start;\n-\t\t\tccq-\u003ereg.len_mask = PF_FW_ARQLEN_ARQLEN_M;\n-\t\t\tccq-\u003ereg.len_ena_mask = PF_FW_ARQLEN_ARQENABLE_M;\n-\t\t\tccq-\u003ereg.head_mask = PF_FW_ARQH_ARQH_M;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tbreak;\n-\t\t}\n-\t}\n+\tstruct libie_ctlq_reg *tx_reg = \u0026cci[LIBIE_CTLQ_TYPE_TX].reg;\n+\tstruct libie_ctlq_reg *rx_reg = \u0026cci[LIBIE_CTLQ_TYPE_RX].reg;\n+\n+\ttx_reg-\u003ehead\t\t= libie_pci_get_mmio_addr(mmio, PF_FW_ATQH);\n+\ttx_reg-\u003etail\t\t= libie_pci_get_mmio_addr(mmio, PF_FW_ATQT);\n+\ttx_reg-\u003elen\t\t= libie_pci_get_mmio_addr(mmio, PF_FW_ATQLEN);\n+\ttx_reg-\u003eaddr_high\t= libie_pci_get_mmio_addr(mmio, PF_FW_ATQBAH);\n+\ttx_reg-\u003eaddr_low\t= libie_pci_get_mmio_addr(mmio, PF_FW_ATQBAL);\n+\ttx_reg-\u003elen_mask\t= PF_FW_ATQLEN_ATQLEN_M;\n+\ttx_reg-\u003elen_ena_mask\t= PF_FW_ATQLEN_ATQENABLE_M;\n+\ttx_reg-\u003ehead_mask\t= PF_FW_ATQH_ATQH_M;\n+\n+\trx_reg-\u003ehead\t\t= libie_pci_get_mmio_addr(mmio, PF_FW_ARQH);\n+\trx_reg-\u003etail\t\t= libie_pci_get_mmio_addr(mmio, PF_FW_ARQT);\n+\trx_reg-\u003elen\t\t= libie_pci_get_mmio_addr(mmio, PF_FW_ARQLEN);\n+\trx_reg-\u003eaddr_high\t= libie_pci_get_mmio_addr(mmio, PF_FW_ARQBAH);\n+\trx_reg-\u003eaddr_low\t= libie_pci_get_mmio_addr(mmio, PF_FW_ARQBAL);\n+\trx_reg-\u003elen_mask\t= PF_FW_ARQLEN_ARQLEN_M;\n+\trx_reg-\u003elen_ena_mask\t= PF_FW_ARQLEN_ARQENABLE_M;\n+\trx_reg-\u003ehead_mask\t= PF_FW_ARQH_ARQH_M;\n }\n \n /**\n@@ -57,13 +44,14 @@ static void idpf_ctlq_reg_init(struct idpf_adapter *adapter,\n */\n static void idpf_mb_intr_reg_init(struct idpf_adapter *adapter)\n {\n+\tstruct libie_mmio_info *mmio = \u0026adapter-\u003ectlq_ctx.mmio_info;\n \tstruct idpf_intr_reg *intr = \u0026adapter-\u003emb_vector.intr_reg;\n \tu32 dyn_ctl = le32_to_cpu(adapter-\u003ecaps.mailbox_dyn_ctl);\n \n-\tintr-\u003edyn_ctl = idpf_get_reg_addr(adapter, dyn_ctl);\n+\tintr-\u003edyn_ctl = libie_pci_get_mmio_addr(mmio, dyn_ctl);\n \tintr-\u003edyn_ctl_intena_m = PF_GLINT_DYN_CTL_INTENA_M;\n \tintr-\u003edyn_ctl_itridx_m = PF_GLINT_DYN_CTL_ITR_INDX_M;\n-\tintr-\u003eicr_ena = idpf_get_reg_addr(adapter, PF_INT_DIR_OICR_ENA);\n+\tintr-\u003eicr_ena = libie_pci_get_mmio_addr(mmio, PF_INT_DIR_OICR_ENA);\n \tintr-\u003eicr_ena_ctlq_m = PF_INT_DIR_OICR_ENA_M;\n }\n \n@@ -78,6 +66,7 @@ static int idpf_intr_reg_init(struct idpf_vport *vport,\n \tstruct idpf_adapter *adapter = vport-\u003eadapter;\n \tu16 num_vecs = rsrc-\u003enum_q_vectors;\n \tstruct idpf_vec_regs *reg_vals;\n+\tstruct libie_mmio_info *mmio;\n \tint num_regs, i, err = 0;\n \tu32 rx_itr, tx_itr, val;\n \tu16 total_vecs;\n@@ -93,14 +82,17 @@ static int idpf_intr_reg_init(struct idpf_vport *vport,\n \t\tgoto free_reg_vals;\n \t}\n \n+\tmmio = \u0026adapter-\u003ectlq_ctx.mmio_info;\n+\n \tfor (i = 0; i \u003c num_vecs; i++) {\n \t\tstruct idpf_q_vector *q_vector = \u0026rsrc-\u003eq_vectors[i];\n \t\tu16 vec_id = rsrc-\u003eq_vector_idxs[i] - IDPF_MBX_Q_VEC;\n \t\tstruct idpf_intr_reg *intr = \u0026q_vector-\u003eintr_reg;\n+\t\tstruct idpf_vec_regs *reg = \u0026reg_vals[vec_id];\n \t\tu32 spacing;\n \n-\t\tintr-\u003edyn_ctl = idpf_get_reg_addr(adapter,\n-\t\t\t\t\t\t reg_vals[vec_id].dyn_ctl_reg);\n+\t\tintr-\u003edyn_ctl = libie_pci_get_mmio_addr(mmio,\n+\t\t\t\t\t\t\treg-\u003edyn_ctl_reg);\n \t\tintr-\u003edyn_ctl_intena_m = PF_GLINT_DYN_CTL_INTENA_M;\n \t\tintr-\u003edyn_ctl_intena_msk_m = PF_GLINT_DYN_CTL_INTENA_MSK_M;\n \t\tintr-\u003edyn_ctl_itridx_s = PF_GLINT_DYN_CTL_ITR_INDX_S;\n@@ -110,22 +102,21 @@ static int idpf_intr_reg_init(struct idpf_vport *vport,\n \t\tintr-\u003edyn_ctl_sw_itridx_ena_m =\n \t\t\tPF_GLINT_DYN_CTL_SW_ITR_INDX_ENA_M;\n \n-\t\tspacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing,\n+\t\tspacing = IDPF_ITR_IDX_SPACING(reg-\u003eitrn_index_spacing,\n \t\t\t\t\t IDPF_PF_ITR_IDX_SPACING);\n \t\trx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_0,\n-\t\t\t\t\t reg_vals[vec_id].itrn_reg,\n-\t\t\t\t\t spacing);\n+\t\t\t\t\t reg-\u003eitrn_reg, spacing);\n \t\ttx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_1,\n-\t\t\t\t\t reg_vals[vec_id].itrn_reg,\n-\t\t\t\t\t spacing);\n-\t\tintr-\u003erx_itr = idpf_get_reg_addr(adapter, rx_itr);\n-\t\tintr-\u003etx_itr = idpf_get_reg_addr(adapter, tx_itr);\n+\t\t\t\t\t reg-\u003eitrn_reg, spacing);\n+\t\tintr-\u003erx_itr = libie_pci_get_mmio_addr(mmio, rx_itr);\n+\t\tintr-\u003etx_itr = libie_pci_get_mmio_addr(mmio, tx_itr);\n \t}\n \n \t/* Data vector for NOIRQ queues */\n \n \tval = reg_vals[rsrc-\u003eq_vector_idxs[i] - IDPF_MBX_Q_VEC].dyn_ctl_reg;\n-\trsrc-\u003enoirq_dyn_ctl = idpf_get_reg_addr(adapter, val);\n+\trsrc-\u003enoirq_dyn_ctl =\n+\t\tlibie_pci_get_mmio_addr(\u0026adapter-\u003ectlq_ctx.mmio_info, val);\n \n \tval = PF_GLINT_DYN_CTL_WB_ON_ITR_M | PF_GLINT_DYN_CTL_INTENA_MSK_M |\n \t FIELD_PREP(PF_GLINT_DYN_CTL_ITR_INDX_M, IDPF_NO_ITR_UPDATE_IDX);\n@@ -143,7 +134,9 @@ static int idpf_intr_reg_init(struct idpf_vport *vport,\n */\n static void idpf_reset_reg_init(struct idpf_adapter *adapter)\n {\n-\tadapter-\u003ereset_reg.rstat = idpf_get_rstat_reg_addr(adapter, PFGEN_RSTAT);\n+\tadapter-\u003ereset_reg.rstat =\n+\t\tlibie_pci_get_mmio_addr(\u0026adapter-\u003ectlq_ctx.mmio_info,\n+\t\t\t\t\tPFGEN_RSTAT);\n \tadapter-\u003ereset_reg.rstat_m = PFGEN_RSTAT_PFR_STATE_M;\n }\n \n@@ -155,11 +148,11 @@ static void idpf_reset_reg_init(struct idpf_adapter *adapter)\n static void idpf_trigger_reset(struct idpf_adapter *adapter,\n \t\t\t enum idpf_flags __always_unused trig_cause)\n {\n-\tu32 reset_reg;\n+\tvoid __iomem *addr;\n \n-\treset_reg = readl(idpf_get_rstat_reg_addr(adapter, PFGEN_CTRL));\n-\twritel(reset_reg | PFGEN_CTRL_PFSWR,\n-\t idpf_get_rstat_reg_addr(adapter, PFGEN_CTRL));\n+\taddr = libie_pci_get_mmio_addr(\u0026adapter-\u003ectlq_ctx.mmio_info,\n+\t\t\t\t PFGEN_CTRL);\n+\twritel(readl(addr) | PFGEN_CTRL_PFSWR, addr);\n }\n \n /**\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c\nindex bb99d9e7c65d5..95c45f12b0f9e 100644\n--- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c\n+++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c\n@@ -225,7 +225,7 @@ static int idpf_add_flow_steer(struct net_device *netdev,\n \tspin_unlock_bh(\u0026vport_config-\u003eflow_steer_list_lock);\n \n \tif (err)\n-\t\tgoto out;\n+\t\tgoto out_free_fltr;\n \n \trule-\u003evport_id = cpu_to_le32(vport-\u003evport_id);\n \trule-\u003ecount = cpu_to_le32(1);\n@@ -252,17 +252,15 @@ static int idpf_add_flow_steer(struct net_device *netdev,\n \t\tbreak;\n \tdefault:\n \t\terr = -EINVAL;\n-\t\tgoto out;\n+\t\tgoto out_free_fltr;\n \t}\n \n \terr = idpf_add_del_fsteer_filters(vport-\u003eadapter, rule,\n \t\t\t\t\t VIRTCHNL2_OP_ADD_FLOW_RULE);\n-\tif (err)\n-\t\tgoto out;\n-\n-\tif (info-\u003estatus != cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS)) {\n-\t\terr = -EIO;\n-\t\tgoto out;\n+\tif (err) {\n+\t\t/* virtchnl2 rule is already consumed */\n+\t\tkfree(fltr);\n+\t\treturn err;\n \t}\n \n \t/* Save a copy of the user's flow spec so ethtool can later retrieve it */\n@@ -274,9 +272,10 @@ static int idpf_add_flow_steer(struct net_device *netdev,\n \n \tuser_config-\u003enum_fsteer_fltrs++;\n \tspin_unlock_bh(\u0026vport_config-\u003eflow_steer_list_lock);\n-\tgoto out_free_rule;\n \n-out:\n+\treturn 0;\n+\n+out_free_fltr:\n \tkfree(fltr);\n out_free_rule:\n \tkfree(rule);\n@@ -319,12 +318,7 @@ static int idpf_del_flow_steer(struct net_device *netdev,\n \terr = idpf_add_del_fsteer_filters(vport-\u003eadapter, rule,\n \t\t\t\t\t VIRTCHNL2_OP_DEL_FLOW_RULE);\n \tif (err)\n-\t\tgoto out;\n-\n-\tif (info-\u003estatus != cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS)) {\n-\t\terr = -EIO;\n-\t\tgoto out;\n-\t}\n+\t\treturn err;\n \n \tspin_lock_bh(\u0026vport_config-\u003eflow_steer_list_lock);\n \tlist_for_each_entry_safe(f, iter,\n@@ -340,8 +334,6 @@ static int idpf_del_flow_steer(struct net_device *netdev,\n \n out_unlock:\n \tspin_unlock_bh(\u0026vport_config-\u003eflow_steer_list_lock);\n-out:\n-\tkfree(rule);\n \treturn err;\n }\n \ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_idc.c b/drivers/net/ethernet/intel/idpf/idpf_idc.c\nindex b7d6b08fc89e8..b6cd1c25ae5db 100644\n--- a/drivers/net/ethernet/intel/idpf/idpf_idc.c\n+++ b/drivers/net/ethernet/intel/idpf/idpf_idc.c\n@@ -416,9 +416,12 @@ idpf_idc_init_msix_data(struct idpf_adapter *adapter)\n int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter,\n \t\t\t enum iidc_function_type ftype)\n {\n+\tstruct libie_mmio_info *mmio = \u0026adapter-\u003ectlq_ctx.mmio_info;\n \tstruct iidc_rdma_core_dev_info *cdev_info;\n \tstruct iidc_rdma_priv_dev_info *privd;\n-\tint err, i;\n+\tstruct libie_pci_mmio_region *mr;\n+\tsize_t num_mem_regions;\n+\tint err, i = 0;\n \n \tadapter-\u003ecdev_info = kzalloc_obj(*cdev_info);\n \tif (!adapter-\u003ecdev_info)\n@@ -436,22 +439,31 @@ int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter,\n \tcdev_info-\u003erdma_protocol = IIDC_RDMA_PROTOCOL_ROCEV2;\n \tprivd-\u003eftype = ftype;\n \n+\tnum_mem_regions = list_count_nodes(\u0026mmio-\u003emmio_list);\n+\tif (num_mem_regions \u003c= IDPF_MMIO_REG_NUM_STATIC) {\n+\t\terr = -EINVAL;\n+\t\tgoto err_plug_aux_dev;\n+\t}\n+\n+\tnum_mem_regions -= IDPF_MMIO_REG_NUM_STATIC;\n \tprivd-\u003emapped_mem_regions =\n \t\tkzalloc_objs(struct iidc_rdma_lan_mapped_mem_region,\n-\t\t\t adapter-\u003ehw.num_lan_regs);\n+\t\t\t num_mem_regions);\n \tif (!privd-\u003emapped_mem_regions) {\n \t\terr = -ENOMEM;\n \t\tgoto err_plug_aux_dev;\n \t}\n \n-\tprivd-\u003enum_memory_regions = cpu_to_le16(adapter-\u003ehw.num_lan_regs);\n-\tfor (i = 0; i \u003c adapter-\u003ehw.num_lan_regs; i++) {\n-\t\tprivd-\u003emapped_mem_regions[i].region_addr =\n-\t\t\tadapter-\u003ehw.lan_regs[i].vaddr;\n-\t\tprivd-\u003emapped_mem_regions[i].size =\n-\t\t\tcpu_to_le64(adapter-\u003ehw.lan_regs[i].addr_len);\n-\t\tprivd-\u003emapped_mem_regions[i].start_offset =\n-\t\t\tcpu_to_le64(adapter-\u003ehw.lan_regs[i].addr_start);\n+\tprivd-\u003enum_memory_regions = cpu_to_le16(num_mem_regions);\n+\tlist_for_each_entry(mr, \u0026mmio-\u003emmio_list, list) {\n+\t\tif (!idpf_mmio_region_non_static(\u0026adapter-\u003ectlq_ctx.mmio_info,\n+\t\t\t\t\t\t mr))\n+\t\t\tcontinue;\n+\n+\t\tprivd-\u003emapped_mem_regions[i].region_addr = mr-\u003eaddr;\n+\t\tprivd-\u003emapped_mem_regions[i].size = cpu_to_le64(mr-\u003esize);\n+\t\tprivd-\u003emapped_mem_regions[i++].start_offset =\n+\t\t\t\t\t\tcpu_to_le64(mr-\u003eoffset);\n \t}\n \n \tidpf_idc_init_msix_data(adapter);\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c\nindex bb81e620c5c87..827c795afcb62 100644\n--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c\n+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c\n@@ -68,9 +68,11 @@ static void idpf_deinit_vector_stack(struct idpf_adapter *adapter)\n * This will also disable interrupt mode and queue up mailbox task. Mailbox\n * task will reschedule itself if not in interrupt mode.\n */\n-static void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter)\n+void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter)\n {\n-\tclear_bit(IDPF_MB_INTR_MODE, adapter-\u003eflags);\n+\tif (!test_and_clear_bit(IDPF_MB_INTR_MODE, adapter-\u003eflags))\n+\t\treturn;\n+\n \tkfree(free_irq(adapter-\u003emsix_entries[0].vector, adapter));\n \tqueue_delayed_work(adapter-\u003embx_wq, \u0026adapter-\u003embx_task, 0);\n }\n@@ -1109,8 +1111,6 @@ static void idpf_vport_rel(struct idpf_vport *vport)\n \n \tkfree(adapter-\u003evport_params_recvd[idx]);\n \tadapter-\u003evport_params_recvd[idx] = NULL;\n-\tkfree(adapter-\u003evport_params_reqd[idx]);\n-\tadapter-\u003evport_params_reqd[idx] = NULL;\n \n \tkfree(vport);\n \tadapter-\u003enum_alloc_vports--;\n@@ -1373,6 +1373,7 @@ void idpf_statistics_task(struct work_struct *work)\n */\n void idpf_mbx_task(struct work_struct *work)\n {\n+\tstruct libie_ctlq_xn_recv_params xn_params;\n \tstruct idpf_adapter *adapter;\n \n \tadapter = container_of(work, struct idpf_adapter, mbx_task.work);\n@@ -1383,7 +1384,14 @@ void idpf_mbx_task(struct work_struct *work)\n \t\tqueue_delayed_work(adapter-\u003embx_wq, \u0026adapter-\u003embx_task,\n \t\t\t\t usecs_to_jiffies(300));\n \n-\tidpf_recv_mb_msg(adapter, adapter-\u003ehw.arq);\n+\txn_params = (struct libie_ctlq_xn_recv_params) {\n+\t\t.xnm = adapter-\u003exnm,\n+\t\t.ctlq = adapter-\u003earq,\n+\t\t.ctlq_msg_handler = idpf_recv_event_msg,\n+\t\t.budget = LIBIE_CTLQ_MAX_XN_ENTRIES,\n+\t};\n+\n+\tlibie_ctlq_xn_recv(\u0026xn_params);\n }\n \n /**\n@@ -1849,15 +1857,14 @@ void idpf_deinit_task(struct idpf_adapter *adapter)\n \n /**\n * idpf_check_reset_complete - check that reset is complete\n- * @hw: pointer to hw struct\n+ * @adapter: adapter to check\n * @reset_reg: struct with reset registers\n *\n * Returns 0 if device is ready to use, or -EBUSY if it's in reset.\n **/\n-static int idpf_check_reset_complete(struct idpf_hw *hw,\n+static int idpf_check_reset_complete(struct idpf_adapter *adapter,\n \t\t\t\t struct idpf_reset_reg *reset_reg)\n {\n-\tstruct idpf_adapter *adapter = hw-\u003eback;\n \tint i;\n \n \tfor (i = 0; i \u003c 2000; i++) {\n@@ -1920,7 +1927,7 @@ static void idpf_init_hard_reset(struct idpf_adapter *adapter)\n \t}\n \n \t/* Wait for reset to complete */\n-\terr = idpf_check_reset_complete(\u0026adapter-\u003ehw, \u0026adapter-\u003ereset_reg);\n+\terr = idpf_check_reset_complete(adapter, \u0026adapter-\u003ereset_reg);\n \tif (err) {\n \t\tdev_err(dev, \"The driver was unable to contact the device's firmware. Check that the FW is running. Driver state= 0x%x\\n\",\n \t\t\tadapter-\u003estate);\n@@ -1934,14 +1941,11 @@ static void idpf_init_hard_reset(struct idpf_adapter *adapter)\n \t\tgoto unlock_mutex;\n \t}\n \n-\tqueue_delayed_work(adapter-\u003embx_wq, \u0026adapter-\u003embx_task, 0);\n-\n \t/* Initialize the state machine, also allocate memory and request\n \t * resources\n \t */\n \terr = idpf_vc_core_init(adapter);\n \tif (err) {\n-\t\tcancel_delayed_work_sync(\u0026adapter-\u003embx_task);\n \t\tidpf_deinit_dflt_mbx(adapter);\n \t\tgoto unlock_mutex;\n \t}\n@@ -1987,7 +1991,8 @@ void idpf_vc_event_task(struct work_struct *work)\n \treturn;\n \n func_reset:\n-\tidpf_vc_xn_shutdown(adapter-\u003evcxn_mngr);\n+\tif (adapter-\u003exnm)\n+\t\tlibie_ctlq_xn_shutdown(adapter-\u003exnm);\n drv_load:\n \tset_bit(IDPF_HR_RESET_IN_PROG, adapter-\u003eflags);\n \tidpf_init_hard_reset(adapter);\n@@ -2570,44 +2575,6 @@ static int idpf_set_mac(struct net_device *netdev, void *p)\n \treturn err;\n }\n \n-/**\n- * idpf_alloc_dma_mem - Allocate dma memory\n- * @hw: pointer to hw struct\n- * @mem: pointer to dma_mem struct\n- * @size: size of the memory to allocate\n- */\n-void *idpf_alloc_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem, u64 size)\n-{\n-\tstruct idpf_adapter *adapter = hw-\u003eback;\n-\tsize_t sz = ALIGN(size, 4096);\n-\n-\t/* The control queue resources are freed under a spinlock, contiguous\n-\t * pages will avoid IOMMU remapping and the use vmap (and vunmap in\n-\t * dma_free_*() path.\n-\t */\n-\tmem-\u003eva = dma_alloc_attrs(\u0026adapter-\u003epdev-\u003edev, sz, \u0026mem-\u003epa,\n-\t\t\t\t GFP_KERNEL, DMA_ATTR_FORCE_CONTIGUOUS);\n-\tmem-\u003esize = sz;\n-\n-\treturn mem-\u003eva;\n-}\n-\n-/**\n- * idpf_free_dma_mem - Free the allocated dma memory\n- * @hw: pointer to hw struct\n- * @mem: pointer to dma_mem struct\n- */\n-void idpf_free_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem)\n-{\n-\tstruct idpf_adapter *adapter = hw-\u003eback;\n-\n-\tdma_free_attrs(\u0026adapter-\u003epdev-\u003edev, mem-\u003esize,\n-\t\t mem-\u003eva, mem-\u003epa, DMA_ATTR_FORCE_CONTIGUOUS);\n-\tmem-\u003esize = 0;\n-\tmem-\u003eva = NULL;\n-\tmem-\u003epa = 0;\n-}\n-\n static int idpf_hwtstamp_set(struct net_device *netdev,\n \t\t\t struct kernel_hwtstamp_config *config,\n \t\t\t struct netlink_ext_ack *extack)\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c\nindex ab3c409e587bb..9840580fbe51e 100644\n--- a/drivers/net/ethernet/intel/idpf/idpf_main.c\n+++ b/drivers/net/ethernet/intel/idpf/idpf_main.c\n@@ -15,6 +15,8 @@\n \n MODULE_DESCRIPTION(DRV_SUMMARY);\n MODULE_IMPORT_NS(\"LIBETH\");\n+MODULE_IMPORT_NS(\"LIBIE_CP\");\n+MODULE_IMPORT_NS(\"LIBIE_PCI\");\n MODULE_IMPORT_NS(\"LIBETH_XDP\");\n MODULE_LICENSE(\"GPL\");\n \n@@ -56,8 +58,16 @@ static int idpf_get_device_type(struct pci_dev *pdev)\n static int idpf_dev_init(struct idpf_adapter *adapter,\n \t\t\t const struct pci_device_id *ent)\n {\n+\tstruct libie_mmio_info *mmio_info = \u0026adapter-\u003ectlq_ctx.mmio_info;\n \tint ret;\n \n+\tret = libie_pci_init_dev(adapter-\u003epdev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tmmio_info-\u003epdev = adapter-\u003epdev;\n+\tINIT_LIST_HEAD(\u0026mmio_info-\u003emmio_list);\n+\n \tif (ent-\u003eclass == IDPF_CLASS_NETWORK_ETHERNET_PROGIF) {\n \t\tret = idpf_get_device_type(adapter-\u003epdev);\n \t\tswitch (ret) {\n@@ -90,6 +100,15 @@ static int idpf_dev_init(struct idpf_adapter *adapter,\n \treturn 0;\n }\n \n+/**\n+ * idpf_decfg_device - deconfigure device and device specific resources\n+ * @adapter: driver specific private structure\n+ */\n+static void idpf_decfg_device(struct idpf_adapter *adapter)\n+{\n+\tlibie_pci_unmap_all_mmio_regions(\u0026adapter-\u003ectlq_ctx.mmio_info);\n+}\n+\n /**\n * idpf_remove - Device removal routine\n * @pdev: PCI device information struct\n@@ -151,14 +170,13 @@ static void idpf_remove(struct pci_dev *pdev)\n \tadapter-\u003evport_config = NULL;\n \tkfree(adapter-\u003enetdevs);\n \tadapter-\u003enetdevs = NULL;\n-\tkfree(adapter-\u003evcxn_mngr);\n-\tadapter-\u003evcxn_mngr = NULL;\n \n \tmutex_destroy(\u0026adapter-\u003evport_ctrl_lock);\n \tmutex_destroy(\u0026adapter-\u003evector_lock);\n \tmutex_destroy(\u0026adapter-\u003equeue_lock);\n \tmutex_destroy(\u0026adapter-\u003evc_buf_lock);\n \n+\tidpf_decfg_device(adapter);\n \tpci_set_drvdata(pdev, NULL);\n \tkfree(adapter);\n }\n@@ -181,46 +199,44 @@ static void idpf_shutdown(struct pci_dev *pdev)\n }\n \n /**\n- * idpf_cfg_hw - Initialize HW struct\n- * @adapter: adapter to setup hw struct for\n+ * idpf_cfg_device - configure device and device specific resources\n+ * @adapter: driver specific private structure\n *\n- * Returns 0 on success, negative on failure\n+ * Return: %0 on success, -%errno on failure.\n */\n-static int idpf_cfg_hw(struct idpf_adapter *adapter)\n+static int idpf_cfg_device(struct idpf_adapter *adapter)\n {\n-\tresource_size_t res_start, mbx_start, rstat_start;\n+\tstruct libie_mmio_info *mmio_info = \u0026adapter-\u003ectlq_ctx.mmio_info;\n \tstruct pci_dev *pdev = adapter-\u003epdev;\n-\tstruct idpf_hw *hw = \u0026adapter-\u003ehw;\n-\tstruct device *dev = \u0026pdev-\u003edev;\n-\tlong len;\n-\n-\tres_start = pci_resource_start(pdev, 0);\n+\tstruct resource *region;\n+\tbool mapped;\n+\tint err;\n \n \t/* Map mailbox space for virtchnl communication */\n-\tmbx_start = res_start + adapter-\u003edev_ops.static_reg_info[0].start;\n-\tlen = resource_size(\u0026adapter-\u003edev_ops.static_reg_info[0]);\n-\thw-\u003embx.vaddr = devm_ioremap(dev, mbx_start, len);\n-\tif (!hw-\u003embx.vaddr) {\n-\t\tpci_err(pdev, \"failed to allocate BAR0 mbx region\\n\");\n-\n+\tregion = \u0026adapter-\u003edev_ops.static_reg_info[0];\n+\tmapped = libie_pci_map_mmio_region(mmio_info, region-\u003estart,\n+\t\t\t\t\t resource_size(region));\n+\tif (!mapped) {\n+\t\tpci_err(pdev, \"failed to map BAR0 mbx region\\n\");\n \t\treturn -ENOMEM;\n \t}\n-\thw-\u003embx.addr_start = adapter-\u003edev_ops.static_reg_info[0].start;\n-\thw-\u003embx.addr_len = len;\n \n \t/* Map rstat space for resets */\n-\trstat_start = res_start + adapter-\u003edev_ops.static_reg_info[1].start;\n-\tlen = resource_size(\u0026adapter-\u003edev_ops.static_reg_info[1]);\n-\thw-\u003erstat.vaddr = devm_ioremap(dev, rstat_start, len);\n-\tif (!hw-\u003erstat.vaddr) {\n-\t\tpci_err(pdev, \"failed to allocate BAR0 rstat region\\n\");\n+\tregion = \u0026adapter-\u003edev_ops.static_reg_info[1];\n \n+\tmapped = libie_pci_map_mmio_region(mmio_info, region-\u003estart,\n+\t\t\t\t\t resource_size(region));\n+\tif (!mapped) {\n+\t\tpci_err(pdev, \"failed to map BAR0 rstat region\\n\");\n+\t\tlibie_pci_unmap_all_mmio_regions(mmio_info);\n \t\treturn -ENOMEM;\n \t}\n-\thw-\u003erstat.addr_start = adapter-\u003edev_ops.static_reg_info[1].start;\n-\thw-\u003erstat.addr_len = len;\n \n-\thw-\u003eback = adapter;\n+\terr = pci_enable_ptm(pdev);\n+\tif (err)\n+\t\tpci_dbg(pdev, \"PCIe PTM is not supported by PCIe bus/controller\\n\");\n+\n+\tpci_set_drvdata(pdev, adapter);\n \n \treturn 0;\n }\n@@ -246,32 +262,21 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n \tadapter-\u003ereq_rx_splitq = true;\n \n \tadapter-\u003epdev = pdev;\n-\terr = pcim_enable_device(pdev);\n-\tif (err)\n-\t\tgoto err_free;\n \n-\terr = pcim_request_region(pdev, 0, pci_name(pdev));\n+\terr = idpf_dev_init(adapter, ent);\n \tif (err) {\n-\t\tpci_err(pdev, \"pcim_request_region failed %pe\\n\", ERR_PTR(err));\n-\n+\t\tdev_err(\u0026pdev-\u003edev, \"Failed to initialize device (ID 0x%x): %d\\n\",\n+\t\t\tent-\u003edevice, err);\n \t\tgoto err_free;\n \t}\n \n-\terr = pci_enable_ptm(pdev);\n-\tif (err)\n-\t\tpci_dbg(pdev, \"PCIe PTM is not supported by PCIe bus/controller\\n\");\n-\n-\t/* set up for high or low dma */\n-\terr = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));\n+\terr = idpf_cfg_device(adapter);\n \tif (err) {\n-\t\tpci_err(pdev, \"DMA configuration failed: %pe\\n\", ERR_PTR(err));\n-\n+\t\tpci_err(pdev, \"Failed to configure device specific resources: %pe\\n\",\n+\t\t\tERR_PTR(err));\n \t\tgoto err_free;\n \t}\n \n-\tpci_set_master(pdev);\n-\tpci_set_drvdata(pdev, adapter);\n-\n \tadapter-\u003einit_wq = alloc_workqueue(\"%s-%s-init\",\n \t\t\t\t\t WQ_UNBOUND | WQ_MEM_RECLAIM, 0,\n \t\t\t\t\t dev_driver_string(dev),\n@@ -279,7 +284,7 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n \tif (!adapter-\u003einit_wq) {\n \t\tdev_err(dev, \"Failed to allocate init workqueue\\n\");\n \t\terr = -ENOMEM;\n-\t\tgoto err_free;\n+\t\tgoto err_init_wq;\n \t}\n \n \tadapter-\u003eserv_wq = alloc_workqueue(\"%s-%s-service\",\n@@ -324,20 +329,6 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n \t/* setup msglvl */\n \tadapter-\u003emsg_enable = netif_msg_init(-1, IDPF_AVAIL_NETIF_M);\n \n-\terr = idpf_dev_init(adapter, ent);\n-\tif (err) {\n-\t\tdev_err(\u0026pdev-\u003edev, \"Unexpected dev ID 0x%x in idpf probe\\n\",\n-\t\t\tent-\u003edevice);\n-\t\tgoto destroy_vc_event_wq;\n-\t}\n-\n-\terr = idpf_cfg_hw(adapter);\n-\tif (err) {\n-\t\tdev_err(dev, \"Failed to configure HW structure for adapter: %d\\n\",\n-\t\t\terr);\n-\t\tgoto destroy_vc_event_wq;\n-\t}\n-\n \tmutex_init(\u0026adapter-\u003evport_ctrl_lock);\n \tmutex_init(\u0026adapter-\u003evector_lock);\n \tmutex_init(\u0026adapter-\u003equeue_lock);\n@@ -356,8 +347,6 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n \n \treturn 0;\n \n-destroy_vc_event_wq:\n-\tdestroy_workqueue(adapter-\u003evc_event_wq);\n err_vc_event_wq_alloc:\n \tdestroy_workqueue(adapter-\u003estats_wq);\n err_stats_wq_alloc:\n@@ -366,6 +355,8 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n \tdestroy_workqueue(adapter-\u003eserv_wq);\n err_serv_wq_alloc:\n \tdestroy_workqueue(adapter-\u003einit_wq);\n+err_init_wq:\n+\tidpf_decfg_device(adapter);\n err_free:\n \tkfree(adapter);\n \treturn err;\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_mem.h b/drivers/net/ethernet/intel/idpf/idpf_mem.h\ndeleted file mode 100644\nindex 2aaabdc02dd24..0000000000000\n--- a/drivers/net/ethernet/intel/idpf/idpf_mem.h\n+++ /dev/null\n@@ -1,20 +0,0 @@\n-/* SPDX-License-Identifier: GPL-2.0-only */\n-/* Copyright (C) 2023 Intel Corporation */\n-\n-#ifndef _IDPF_MEM_H_\n-#define _IDPF_MEM_H_\n-\n-#include \u003clinux/io.h\u003e\n-\n-struct idpf_dma_mem {\n-\tvoid *va;\n-\tdma_addr_t pa;\n-\tsize_t size;\n-};\n-\n-#define idpf_mbx_wr32(a, reg, value)\twritel((value), ((a)-\u003embx.vaddr + (reg)))\n-#define idpf_mbx_rd32(a, reg)\t\treadl((a)-\u003embx.vaddr + (reg))\n-#define idpf_mbx_wr64(a, reg, value)\twriteq((value), ((a)-\u003embx.vaddr + (reg)))\n-#define idpf_mbx_rd64(a, reg)\t\treadq((a)-\u003embx.vaddr + (reg))\n-\n-#endif /* _IDPF_MEM_H_ */\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c\nindex 99fcd8e298d64..c3ffb445297f8 100644\n--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c\n+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c\n@@ -4676,11 +4676,11 @@ int idpf_config_rss(struct idpf_vport *vport, struct idpf_rss_data *rss_data)\n \tu32 vport_id = vport-\u003evport_id;\n \tint err;\n \n-\terr = idpf_send_get_set_rss_key_msg(adapter, rss_data, vport_id, false);\n+\terr = idpf_send_set_rss_key_msg(adapter, rss_data, vport_id);\n \tif (err)\n \t\treturn err;\n \n-\treturn idpf_send_get_set_rss_lut_msg(adapter, rss_data, vport_id, false);\n+\treturn idpf_send_set_rss_lut_msg(adapter, rss_data, vport_id);\n }\n \n /**\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h\nindex 908dfa28674eb..93547597efd2a 100644\n--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h\n+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h\n@@ -5,6 +5,7 @@\n #define _IDPF_TXRX_H_\n \n #include \u003clinux/dim.h\u003e\n+#include \u003clinux/net/intel/virtchnl2_lan_desc.h\u003e\n \n #include \u003cnet/libeth/cache.h\u003e\n #include \u003cnet/libeth/types.h\u003e\n@@ -13,7 +14,6 @@\n #include \u003cnet/xdp.h\u003e\n \n #include \"idpf_lan_txrx.h\"\n-#include \"virtchnl2_lan_desc.h\"\n \n #define IDPF_LARGE_MAX_Q\t\t\t256\n #define IDPF_MAX_Q\t\t\t\t16\n@@ -236,7 +236,7 @@ enum idpf_tx_ctx_desc_eipt_offload {\n \t\t\t\t (sizeof(u16) * IDPF_RX_MAX_PTYPE_PROTO_IDS))\n #define IDPF_RX_PTYPE_HDR_SZ\tsizeof(struct virtchnl2_get_ptype_info)\n #define IDPF_RX_MAX_PTYPES_PER_BUF\t\\\n-\tDIV_ROUND_DOWN_ULL((IDPF_CTLQ_MAX_BUF_LEN - IDPF_RX_PTYPE_HDR_SZ), \\\n+\tDIV_ROUND_DOWN_ULL(LIBIE_CTLQ_MAX_BUF_LEN - IDPF_RX_PTYPE_HDR_SZ, \\\n \t\t\t IDPF_RX_MAX_PTYPE_SZ)\n \n #define IDPF_GET_PTYPE_SIZE(p) struct_size((p), proto_id, (p)-\u003eproto_id_count)\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c\nindex 6726084f6cfa0..b537de3592f43 100644\n--- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c\n+++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c\n@@ -9,45 +9,32 @@\n \n /**\n * idpf_vf_ctlq_reg_init - initialize default mailbox registers\n- * @adapter: adapter structure\n- * @cq: pointer to the array of create control queues\n+ * @mmio: struct that contains MMIO region info\n+ * @cci: struct where the register offset pointer to be copied to\n */\n-static void idpf_vf_ctlq_reg_init(struct idpf_adapter *adapter,\n-\t\t\t\t struct idpf_ctlq_create_info *cq)\n+static void idpf_vf_ctlq_reg_init(struct libie_mmio_info *mmio,\n+\t\t\t\t struct libie_ctlq_create_info *cci)\n {\n-\tresource_size_t mbx_start = adapter-\u003edev_ops.static_reg_info[0].start;\n-\tint i;\n-\n-\tfor (i = 0; i \u003c IDPF_NUM_DFLT_MBX_Q; i++) {\n-\t\tstruct idpf_ctlq_create_info *ccq = cq + i;\n-\n-\t\tswitch (ccq-\u003etype) {\n-\t\tcase IDPF_CTLQ_TYPE_MAILBOX_TX:\n-\t\t\t/* set head and tail registers in our local struct */\n-\t\t\tccq-\u003ereg.head = VF_ATQH - mbx_start;\n-\t\t\tccq-\u003ereg.tail = VF_ATQT - mbx_start;\n-\t\t\tccq-\u003ereg.len = VF_ATQLEN - mbx_start;\n-\t\t\tccq-\u003ereg.bah = VF_ATQBAH - mbx_start;\n-\t\t\tccq-\u003ereg.bal = VF_ATQBAL - mbx_start;\n-\t\t\tccq-\u003ereg.len_mask = VF_ATQLEN_ATQLEN_M;\n-\t\t\tccq-\u003ereg.len_ena_mask = VF_ATQLEN_ATQENABLE_M;\n-\t\t\tccq-\u003ereg.head_mask = VF_ATQH_ATQH_M;\n-\t\t\tbreak;\n-\t\tcase IDPF_CTLQ_TYPE_MAILBOX_RX:\n-\t\t\t/* set head and tail registers in our local struct */\n-\t\t\tccq-\u003ereg.head = VF_ARQH - mbx_start;\n-\t\t\tccq-\u003ereg.tail = VF_ARQT - mbx_start;\n-\t\t\tccq-\u003ereg.len = VF_ARQLEN - mbx_start;\n-\t\t\tccq-\u003ereg.bah = VF_ARQBAH - mbx_start;\n-\t\t\tccq-\u003ereg.bal = VF_ARQBAL - mbx_start;\n-\t\t\tccq-\u003ereg.len_mask = VF_ARQLEN_ARQLEN_M;\n-\t\t\tccq-\u003ereg.len_ena_mask = VF_ARQLEN_ARQENABLE_M;\n-\t\t\tccq-\u003ereg.head_mask = VF_ARQH_ARQH_M;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tbreak;\n-\t\t}\n-\t}\n+\tstruct libie_ctlq_reg *tx_reg = \u0026cci[LIBIE_CTLQ_TYPE_TX].reg;\n+\tstruct libie_ctlq_reg *rx_reg = \u0026cci[LIBIE_CTLQ_TYPE_RX].reg;\n+\n+\ttx_reg-\u003ehead\t\t= libie_pci_get_mmio_addr(mmio, VF_ATQH);\n+\ttx_reg-\u003etail\t\t= libie_pci_get_mmio_addr(mmio, VF_ATQT);\n+\ttx_reg-\u003elen\t\t= libie_pci_get_mmio_addr(mmio, VF_ATQLEN);\n+\ttx_reg-\u003eaddr_high\t= libie_pci_get_mmio_addr(mmio, VF_ATQBAH);\n+\ttx_reg-\u003eaddr_low\t= libie_pci_get_mmio_addr(mmio, VF_ATQBAL);\n+\ttx_reg-\u003elen_mask\t= VF_ATQLEN_ATQLEN_M;\n+\ttx_reg-\u003elen_ena_mask\t= VF_ATQLEN_ATQENABLE_M;\n+\ttx_reg-\u003ehead_mask\t= VF_ATQH_ATQH_M;\n+\n+\trx_reg-\u003ehead\t\t= libie_pci_get_mmio_addr(mmio, VF_ARQH);\n+\trx_reg-\u003etail\t\t= libie_pci_get_mmio_addr(mmio, VF_ARQT);\n+\trx_reg-\u003elen\t\t= libie_pci_get_mmio_addr(mmio, VF_ARQLEN);\n+\trx_reg-\u003eaddr_high\t= libie_pci_get_mmio_addr(mmio, VF_ARQBAH);\n+\trx_reg-\u003eaddr_low\t= libie_pci_get_mmio_addr(mmio, VF_ARQBAL);\n+\trx_reg-\u003elen_mask\t= VF_ARQLEN_ARQLEN_M;\n+\trx_reg-\u003elen_ena_mask\t= VF_ARQLEN_ARQENABLE_M;\n+\trx_reg-\u003ehead_mask\t= VF_ARQH_ARQH_M;\n }\n \n /**\n@@ -56,13 +43,14 @@ static void idpf_vf_ctlq_reg_init(struct idpf_adapter *adapter,\n */\n static void idpf_vf_mb_intr_reg_init(struct idpf_adapter *adapter)\n {\n+\tstruct libie_mmio_info *mmio = \u0026adapter-\u003ectlq_ctx.mmio_info;\n \tstruct idpf_intr_reg *intr = \u0026adapter-\u003emb_vector.intr_reg;\n \tu32 dyn_ctl = le32_to_cpu(adapter-\u003ecaps.mailbox_dyn_ctl);\n \n-\tintr-\u003edyn_ctl = idpf_get_reg_addr(adapter, dyn_ctl);\n+\tintr-\u003edyn_ctl = libie_pci_get_mmio_addr(mmio, dyn_ctl);\n \tintr-\u003edyn_ctl_intena_m = VF_INT_DYN_CTL0_INTENA_M;\n \tintr-\u003edyn_ctl_itridx_m = VF_INT_DYN_CTL0_ITR_INDX_M;\n-\tintr-\u003eicr_ena = idpf_get_reg_addr(adapter, VF_INT_ICR0_ENA1);\n+\tintr-\u003eicr_ena = libie_pci_get_mmio_addr(mmio, VF_INT_ICR0_ENA1);\n \tintr-\u003eicr_ena_ctlq_m = VF_INT_ICR0_ENA1_ADMINQ_M;\n }\n \n@@ -77,6 +65,7 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport,\n \tstruct idpf_adapter *adapter = vport-\u003eadapter;\n \tu16 num_vecs = rsrc-\u003enum_q_vectors;\n \tstruct idpf_vec_regs *reg_vals;\n+\tstruct libie_mmio_info *mmio;\n \tint num_regs, i, err = 0;\n \tu32 rx_itr, tx_itr, val;\n \tu16 total_vecs;\n@@ -92,14 +81,17 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport,\n \t\tgoto free_reg_vals;\n \t}\n \n+\tmmio = \u0026adapter-\u003ectlq_ctx.mmio_info;\n+\n \tfor (i = 0; i \u003c num_vecs; i++) {\n \t\tstruct idpf_q_vector *q_vector = \u0026rsrc-\u003eq_vectors[i];\n \t\tu16 vec_id = rsrc-\u003eq_vector_idxs[i] - IDPF_MBX_Q_VEC;\n \t\tstruct idpf_intr_reg *intr = \u0026q_vector-\u003eintr_reg;\n+\t\tstruct idpf_vec_regs *reg = \u0026reg_vals[vec_id];\n \t\tu32 spacing;\n \n-\t\tintr-\u003edyn_ctl = idpf_get_reg_addr(adapter,\n-\t\t\t\t\t\t reg_vals[vec_id].dyn_ctl_reg);\n+\t\tintr-\u003edyn_ctl = libie_pci_get_mmio_addr(mmio,\n+\t\t\t\t\t\t\treg-\u003edyn_ctl_reg);\n \t\tintr-\u003edyn_ctl_intena_m = VF_INT_DYN_CTLN_INTENA_M;\n \t\tintr-\u003edyn_ctl_intena_msk_m = VF_INT_DYN_CTLN_INTENA_MSK_M;\n \t\tintr-\u003edyn_ctl_itridx_s = VF_INT_DYN_CTLN_ITR_INDX_S;\n@@ -109,22 +101,21 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport,\n \t\tintr-\u003edyn_ctl_sw_itridx_ena_m =\n \t\t\tVF_INT_DYN_CTLN_SW_ITR_INDX_ENA_M;\n \n-\t\tspacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing,\n+\t\tspacing = IDPF_ITR_IDX_SPACING(reg-\u003eitrn_index_spacing,\n \t\t\t\t\t IDPF_VF_ITR_IDX_SPACING);\n \t\trx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_0,\n-\t\t\t\t\t reg_vals[vec_id].itrn_reg,\n-\t\t\t\t\t spacing);\n+\t\t\t\t\t reg-\u003eitrn_reg, spacing);\n \t\ttx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_1,\n-\t\t\t\t\t reg_vals[vec_id].itrn_reg,\n-\t\t\t\t\t spacing);\n-\t\tintr-\u003erx_itr = idpf_get_reg_addr(adapter, rx_itr);\n-\t\tintr-\u003etx_itr = idpf_get_reg_addr(adapter, tx_itr);\n+\t\t\t\t\t reg-\u003eitrn_reg, spacing);\n+\t\tintr-\u003erx_itr = libie_pci_get_mmio_addr(mmio, rx_itr);\n+\t\tintr-\u003etx_itr = libie_pci_get_mmio_addr(mmio, tx_itr);\n \t}\n \n \t/* Data vector for NOIRQ queues */\n \n \tval = reg_vals[rsrc-\u003eq_vector_idxs[i] - IDPF_MBX_Q_VEC].dyn_ctl_reg;\n-\trsrc-\u003enoirq_dyn_ctl = idpf_get_reg_addr(adapter, val);\n+\trsrc-\u003enoirq_dyn_ctl =\n+\t\tlibie_pci_get_mmio_addr(\u0026adapter-\u003ectlq_ctx.mmio_info, val);\n \n \tval = VF_INT_DYN_CTLN_WB_ON_ITR_M | VF_INT_DYN_CTLN_INTENA_MSK_M |\n \t FIELD_PREP(VF_INT_DYN_CTLN_ITR_INDX_M, IDPF_NO_ITR_UPDATE_IDX);\n@@ -142,7 +133,9 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport,\n */\n static void idpf_vf_reset_reg_init(struct idpf_adapter *adapter)\n {\n-\tadapter-\u003ereset_reg.rstat = idpf_get_rstat_reg_addr(adapter, VFGEN_RSTAT);\n+\tadapter-\u003ereset_reg.rstat =\n+\t\tlibie_pci_get_mmio_addr(\u0026adapter-\u003ectlq_ctx.mmio_info,\n+\t\t\t\t\tVFGEN_RSTAT);\n \tadapter-\u003ereset_reg.rstat_m = VFGEN_RSTAT_VFR_STATE_M;\n }\n \n@@ -157,8 +150,7 @@ static void idpf_vf_trigger_reset(struct idpf_adapter *adapter,\n \t/* Do not send VIRTCHNL2_OP_RESET_VF message on driver unload */\n \tif (trig_cause == IDPF_HR_FUNC_RESET \u0026\u0026\n \t !test_bit(IDPF_REMOVE_IN_PROG, adapter-\u003eflags))\n-\t\tidpf_send_mb_msg(adapter, adapter-\u003ehw.asq,\n-\t\t\t\t VIRTCHNL2_OP_RESET_VF, 0, NULL, 0);\n+\t\tidpf_send_vf_reset_msg(adapter);\n }\n \n /**\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c\nindex 8bd6cca64c9bf..1caf527069737 100644\n--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c\n+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c\n@@ -2,26 +2,13 @@\n /* Copyright (C) 2023 Intel Corporation */\n \n #include \u003clinux/export.h\u003e\n+#include \u003clinux/net/intel/libie/pci.h\u003e\n #include \u003cnet/libeth/rx.h\u003e\n \n #include \"idpf.h\"\n #include \"idpf_virtchnl.h\"\n #include \"idpf_ptp.h\"\n \n-/**\n- * struct idpf_vc_xn_manager - Manager for tracking transactions\n- * @ring: backing and lookup for transactions\n- * @free_xn_bm: bitmap for free transactions\n- * @xn_bm_lock: make bitmap access synchronous where necessary\n- * @salt: used to make cookie unique every message\n- */\n-struct idpf_vc_xn_manager {\n-\tstruct idpf_vc_xn ring[IDPF_VC_XN_RING_LEN];\n-\tDECLARE_BITMAP(free_xn_bm, IDPF_VC_XN_RING_LEN);\n-\tspinlock_t xn_bm_lock;\n-\tu8 salt;\n-};\n-\n /**\n * idpf_vid_to_vport - Translate vport id to vport pointer\n * @adapter: private data struct\n@@ -82,79 +69,62 @@ static void idpf_handle_event_link(struct idpf_adapter *adapter,\n \n /**\n * idpf_recv_event_msg - Receive virtchnl event message\n- * @adapter: Driver specific private structure\n+ * @ctx: control queue context\n * @ctlq_msg: message to copy from\n *\n * Receive virtchnl event message\n */\n-static void idpf_recv_event_msg(struct idpf_adapter *adapter,\n-\t\t\t\tstruct idpf_ctlq_msg *ctlq_msg)\n+void idpf_recv_event_msg(struct libie_ctlq_ctx *ctx,\n+\t\t\t struct libie_ctlq_msg *ctlq_msg)\n {\n-\tint payload_size = ctlq_msg-\u003ectx.indirect.payload-\u003esize;\n+\tstruct kvec *buff = \u0026ctlq_msg-\u003erecv_mem;\n+\tint payload_size = buff-\u003eiov_len;\n+\tstruct idpf_adapter *adapter;\n \tstruct virtchnl2_event *v2e;\n \tu32 event;\n \n+\tadapter = container_of(ctx, struct idpf_adapter, ctlq_ctx);\n+\tif (ctlq_msg-\u003echnl_opcode != VIRTCHNL2_OP_EVENT) {\n+\t\tdev_dbg(\u0026adapter-\u003epdev-\u003edev,\n+\t\t\t\"Unhandled message with opcode %u from CP\\n\",\n+\t\t\tctlq_msg-\u003echnl_opcode);\n+\t\tgoto free_rx_buf;\n+\t}\n+\n \tif (payload_size \u003c sizeof(*v2e)) {\n \t\tdev_err_ratelimited(\u0026adapter-\u003epdev-\u003edev, \"Failed to receive valid payload for event msg (op %d len %d)\\n\",\n-\t\t\t\t ctlq_msg-\u003ecookie.mbx.chnl_opcode,\n+\t\t\t\t ctlq_msg-\u003echnl_opcode,\n \t\t\t\t payload_size);\n-\t\treturn;\n+\t\tgoto free_rx_buf;\n \t}\n \n-\tv2e = (struct virtchnl2_event *)ctlq_msg-\u003ectx.indirect.payload-\u003eva;\n+\tv2e = (struct virtchnl2_event *)buff-\u003eiov_base;\n \tevent = le32_to_cpu(v2e-\u003eevent);\n \n \tswitch (event) {\n \tcase VIRTCHNL2_EVENT_LINK_CHANGE:\n \t\tidpf_handle_event_link(adapter, v2e);\n-\t\treturn;\n+\t\tbreak;\n \tdefault:\n \t\tdev_err(\u0026adapter-\u003epdev-\u003edev,\n \t\t\t\"Unknown event %d from PF\\n\", event);\n \t\tbreak;\n \t}\n+\n+free_rx_buf:\n+\tlibie_ctlq_release_rx_buf(buff);\n }\n \n /**\n * idpf_mb_clean - Reclaim the send mailbox queue entries\n- * @adapter: driver specific private structure\n * @asq: send control queue info\n+ * @deinit: release all buffers before destroying the queue\n *\n- * Reclaim the send mailbox queue entries to be used to send further messages\n- *\n- * Return: 0 on success, negative on failure\n+ * This is a helper function to clean the send mailbox queue entries.\n */\n-static int idpf_mb_clean(struct idpf_adapter *adapter,\n-\t\t\t struct idpf_ctlq_info *asq)\n+static void idpf_mb_clean(struct libie_ctlq_info *asq, bool deinit)\n {\n-\tu16 i, num_q_msg = IDPF_DFLT_MBX_Q_LEN;\n-\tstruct idpf_ctlq_msg **q_msg;\n-\tstruct idpf_dma_mem *dma_mem;\n-\tint err;\n-\n-\tq_msg = kzalloc_objs(struct idpf_ctlq_msg *, num_q_msg, GFP_ATOMIC);\n-\tif (!q_msg)\n-\t\treturn -ENOMEM;\n-\n-\terr = idpf_ctlq_clean_sq(asq, \u0026num_q_msg, q_msg);\n-\tif (err)\n-\t\tgoto err_kfree;\n-\n-\tfor (i = 0; i \u003c num_q_msg; i++) {\n-\t\tif (!q_msg[i])\n-\t\t\tcontinue;\n-\t\tdma_mem = q_msg[i]-\u003ectx.indirect.payload;\n-\t\tif (dma_mem)\n-\t\t\tdma_free_coherent(\u0026adapter-\u003epdev-\u003edev, dma_mem-\u003esize,\n-\t\t\t\t\t dma_mem-\u003eva, dma_mem-\u003epa);\n-\t\tkfree(q_msg[i]);\n-\t\tkfree(dma_mem);\n-\t}\n-\n-err_kfree:\n-\tkfree(q_msg);\n-\n-\treturn err;\n+\tlibie_ctlq_xn_send_clean(asq, kfree, deinit);\n }\n \n #if IS_ENABLED(CONFIG_PTP_1588_CLOCK)\n@@ -188,7 +158,7 @@ static bool idpf_ptp_is_mb_msg(u32 op)\n * @ctlq_msg: Corresponding control queue message\n */\n static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,\n-\t\t\t\t struct idpf_ctlq_msg *ctlq_msg)\n+\t\t\t\t struct libie_ctlq_msg *ctlq_msg)\n {\n \t/* If the message is PTP-related and the secondary mailbox is available,\n \t * send the message through the secondary mailbox.\n@@ -196,530 +166,106 @@ static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,\n \tif (!idpf_ptp_is_mb_msg(op) || !adapter-\u003eptp-\u003esecondary_mbx.valid)\n \t\treturn;\n \n-\tctlq_msg-\u003eopcode = idpf_mbq_opc_send_msg_to_peer_drv;\n+\tctlq_msg-\u003eopcode = LIBIE_CTLQ_SEND_MSG_TO_PEER;\n \tctlq_msg-\u003efunc_id = adapter-\u003eptp-\u003esecondary_mbx.peer_mbx_q_id;\n-\tctlq_msg-\u003ehost_id = adapter-\u003eptp-\u003esecondary_mbx.peer_id;\n+\tctlq_msg-\u003eflags = FIELD_PREP(LIBIE_CTLQ_DESC_FLAG_HOST_ID,\n+\t\t\t\t adapter-\u003eptp-\u003esecondary_mbx.peer_id);\n }\n #else /* !CONFIG_PTP_1588_CLOCK */\n static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,\n-\t\t\t\t struct idpf_ctlq_msg *ctlq_msg)\n+\t\t\t\t struct libie_ctlq_msg *ctlq_msg)\n { }\n #endif /* CONFIG_PTP_1588_CLOCK */\n \n /**\n- * idpf_send_mb_msg - Send message over mailbox\n+ * idpf_send_mb_msg - send mailbox message to the device control plane\n * @adapter: driver specific private structure\n- * @asq: control queue to send message to\n- * @op: virtchnl opcode\n- * @msg_size: size of the payload\n- * @msg: pointer to buffer holding the payload\n- * @cookie: unique SW generated cookie per message\n+ * @xn_params: Xn send parameters to fill\n+ * @send_buf: buffer to send\n+ * @send_buf_size: size of the send buffer\n *\n- * Will prepare the control queue message and initiates the send api\n+ * Fill the Xn parameters with the required info to send a virtchnl message.\n+ * The send buffer is DMA mapped in the libie to avoid memcpy.\n *\n- * Return: 0 on success, negative on failure\n- */\n-int idpf_send_mb_msg(struct idpf_adapter *adapter, struct idpf_ctlq_info *asq,\n-\t\t u32 op, u16 msg_size, u8 *msg, u16 cookie)\n-{\n-\tstruct idpf_ctlq_msg *ctlq_msg;\n-\tstruct idpf_dma_mem *dma_mem;\n-\tint err;\n-\n-\t/* If we are here and a reset is detected nothing much can be\n-\t * done. This thread should silently abort and expected to\n-\t * be corrected with a new run either by user or driver\n-\t * flows after reset\n-\t */\n-\tif (idpf_is_reset_detected(adapter))\n-\t\treturn 0;\n-\n-\terr = idpf_mb_clean(adapter, asq);\n-\tif (err)\n-\t\treturn err;\n-\n-\tctlq_msg = kzalloc_obj(*ctlq_msg, GFP_ATOMIC);\n-\tif (!ctlq_msg)\n-\t\treturn -ENOMEM;\n-\n-\tdma_mem = kzalloc_obj(*dma_mem, GFP_ATOMIC);\n-\tif (!dma_mem) {\n-\t\terr = -ENOMEM;\n-\t\tgoto dma_mem_error;\n-\t}\n-\n-\tctlq_msg-\u003eopcode = idpf_mbq_opc_send_msg_to_cp;\n-\tctlq_msg-\u003efunc_id = 0;\n-\n-\tidpf_prepare_ptp_mb_msg(adapter, op, ctlq_msg);\n-\n-\tctlq_msg-\u003edata_len = msg_size;\n-\tctlq_msg-\u003ecookie.mbx.chnl_opcode = op;\n-\tctlq_msg-\u003ecookie.mbx.chnl_retval = 0;\n-\tdma_mem-\u003esize = IDPF_CTLQ_MAX_BUF_LEN;\n-\tdma_mem-\u003eva = dma_alloc_coherent(\u0026adapter-\u003epdev-\u003edev, dma_mem-\u003esize,\n-\t\t\t\t\t \u0026dma_mem-\u003epa, GFP_ATOMIC);\n-\tif (!dma_mem-\u003eva) {\n-\t\terr = -ENOMEM;\n-\t\tgoto dma_alloc_error;\n-\t}\n-\n-\t/* It's possible we're just sending an opcode but no buffer */\n-\tif (msg \u0026\u0026 msg_size)\n-\t\tmemcpy(dma_mem-\u003eva, msg, msg_size);\n-\tctlq_msg-\u003ectx.indirect.payload = dma_mem;\n-\tctlq_msg-\u003ectx.sw_cookie.data = cookie;\n-\n-\terr = idpf_ctlq_send(\u0026adapter-\u003ehw, asq, 1, ctlq_msg);\n-\tif (err)\n-\t\tgoto send_error;\n-\n-\treturn 0;\n-\n-send_error:\n-\tdma_free_coherent(\u0026adapter-\u003epdev-\u003edev, dma_mem-\u003esize, dma_mem-\u003eva,\n-\t\t\t dma_mem-\u003epa);\n-dma_alloc_error:\n-\tkfree(dma_mem);\n-dma_mem_error:\n-\tkfree(ctlq_msg);\n-\n-\treturn err;\n-}\n-\n-/* API for virtchnl \"transaction\" support (\"xn\" for short). */\n-\n-/**\n- * idpf_vc_xn_lock - Request exclusive access to vc transaction\n- * @xn: struct idpf_vc_xn* to access\n- */\n-#define idpf_vc_xn_lock(xn)\t\t\t\\\n-\tspin_lock(\u0026(xn)-\u003elock)\n-\n-/**\n- * idpf_vc_xn_unlock - Release exclusive access to vc transaction\n- * @xn: struct idpf_vc_xn* to access\n- */\n-#define idpf_vc_xn_unlock(xn)\t\t\\\n-\tspin_unlock(\u0026(xn)-\u003elock)\n-\n-/**\n- * idpf_vc_xn_release_bufs - Release reference to reply buffer(s) and\n- * reset the transaction state.\n- * @xn: struct idpf_vc_xn to update\n- */\n-static void idpf_vc_xn_release_bufs(struct idpf_vc_xn *xn)\n-{\n-\txn-\u003ereply.iov_base = NULL;\n-\txn-\u003ereply.iov_len = 0;\n-\n-\tif (xn-\u003estate != IDPF_VC_XN_SHUTDOWN)\n-\t\txn-\u003estate = IDPF_VC_XN_IDLE;\n-}\n-\n-/**\n- * idpf_vc_xn_init - Initialize virtchnl transaction object\n- * @vcxn_mngr: pointer to vc transaction manager struct\n- */\n-static void idpf_vc_xn_init(struct idpf_vc_xn_manager *vcxn_mngr)\n-{\n-\tint i;\n-\n-\tspin_lock_init(\u0026vcxn_mngr-\u003exn_bm_lock);\n-\n-\tfor (i = 0; i \u003c ARRAY_SIZE(vcxn_mngr-\u003ering); i++) {\n-\t\tstruct idpf_vc_xn *xn = \u0026vcxn_mngr-\u003ering[i];\n-\n-\t\txn-\u003estate = IDPF_VC_XN_IDLE;\n-\t\txn-\u003eidx = i;\n-\t\tidpf_vc_xn_release_bufs(xn);\n-\t\tspin_lock_init(\u0026xn-\u003elock);\n-\t\tinit_completion(\u0026xn-\u003ecompleted);\n-\t}\n-\n-\tbitmap_fill(vcxn_mngr-\u003efree_xn_bm, IDPF_VC_XN_RING_LEN);\n-}\n-\n-/**\n- * idpf_vc_xn_shutdown - Uninitialize virtchnl transaction object\n- * @vcxn_mngr: pointer to vc transaction manager struct\n+ * Cleanup the mailbox queue entries of the previously sent message to\n+ * unmap and release the buffer.\n *\n- * All waiting threads will be woken-up and their transaction aborted. Further\n- * operations on that object will fail.\n+ * Return: 0 if the request was successful, -%EBUSY if reset is detected\n+ *\t or Tx control queue is full, other negative error code on failure.\n */\n-void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr)\n+int idpf_send_mb_msg(struct idpf_adapter *adapter,\n+\t\t struct libie_ctlq_xn_send_params *xn_params,\n+\t\t void *send_buf, size_t send_buf_size)\n {\n-\tint i;\n+\tstruct libie_ctlq_msg ctlq_msg = {};\n \n-\tspin_lock_bh(\u0026vcxn_mngr-\u003exn_bm_lock);\n-\tbitmap_zero(vcxn_mngr-\u003efree_xn_bm, IDPF_VC_XN_RING_LEN);\n-\tspin_unlock_bh(\u0026vcxn_mngr-\u003exn_bm_lock);\n+\tif (idpf_is_reset_detected(adapter)) {\n+\t\tif (!libie_cp_can_send_onstack(send_buf_size))\n+\t\t\tkfree(send_buf);\n \n-\tfor (i = 0; i \u003c ARRAY_SIZE(vcxn_mngr-\u003ering); i++) {\n-\t\tstruct idpf_vc_xn *xn = \u0026vcxn_mngr-\u003ering[i];\n-\n-\t\tidpf_vc_xn_lock(xn);\n-\t\txn-\u003estate = IDPF_VC_XN_SHUTDOWN;\n-\t\tidpf_vc_xn_release_bufs(xn);\n-\t\tidpf_vc_xn_unlock(xn);\n-\t\tcomplete_all(\u0026xn-\u003ecompleted);\n+\t\treturn -EBUSY;\n \t}\n-}\n \n-/**\n- * idpf_vc_xn_pop_free - Pop a free transaction from free list\n- * @vcxn_mngr: transaction manager to pop from\n- *\n- * Returns NULL if no free transactions\n- */\n-static\n-struct idpf_vc_xn *idpf_vc_xn_pop_free(struct idpf_vc_xn_manager *vcxn_mngr)\n-{\n-\tstruct idpf_vc_xn *xn = NULL;\n-\tunsigned long free_idx;\n-\n-\tspin_lock_bh(\u0026vcxn_mngr-\u003exn_bm_lock);\n-\tfree_idx = find_first_bit(vcxn_mngr-\u003efree_xn_bm, IDPF_VC_XN_RING_LEN);\n-\tif (free_idx == IDPF_VC_XN_RING_LEN)\n-\t\tgoto do_unlock;\n+\tidpf_prepare_ptp_mb_msg(adapter, xn_params-\u003echnl_opcode, \u0026ctlq_msg);\n+\txn_params-\u003ectlq_msg = ctlq_msg.opcode ? \u0026ctlq_msg : NULL;\n \n-\tclear_bit(free_idx, vcxn_mngr-\u003efree_xn_bm);\n-\txn = \u0026vcxn_mngr-\u003ering[free_idx];\n-\txn-\u003esalt = vcxn_mngr-\u003esalt++;\n+\txn_params-\u003esend_buf.iov_base = send_buf;\n+\txn_params-\u003esend_buf.iov_len = send_buf_size;\n+\txn_params-\u003exnm = adapter-\u003exnm;\n+\txn_params-\u003ectlq = xn_params-\u003ectlq ? xn_params-\u003ectlq : adapter-\u003easq;\n+\txn_params-\u003erel_tx_buf = kfree;\n \n-do_unlock:\n-\tspin_unlock_bh(\u0026vcxn_mngr-\u003exn_bm_lock);\n+\tidpf_mb_clean(xn_params-\u003ectlq, false);\n \n-\treturn xn;\n-}\n-\n-/**\n- * idpf_vc_xn_push_free - Push a free transaction to free list\n- * @vcxn_mngr: transaction manager to push to\n- * @xn: transaction to push\n- */\n-static void idpf_vc_xn_push_free(struct idpf_vc_xn_manager *vcxn_mngr,\n-\t\t\t\t struct idpf_vc_xn *xn)\n-{\n-\tidpf_vc_xn_release_bufs(xn);\n-\tspin_lock_bh(\u0026vcxn_mngr-\u003exn_bm_lock);\n-\tset_bit(xn-\u003eidx, vcxn_mngr-\u003efree_xn_bm);\n-\tspin_unlock_bh(\u0026vcxn_mngr-\u003exn_bm_lock);\n+\treturn libie_ctlq_xn_send(xn_params);\n }\n \n /**\n- * idpf_vc_xn_exec - Perform a send/recv virtchnl transaction\n- * @adapter: driver specific private structure with vcxn_mngr\n- * @params: parameters for this particular transaction including\n- * -vc_op: virtchannel operation to send\n- * -send_buf: kvec iov for send buf and len\n- * -recv_buf: kvec iov for recv buf and len (ignored if NULL)\n- * -timeout_ms: timeout waiting for a reply (milliseconds)\n- * -async: don't wait for message reply, will lose caller context\n- * -async_handler: callback to handle async replies\n+ * idpf_send_mb_msg_kfree - send mailbox message and free the send buffer\n+ * @adapter: driver specific private structure\n+ * @xn_params: Xn send parameters to fill\n+ * @send_buf: buffer to send, can be released with kfree()\n+ * @send_buf_size: size of the send buffer\n *\n- * @returns \u003e= 0 for success, the size of the initial reply (may or may not be\n- * \u003e= @recv_buf.iov_len, but we never overflow @@recv_buf_iov_base). \u003c 0 for\n- * error.\n- */\n-ssize_t idpf_vc_xn_exec(struct idpf_adapter *adapter,\n-\t\t\tconst struct idpf_vc_xn_params *params)\n-{\n-\tconst struct kvec *send_buf = \u0026params-\u003esend_buf;\n-\tstruct idpf_vc_xn *xn;\n-\tssize_t retval;\n-\tu16 cookie;\n-\n-\txn = idpf_vc_xn_pop_free(adapter-\u003evcxn_mngr);\n-\t/* no free transactions available */\n-\tif (!xn)\n-\t\treturn -ENOSPC;\n-\n-\tidpf_vc_xn_lock(xn);\n-\tif (xn-\u003estate == IDPF_VC_XN_SHUTDOWN) {\n-\t\tretval = -ENXIO;\n-\t\tgoto only_unlock;\n-\t} else if (xn-\u003estate != IDPF_VC_XN_IDLE) {\n-\t\t/* We're just going to clobber this transaction even though\n-\t\t * it's not IDLE. If we don't reuse it we could theoretically\n-\t\t * eventually leak all the free transactions and not be able to\n-\t\t * send any messages. At least this way we make an attempt to\n-\t\t * remain functional even though something really bad is\n-\t\t * happening that's corrupting what was supposed to be free\n-\t\t * transactions.\n-\t\t */\n-\t\tWARN_ONCE(1, \"There should only be idle transactions in free list (idx %d op %d)\\n\",\n-\t\t\t xn-\u003eidx, xn-\u003evc_op);\n-\t}\n-\n-\txn-\u003ereply = params-\u003erecv_buf;\n-\txn-\u003ereply_sz = 0;\n-\txn-\u003estate = params-\u003easync ? IDPF_VC_XN_ASYNC : IDPF_VC_XN_WAITING;\n-\txn-\u003evc_op = params-\u003evc_op;\n-\txn-\u003easync_handler = params-\u003easync_handler;\n-\tidpf_vc_xn_unlock(xn);\n-\n-\tif (!params-\u003easync)\n-\t\treinit_completion(\u0026xn-\u003ecompleted);\n-\tcookie = FIELD_PREP(IDPF_VC_XN_SALT_M, xn-\u003esalt) |\n-\t\t FIELD_PREP(IDPF_VC_XN_IDX_M, xn-\u003eidx);\n-\n-\tretval = idpf_send_mb_msg(adapter, adapter-\u003ehw.asq, params-\u003evc_op,\n-\t\t\t\t send_buf-\u003eiov_len, send_buf-\u003eiov_base,\n-\t\t\t\t cookie);\n-\tif (retval) {\n-\t\tidpf_vc_xn_lock(xn);\n-\t\tgoto release_and_unlock;\n-\t}\n-\n-\tif (params-\u003easync)\n-\t\treturn 0;\n-\n-\twait_for_completion_timeout(\u0026xn-\u003ecompleted,\n-\t\t\t\t msecs_to_jiffies(params-\u003etimeout_ms));\n-\n-\t/* No need to check the return value; we check the final state of the\n-\t * transaction below. It's possible the transaction actually gets more\n-\t * timeout than specified if we get preempted here but after\n-\t * wait_for_completion_timeout returns. This should be non-issue\n-\t * however.\n-\t */\n-\tidpf_vc_xn_lock(xn);\n-\tswitch (xn-\u003estate) {\n-\tcase IDPF_VC_XN_SHUTDOWN:\n-\t\tretval = -ENXIO;\n-\t\tgoto only_unlock;\n-\tcase IDPF_VC_XN_WAITING:\n-\t\tdev_notice_ratelimited(\u0026adapter-\u003epdev-\u003edev,\n-\t\t\t\t \"Transaction timed-out (op:%d cookie:%04x vc_op:%d salt:%02x timeout:%dms)\\n\",\n-\t\t\t\t params-\u003evc_op, cookie, xn-\u003evc_op,\n-\t\t\t\t xn-\u003esalt, params-\u003etimeout_ms);\n-\t\tretval = -ETIME;\n-\t\tbreak;\n-\tcase IDPF_VC_XN_COMPLETED_SUCCESS:\n-\t\tretval = xn-\u003ereply_sz;\n-\t\tbreak;\n-\tcase IDPF_VC_XN_COMPLETED_FAILED:\n-\t\tdev_notice_ratelimited(\u0026adapter-\u003epdev-\u003edev, \"Transaction failed (op %d)\\n\",\n-\t\t\t\t params-\u003evc_op);\n-\t\tretval = -EIO;\n-\t\tbreak;\n-\tdefault:\n-\t\t/* Invalid state. */\n-\t\tWARN_ON_ONCE(1);\n-\t\tretval = -EIO;\n-\t\tbreak;\n-\t}\n-\n-release_and_unlock:\n-\tidpf_vc_xn_push_free(adapter-\u003evcxn_mngr, xn);\n-\t/* If we receive a VC reply after here, it will be dropped. */\n-only_unlock:\n-\tidpf_vc_xn_unlock(xn);\n-\n-\treturn retval;\n-}\n-\n-/**\n- * idpf_vc_xn_forward_async - Handle async reply receives\n- * @adapter: private data struct\n- * @xn: transaction to handle\n- * @ctlq_msg: corresponding ctlq_msg\n+ * libie_cp functions consume only buffers above certain size,\n+ * smaller buffers are assumed to be on the stack. However, for some\n+ * commands with variable message size it makes sense to always use kzalloc(),\n+ * which means we have to free smaller buffers ourselves.\n *\n- * For async sends we're going to lose the caller's context so, if an\n- * async_handler was provided, it can deal with the reply, otherwise we'll just\n- * check and report if there is an error.\n- */\n-static int\n-idpf_vc_xn_forward_async(struct idpf_adapter *adapter, struct idpf_vc_xn *xn,\n-\t\t\t const struct idpf_ctlq_msg *ctlq_msg)\n-{\n-\tint err = 0;\n-\n-\tif (ctlq_msg-\u003ecookie.mbx.chnl_opcode != xn-\u003evc_op) {\n-\t\tdev_err_ratelimited(\u0026adapter-\u003epdev-\u003edev, \"Async message opcode does not match transaction opcode (msg: %d) (xn: %d)\\n\",\n-\t\t\t\t ctlq_msg-\u003ecookie.mbx.chnl_opcode, xn-\u003evc_op);\n-\t\txn-\u003ereply_sz = 0;\n-\t\terr = -EINVAL;\n-\t\tgoto release_bufs;\n-\t}\n-\n-\tif (xn-\u003easync_handler) {\n-\t\terr = xn-\u003easync_handler(adapter, xn, ctlq_msg);\n-\t\tgoto release_bufs;\n-\t}\n-\n-\tif (ctlq_msg-\u003ecookie.mbx.chnl_retval) {\n-\t\txn-\u003ereply_sz = 0;\n-\t\tdev_err_ratelimited(\u0026adapter-\u003epdev-\u003edev, \"Async message failure (op %d)\\n\",\n-\t\t\t\t ctlq_msg-\u003ecookie.mbx.chnl_opcode);\n-\t\terr = -EINVAL;\n-\t}\n-\n-release_bufs:\n-\tidpf_vc_xn_push_free(adapter-\u003evcxn_mngr, xn);\n-\n-\treturn err;\n-}\n-\n-/**\n- * idpf_vc_xn_forward_reply - copy a reply back to receiving thread\n- * @adapter: driver specific private structure with vcxn_mngr\n- * @ctlq_msg: controlq message to send back to receiving thread\n+ * Return: 0 if no unexpected errors were encountered,\n+ *\t negative error code otherwise.\n */\n-static int\n-idpf_vc_xn_forward_reply(struct idpf_adapter *adapter,\n-\t\t\t const struct idpf_ctlq_msg *ctlq_msg)\n+int idpf_send_mb_msg_kfree(struct idpf_adapter *adapter,\n+\t\t\t struct libie_ctlq_xn_send_params *xn_params,\n+\t\t\t void *send_buf, size_t send_buf_size)\n {\n-\tconst void *payload = NULL;\n-\tsize_t payload_size = 0;\n-\tstruct idpf_vc_xn *xn;\n-\tu16 msg_info;\n-\tint err = 0;\n-\tu16 xn_idx;\n-\tu16 salt;\n-\n-\tmsg_info = ctlq_msg-\u003ectx.sw_cookie.data;\n-\txn_idx = FIELD_GET(IDPF_VC_XN_IDX_M, msg_info);\n-\tif (xn_idx \u003e= ARRAY_SIZE(adapter-\u003evcxn_mngr-\u003ering)) {\n-\t\tdev_err_ratelimited(\u0026adapter-\u003epdev-\u003edev, \"Out of bounds cookie received: %02x\\n\",\n-\t\t\t\t xn_idx);\n-\t\treturn -EINVAL;\n-\t}\n-\txn = \u0026adapter-\u003evcxn_mngr-\u003ering[xn_idx];\n-\tidpf_vc_xn_lock(xn);\n-\tsalt = FIELD_GET(IDPF_VC_XN_SALT_M, msg_info);\n-\tif (xn-\u003esalt != salt) {\n-\t\tdev_err_ratelimited(\u0026adapter-\u003epdev-\u003edev, \"Transaction salt does not match (exp:%d@%02x(%d) != got:%d@%02x)\\n\",\n-\t\t\t\t xn-\u003evc_op, xn-\u003esalt, xn-\u003estate,\n-\t\t\t\t ctlq_msg-\u003ecookie.mbx.chnl_opcode, salt);\n-\t\tidpf_vc_xn_unlock(xn);\n-\t\treturn -EINVAL;\n-\t}\n-\n-\tswitch (xn-\u003estate) {\n-\tcase IDPF_VC_XN_WAITING:\n-\t\t/* success */\n-\t\tbreak;\n-\tcase IDPF_VC_XN_IDLE:\n-\t\tdev_err_ratelimited(\u0026adapter-\u003epdev-\u003edev, \"Unexpected or belated VC reply (op %d)\\n\",\n-\t\t\t\t ctlq_msg-\u003ecookie.mbx.chnl_opcode);\n-\t\terr = -EINVAL;\n-\t\tgoto out_unlock;\n-\tcase IDPF_VC_XN_SHUTDOWN:\n-\t\t/* ENXIO is a bit special here as the recv msg loop uses that\n-\t\t * know if it should stop trying to clean the ring if we lost\n-\t\t * the virtchnl. We need to stop playing with registers and\n-\t\t * yield.\n-\t\t */\n-\t\terr = -ENXIO;\n-\t\tgoto out_unlock;\n-\tcase IDPF_VC_XN_ASYNC:\n-\t\t/* Set reply_sz from the actual payload so that async_handler\n-\t\t * can evaluate the response.\n-\t\t */\n-\t\txn-\u003ereply_sz = ctlq_msg-\u003edata_len;\n-\t\terr = idpf_vc_xn_forward_async(adapter, xn, ctlq_msg);\n-\t\tidpf_vc_xn_unlock(xn);\n-\t\treturn err;\n-\tdefault:\n-\t\tdev_err_ratelimited(\u0026adapter-\u003epdev-\u003edev, \"Overwriting VC reply (op %d)\\n\",\n-\t\t\t\t ctlq_msg-\u003ecookie.mbx.chnl_opcode);\n-\t\terr = -EBUSY;\n-\t\tgoto out_unlock;\n-\t}\n-\n-\tif (ctlq_msg-\u003ecookie.mbx.chnl_opcode != xn-\u003evc_op) {\n-\t\tdev_err_ratelimited(\u0026adapter-\u003epdev-\u003edev, \"Message opcode does not match transaction opcode (msg: %d) (xn: %d)\\n\",\n-\t\t\t\t ctlq_msg-\u003ecookie.mbx.chnl_opcode, xn-\u003evc_op);\n-\t\txn-\u003ereply_sz = 0;\n-\t\txn-\u003estate = IDPF_VC_XN_COMPLETED_FAILED;\n-\t\terr = -EINVAL;\n-\t\tgoto out_unlock;\n-\t}\n+\tint err = idpf_send_mb_msg(adapter, xn_params, send_buf, send_buf_size);\n \n-\tif (ctlq_msg-\u003ecookie.mbx.chnl_retval) {\n-\t\txn-\u003ereply_sz = 0;\n-\t\txn-\u003estate = IDPF_VC_XN_COMPLETED_FAILED;\n-\t\terr = -EINVAL;\n-\t\tgoto out_unlock;\n-\t}\n-\n-\tif (ctlq_msg-\u003edata_len) {\n-\t\tpayload = ctlq_msg-\u003ectx.indirect.payload-\u003eva;\n-\t\tpayload_size = ctlq_msg-\u003edata_len;\n-\t}\n-\n-\txn-\u003ereply_sz = payload_size;\n-\txn-\u003estate = IDPF_VC_XN_COMPLETED_SUCCESS;\n-\n-\tif (xn-\u003ereply.iov_base \u0026\u0026 xn-\u003ereply.iov_len \u0026\u0026 payload_size)\n-\t\tmemcpy(xn-\u003ereply.iov_base, payload,\n-\t\t min_t(size_t, xn-\u003ereply.iov_len, payload_size));\n-\n-out_unlock:\n-\tidpf_vc_xn_unlock(xn);\n-\t/* we _cannot_ hold lock while calling complete */\n-\tcomplete(\u0026xn-\u003ecompleted);\n+\tif (libie_cp_can_send_onstack(send_buf_size))\n+\t\tkfree(send_buf);\n \n \treturn err;\n }\n \n /**\n- * idpf_recv_mb_msg - Receive message over mailbox\n+ * idpf_send_vf_reset_msg - send one way VF reset message\n * @adapter: driver specific private structure\n- * @arq: control queue to receive message from\n- *\n- * Will receive control queue message and posts the receive buffer.\n- *\n- * Return: 0 on success and negative on failure.\n */\n-int idpf_recv_mb_msg(struct idpf_adapter *adapter, struct idpf_ctlq_info *arq)\n+void idpf_send_vf_reset_msg(struct idpf_adapter *adapter)\n {\n-\tstruct idpf_ctlq_msg ctlq_msg;\n-\tstruct idpf_dma_mem *dma_mem;\n-\tint post_err, err;\n-\tu16 num_recv;\n-\n-\twhile (1) {\n-\t\t/* This will get \u003c= num_recv messages and output how many\n-\t\t * actually received on num_recv.\n-\t\t */\n-\t\tnum_recv = 1;\n-\t\terr = idpf_ctlq_recv(arq, \u0026num_recv, \u0026ctlq_msg);\n-\t\tif (err || !num_recv)\n-\t\t\tbreak;\n-\n-\t\tif (ctlq_msg.data_len) {\n-\t\t\tdma_mem = ctlq_msg.ctx.indirect.payload;\n-\t\t} else {\n-\t\t\tdma_mem = NULL;\n-\t\t\tnum_recv = 0;\n-\t\t}\n+\tstruct libie_ctlq_info *ctlq = adapter-\u003easq;\n \n-\t\tif (ctlq_msg.cookie.mbx.chnl_opcode == VIRTCHNL2_OP_EVENT)\n-\t\t\tidpf_recv_event_msg(adapter, \u0026ctlq_msg);\n-\t\telse\n-\t\t\terr = idpf_vc_xn_forward_reply(adapter, \u0026ctlq_msg);\n+\t/* Forcefully claim send queue slot */\n+\tidpf_mb_clean(ctlq, true);\n \n-\t\tpost_err = idpf_ctlq_post_rx_buffs(\u0026adapter-\u003ehw, arq,\n-\t\t\t\t\t\t \u0026num_recv, \u0026dma_mem);\n+\tscoped_guard(spinlock, \u0026ctlq-\u003elock) {\n+\t\t*ctlq-\u003etx_msg[ctlq-\u003enext_to_use] = (struct libie_ctlq_msg) {\n+\t\t\t.opcode = LIBIE_CTLQ_SEND_MSG_TO_CP,\n+\t\t\t.chnl_opcode = VIRTCHNL2_OP_RESET_VF,\n+\t\t};\n \n-\t\t/* If post failed clear the only buffer we supplied */\n-\t\tif (post_err) {\n-\t\t\tif (dma_mem)\n-\t\t\t\tdma_free_coherent(\u0026adapter-\u003epdev-\u003edev,\n-\t\t\t\t\t\t dma_mem-\u003esize, dma_mem-\u003eva,\n-\t\t\t\t\t\t dma_mem-\u003epa);\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\t/* virtchnl trying to shutdown, stop cleaning */\n-\t\tif (err == -ENXIO)\n-\t\t\tbreak;\n+\t\tlibie_ctlq_send(adapter-\u003easq, 1);\n \t}\n-\n-\treturn err;\n }\n \n struct idpf_chunked_msg_params {\n@@ -767,45 +313,43 @@ struct idpf_queue_set *idpf_alloc_queue_set(struct idpf_adapter *adapter,\n static int idpf_send_chunked_msg(struct idpf_adapter *adapter,\n \t\t\t\t const struct idpf_chunked_msg_params *params)\n {\n-\tstruct idpf_vc_xn_params xn_params = {\n-\t\t.vc_op\t\t= params-\u003evc_op,\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n \t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= params-\u003evc_op,\n \t};\n \tconst void *pos = params-\u003echunks;\n-\tu32 num_chunks, num_msgs, buf_sz;\n-\tvoid *buf __free(kfree) = NULL;\n \tu32 totqs = params-\u003enum_chunks;\n \tu32 vid = params-\u003evport_id;\n+\tu32 num_chunks, num_msgs;\n \n-\tnum_chunks = min(IDPF_NUM_CHUNKS_PER_MSG(params-\u003econfig_sz,\n-\t\t\t\t\t\t params-\u003echunk_sz), totqs);\n+\tnum_chunks = IDPF_NUM_CHUNKS_PER_MSG(params-\u003econfig_sz,\n+\t\t\t\t\t params-\u003echunk_sz);\n \tnum_msgs = DIV_ROUND_UP(totqs, num_chunks);\n \n-\tbuf_sz = params-\u003econfig_sz + num_chunks * params-\u003echunk_sz;\n-\tbuf = kzalloc(buf_sz, GFP_KERNEL);\n-\tif (!buf)\n-\t\treturn -ENOMEM;\n-\n-\txn_params.send_buf.iov_base = buf;\n-\n \tfor (u32 i = 0; i \u003c num_msgs; i++) {\n-\t\tssize_t reply_sz;\n+\t\tu32 buf_sz;\n+\t\tvoid *buf;\n+\t\tint err;\n \n-\t\tmemset(buf, 0, buf_sz);\n-\t\txn_params.send_buf.iov_len = buf_sz;\n+\t\tnum_chunks = min(num_chunks, totqs);\n+\t\tbuf_sz = params-\u003econfig_sz + num_chunks * params-\u003echunk_sz;\n+\t\tbuf = kzalloc(buf_sz, GFP_KERNEL);\n+\t\tif (!buf)\n+\t\t\treturn -ENOMEM;\n \n-\t\tif (params-\u003eprepare_msg(vid, buf, pos, num_chunks) != buf_sz)\n+\t\tif (params-\u003eprepare_msg(vid, buf, pos, num_chunks) != buf_sz) {\n+\t\t\tkfree(buf);\n \t\t\treturn -EINVAL;\n+\t\t}\n \n-\t\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\t\tif (reply_sz \u003c 0)\n-\t\t\treturn reply_sz;\n+\t\terr = idpf_send_mb_msg_kfree(adapter, \u0026xn_params, buf, buf_sz);\n+\t\tif (err)\n+\t\t\treturn err;\n \n+\t\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\t\txn_params.recv_mem = (struct kvec) {};\n \t\tpos += num_chunks * params-\u003echunk_sz;\n \t\ttotqs -= num_chunks;\n-\n-\t\tnum_chunks = min(num_chunks, totqs);\n-\t\tbuf_sz = params-\u003econfig_sz + num_chunks * params-\u003echunk_sz;\n \t}\n \n \treturn 0;\n@@ -880,11 +424,14 @@ static int idpf_wait_for_marker_event(struct idpf_vport *vport)\n */\n static int idpf_send_ver_msg(struct idpf_adapter *adapter)\n {\n-\tstruct idpf_vc_xn_params xn_params = {};\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_VERSION,\n+\t};\n+\tstruct virtchnl2_version_info *vvi_recv;\n \tstruct virtchnl2_version_info vvi;\n-\tssize_t reply_sz;\n \tu32 major, minor;\n-\tint err = 0;\n+\tint err;\n \n \tif (adapter-\u003evirt_ver_maj) {\n \t\tvvi.major = cpu_to_le32(adapter-\u003evirt_ver_maj);\n@@ -894,24 +441,23 @@ static int idpf_send_ver_msg(struct idpf_adapter *adapter)\n \t\tvvi.minor = cpu_to_le32(IDPF_VIRTCHNL_VERSION_MINOR);\n \t}\n \n-\txn_params.vc_op = VIRTCHNL2_OP_VERSION;\n-\txn_params.send_buf.iov_base = \u0026vvi;\n-\txn_params.send_buf.iov_len = sizeof(vvi);\n-\txn_params.recv_buf = xn_params.send_buf;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params, \u0026vvi);\n+\tif (err)\n+\t\treturn err;\n \n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n-\tif (reply_sz \u003c sizeof(vvi))\n-\t\treturn -EIO;\n+\tif (xn_params.recv_mem.iov_len \u003c sizeof(*vvi_recv)) {\n+\t\terr = -EIO;\n+\t\tgoto free_rx_buf;\n+\t}\n \n-\tmajor = le32_to_cpu(vvi.major);\n-\tminor = le32_to_cpu(vvi.minor);\n+\tvvi_recv = xn_params.recv_mem.iov_base;\n+\tmajor = le32_to_cpu(vvi_recv-\u003emajor);\n+\tminor = le32_to_cpu(vvi_recv-\u003eminor);\n \n \tif (major \u003e IDPF_VIRTCHNL_VERSION_MAJOR) {\n \t\tdev_warn(\u0026adapter-\u003epdev-\u003edev, \"Virtchnl major version greater than supported\\n\");\n-\t\treturn -EINVAL;\n+\t\terr = -EINVAL;\n+\t\tgoto free_rx_buf;\n \t}\n \n \tif (major == IDPF_VIRTCHNL_VERSION_MAJOR \u0026\u0026\n@@ -929,6 +475,9 @@ static int idpf_send_ver_msg(struct idpf_adapter *adapter)\n \tadapter-\u003evirt_ver_maj = major;\n \tadapter-\u003evirt_ver_min = minor;\n \n+free_rx_buf:\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\n \treturn err;\n }\n \n@@ -941,9 +490,12 @@ static int idpf_send_ver_msg(struct idpf_adapter *adapter)\n */\n static int idpf_send_get_caps_msg(struct idpf_adapter *adapter)\n {\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_GET_CAPS,\n+\t};\n \tstruct virtchnl2_get_capabilities caps = {};\n-\tstruct idpf_vc_xn_params xn_params = {};\n-\tssize_t reply_sz;\n+\tint err;\n \n \tcaps.csum_caps =\n \t\tcpu_to_le32(VIRTCHNL2_CAP_TX_CSUM_L3_IPV4\t|\n@@ -1003,143 +555,154 @@ static int idpf_send_get_caps_msg(struct idpf_adapter *adapter)\n \t\t\t VIRTCHNL2_CAP_LOOPBACK\t\t|\n \t\t\t VIRTCHNL2_CAP_PTP);\n \n-\txn_params.vc_op = VIRTCHNL2_OP_GET_CAPS;\n-\txn_params.send_buf.iov_base = \u0026caps;\n-\txn_params.send_buf.iov_len = sizeof(caps);\n-\txn_params.recv_buf.iov_base = \u0026adapter-\u003ecaps;\n-\txn_params.recv_buf.iov_len = sizeof(adapter-\u003ecaps);\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params, \u0026caps);\n+\tif (err)\n+\t\treturn err;\n \n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n-\tif (reply_sz \u003c sizeof(adapter-\u003ecaps))\n-\t\treturn -EIO;\n+\tif (xn_params.recv_mem.iov_len \u003c sizeof(adapter-\u003ecaps)) {\n+\t\terr = -EIO;\n+\t\tgoto free_rx_buf;\n+\t}\n \n-\treturn 0;\n+\tmemcpy(\u0026adapter-\u003ecaps, xn_params.recv_mem.iov_base,\n+\t sizeof(adapter-\u003ecaps));\n+\n+free_rx_buf:\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\n+\treturn err;\n+}\n+\n+/**\n+ * idpf_mmio_region_non_static - Check if region is not static\n+ * @mmio_info: PCI resources info\n+ * @reg: region to check\n+ *\n+ * Return: %true if region can be received though virtchnl command,\n+ *\t %false if region is related to mailbox or resetting\n+ */\n+bool idpf_mmio_region_non_static(struct libie_mmio_info *mmio_info,\n+\t\t\t\t struct libie_pci_mmio_region *reg)\n+{\n+\tstruct idpf_adapter *adapter =\n+\t\tcontainer_of(mmio_info, struct idpf_adapter,\n+\t\t\t ctlq_ctx.mmio_info);\n+\n+\tfor (uint i = 0; i \u003c IDPF_MMIO_REG_NUM_STATIC; i++) {\n+\t\tif (reg-\u003ebar_idx == 0 \u0026\u0026\n+\t\t reg-\u003eoffset == adapter-\u003edev_ops.static_reg_info[i].start)\n+\t\t\treturn false;\n+\t}\n+\n+\treturn true;\n+}\n+\n+/**\n+ * idpf_decfg_lan_memory_regions - Unmap non-static memory regions\n+ * @adapter: Driver specific private structure\n+ */\n+static void idpf_decfg_lan_memory_regions(struct idpf_adapter *adapter)\n+{\n+\tlibie_pci_unmap_fltr_regs(\u0026adapter-\u003ectlq_ctx.mmio_info,\n+\t\t\t\t idpf_mmio_region_non_static);\n }\n \n /**\n- * idpf_send_get_lan_memory_regions - Send virtchnl get LAN memory regions msg\n+ * idpf_cfg_lan_memory_regions - Get (via virtchnl) and map LAN memory regions\n * @adapter: Driver specific private struct\n *\n * Return: 0 on success or error code on failure.\n */\n-static int idpf_send_get_lan_memory_regions(struct idpf_adapter *adapter)\n+static int idpf_cfg_lan_memory_regions(struct idpf_adapter *adapter)\n {\n-\tstruct virtchnl2_get_lan_memory_regions *rcvd_regions __free(kfree);\n-\tstruct idpf_vc_xn_params xn_params = {\n-\t\t.vc_op = VIRTCHNL2_OP_GET_LAN_MEMORY_REGIONS,\n-\t\t.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN,\n-\t\t.send_buf.iov_len =\n-\t\t\tsizeof(struct virtchnl2_get_lan_memory_regions) +\n-\t\t\tsizeof(struct virtchnl2_mem_region),\n+\tstruct virtchnl2_get_lan_memory_regions *send_regions, *rcvd_regions;\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.chnl_opcode = VIRTCHNL2_OP_GET_LAN_MEMORY_REGIONS,\n \t\t.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n \t};\n-\tint num_regions, size;\n-\tstruct idpf_hw *hw;\n-\tssize_t reply_sz;\n+\tsize_t send_sz, reply_sz, size;\n+\tint num_regions;\n \tint err = 0;\n \n-\trcvd_regions = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);\n-\tif (!rcvd_regions)\n+\tsend_sz = sizeof(struct virtchnl2_get_lan_memory_regions) +\n+\t\t sizeof(struct virtchnl2_mem_region);\n+\tsend_regions = kzalloc(send_sz, GFP_KERNEL);\n+\tif (!send_regions)\n \t\treturn -ENOMEM;\n \n-\txn_params.recv_buf.iov_base = rcvd_regions;\n-\trcvd_regions-\u003enum_memory_regions = cpu_to_le16(1);\n-\txn_params.send_buf.iov_base = rcvd_regions;\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n+\tsend_regions-\u003enum_memory_regions = cpu_to_le16(1);\n+\terr = idpf_send_mb_msg_kfree(adapter, \u0026xn_params, send_regions,\n+\t\t\t\t send_sz);\n+\tif (err)\n+\t\treturn err;\n \n+\trcvd_regions = xn_params.recv_mem.iov_base;\n+\treply_sz = xn_params.recv_mem.iov_len;\n+\tif (reply_sz \u003c sizeof(*rcvd_regions)) {\n+\t\terr = -EIO;\n+\t\tgoto rel_rx_buf;\n+\t}\n \tnum_regions = le16_to_cpu(rcvd_regions-\u003enum_memory_regions);\n \tsize = struct_size(rcvd_regions, mem_reg, num_regions);\n-\tif (reply_sz \u003c size)\n-\t\treturn -EIO;\n-\n-\tif (size \u003e IDPF_CTLQ_MAX_BUF_LEN)\n-\t\treturn -EINVAL;\n-\n-\thw = \u0026adapter-\u003ehw;\n-\thw-\u003elan_regs = kzalloc_objs(*hw-\u003elan_regs, num_regions);\n-\tif (!hw-\u003elan_regs)\n-\t\treturn -ENOMEM;\n+\tif (reply_sz \u003c size) {\n+\t\terr = -EIO;\n+\t\tgoto rel_rx_buf;\n+\t}\n \n \tfor (int i = 0; i \u003c num_regions; i++) {\n-\t\thw-\u003elan_regs[i].addr_len =\n-\t\t\tle64_to_cpu(rcvd_regions-\u003emem_reg[i].size);\n-\t\thw-\u003elan_regs[i].addr_start =\n-\t\t\tle64_to_cpu(rcvd_regions-\u003emem_reg[i].start_offset);\n+\t\tstruct libie_mmio_info *mmio = \u0026adapter-\u003ectlq_ctx.mmio_info;\n+\t\tresource_size_t offset, len;\n+\n+\t\toffset = le64_to_cpu(rcvd_regions-\u003emem_reg[i].start_offset);\n+\t\tlen = le64_to_cpu(rcvd_regions-\u003emem_reg[i].size);\n+\t\tif (len \u0026\u0026 !libie_pci_map_mmio_region(mmio, offset, len)) {\n+\t\t\tidpf_decfg_lan_memory_regions(adapter);\n+\t\t\terr = -EIO;\n+\t\t\tgoto rel_rx_buf;\n+\t\t}\n \t}\n-\thw-\u003enum_lan_regs = num_regions;\n+\n+rel_rx_buf:\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n \n \treturn err;\n }\n \n /**\n- * idpf_calc_remaining_mmio_regs - calculate MMIO regions outside mbx and rstat\n+ * idpf_map_remaining_mmio_regs - map MMIO regions outside mbx and rstat\n * @adapter: Driver specific private structure\n *\n- * Called when idpf_send_get_lan_memory_regions is not supported. This will\n+ * Called when idpf_cfg_lan_memory_regions is not supported. This will\n * calculate the offsets and sizes for the regions before, in between, and\n- * after the mailbox and rstat MMIO mappings.\n+ * after the mailbox and rstat MMIO mappings, and map those ranges.\n *\n * Return: 0 on success or error code on failure.\n */\n-static int idpf_calc_remaining_mmio_regs(struct idpf_adapter *adapter)\n+static int idpf_map_remaining_mmio_regs(struct idpf_adapter *adapter)\n {\n \tstruct resource *rstat_reg = \u0026adapter-\u003edev_ops.static_reg_info[1];\n \tstruct resource *mbx_reg = \u0026adapter-\u003edev_ops.static_reg_info[0];\n-\tstruct idpf_hw *hw = \u0026adapter-\u003ehw;\n-\n-\thw-\u003enum_lan_regs = IDPF_MMIO_MAP_FALLBACK_MAX_REMAINING;\n-\thw-\u003elan_regs = kzalloc_objs(*hw-\u003elan_regs, hw-\u003enum_lan_regs);\n-\tif (!hw-\u003elan_regs)\n-\t\treturn -ENOMEM;\n+\tstruct libie_mmio_info *mmio = \u0026adapter-\u003ectlq_ctx.mmio_info;\n+\tresource_size_t reg_start, size;\n+\tbool ok = true;\n \n \t/* Region preceding mailbox */\n-\thw-\u003elan_regs[0].addr_start = 0;\n-\thw-\u003elan_regs[0].addr_len = mbx_reg-\u003estart;\n-\t/* Region between mailbox and rstat */\n-\thw-\u003elan_regs[1].addr_start = mbx_reg-\u003eend + 1;\n-\thw-\u003elan_regs[1].addr_len = rstat_reg-\u003estart -\n-\t\t\t\t\thw-\u003elan_regs[1].addr_start;\n-\t/* Region after rstat */\n-\thw-\u003elan_regs[2].addr_start = rstat_reg-\u003eend + 1;\n-\thw-\u003elan_regs[2].addr_len = pci_resource_len(adapter-\u003epdev, 0) -\n-\t\t\t\t\thw-\u003elan_regs[2].addr_start;\n-\n-\treturn 0;\n-}\n+\tsize = mbx_reg-\u003estart;\n+\tok \u0026= !size || libie_pci_map_mmio_region(mmio, 0, size);\n \n-/**\n- * idpf_map_lan_mmio_regs - map remaining LAN BAR regions\n- * @adapter: Driver specific private structure\n- *\n- * Return: 0 on success or error code on failure.\n- */\n-static int idpf_map_lan_mmio_regs(struct idpf_adapter *adapter)\n-{\n-\tstruct pci_dev *pdev = adapter-\u003epdev;\n-\tstruct idpf_hw *hw = \u0026adapter-\u003ehw;\n-\tresource_size_t res_start;\n-\n-\tres_start = pci_resource_start(pdev, 0);\n-\n-\tfor (int i = 0; i \u003c hw-\u003enum_lan_regs; i++) {\n-\t\tresource_size_t start;\n-\t\tlong len;\n+\t/* Region between mailbox and rstat */\n+\treg_start = mbx_reg-\u003eend + 1;\n+\tsize = rstat_reg-\u003estart - reg_start;\n+\tok \u0026= !size || libie_pci_map_mmio_region(mmio, reg_start, size);\n \n-\t\tlen = hw-\u003elan_regs[i].addr_len;\n-\t\tif (!len)\n-\t\t\tcontinue;\n-\t\tstart = hw-\u003elan_regs[i].addr_start + res_start;\n+\t/* Region after rstat */\n+\treg_start = rstat_reg-\u003eend + 1;\n+\tsize = pci_resource_len(adapter-\u003epdev, 0) - reg_start;\n+\tok \u0026= !size || libie_pci_map_mmio_region(mmio, reg_start, size);\n \n-\t\thw-\u003elan_regs[i].vaddr = devm_ioremap(\u0026pdev-\u003edev, start, len);\n-\t\tif (!hw-\u003elan_regs[i].vaddr) {\n-\t\t\tpci_err(pdev, \"failed to allocate BAR0 region\\n\");\n-\t\t\treturn -ENOMEM;\n-\t\t}\n+\tif (!ok) {\n+\t\tidpf_decfg_lan_memory_regions(adapter);\n+\t\treturn -ENOMEM;\n \t}\n \n \treturn 0;\n@@ -1160,24 +723,43 @@ int idpf_add_del_fsteer_filters(struct idpf_adapter *adapter,\n \t\t\t\tstruct virtchnl2_flow_rule_add_del *rule,\n \t\t\t\tenum virtchnl2_op opcode)\n {\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.chnl_opcode = opcode,\n+\t\t.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t};\n+\tstruct virtchnl2_flow_rule_add_del *rx_rule;\n \tint rule_count = le32_to_cpu(rule-\u003ecount);\n-\tstruct idpf_vc_xn_params xn_params = {};\n-\tssize_t reply_sz;\n+\tsize_t send_sz;\n+\tint err;\n \n \tif (opcode != VIRTCHNL2_OP_ADD_FLOW_RULE \u0026\u0026\n-\t opcode != VIRTCHNL2_OP_DEL_FLOW_RULE)\n+\t opcode != VIRTCHNL2_OP_DEL_FLOW_RULE) {\n+\t\tkfree(rule);\n \t\treturn -EINVAL;\n+\t}\n+\n+\tsend_sz = struct_size(rule, rule_info, rule_count);\n+\terr = idpf_send_mb_msg_kfree(adapter, \u0026xn_params, rule, send_sz);\n+\tif (err)\n+\t\treturn err;\n+\n+\tif (xn_params.recv_mem.iov_len \u003c send_sz) {\n+\t\terr = -EIO;\n+\t\tgoto rel_rx;\n+\t}\n \n-\txn_params.vc_op = opcode;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\txn_params.async = false;\n-\txn_params.send_buf.iov_base = rule;\n-\txn_params.send_buf.iov_len = struct_size(rule, rule_info, rule_count);\n-\txn_params.recv_buf.iov_base = rule;\n-\txn_params.recv_buf.iov_len = struct_size(rule, rule_info, rule_count);\n+\trx_rule = xn_params.recv_mem.iov_base;\n+\tfor (int i = 0; i \u003c rule_count; i++) {\n+\t\tif (rx_rule-\u003erule_info[i].status !=\n+\t\t cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS)) {\n+\t\t\terr = -EIO;\n+\t\t\tgoto rel_rx;\n+\t\t}\n+\t}\n \n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\treturn reply_sz \u003c 0 ? reply_sz : 0;\n+rel_rx:\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\treturn err;\n }\n \n /**\n@@ -1414,7 +996,7 @@ static int __idpf_queue_reg_init(struct idpf_vport *vport,\n \t\t\t\t struct idpf_q_vec_rsrc *rsrc, u32 *reg_vals,\n \t\t\t\t int num_regs, u32 q_type)\n {\n-\tstruct idpf_adapter *adapter = vport-\u003eadapter;\n+\tstruct libie_mmio_info *mmio = \u0026vport-\u003eadapter-\u003ectlq_ctx.mmio_info;\n \tint i, j, k = 0;\n \n \tswitch (q_type) {\n@@ -1424,7 +1006,8 @@ static int __idpf_queue_reg_init(struct idpf_vport *vport,\n \n \t\t\tfor (j = 0; j \u003c tx_qgrp-\u003enum_txq \u0026\u0026 k \u003c num_regs; j++, k++)\n \t\t\t\ttx_qgrp-\u003etxqs[j]-\u003etail =\n-\t\t\t\t\tidpf_get_reg_addr(adapter, reg_vals[k]);\n+\t\t\t\t\tlibie_pci_get_mmio_addr(mmio,\n+\t\t\t\t\t\t\t\treg_vals[k]);\n \t\t}\n \t\tbreak;\n \tcase VIRTCHNL2_QUEUE_TYPE_RX:\n@@ -1436,8 +1019,8 @@ static int __idpf_queue_reg_init(struct idpf_vport *vport,\n \t\t\t\tstruct idpf_rx_queue *q;\n \n \t\t\t\tq = rx_qgrp-\u003esingleq.rxqs[j];\n-\t\t\t\tq-\u003etail = idpf_get_reg_addr(adapter,\n-\t\t\t\t\t\t\t reg_vals[k]);\n+\t\t\t\tq-\u003etail = libie_pci_get_mmio_addr(mmio,\n+\t\t\t\t\t\t\t\t reg_vals[k]);\n \t\t\t}\n \t\t}\n \t\tbreak;\n@@ -1450,8 +1033,8 @@ static int __idpf_queue_reg_init(struct idpf_vport *vport,\n \t\t\t\tstruct idpf_buf_queue *q;\n \n \t\t\t\tq = \u0026rx_qgrp-\u003esplitq.bufq_sets[j].bufq;\n-\t\t\t\tq-\u003etail = idpf_get_reg_addr(adapter,\n-\t\t\t\t\t\t\t reg_vals[k]);\n+\t\t\t\tq-\u003etail = libie_pci_get_mmio_addr(mmio,\n+\t\t\t\t\t\t\t\t reg_vals[k]);\n \t\t\t}\n \t\t}\n \t\tbreak;\n@@ -1551,21 +1134,19 @@ int idpf_queue_reg_init(struct idpf_vport *vport,\n int idpf_send_create_vport_msg(struct idpf_adapter *adapter,\n \t\t\t struct idpf_vport_max_q *max_q)\n {\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_CREATE_VPORT,\n+\t};\n \tstruct virtchnl2_create_vport *vport_msg;\n-\tstruct idpf_vc_xn_params xn_params = {};\n \tu16 idx = adapter-\u003enext_vport;\n \tint err, buf_size;\n-\tssize_t reply_sz;\n \n \tbuf_size = sizeof(struct virtchnl2_create_vport);\n-\tif (!adapter-\u003evport_params_reqd[idx]) {\n-\t\tadapter-\u003evport_params_reqd[idx] = kzalloc(buf_size,\n-\t\t\t\t\t\t\t GFP_KERNEL);\n-\t\tif (!adapter-\u003evport_params_reqd[idx])\n-\t\t\treturn -ENOMEM;\n-\t}\n+\tvport_msg = kzalloc(buf_size, GFP_KERNEL);\n+\tif (!vport_msg)\n+\t\treturn -ENOMEM;\n \n-\tvport_msg = adapter-\u003evport_params_reqd[idx];\n \tvport_msg-\u003evport_type = cpu_to_le16(VIRTCHNL2_VPORT_TYPE_DEFAULT);\n \tvport_msg-\u003evport_index = cpu_to_le16(idx);\n \n@@ -1582,38 +1163,35 @@ int idpf_send_create_vport_msg(struct idpf_adapter *adapter,\n \terr = idpf_vport_calc_total_qs(adapter, idx, vport_msg, max_q);\n \tif (err) {\n \t\tdev_err(\u0026adapter-\u003epdev-\u003edev, \"Enough queues are not available\");\n-\n-\t\treturn err;\n+\t\tgoto rel_buf;\n \t}\n \n \tif (!adapter-\u003evport_params_recvd[idx]) {\n-\t\tadapter-\u003evport_params_recvd[idx] = kzalloc(IDPF_CTLQ_MAX_BUF_LEN,\n-\t\t\t\t\t\t\t GFP_KERNEL);\n+\t\tadapter-\u003evport_params_recvd[idx] =\n+\t\t\tkzalloc(LIBIE_CTLQ_MAX_BUF_LEN, GFP_KERNEL);\n \t\tif (!adapter-\u003evport_params_recvd[idx]) {\n \t\t\terr = -ENOMEM;\n-\t\t\tgoto free_vport_params;\n+\t\t\tgoto rel_buf;\n \t\t}\n \t}\n \n-\txn_params.vc_op = VIRTCHNL2_OP_CREATE_VPORT;\n-\txn_params.send_buf.iov_base = vport_msg;\n-\txn_params.send_buf.iov_len = buf_size;\n-\txn_params.recv_buf.iov_base = adapter-\u003evport_params_recvd[idx];\n-\txn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0) {\n-\t\terr = reply_sz;\n-\t\tgoto free_vport_params;\n+\terr = idpf_send_mb_msg_kfree(adapter, \u0026xn_params, vport_msg,\n+\t\t\t\t sizeof(*vport_msg));\n+\tif (err) {\n+\t\tkfree(adapter-\u003evport_params_recvd[idx]);\n+\t\tadapter-\u003evport_params_recvd[idx] = NULL;\n+\t\treturn err;\n \t}\n \n+\tmemcpy(adapter-\u003evport_params_recvd[idx], xn_params.recv_mem.iov_base,\n+\t xn_params.recv_mem.iov_len);\n+\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\n \treturn 0;\n \n-free_vport_params:\n-\tkfree(adapter-\u003evport_params_recvd[idx]);\n-\tadapter-\u003evport_params_recvd[idx] = NULL;\n-\tkfree(adapter-\u003evport_params_reqd[idx]);\n-\tadapter-\u003evport_params_reqd[idx] = NULL;\n+rel_buf:\n+\tkfree(vport_msg);\n \n \treturn err;\n }\n@@ -1673,19 +1251,22 @@ int idpf_check_supported_desc_ids(struct idpf_vport *vport)\n */\n int idpf_send_destroy_vport_msg(struct idpf_adapter *adapter, u32 vport_id)\n {\n-\tstruct idpf_vc_xn_params xn_params = {};\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_DESTROY_VPORT,\n+\t};\n \tstruct virtchnl2_vport v_id;\n-\tssize_t reply_sz;\n+\tint err;\n \n \tv_id.vport_id = cpu_to_le32(vport_id);\n \n-\txn_params.vc_op = VIRTCHNL2_OP_DESTROY_VPORT;\n-\txn_params.send_buf.iov_base = \u0026v_id;\n-\txn_params.send_buf.iov_len = sizeof(v_id);\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params, \u0026v_id);\n+\tif (err)\n+\t\treturn err;\n+\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n \n-\treturn reply_sz \u003c 0 ? reply_sz : 0;\n+\treturn 0;\n }\n \n /**\n@@ -1697,19 +1278,22 @@ int idpf_send_destroy_vport_msg(struct idpf_adapter *adapter, u32 vport_id)\n */\n int idpf_send_enable_vport_msg(struct idpf_adapter *adapter, u32 vport_id)\n {\n-\tstruct idpf_vc_xn_params xn_params = {};\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_ENABLE_VPORT,\n+\t};\n \tstruct virtchnl2_vport v_id;\n-\tssize_t reply_sz;\n+\tint err;\n \n \tv_id.vport_id = cpu_to_le32(vport_id);\n \n-\txn_params.vc_op = VIRTCHNL2_OP_ENABLE_VPORT;\n-\txn_params.send_buf.iov_base = \u0026v_id;\n-\txn_params.send_buf.iov_len = sizeof(v_id);\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params, \u0026v_id);\n+\tif (err)\n+\t\treturn err;\n+\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n \n-\treturn reply_sz \u003c 0 ? reply_sz : 0;\n+\treturn 0;\n }\n \n /**\n@@ -1721,19 +1305,22 @@ int idpf_send_enable_vport_msg(struct idpf_adapter *adapter, u32 vport_id)\n */\n int idpf_send_disable_vport_msg(struct idpf_adapter *adapter, u32 vport_id)\n {\n-\tstruct idpf_vc_xn_params xn_params = {};\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_DISABLE_VPORT,\n+\t};\n \tstruct virtchnl2_vport v_id;\n-\tssize_t reply_sz;\n+\tint err;\n \n \tv_id.vport_id = cpu_to_le32(vport_id);\n \n-\txn_params.vc_op = VIRTCHNL2_OP_DISABLE_VPORT;\n-\txn_params.send_buf.iov_base = \u0026v_id;\n-\txn_params.send_buf.iov_len = sizeof(v_id);\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params, \u0026v_id);\n+\tif (err)\n+\t\treturn err;\n+\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n \n-\treturn reply_sz \u003c 0 ? reply_sz : 0;\n+\treturn 0;\n }\n \n /**\n@@ -2572,11 +2159,14 @@ int idpf_send_delete_queues_msg(struct idpf_adapter *adapter,\n \t\t\t\tstruct idpf_queue_id_reg_info *chunks,\n \t\t\t\tu32 vport_id)\n {\n-\tstruct virtchnl2_del_ena_dis_queues *eq __free(kfree) = NULL;\n-\tstruct idpf_vc_xn_params xn_params = {};\n-\tssize_t reply_sz;\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_DEL_QUEUES,\n+\t};\n+\tstruct virtchnl2_del_ena_dis_queues *eq;\n+\tssize_t buf_size;\n \tu16 num_chunks;\n-\tint buf_size;\n+\tint err;\n \n \tnum_chunks = chunks-\u003enum_chunks;\n \tbuf_size = struct_size(eq, chunks.chunks, num_chunks);\n@@ -2591,13 +2181,13 @@ int idpf_send_delete_queues_msg(struct idpf_adapter *adapter,\n \tidpf_convert_reg_to_queue_chunks(eq-\u003echunks.chunks, chunks-\u003equeue_chunks,\n \t\t\t\t\t num_chunks);\n \n-\txn_params.vc_op = VIRTCHNL2_OP_DEL_QUEUES;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\txn_params.send_buf.iov_base = eq;\n-\txn_params.send_buf.iov_len = buf_size;\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n+\terr = idpf_send_mb_msg_kfree(adapter, \u0026xn_params, eq, buf_size);\n+\tif (err)\n+\t\treturn err;\n \n-\treturn reply_sz \u003c 0 ? reply_sz : 0;\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\n+\treturn 0;\n }\n \n /**\n@@ -2635,15 +2225,14 @@ int idpf_send_add_queues_msg(struct idpf_adapter *adapter,\n \t\t\t struct idpf_q_vec_rsrc *rsrc,\n \t\t\t u32 vport_id)\n {\n-\tstruct virtchnl2_add_queues *vc_msg __free(kfree) = NULL;\n-\tstruct idpf_vc_xn_params xn_params = {};\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_ADD_QUEUES,\n+\t};\n+\tstruct virtchnl2_add_queues *vc_msg;\n \tstruct virtchnl2_add_queues aq = {};\n-\tssize_t reply_sz;\n-\tint size;\n-\n-\tvc_msg = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);\n-\tif (!vc_msg)\n-\t\treturn -ENOMEM;\n+\tsize_t size;\n+\tint err;\n \n \taq.vport_id = cpu_to_le32(vport_id);\n \taq.num_tx_q = cpu_to_le16(rsrc-\u003enum_txq);\n@@ -2651,29 +2240,38 @@ int idpf_send_add_queues_msg(struct idpf_adapter *adapter,\n \taq.num_rx_q = cpu_to_le16(rsrc-\u003enum_rxq);\n \taq.num_rx_bufq = cpu_to_le16(rsrc-\u003enum_bufq);\n \n-\txn_params.vc_op = VIRTCHNL2_OP_ADD_QUEUES;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\txn_params.send_buf.iov_base = \u0026aq;\n-\txn_params.send_buf.iov_len = sizeof(aq);\n-\txn_params.recv_buf.iov_base = vc_msg;\n-\txn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params, \u0026aq);\n+\tif (err)\n+\t\treturn err;\n+\n+\tvc_msg = xn_params.recv_mem.iov_base;\n+\tif (xn_params.recv_mem.iov_len \u003c sizeof(*vc_msg)) {\n+\t\terr = -EIO;\n+\t\tgoto free_rx_buf;\n+\t}\n \n \t/* compare vc_msg num queues with vport num queues */\n \tif (le16_to_cpu(vc_msg-\u003enum_tx_q) != rsrc-\u003enum_txq ||\n \t le16_to_cpu(vc_msg-\u003enum_rx_q) != rsrc-\u003enum_rxq ||\n \t le16_to_cpu(vc_msg-\u003enum_tx_complq) != rsrc-\u003enum_complq ||\n-\t le16_to_cpu(vc_msg-\u003enum_rx_bufq) != rsrc-\u003enum_bufq)\n-\t\treturn -EINVAL;\n+\t le16_to_cpu(vc_msg-\u003enum_rx_bufq) != rsrc-\u003enum_bufq) {\n+\t\terr = -EINVAL;\n+\t\tgoto free_rx_buf;\n+\t}\n \n \tsize = struct_size(vc_msg, chunks.chunks,\n \t\t\t le16_to_cpu(vc_msg-\u003echunks.num_chunks));\n-\tif (reply_sz \u003c size)\n-\t\treturn -EIO;\n+\tif (xn_params.recv_mem.iov_len \u003c size) {\n+\t\terr = -EIO;\n+\t\tgoto free_rx_buf;\n+\t}\n+\n+\terr = idpf_vport_init_queue_reg_chunks(vport_config, \u0026vc_msg-\u003echunks);\n+\n+free_rx_buf:\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n \n-\treturn idpf_vport_init_queue_reg_chunks(vport_config, \u0026vc_msg-\u003echunks);\n+\treturn err;\n }\n \n /**\n@@ -2685,49 +2283,51 @@ int idpf_send_add_queues_msg(struct idpf_adapter *adapter,\n */\n int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors)\n {\n-\tstruct virtchnl2_alloc_vectors *rcvd_vec __free(kfree) = NULL;\n-\tstruct idpf_vc_xn_params xn_params = {};\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_ALLOC_VECTORS,\n+\t};\n+\tstruct virtchnl2_alloc_vectors *rcvd_vec;\n \tstruct virtchnl2_alloc_vectors ac = {};\n-\tssize_t reply_sz;\n \tu16 num_vchunks;\n-\tint size;\n+\tint size, err;\n \n \tac.num_vectors = cpu_to_le16(num_vectors);\n \n-\trcvd_vec = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);\n-\tif (!rcvd_vec)\n-\t\treturn -ENOMEM;\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params, \u0026ac);\n+\tif (err)\n+\t\treturn err;\n \n-\txn_params.vc_op = VIRTCHNL2_OP_ALLOC_VECTORS;\n-\txn_params.send_buf.iov_base = \u0026ac;\n-\txn_params.send_buf.iov_len = sizeof(ac);\n-\txn_params.recv_buf.iov_base = rcvd_vec;\n-\txn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n+\trcvd_vec = xn_params.recv_mem.iov_base;\n+\tif (xn_params.recv_mem.iov_len \u003c sizeof(*rcvd_vec)) {\n+\t\terr = -EIO;\n+\t\tgoto free_rx_buf;\n+\t}\n \n \tnum_vchunks = le16_to_cpu(rcvd_vec-\u003evchunks.num_vchunks);\n \tsize = struct_size(rcvd_vec, vchunks.vchunks, num_vchunks);\n-\tif (reply_sz \u003c size)\n-\t\treturn -EIO;\n-\n-\tif (size \u003e IDPF_CTLQ_MAX_BUF_LEN)\n-\t\treturn -EINVAL;\n+\tif (xn_params.recv_mem.iov_len \u003c size) {\n+\t\terr = -EIO;\n+\t\tgoto free_rx_buf;\n+\t}\n \n \tkfree(adapter-\u003ereq_vec_chunks);\n \tadapter-\u003ereq_vec_chunks = kmemdup(rcvd_vec, size, GFP_KERNEL);\n-\tif (!adapter-\u003ereq_vec_chunks)\n-\t\treturn -ENOMEM;\n+\tif (!adapter-\u003ereq_vec_chunks) {\n+\t\terr = -ENOMEM;\n+\t\tgoto free_rx_buf;\n+\t}\n \n \tif (le16_to_cpu(adapter-\u003ereq_vec_chunks-\u003enum_vectors) \u003c num_vectors) {\n \t\tkfree(adapter-\u003ereq_vec_chunks);\n \t\tadapter-\u003ereq_vec_chunks = NULL;\n-\t\treturn -EINVAL;\n+\t\terr = -EINVAL;\n \t}\n \n-\treturn 0;\n+free_rx_buf:\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\n+\treturn err;\n }\n \n /**\n@@ -2739,24 +2339,28 @@ int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors)\n int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter)\n {\n \tstruct virtchnl2_alloc_vectors *ac = adapter-\u003ereq_vec_chunks;\n-\tstruct virtchnl2_vector_chunks *vcs = \u0026ac-\u003evchunks;\n-\tstruct idpf_vc_xn_params xn_params = {};\n-\tssize_t reply_sz;\n-\tint buf_size;\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_DEALLOC_VECTORS,\n+\t};\n+\tstruct virtchnl2_vector_chunks *vcs;\n+\tint buf_size, err;\n \n-\tbuf_size = struct_size(vcs, vchunks, le16_to_cpu(vcs-\u003enum_vchunks));\n+\tbuf_size = struct_size(\u0026ac-\u003evchunks, vchunks,\n+\t\t\t le16_to_cpu(ac-\u003evchunks.num_vchunks));\n+\tvcs = kmemdup(\u0026ac-\u003evchunks, buf_size, GFP_KERNEL);\n+\tif (!vcs)\n+\t\treturn -ENOMEM;\n \n-\txn_params.vc_op = VIRTCHNL2_OP_DEALLOC_VECTORS;\n-\txn_params.send_buf.iov_base = vcs;\n-\txn_params.send_buf.iov_len = buf_size;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n+\terr = idpf_send_mb_msg_kfree(adapter, \u0026xn_params, vcs, buf_size);\n+\tif (err)\n+\t\treturn err;\n \n \tkfree(adapter-\u003ereq_vec_chunks);\n \tadapter-\u003ereq_vec_chunks = NULL;\n \n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\n \treturn 0;\n }\n \n@@ -2780,18 +2384,22 @@ static int idpf_get_max_vfs(struct idpf_adapter *adapter)\n */\n int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs)\n {\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_SET_SRIOV_VFS,\n+\t};\n \tstruct virtchnl2_sriov_vfs_info svi = {};\n-\tstruct idpf_vc_xn_params xn_params = {};\n-\tssize_t reply_sz;\n+\tint err;\n \n \tsvi.num_vfs = cpu_to_le16(num_vfs);\n-\txn_params.vc_op = VIRTCHNL2_OP_SET_SRIOV_VFS;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\txn_params.send_buf.iov_base = \u0026svi;\n-\txn_params.send_buf.iov_len = sizeof(svi);\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n \n-\treturn reply_sz \u003c 0 ? reply_sz : 0;\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params, \u0026svi);\n+\tif (err)\n+\t\treturn err;\n+\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\n+\treturn 0;\n }\n \n /**\n@@ -2804,10 +2412,14 @@ int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs)\n int idpf_send_get_stats_msg(struct idpf_netdev_priv *np,\n \t\t\t struct idpf_port_stats *port_stats)\n {\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_GET_STATS,\n+\t};\n \tstruct rtnl_link_stats64 *netstats = \u0026np-\u003enetstats;\n+\tstruct virtchnl2_vport_stats *stats_recv;\n \tstruct virtchnl2_vport_stats stats_msg = {};\n-\tstruct idpf_vc_xn_params xn_params = {};\n-\tssize_t reply_sz;\n+\tint err;\n \n \n \t/* Don't send get_stats message if the link is down */\n@@ -2816,65 +2428,65 @@ int idpf_send_get_stats_msg(struct idpf_netdev_priv *np,\n \n \tstats_msg.vport_id = cpu_to_le32(np-\u003evport_id);\n \n-\txn_params.vc_op = VIRTCHNL2_OP_GET_STATS;\n-\txn_params.send_buf.iov_base = \u0026stats_msg;\n-\txn_params.send_buf.iov_len = sizeof(stats_msg);\n-\txn_params.recv_buf = xn_params.send_buf;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n+\terr = idpf_send_mb_msg_stack(np-\u003eadapter, \u0026xn_params, \u0026stats_msg);\n+\tif (err)\n+\t\treturn err;\n+\n+\tif (xn_params.recv_mem.iov_len \u003c sizeof(*stats_recv)) {\n+\t\terr = -EIO;\n+\t\tgoto free_rx_buf;\n+\t}\n \n-\treply_sz = idpf_vc_xn_exec(np-\u003eadapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n-\tif (reply_sz \u003c sizeof(stats_msg))\n-\t\treturn -EIO;\n+\tstats_recv = xn_params.recv_mem.iov_base;\n \n \tspin_lock_bh(\u0026np-\u003estats_lock);\n \n-\tnetstats-\u003erx_packets = le64_to_cpu(stats_msg.rx_unicast) +\n-\t\t\t le64_to_cpu(stats_msg.rx_multicast) +\n-\t\t\t le64_to_cpu(stats_msg.rx_broadcast);\n-\tnetstats-\u003etx_packets = le64_to_cpu(stats_msg.tx_unicast) +\n-\t\t\t le64_to_cpu(stats_msg.tx_multicast) +\n-\t\t\t le64_to_cpu(stats_msg.tx_broadcast);\n-\tnetstats-\u003erx_bytes = le64_to_cpu(stats_msg.rx_bytes);\n-\tnetstats-\u003etx_bytes = le64_to_cpu(stats_msg.tx_bytes);\n-\tnetstats-\u003erx_errors = le64_to_cpu(stats_msg.rx_errors);\n-\tnetstats-\u003etx_errors = le64_to_cpu(stats_msg.tx_errors);\n-\tnetstats-\u003erx_dropped = le64_to_cpu(stats_msg.rx_discards);\n-\tnetstats-\u003etx_dropped = le64_to_cpu(stats_msg.tx_discards);\n-\n-\tport_stats-\u003evport_stats = stats_msg;\n+\tnetstats-\u003erx_packets = le64_to_cpu(stats_recv-\u003erx_unicast) +\n+\t\t\t le64_to_cpu(stats_recv-\u003erx_multicast) +\n+\t\t\t le64_to_cpu(stats_recv-\u003erx_broadcast);\n+\tnetstats-\u003etx_packets = le64_to_cpu(stats_recv-\u003etx_unicast) +\n+\t\t\t le64_to_cpu(stats_recv-\u003etx_multicast) +\n+\t\t\t le64_to_cpu(stats_recv-\u003etx_broadcast);\n+\tnetstats-\u003erx_bytes = le64_to_cpu(stats_recv-\u003erx_bytes);\n+\tnetstats-\u003etx_bytes = le64_to_cpu(stats_recv-\u003etx_bytes);\n+\tnetstats-\u003erx_errors = le64_to_cpu(stats_recv-\u003erx_errors);\n+\tnetstats-\u003etx_errors = le64_to_cpu(stats_recv-\u003etx_errors);\n+\tnetstats-\u003erx_dropped = le64_to_cpu(stats_recv-\u003erx_discards);\n+\tnetstats-\u003etx_dropped = le64_to_cpu(stats_recv-\u003etx_discards);\n+\n+\tport_stats-\u003evport_stats = *stats_recv;\n \n \tspin_unlock_bh(\u0026np-\u003estats_lock);\n \n-\treturn 0;\n+free_rx_buf:\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\n+\treturn err;\n }\n \n /**\n- * idpf_send_get_set_rss_lut_msg - Send virtchnl get or set RSS lut message\n+ * idpf_send_set_rss_lut_msg - Send virtchnl set RSS lut message\n * @adapter: adapter pointer used to send virtchnl message\n * @rss_data: pointer to RSS key and lut info\n * @vport_id: vport identifier used while preparing the virtchnl message\n- * @get: flag to set or get RSS look up table\n *\n- * When rxhash is disabled, RSS LUT will be configured with zeros. If rxhash\n+ * When rxhash is disabled, RSS LUT will be configured with zeros. If rxhash\n * is enabled, the LUT values stored in driver's soft copy will be used to setup\n * the HW.\n *\n * Return: 0 on success, negative on failure.\n */\n-int idpf_send_get_set_rss_lut_msg(struct idpf_adapter *adapter,\n-\t\t\t\t struct idpf_rss_data *rss_data,\n-\t\t\t\t u32 vport_id, bool get)\n+int idpf_send_set_rss_lut_msg(struct idpf_adapter *adapter,\n+\t\t\t struct idpf_rss_data *rss_data, u32 vport_id)\n {\n-\tstruct virtchnl2_rss_lut *recv_rl __free(kfree) = NULL;\n-\tstruct virtchnl2_rss_lut *rl __free(kfree) = NULL;\n-\tstruct idpf_vc_xn_params xn_params = {};\n-\tint buf_size, lut_buf_size;\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_SET_RSS_LUT,\n+\t};\n+\tstruct virtchnl2_rss_lut *rl;\n \tstruct idpf_vport *vport;\n-\tssize_t reply_sz;\n+\tint buf_size, i, err;\n \tbool rxhash_ena;\n-\tint i;\n \n \tvport = idpf_vid_to_vport(adapter, vport_id);\n \tif (!vport)\n@@ -2888,76 +2500,36 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_adapter *adapter,\n \t\treturn -ENOMEM;\n \n \trl-\u003evport_id = cpu_to_le32(vport_id);\n+\trl-\u003elut_entries = cpu_to_le16(rss_data-\u003erss_lut_size);\n+\tfor (i = 0; i \u003c rss_data-\u003erss_lut_size; i++)\n+\t\trl-\u003elut[i] = rxhash_ena ? cpu_to_le32(rss_data-\u003erss_lut[i]) : 0;\n \n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\txn_params.send_buf.iov_base = rl;\n-\txn_params.send_buf.iov_len = buf_size;\n-\n-\tif (get) {\n-\t\trecv_rl = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);\n-\t\tif (!recv_rl)\n-\t\t\treturn -ENOMEM;\n-\t\txn_params.vc_op = VIRTCHNL2_OP_GET_RSS_LUT;\n-\t\txn_params.recv_buf.iov_base = recv_rl;\n-\t\txn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;\n-\t} else {\n-\t\trl-\u003elut_entries = cpu_to_le16(rss_data-\u003erss_lut_size);\n-\t\tfor (i = 0; i \u003c rss_data-\u003erss_lut_size; i++)\n-\t\t\trl-\u003elut[i] = rxhash_ena ?\n-\t\t\t\tcpu_to_le32(rss_data-\u003erss_lut[i]) : 0;\n-\n-\t\txn_params.vc_op = VIRTCHNL2_OP_SET_RSS_LUT;\n-\t}\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n-\tif (!get)\n-\t\treturn 0;\n-\tif (reply_sz \u003c sizeof(struct virtchnl2_rss_lut))\n-\t\treturn -EIO;\n-\n-\tlut_buf_size = le16_to_cpu(recv_rl-\u003elut_entries) * sizeof(u32);\n-\tif (reply_sz \u003c lut_buf_size)\n-\t\treturn -EIO;\n-\n-\t/* size didn't change, we can reuse existing lut buf */\n-\tif (rss_data-\u003erss_lut_size == le16_to_cpu(recv_rl-\u003elut_entries))\n-\t\tgoto do_memcpy;\n-\n-\trss_data-\u003erss_lut_size = le16_to_cpu(recv_rl-\u003elut_entries);\n-\tkfree(rss_data-\u003erss_lut);\n-\n-\trss_data-\u003erss_lut = kzalloc(lut_buf_size, GFP_KERNEL);\n-\tif (!rss_data-\u003erss_lut) {\n-\t\trss_data-\u003erss_lut_size = 0;\n-\t\treturn -ENOMEM;\n-\t}\n+\terr = idpf_send_mb_msg_kfree(adapter, \u0026xn_params, rl, buf_size);\n+\tif (err)\n+\t\treturn err;\n \n-do_memcpy:\n-\tmemcpy(rss_data-\u003erss_lut, recv_rl-\u003elut, rss_data-\u003erss_lut_size);\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n \n-\treturn 0;\n+\treturn err;\n }\n \n /**\n- * idpf_send_get_set_rss_key_msg - Send virtchnl get or set RSS key message\n+ * idpf_send_set_rss_key_msg - Send virtchnl set RSS key message\n * @adapter: adapter pointer used to send virtchnl message\n * @rss_data: pointer to RSS key and lut info\n * @vport_id: vport identifier used while preparing the virtchnl message\n- * @get: flag to set or get RSS look up table\n *\n * Return: 0 on success, negative on failure\n */\n-int idpf_send_get_set_rss_key_msg(struct idpf_adapter *adapter,\n-\t\t\t\t struct idpf_rss_data *rss_data,\n-\t\t\t\t u32 vport_id, bool get)\n+int idpf_send_set_rss_key_msg(struct idpf_adapter *adapter,\n+\t\t\t struct idpf_rss_data *rss_data, u32 vport_id)\n {\n-\tstruct virtchnl2_rss_key *recv_rk __free(kfree) = NULL;\n-\tstruct virtchnl2_rss_key *rk __free(kfree) = NULL;\n-\tstruct idpf_vc_xn_params xn_params = {};\n-\tssize_t reply_sz;\n-\tint i, buf_size;\n-\tu16 key_size;\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_SET_RSS_KEY,\n+\t};\n+\tstruct virtchnl2_rss_key *rk;\n+\tint i, buf_size, err;\n \n \tbuf_size = struct_size(rk, key_flex, rss_data-\u003erss_key_size);\n \trk = kzalloc(buf_size, GFP_KERNEL);\n@@ -2965,54 +2537,17 @@ int idpf_send_get_set_rss_key_msg(struct idpf_adapter *adapter,\n \t\treturn -ENOMEM;\n \n \trk-\u003evport_id = cpu_to_le32(vport_id);\n-\txn_params.send_buf.iov_base = rk;\n-\txn_params.send_buf.iov_len = buf_size;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\tif (get) {\n-\t\trecv_rk = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);\n-\t\tif (!recv_rk)\n-\t\t\treturn -ENOMEM;\n-\n-\t\txn_params.vc_op = VIRTCHNL2_OP_GET_RSS_KEY;\n-\t\txn_params.recv_buf.iov_base = recv_rk;\n-\t\txn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;\n-\t} else {\n-\t\trk-\u003ekey_len = cpu_to_le16(rss_data-\u003erss_key_size);\n-\t\tfor (i = 0; i \u003c rss_data-\u003erss_key_size; i++)\n-\t\t\trk-\u003ekey_flex[i] = rss_data-\u003erss_key[i];\n+\trk-\u003ekey_len = cpu_to_le16(rss_data-\u003erss_key_size);\n+\tfor (i = 0; i \u003c rss_data-\u003erss_key_size; i++)\n+\t\trk-\u003ekey_flex[i] = rss_data-\u003erss_key[i];\n \n-\t\txn_params.vc_op = VIRTCHNL2_OP_SET_RSS_KEY;\n-\t}\n-\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n-\tif (!get)\n-\t\treturn 0;\n-\tif (reply_sz \u003c sizeof(struct virtchnl2_rss_key))\n-\t\treturn -EIO;\n-\n-\tkey_size = min_t(u16, NETDEV_RSS_KEY_LEN,\n-\t\t\t le16_to_cpu(recv_rk-\u003ekey_len));\n-\tif (reply_sz \u003c key_size)\n-\t\treturn -EIO;\n-\n-\t/* key len didn't change, reuse existing buf */\n-\tif (rss_data-\u003erss_key_size == key_size)\n-\t\tgoto do_memcpy;\n-\n-\trss_data-\u003erss_key_size = key_size;\n-\tkfree(rss_data-\u003erss_key);\n-\trss_data-\u003erss_key = kzalloc(key_size, GFP_KERNEL);\n-\tif (!rss_data-\u003erss_key) {\n-\t\trss_data-\u003erss_key_size = 0;\n-\t\treturn -ENOMEM;\n-\t}\n+\terr = idpf_send_mb_msg_kfree(adapter, \u0026xn_params, rk, buf_size);\n+\tif (err)\n+\t\treturn err;\n \n-do_memcpy:\n-\tmemcpy(rss_data-\u003erss_key, recv_rk-\u003ekey_flex, rss_data-\u003erss_key_size);\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n \n-\treturn 0;\n+\treturn err;\n }\n \n /**\n@@ -3189,60 +2724,63 @@ static void idpf_parse_protocol_ids(struct virtchnl2_ptype *ptype,\n */\n static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)\n {\n-\tstruct virtchnl2_get_ptype_info *get_ptype_info __free(kfree) = NULL;\n-\tstruct virtchnl2_get_ptype_info *ptype_info __free(kfree) = NULL;\n-\tstruct libeth_rx_pt *singleq_pt_lkup __free(kfree) = NULL;\n-\tstruct libeth_rx_pt *splitq_pt_lkup __free(kfree) = NULL;\n-\tstruct idpf_vc_xn_params xn_params = {};\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_GET_PTYPE_INFO,\n+\t};\n+\tstruct virtchnl2_get_ptype_info *get_ptype_info;\n+\tstruct virtchnl2_get_ptype_info *ptype_info;\n+\tint err = 0, max_ptype = IDPF_RX_MAX_PTYPE;\n+\tint buf_size = sizeof(*get_ptype_info);\n+\tstruct libeth_rx_pt *singleq_pt_lkup;\n+\tstruct libeth_rx_pt *splitq_pt_lkup;\n \tint ptypes_recvd = 0, ptype_offset;\n-\tu32 max_ptype = IDPF_RX_MAX_PTYPE;\n \tu16 next_ptype_id = 0;\n-\tssize_t reply_sz;\n \n \tsingleq_pt_lkup = kzalloc_objs(*singleq_pt_lkup, IDPF_RX_MAX_BASE_PTYPE);\n \tif (!singleq_pt_lkup)\n \t\treturn -ENOMEM;\n \n \tsplitq_pt_lkup = kzalloc_objs(*splitq_pt_lkup, max_ptype);\n-\tif (!splitq_pt_lkup)\n-\t\treturn -ENOMEM;\n-\n-\tget_ptype_info = kzalloc_obj(*get_ptype_info);\n-\tif (!get_ptype_info)\n-\t\treturn -ENOMEM;\n+\tif (!splitq_pt_lkup) {\n+\t\terr = -ENOMEM;\n+\t\tgoto free_singleq;\n+\t}\n \n-\tptype_info = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);\n-\tif (!ptype_info)\n-\t\treturn -ENOMEM;\n+\twhile (next_ptype_id \u003c max_ptype) {\n+\t\tu16 num_ptypes;\n \n-\txn_params.vc_op = VIRTCHNL2_OP_GET_PTYPE_INFO;\n-\txn_params.send_buf.iov_base = get_ptype_info;\n-\txn_params.send_buf.iov_len = sizeof(*get_ptype_info);\n-\txn_params.recv_buf.iov_base = ptype_info;\n-\txn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n+\t\tget_ptype_info = kzalloc(buf_size, GFP_KERNEL);\n+\t\tif (!get_ptype_info) {\n+\t\t\terr = -ENOMEM;\n+\t\t\tgoto free_splitq;\n+\t\t}\n \n-\twhile (next_ptype_id \u003c max_ptype) {\n \t\tget_ptype_info-\u003estart_ptype_id = cpu_to_le16(next_ptype_id);\n \n \t\tif ((next_ptype_id + IDPF_RX_MAX_PTYPES_PER_BUF) \u003e max_ptype)\n-\t\t\tget_ptype_info-\u003enum_ptypes =\n-\t\t\t\tcpu_to_le16(max_ptype - next_ptype_id);\n+\t\t\tnum_ptypes = max_ptype - next_ptype_id;\n \t\telse\n-\t\t\tget_ptype_info-\u003enum_ptypes =\n-\t\t\t\tcpu_to_le16(IDPF_RX_MAX_PTYPES_PER_BUF);\n-\n-\t\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\t\tif (reply_sz \u003c 0)\n-\t\t\treturn reply_sz;\n-\n+\t\t\tnum_ptypes = IDPF_RX_MAX_PTYPES_PER_BUF;\n+\n+\t\tget_ptype_info-\u003enum_ptypes = cpu_to_le16(num_ptypes);\n+\t\terr = idpf_send_mb_msg_kfree(adapter, \u0026xn_params,\n+\t\t\t\t\t get_ptype_info, buf_size);\n+\t\tif (err)\n+\t\t\tgoto free_splitq;\n+\n+\t\tptype_info = xn_params.recv_mem.iov_base;\n+\t\tif (xn_params.recv_mem.iov_len \u003c sizeof(*ptype_info)) {\n+\t\t\terr = -EIO;\n+\t\t\tgoto free_rx_buf;\n+\t\t}\n \t\tptypes_recvd += le16_to_cpu(ptype_info-\u003enum_ptypes);\n-\t\tif (ptypes_recvd \u003e max_ptype)\n-\t\t\treturn -EINVAL;\n-\n-\t\tnext_ptype_id = le16_to_cpu(get_ptype_info-\u003estart_ptype_id) +\n-\t\t\t\tle16_to_cpu(get_ptype_info-\u003enum_ptypes);\n+\t\tif (ptypes_recvd \u003e max_ptype) {\n+\t\t\terr = -EINVAL;\n+\t\t\tgoto free_rx_buf;\n+\t\t}\n \n+\t\tnext_ptype_id = next_ptype_id + num_ptypes;\n \t\tptype_offset = IDPF_RX_PTYPE_HDR_SZ;\n \n \t\tfor (u16 i = 0; i \u003c le16_to_cpu(ptype_info-\u003enum_ptypes); i++) {\n@@ -3252,19 +2790,28 @@ static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)\n \n \t\t\tptype = (struct virtchnl2_ptype *)\n \t\t\t\t\t((u8 *)ptype_info + ptype_offset);\n+\t\t\tif (xn_params.recv_mem.iov_len \u003c\n+\t\t\t ptype_offset + sizeof(struct virtchnl2_ptype)) {\n+\t\t\t\terr = -EINVAL;\n+\t\t\t\tgoto free_rx_buf;\n+\t\t\t}\n \n \t\t\tpt_10 = le16_to_cpu(ptype-\u003eptype_id_10);\n \t\t\tpt_8 = ptype-\u003eptype_id_8;\n \n \t\t\tptype_offset += IDPF_GET_PTYPE_SIZE(ptype);\n-\t\t\tif (ptype_offset \u003e IDPF_CTLQ_MAX_BUF_LEN)\n-\t\t\t\treturn -EINVAL;\n+\t\t\tif (xn_params.recv_mem.iov_len \u003c ptype_offset) {\n+\t\t\t\terr = -EINVAL;\n+\t\t\t\tgoto free_rx_buf;\n+\t\t\t}\n \n \t\t\t/* 0xFFFF indicates end of ptypes */\n \t\t\tif (pt_10 == IDPF_INVALID_PTYPE_ID)\n \t\t\t\tgoto out;\n-\t\t\tif (pt_10 \u003e= max_ptype)\n-\t\t\t\treturn -EINVAL;\n+\t\t\tif (pt_10 \u003e= max_ptype) {\n+\t\t\t\terr = -EINVAL;\n+\t\t\t\tgoto free_rx_buf;\n+\t\t\t}\n \n \t\t\tidpf_parse_protocol_ids(ptype, \u0026rx_pt);\n \t\t\tidpf_finalize_ptype_lookup(\u0026rx_pt);\n@@ -3278,13 +2825,24 @@ static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)\n \t\t\tif (!singleq_pt_lkup[pt_8].outer_ip)\n \t\t\t\tsingleq_pt_lkup[pt_8] = rx_pt;\n \t\t}\n+\n+\t\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\t\txn_params.recv_mem = (struct kvec) {};\n \t}\n \n out:\n-\tadapter-\u003esplitq_pt_lkup = no_free_ptr(splitq_pt_lkup);\n-\tadapter-\u003esingleq_pt_lkup = no_free_ptr(singleq_pt_lkup);\n+\tadapter-\u003esplitq_pt_lkup = splitq_pt_lkup;\n+\tadapter-\u003esingleq_pt_lkup = singleq_pt_lkup;\n+\tsplitq_pt_lkup = NULL;\n+\tsingleq_pt_lkup = NULL;\n+free_rx_buf:\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+free_splitq:\n+\tkfree(splitq_pt_lkup);\n+free_singleq:\n+\tkfree(singleq_pt_lkup);\n \n-\treturn 0;\n+\treturn err;\n }\n \n /**\n@@ -3312,40 +2870,23 @@ static void idpf_rel_rx_pt_lkup(struct idpf_adapter *adapter)\n int idpf_send_ena_dis_loopback_msg(struct idpf_adapter *adapter, u32 vport_id,\n \t\t\t\t bool loopback_ena)\n {\n-\tstruct idpf_vc_xn_params xn_params = {};\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_LOOPBACK,\n+\t};\n \tstruct virtchnl2_loopback loopback;\n-\tssize_t reply_sz;\n+\tint err;\n \n \tloopback.vport_id = cpu_to_le32(vport_id);\n \tloopback.enable = loopback_ena;\n \n-\txn_params.vc_op = VIRTCHNL2_OP_LOOPBACK;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\txn_params.send_buf.iov_base = \u0026loopback;\n-\txn_params.send_buf.iov_len = sizeof(loopback);\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\n-\treturn reply_sz \u003c 0 ? reply_sz : 0;\n-}\n-\n-/**\n- * idpf_find_ctlq - Given a type and id, find ctlq info\n- * @hw: hardware struct\n- * @type: type of ctrlq to find\n- * @id: ctlq id to find\n- *\n- * Returns pointer to found ctlq info struct, NULL otherwise.\n- */\n-static struct idpf_ctlq_info *idpf_find_ctlq(struct idpf_hw *hw,\n-\t\t\t\t\t enum idpf_ctlq_type type, int id)\n-{\n-\tstruct idpf_ctlq_info *cq, *tmp;\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params, \u0026loopback);\n+\tif (err)\n+\t\treturn err;\n \n-\tlist_for_each_entry_safe(cq, tmp, \u0026hw-\u003ecq_list_head, cq_list)\n-\t\tif (cq-\u003eq_id == id \u0026\u0026 cq-\u003ecq_type == type)\n-\t\t\treturn cq;\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n \n-\treturn NULL;\n+\treturn 0;\n }\n \n /**\n@@ -3356,42 +2897,49 @@ static struct idpf_ctlq_info *idpf_find_ctlq(struct idpf_hw *hw,\n */\n int idpf_init_dflt_mbx(struct idpf_adapter *adapter)\n {\n-\tstruct idpf_ctlq_create_info ctlq_info[] = {\n+\tstruct libie_ctlq_ctx *ctx = \u0026adapter-\u003ectlq_ctx;\n+\tstruct libie_ctlq_create_info ctlq_info[] = {\n \t\t{\n-\t\t\t.type = IDPF_CTLQ_TYPE_MAILBOX_TX,\n-\t\t\t.id = IDPF_DFLT_MBX_ID,\n+\t\t\t.type = LIBIE_CTLQ_TYPE_TX,\n+\t\t\t.id = LIBIE_CTLQ_MBX_ID,\n \t\t\t.len = IDPF_DFLT_MBX_Q_LEN,\n-\t\t\t.buf_size = IDPF_CTLQ_MAX_BUF_LEN\n \t\t},\n \t\t{\n-\t\t\t.type = IDPF_CTLQ_TYPE_MAILBOX_RX,\n-\t\t\t.id = IDPF_DFLT_MBX_ID,\n+\t\t\t.type = LIBIE_CTLQ_TYPE_RX,\n+\t\t\t.id = LIBIE_CTLQ_MBX_ID,\n \t\t\t.len = IDPF_DFLT_MBX_Q_LEN,\n-\t\t\t.buf_size = IDPF_CTLQ_MAX_BUF_LEN\n \t\t}\n \t};\n-\tstruct idpf_hw *hw = \u0026adapter-\u003ehw;\n+\tstruct libie_ctlq_xn_init_params params = {\n+\t\t.num_qs = IDPF_NUM_DFLT_MBX_Q,\n+\t\t.cctlq_info = ctlq_info,\n+\t\t.ctx = ctx,\n+\t};\n \tint err;\n \n-\tadapter-\u003edev_ops.reg_ops.ctlq_reg_init(adapter, ctlq_info);\n+\tadapter-\u003edev_ops.reg_ops.ctlq_reg_init(\u0026ctx-\u003emmio_info,\n+\t\t\t\t\t params.cctlq_info);\n \n-\terr = idpf_ctlq_init(hw, IDPF_NUM_DFLT_MBX_Q, ctlq_info);\n+\terr = libie_ctlq_xn_init(\u0026params);\n \tif (err)\n \t\treturn err;\n \n-\thw-\u003easq = idpf_find_ctlq(hw, IDPF_CTLQ_TYPE_MAILBOX_TX,\n-\t\t\t\t IDPF_DFLT_MBX_ID);\n-\thw-\u003earq = idpf_find_ctlq(hw, IDPF_CTLQ_TYPE_MAILBOX_RX,\n-\t\t\t\t IDPF_DFLT_MBX_ID);\n-\n-\tif (!hw-\u003easq || !hw-\u003earq) {\n-\t\tidpf_ctlq_deinit(hw);\n-\n+\tadapter-\u003easq = libie_find_ctlq(ctx, LIBIE_CTLQ_TYPE_TX,\n+\t\t\t\t LIBIE_CTLQ_MBX_ID);\n+\tadapter-\u003earq = libie_find_ctlq(ctx, LIBIE_CTLQ_TYPE_RX,\n+\t\t\t\t LIBIE_CTLQ_MBX_ID);\n+\tif (!adapter-\u003easq || !adapter-\u003earq) {\n+\t\tadapter-\u003easq = NULL;\n+\t\tadapter-\u003earq = NULL;\n+\t\tlibie_ctlq_xn_deinit(params.xnm, ctx);\n \t\treturn -ENOENT;\n \t}\n \n+\tadapter-\u003exnm = params.xnm;\n \tadapter-\u003estate = __IDPF_VER_CHECK;\n \n+\tqueue_delayed_work(adapter-\u003embx_wq, \u0026adapter-\u003embx_task, 0);\n+\n \treturn 0;\n }\n \n@@ -3401,12 +2949,18 @@ int idpf_init_dflt_mbx(struct idpf_adapter *adapter)\n */\n void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter)\n {\n-\tif (adapter-\u003ehw.arq \u0026\u0026 adapter-\u003ehw.asq) {\n-\t\tidpf_mb_clean(adapter, adapter-\u003ehw.asq);\n-\t\tidpf_ctlq_deinit(\u0026adapter-\u003ehw);\n+\tidpf_mb_intr_rel_irq(adapter);\n+\tcancel_delayed_work_sync(\u0026adapter-\u003embx_task);\n+\n+\tif (adapter-\u003exnm) {\n+\t\tlibie_ctlq_xn_shutdown(adapter-\u003exnm);\n+\t\tidpf_mb_clean(adapter-\u003easq, true);\n+\t\tlibie_ctlq_xn_deinit(adapter-\u003exnm, \u0026adapter-\u003ectlq_ctx);\n \t}\n-\tadapter-\u003ehw.arq = NULL;\n-\tadapter-\u003ehw.asq = NULL;\n+\n+\tadapter-\u003earq = NULL;\n+\tadapter-\u003easq = NULL;\n+\tadapter-\u003exnm = NULL;\n }\n \n /**\n@@ -3419,8 +2973,6 @@ static void idpf_vport_params_buf_rel(struct idpf_adapter *adapter)\n {\n \tkfree(adapter-\u003evport_params_recvd);\n \tadapter-\u003evport_params_recvd = NULL;\n-\tkfree(adapter-\u003evport_params_reqd);\n-\tadapter-\u003evport_params_reqd = NULL;\n \tkfree(adapter-\u003evport_ids);\n \tadapter-\u003evport_ids = NULL;\n }\n@@ -3435,15 +2987,10 @@ static int idpf_vport_params_buf_alloc(struct idpf_adapter *adapter)\n {\n \tu16 num_max_vports = idpf_get_max_vports(adapter);\n \n-\tadapter-\u003evport_params_reqd = kzalloc_objs(*adapter-\u003evport_params_reqd,\n-\t\t\t\t\t\t num_max_vports);\n-\tif (!adapter-\u003evport_params_reqd)\n-\t\treturn -ENOMEM;\n-\n \tadapter-\u003evport_params_recvd = kzalloc_objs(*adapter-\u003evport_params_recvd,\n \t\t\t\t\t\t num_max_vports);\n \tif (!adapter-\u003evport_params_recvd)\n-\t\tgoto err_mem;\n+\t\treturn -ENOMEM;\n \n \tadapter-\u003evport_ids = kcalloc(num_max_vports, sizeof(u32), GFP_KERNEL);\n \tif (!adapter-\u003evport_ids)\n@@ -3484,15 +3031,6 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)\n \tu16 num_max_vports;\n \tint err = 0;\n \n-\tif (!adapter-\u003evcxn_mngr) {\n-\t\tadapter-\u003evcxn_mngr = kzalloc_obj(*adapter-\u003evcxn_mngr);\n-\t\tif (!adapter-\u003evcxn_mngr) {\n-\t\t\terr = -ENOMEM;\n-\t\t\tgoto init_failed;\n-\t\t}\n-\t}\n-\tidpf_vc_xn_init(adapter-\u003evcxn_mngr);\n-\n \twhile (adapter-\u003estate != __IDPF_INIT_SW) {\n \t\tswitch (adapter-\u003estate) {\n \t\tcase __IDPF_VER_CHECK:\n@@ -3531,34 +3069,29 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)\n \t}\n \n \tif (idpf_is_cap_ena(adapter, IDPF_OTHER_CAPS, VIRTCHNL2_CAP_LAN_MEMORY_REGIONS)) {\n-\t\terr = idpf_send_get_lan_memory_regions(adapter);\n+\t\terr = idpf_cfg_lan_memory_regions(adapter);\n \t\tif (err) {\n-\t\t\tdev_err(\u0026adapter-\u003epdev-\u003edev, \"Failed to get LAN memory regions: %d\\n\",\n+\t\t\tdev_err(\u0026adapter-\u003epdev-\u003edev, \"Failed to configure LAN memory regions: %d\\n\",\n \t\t\t\terr);\n \t\t\treturn -EINVAL;\n \t\t}\n \t} else {\n \t\t/* Fallback to mapping the remaining regions of the entire BAR */\n-\t\terr = idpf_calc_remaining_mmio_regs(adapter);\n+\t\terr = idpf_map_remaining_mmio_regs(adapter);\n \t\tif (err) {\n-\t\t\tdev_err(\u0026adapter-\u003epdev-\u003edev, \"Failed to allocate BAR0 region(s): %d\\n\",\n+\t\t\tdev_err(\u0026adapter-\u003epdev-\u003edev, \"Failed to configure BAR0 region(s): %d\\n\",\n \t\t\t\terr);\n-\t\t\treturn -ENOMEM;\n+\t\t\treturn err;\n \t\t}\n \t}\n \n-\terr = idpf_map_lan_mmio_regs(adapter);\n-\tif (err) {\n-\t\tdev_err(\u0026adapter-\u003epdev-\u003edev, \"Failed to map BAR0 region(s): %d\\n\",\n-\t\t\terr);\n-\t\treturn -ENOMEM;\n-\t}\n-\n \tpci_sriov_set_totalvfs(adapter-\u003epdev, idpf_get_max_vfs(adapter));\n \tnum_max_vports = idpf_get_max_vports(adapter);\n \tadapter-\u003evports = kzalloc_objs(*adapter-\u003evports, num_max_vports);\n-\tif (!adapter-\u003evports)\n-\t\treturn -ENOMEM;\n+\tif (!adapter-\u003evports) {\n+\t\terr = -ENOMEM;\n+\t\tgoto decfg_regions;\n+\t}\n \n \tif (!adapter-\u003enetdevs) {\n \t\tadapter-\u003enetdevs = kzalloc_objs(struct net_device *,\n@@ -3630,6 +3163,8 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)\n err_netdev_alloc:\n \tkfree(adapter-\u003evports);\n \tadapter-\u003evports = NULL;\n+decfg_regions:\n+\tidpf_decfg_lan_memory_regions(adapter);\n \treturn err;\n \n init_failed:\n@@ -3647,8 +3182,7 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)\n \t * the mailbox again\n \t */\n \tadapter-\u003estate = __IDPF_VER_CHECK;\n-\tif (adapter-\u003evcxn_mngr)\n-\t\tidpf_vc_xn_shutdown(adapter-\u003evcxn_mngr);\n+\tlibie_ctlq_xn_shutdown(adapter-\u003exnm);\n \tset_bit(IDPF_HR_DRV_LOAD, adapter-\u003eflags);\n \tqueue_delayed_work(adapter-\u003evc_event_wq, \u0026adapter-\u003evc_event_task,\n \t\t\t msecs_to_jiffies(task_delay));\n@@ -3663,7 +3197,6 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)\n */\n void idpf_vc_core_deinit(struct idpf_adapter *adapter)\n {\n-\tstruct idpf_hw *hw = \u0026adapter-\u003ehw;\n \tbool remove_in_prog;\n \n \tif (!test_bit(IDPF_VC_CORE_INIT, adapter-\u003eflags))\n@@ -3672,7 +3205,7 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)\n \t/* Avoid transaction timeouts when called during reset */\n \tremove_in_prog = test_bit(IDPF_REMOVE_IN_PROG, adapter-\u003eflags);\n \tif (!remove_in_prog)\n-\t\tidpf_vc_xn_shutdown(adapter-\u003evcxn_mngr);\n+\t\tlibie_ctlq_xn_shutdown(adapter-\u003exnm);\n \n \tidpf_ptp_release(adapter);\n \tidpf_deinit_task(adapter);\n@@ -3681,19 +3214,17 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)\n \tidpf_intr_rel(adapter);\n \n \tif (remove_in_prog)\n-\t\tidpf_vc_xn_shutdown(adapter-\u003evcxn_mngr);\n+\t\tlibie_ctlq_xn_shutdown(adapter-\u003exnm);\n \n \tcancel_delayed_work_sync(\u0026adapter-\u003eserv_task);\n \tcancel_delayed_work_sync(\u0026adapter-\u003embx_task);\n \n \tidpf_vport_params_buf_rel(adapter);\n \n-\tkfree(hw-\u003elan_regs);\n-\thw-\u003elan_regs = NULL;\n-\n \tkfree(adapter-\u003evports);\n \tadapter-\u003evports = NULL;\n \n+\tidpf_decfg_lan_memory_regions(adapter);\n \tclear_bit(IDPF_VC_CORE_INIT, adapter-\u003eflags);\n }\n \n@@ -4220,9 +3751,9 @@ static void idpf_set_mac_type(const u8 *default_mac_addr,\n \n /**\n * idpf_mac_filter_async_handler - Async callback for mac filters\n- * @adapter: private data struct\n- * @xn: transaction for message\n- * @ctlq_msg: received message\n+ * @ctx: controlq context structure\n+ * @buff: response buffer pointer and size\n+ * @status: async call return value\n *\n * In some scenarios driver can't sleep and wait for a reply (e.g.: stack is\n * holding rtnl_lock) when adding a new mac filter. It puts us in a difficult\n@@ -4230,13 +3761,14 @@ static void idpf_set_mac_type(const u8 *default_mac_addr,\n * ultimately do is remove it from our list of mac filters and report the\n * error.\n */\n-static int idpf_mac_filter_async_handler(struct idpf_adapter *adapter,\n-\t\t\t\t\t struct idpf_vc_xn *xn,\n-\t\t\t\t\t const struct idpf_ctlq_msg *ctlq_msg)\n+static void idpf_mac_filter_async_handler(void *ctx,\n+\t\t\t\t\t struct kvec *buff,\n+\t\t\t\t\t int status)\n {\n \tstruct virtchnl2_mac_addr_list *ma_list;\n \tstruct idpf_vport_config *vport_config;\n \tstruct virtchnl2_mac_addr *mac_addr;\n+\tstruct idpf_adapter *adapter = ctx;\n \tstruct idpf_mac_filter *f, *tmp;\n \tstruct list_head *ma_list_head;\n \tstruct idpf_vport *vport;\n@@ -4244,18 +3776,18 @@ static int idpf_mac_filter_async_handler(struct idpf_adapter *adapter,\n \tint i;\n \n \t/* if success we're done, we're only here if something bad happened */\n-\tif (!ctlq_msg-\u003ecookie.mbx.chnl_retval)\n-\t\treturn 0;\n+\tif (!status || status == -ETIMEDOUT)\n+\t\treturn;\n \n+\tma_list = buff-\u003eiov_base;\n \t/* make sure at least struct is there */\n-\tif (xn-\u003ereply_sz \u003c sizeof(*ma_list))\n+\tif (buff-\u003eiov_len \u003c sizeof(*ma_list))\n \t\tgoto invalid_payload;\n \n-\tma_list = ctlq_msg-\u003ectx.indirect.payload-\u003eva;\n \tmac_addr = ma_list-\u003emac_addr_list;\n \tnum_entries = le16_to_cpu(ma_list-\u003enum_mac_addr);\n \t/* we should have received a buffer at least this big */\n-\tif (xn-\u003ereply_sz \u003c struct_size(ma_list, mac_addr_list, num_entries))\n+\tif (buff-\u003eiov_len \u003c struct_size(ma_list, mac_addr_list, num_entries))\n \t\tgoto invalid_payload;\n \n \tvport = idpf_vid_to_vport(adapter, le32_to_cpu(ma_list-\u003evport_id));\n@@ -4275,16 +3807,13 @@ static int idpf_mac_filter_async_handler(struct idpf_adapter *adapter,\n \t\t\tif (ether_addr_equal(mac_addr[i].addr, f-\u003emacaddr))\n \t\t\t\tlist_del(\u0026f-\u003elist);\n \tspin_unlock_bh(\u0026vport_config-\u003emac_filter_list_lock);\n-\tdev_err_ratelimited(\u0026adapter-\u003epdev-\u003edev, \"Received error sending MAC filter request (op %d)\\n\",\n-\t\t\t xn-\u003evc_op);\n-\n-\treturn 0;\n+\tdev_err_ratelimited(\u0026adapter-\u003epdev-\u003edev, \"Received error %d on sending MAC filter request\\n\",\n+\t\t\t status);\n+\treturn;\n \n invalid_payload:\n-\tdev_err_ratelimited(\u0026adapter-\u003epdev-\u003edev, \"Received invalid MAC filter payload (op %d) (len %zd)\\n\",\n-\t\t\t xn-\u003evc_op, xn-\u003ereply_sz);\n-\n-\treturn -EINVAL;\n+\tdev_err_ratelimited(\u0026adapter-\u003epdev-\u003edev, \"Received invalid MAC filter payload (len %zd)\\n\",\n+\t\t\t buff-\u003eiov_len);\n }\n \n /**\n@@ -4303,19 +3832,21 @@ int idpf_add_del_mac_filters(struct idpf_adapter *adapter,\n \t\t\t const u8 *default_mac_addr, u32 vport_id,\n \t\t\t bool add, bool async)\n {\n-\tstruct virtchnl2_mac_addr_list *ma_list __free(kfree) = NULL;\n \tstruct virtchnl2_mac_addr *mac_addr __free(kfree) = NULL;\n-\tstruct idpf_vc_xn_params xn_params = {};\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= add ? VIRTCHNL2_OP_ADD_MAC_ADDR :\n+\t\t\t\t\tVIRTCHNL2_OP_DEL_MAC_ADDR,\n+\t};\n+\tstruct virtchnl2_mac_addr_list *ma_list;\n \tu32 num_msgs, total_filters = 0;\n \tstruct idpf_mac_filter *f;\n-\tssize_t reply_sz;\n-\tint i = 0, k;\n+\tint i = 0;\n \n-\txn_params.vc_op = add ? VIRTCHNL2_OP_ADD_MAC_ADDR :\n-\t\t\t\tVIRTCHNL2_OP_DEL_MAC_ADDR;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\txn_params.async = async;\n-\txn_params.async_handler = idpf_mac_filter_async_handler;\n+\tif (async) {\n+\t\txn_params.resp_cb = idpf_mac_filter_async_handler;\n+\t\txn_params.send_ctx = adapter;\n+\t}\n \n \tspin_lock_bh(\u0026vport_config-\u003emac_filter_list_lock);\n \n@@ -4370,32 +3901,31 @@ int idpf_add_del_mac_filters(struct idpf_adapter *adapter,\n \t */\n \tnum_msgs = DIV_ROUND_UP(total_filters, IDPF_NUM_FILTERS_PER_MSG);\n \n-\tfor (i = 0, k = 0; i \u003c num_msgs; i++) {\n-\t\tu32 entries_size, buf_size, num_entries;\n+\tfor (u32 i = 0, k = 0; i \u003c num_msgs; i++) {\n+\t\tu32 entries_size, num_entries;\n+\t\tsize_t buf_size;\n+\t\tint err;\n \n \t\tnum_entries = min_t(u32, total_filters,\n \t\t\t\t IDPF_NUM_FILTERS_PER_MSG);\n \t\tentries_size = sizeof(struct virtchnl2_mac_addr) * num_entries;\n \t\tbuf_size = struct_size(ma_list, mac_addr_list, num_entries);\n \n-\t\tif (!ma_list || num_entries != IDPF_NUM_FILTERS_PER_MSG) {\n-\t\t\tkfree(ma_list);\n-\t\t\tma_list = kzalloc(buf_size, GFP_ATOMIC);\n-\t\t\tif (!ma_list)\n-\t\t\t\treturn -ENOMEM;\n-\t\t} else {\n-\t\t\tmemset(ma_list, 0, buf_size);\n-\t\t}\n+\t\tma_list = kzalloc(buf_size, GFP_ATOMIC);\n+\t\tif (!ma_list)\n+\t\t\treturn -ENOMEM;\n \n \t\tma_list-\u003evport_id = cpu_to_le32(vport_id);\n \t\tma_list-\u003enum_mac_addr = cpu_to_le16(num_entries);\n \t\tmemcpy(ma_list-\u003emac_addr_list, \u0026mac_addr[k], entries_size);\n \n-\t\txn_params.send_buf.iov_base = ma_list;\n-\t\txn_params.send_buf.iov_len = buf_size;\n-\t\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\t\tif (reply_sz \u003c 0)\n-\t\t\treturn reply_sz;\n+\t\terr = idpf_send_mb_msg_kfree(adapter, \u0026xn_params, ma_list,\n+\t\t\t\t\t buf_size);\n+\t\tif (err)\n+\t\t\treturn err;\n+\n+\t\tif (!async)\n+\t\t\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n \n \t\tk += num_entries;\n \t\ttotal_filters -= num_entries;\n@@ -4404,6 +3934,26 @@ int idpf_add_del_mac_filters(struct idpf_adapter *adapter,\n \treturn 0;\n }\n \n+/**\n+ * idpf_promiscuous_async_handler - async callback for promiscuous mode\n+ * @ctx: controlq context structure\n+ * @buff: response buffer pointer and size\n+ * @status: async call return value\n+ *\n+ * Nobody is waiting for the promiscuous virtchnl message response. Print\n+ * an error message if something went wrong and return.\n+ */\n+static void idpf_promiscuous_async_handler(void *ctx,\n+\t\t\t\t\t struct kvec *buff,\n+\t\t\t\t\t int status)\n+{\n+\tstruct idpf_adapter *adapter = ctx;\n+\n+\tif (status)\n+\t\tdev_err_ratelimited(\u0026adapter-\u003epdev-\u003edev, \"Failed to set promiscuous mode: %d\\n\",\n+\t\t\t\t status);\n+}\n+\n /**\n * idpf_set_promiscuous - set promiscuous and send message to mailbox\n * @adapter: Driver specific private structure\n@@ -4418,9 +3968,13 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter,\n \t\t\t struct idpf_vport_user_config_data *config_data,\n \t\t\t u32 vport_id)\n {\n-\tstruct idpf_vc_xn_params xn_params = {};\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.timeout_ms\t= IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t\t.chnl_opcode\t= VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE,\n+\t\t.resp_cb\t= idpf_promiscuous_async_handler,\n+\t\t.send_ctx\t= adapter,\n+\t};\n \tstruct virtchnl2_promisc_info vpi;\n-\tssize_t reply_sz;\n \tu16 flags = 0;\n \n \tif (test_bit(__IDPF_PROMISC_UC, config_data-\u003euser_flags))\n@@ -4431,15 +3985,7 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter,\n \tvpi.vport_id = cpu_to_le32(vport_id);\n \tvpi.flags = cpu_to_le16(flags);\n \n-\txn_params.vc_op = VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\txn_params.send_buf.iov_base = \u0026vpi;\n-\txn_params.send_buf.iov_len = sizeof(vpi);\n-\t/* setting promiscuous is only ever done asynchronously */\n-\txn_params.async = true;\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\n-\treturn reply_sz \u003c 0 ? reply_sz : 0;\n+\treturn idpf_send_mb_msg_stack(adapter, \u0026xn_params, \u0026vpi);\n }\n \n /**\n@@ -4448,7 +3994,7 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter,\n * @send_msg: message to send\n * @msg_size: size of message to send\n * @recv_msg: message to populate on reception of response\n- * @recv_len: length of message copied into recv_msg or 0 on error\n+ * @recv_len: on input, maximum response size; on success, actual response size\n *\n * Return: 0 on success or error code on failure.\n */\n@@ -4457,26 +4003,39 @@ int idpf_idc_rdma_vc_send_sync(struct iidc_rdma_core_dev_info *cdev_info,\n \t\t\t u8 *recv_msg, u16 *recv_len)\n {\n \tstruct idpf_adapter *adapter = pci_get_drvdata(cdev_info-\u003epdev);\n-\tstruct idpf_vc_xn_params xn_params = { };\n-\tssize_t reply_sz;\n-\tu16 recv_size;\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.chnl_opcode = VIRTCHNL2_OP_RDMA,\n+\t\t.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n+\t};\n+\tu8 on_stack_buf[LIBIE_CP_TX_COPYBREAK];\n+\tvoid *send_buf;\n+\tint err;\n \n-\tif (!recv_msg || !recv_len || msg_size \u003e IDPF_CTLQ_MAX_BUF_LEN)\n+\tif (!recv_msg || !recv_len || msg_size \u003e LIBIE_CTLQ_MAX_BUF_LEN)\n \t\treturn -EINVAL;\n \n-\trecv_size = min_t(u16, *recv_len, IDPF_CTLQ_MAX_BUF_LEN);\n-\t*recv_len = 0;\n-\txn_params.vc_op = VIRTCHNL2_OP_RDMA;\n-\txn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;\n-\txn_params.send_buf.iov_base = send_msg;\n-\txn_params.send_buf.iov_len = msg_size;\n-\txn_params.recv_buf.iov_base = recv_msg;\n-\txn_params.recv_buf.iov_len = recv_size;\n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n-\t*recv_len = reply_sz;\n+\tif (!libie_cp_can_send_onstack(msg_size)) {\n+\t\tsend_buf = kzalloc(msg_size, GFP_KERNEL);\n+\t\tif (!send_buf)\n+\t\t\treturn -ENOMEM;\n+\t} else {\n+\t\tsend_buf = on_stack_buf;\n+\t}\n \n-\treturn 0;\n+\tmemcpy(send_buf, send_msg, msg_size);\n+\terr = idpf_send_mb_msg(adapter, \u0026xn_params, send_buf, msg_size);\n+\tif (err)\n+\t\treturn err;\n+\n+\tif (xn_params.recv_mem.iov_len \u003e *recv_len) {\n+\t\terr = -EINVAL;\n+\t\tgoto rel_buf;\n+\t}\n+\n+\t*recv_len = xn_params.recv_mem.iov_len;\n+\tmemcpy(recv_msg, xn_params.recv_mem.iov_base, *recv_len);\n+rel_buf:\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\treturn err;\n }\n EXPORT_SYMBOL_GPL(idpf_idc_rdma_vc_send_sync);\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h\nindex 9b1c9c86f6eac..5d27805ff40fb 100644\n--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h\n+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h\n@@ -4,89 +4,9 @@\n #ifndef _IDPF_VIRTCHNL_H_\n #define _IDPF_VIRTCHNL_H_\n \n-#include \"virtchnl2.h\"\n+#include \u003clinux/net/intel/virtchnl2.h\u003e\n \n #define IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC\t(60 * 1000)\n-#define IDPF_VC_XN_IDX_M\t\tGENMASK(7, 0)\n-#define IDPF_VC_XN_SALT_M\t\tGENMASK(15, 8)\n-#define IDPF_VC_XN_RING_LEN\t\tU8_MAX\n-\n-/**\n- * enum idpf_vc_xn_state - Virtchnl transaction status\n- * @IDPF_VC_XN_IDLE: not expecting a reply, ready to be used\n- * @IDPF_VC_XN_WAITING: expecting a reply, not yet received\n- * @IDPF_VC_XN_COMPLETED_SUCCESS: a reply was expected and received, buffer\n- *\t\t\t\t updated\n- * @IDPF_VC_XN_COMPLETED_FAILED: a reply was expected and received, but there\n- *\t\t\t\t was an error, buffer not updated\n- * @IDPF_VC_XN_SHUTDOWN: transaction object cannot be used, VC torn down\n- * @IDPF_VC_XN_ASYNC: transaction sent asynchronously and doesn't have the\n- *\t\t return context; a callback may be provided to handle\n- *\t\t return\n- */\n-enum idpf_vc_xn_state {\n-\tIDPF_VC_XN_IDLE = 1,\n-\tIDPF_VC_XN_WAITING,\n-\tIDPF_VC_XN_COMPLETED_SUCCESS,\n-\tIDPF_VC_XN_COMPLETED_FAILED,\n-\tIDPF_VC_XN_SHUTDOWN,\n-\tIDPF_VC_XN_ASYNC,\n-};\n-\n-struct idpf_vc_xn;\n-/* Callback for asynchronous messages */\n-typedef int (*async_vc_cb) (struct idpf_adapter *, struct idpf_vc_xn *,\n-\t\t\t const struct idpf_ctlq_msg *);\n-\n-/**\n- * struct idpf_vc_xn - Data structure representing virtchnl transactions\n- * @completed: virtchnl event loop uses that to signal when a reply is\n- *\t available, uses kernel completion API\n- * @lock: protects the transaction state fields below\n- * @state: virtchnl event loop stores the data below, protected by @lock\n- * @reply_sz: Original size of reply, may be \u003e reply_buf.iov_len; it will be\n- *\t truncated on its way to the receiver thread according to\n- *\t reply_buf.iov_len.\n- * @reply: Reference to the buffer(s) where the reply data should be written\n- *\t to. May be 0-length (then NULL address permitted) if the reply data\n- *\t should be ignored.\n- * @async_handler: if sent asynchronously, a callback can be provided to handle\n- *\t\t the reply when it's received\n- * @vc_op: corresponding opcode sent with this transaction\n- * @idx: index used as retrieval on reply receive, used for cookie\n- * @salt: changed every message to make unique, used for cookie\n- */\n-struct idpf_vc_xn {\n-\tstruct completion completed;\n-\tspinlock_t lock;\n-\tenum idpf_vc_xn_state state;\n-\tsize_t reply_sz;\n-\tstruct kvec reply;\n-\tasync_vc_cb async_handler;\n-\tu32 vc_op;\n-\tu8 idx;\n-\tu8 salt;\n-};\n-\n-/**\n- * struct idpf_vc_xn_params - Parameters for executing transaction\n- * @send_buf: kvec for send buffer\n- * @recv_buf: kvec for recv buffer, may be NULL, must then have zero length\n- * @timeout_ms: timeout to wait for reply\n- * @async: send message asynchronously, will not wait on completion\n- * @async_handler: If sent asynchronously, optional callback handler. The user\n- *\t\t must be careful when using async handlers as the memory for\n- *\t\t the recv_buf _cannot_ be on stack if this is async.\n- * @vc_op: virtchnl op to send\n- */\n-struct idpf_vc_xn_params {\n-\tstruct kvec send_buf;\n-\tstruct kvec recv_buf;\n-\tint timeout_ms;\n-\tbool async;\n-\tasync_vc_cb async_handler;\n-\tu32 vc_op;\n-};\n \n struct idpf_adapter;\n struct idpf_netdev_priv;\n@@ -96,8 +16,6 @@ struct idpf_vport_max_q;\n struct idpf_vport_config;\n struct idpf_vport_user_config_data;\n \n-ssize_t idpf_vc_xn_exec(struct idpf_adapter *adapter,\n-\t\t\tconst struct idpf_vc_xn_params *params);\n int idpf_init_dflt_mbx(struct idpf_adapter *adapter);\n void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter);\n int idpf_vc_core_init(struct idpf_adapter *adapter);\n@@ -124,9 +42,35 @@ bool idpf_sideband_action_ena(struct idpf_vport *vport,\n \t\t\t struct ethtool_rx_flow_spec *fsp);\n unsigned int idpf_fsteer_max_rules(struct idpf_vport *vport);\n \n-int idpf_recv_mb_msg(struct idpf_adapter *adapter, struct idpf_ctlq_info *arq);\n-int idpf_send_mb_msg(struct idpf_adapter *adapter, struct idpf_ctlq_info *asq,\n-\t\t u32 op, u16 msg_size, u8 *msg, u16 cookie);\n+void idpf_recv_event_msg(struct libie_ctlq_ctx *ctx,\n+\t\t\t struct libie_ctlq_msg *ctlq_msg);\n+int idpf_send_mb_msg(struct idpf_adapter *adapter,\n+\t\t struct libie_ctlq_xn_send_params *xn_params,\n+\t\t void *send_buf, size_t send_buf_size);\n+int idpf_send_mb_msg_kfree(struct idpf_adapter *adapter,\n+\t\t\t struct libie_ctlq_xn_send_params *xn_params,\n+\t\t\t void *send_buf, size_t send_buf_size);\n+void idpf_send_vf_reset_msg(struct idpf_adapter *adapter);\n+bool idpf_mmio_region_non_static(struct libie_mmio_info *mmio_info,\n+\t\t\t\t struct libie_pci_mmio_region *reg);\n+\n+/**\n+ * idpf_send_mb_msg_stack - send a mailbox message from an on-stack buffer\n+ * @adapter: driver specific private structure\n+ * @xn_params: Xn send parameters to fill\n+ * @ptr: pointer to the on-stack message object to send\n+ *\n+ * Send size is deduced based on the pointer type.\n+ *\n+ * Return: %0 on success, -%errno on failure.\n+ */\n+#define idpf_send_mb_msg_stack(adapter, xn_params, ptr)\t\t\t\\\n+({\t\t\t\t\t\t\t\t\t\\\n+\ttypeof(ptr) __ptr = (ptr);\t\t\t\t\t\\\n+\t\t\t\t\t\t\t\t\t\\\n+\tstatic_assert(sizeof(*__ptr) \u003c= LIBIE_CP_TX_COPYBREAK);\t\t\\\n+\tidpf_send_mb_msg(adapter, xn_params, __ptr, sizeof(*__ptr));\t\\\n+})\n \n struct idpf_queue_ptr {\n \tenum virtchnl2_queue_type\ttype;\n@@ -208,13 +152,10 @@ int idpf_send_ena_dis_loopback_msg(struct idpf_adapter *adapter, u32 vport_id,\n int idpf_send_get_stats_msg(struct idpf_netdev_priv *np,\n \t\t\t struct idpf_port_stats *port_stats);\n int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs);\n-int idpf_send_get_set_rss_key_msg(struct idpf_adapter *adapter,\n-\t\t\t\t struct idpf_rss_data *rss_data,\n-\t\t\t\t u32 vport_id, bool get);\n-int idpf_send_get_set_rss_lut_msg(struct idpf_adapter *adapter,\n-\t\t\t\t struct idpf_rss_data *rss_data,\n-\t\t\t\t u32 vport_id, bool get);\n-void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr);\n+int idpf_send_set_rss_key_msg(struct idpf_adapter *adapter,\n+\t\t\t struct idpf_rss_data *rss_data, u32 vport_id);\n+int idpf_send_set_rss_lut_msg(struct idpf_adapter *adapter,\n+\t\t\t struct idpf_rss_data *rss_data, u32 vport_id);\n int idpf_idc_rdma_vc_send_sync(struct iidc_rdma_core_dev_info *cdev_info,\n \t\t\t u8 *send_msg, u16 msg_size,\n \t\t\t u8 *recv_msg, u16 *recv_len);\ndiff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c\nindex d9bcc3f61c658..14dba40a993f7 100644\n--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c\n+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c\n@@ -15,7 +15,6 @@\n */\n int idpf_ptp_get_caps(struct idpf_adapter *adapter)\n {\n-\tstruct virtchnl2_ptp_get_caps *recv_ptp_caps_msg __free(kfree) = NULL;\n \tstruct virtchnl2_ptp_get_caps send_ptp_caps_msg = {\n \t\t.caps = cpu_to_le32(VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME |\n \t\t\t\t VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME_MB |\n@@ -24,33 +23,33 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)\n \t\t\t\t VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK_MB |\n \t\t\t\t VIRTCHNL2_CAP_PTP_TX_TSTAMPS_MB)\n \t};\n-\tstruct idpf_vc_xn_params xn_params = {\n-\t\t.vc_op = VIRTCHNL2_OP_PTP_GET_CAPS,\n-\t\t.send_buf.iov_base = \u0026send_ptp_caps_msg,\n-\t\t.send_buf.iov_len = sizeof(send_ptp_caps_msg),\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.chnl_opcode = VIRTCHNL2_OP_PTP_GET_CAPS,\n \t\t.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n \t};\n \tstruct virtchnl2_ptp_cross_time_reg_offsets cross_tstamp_offsets;\n+\tstruct libie_mmio_info *mmio = \u0026adapter-\u003ectlq_ctx.mmio_info;\n \tstruct virtchnl2_ptp_clk_adj_reg_offsets clk_adj_offsets;\n \tstruct virtchnl2_ptp_clk_reg_offsets clock_offsets;\n+\tstruct virtchnl2_ptp_get_caps *recv_ptp_caps_msg;\n \tstruct idpf_ptp_secondary_mbx *scnd_mbx;\n \tstruct idpf_ptp *ptp = adapter-\u003eptp;\n \tenum idpf_ptp_access access_type;\n \tu32 temp_offset;\n-\tint reply_sz;\n+\tsize_t reply_sz;\n+\tint err;\n \n-\trecv_ptp_caps_msg = kzalloc_obj(struct virtchnl2_ptp_get_caps);\n-\tif (!recv_ptp_caps_msg)\n-\t\treturn -ENOMEM;\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params, \u0026send_ptp_caps_msg);\n+\tif (err)\n+\t\treturn err;\n \n-\txn_params.recv_buf.iov_base = recv_ptp_caps_msg;\n-\txn_params.recv_buf.iov_len = sizeof(*recv_ptp_caps_msg);\n+\treply_sz = xn_params.recv_mem.iov_len;\n+\tif (reply_sz != sizeof(*recv_ptp_caps_msg)) {\n+\t\terr = -EIO;\n+\t\tgoto free_resp;\n+\t}\n \n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n-\telse if (reply_sz != sizeof(*recv_ptp_caps_msg))\n-\t\treturn -EIO;\n+\trecv_ptp_caps_msg = xn_params.recv_mem.iov_base;\n \n \tptp-\u003ecaps = le32_to_cpu(recv_ptp_caps_msg-\u003ecaps);\n \tptp-\u003ebase_incval = le64_to_cpu(recv_ptp_caps_msg-\u003ebase_incval);\n@@ -76,19 +75,20 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)\n \tclock_offsets = recv_ptp_caps_msg-\u003eclk_offsets;\n \n \ttemp_offset = le32_to_cpu(clock_offsets.dev_clk_ns_l);\n-\tptp-\u003edev_clk_regs.dev_clk_ns_l = idpf_get_reg_addr(adapter,\n-\t\t\t\t\t\t\t temp_offset);\n+\tptp-\u003edev_clk_regs.dev_clk_ns_l =\n+\t\tlibie_pci_get_mmio_addr(mmio, temp_offset);\n \ttemp_offset = le32_to_cpu(clock_offsets.dev_clk_ns_h);\n-\tptp-\u003edev_clk_regs.dev_clk_ns_h = idpf_get_reg_addr(adapter,\n-\t\t\t\t\t\t\t temp_offset);\n+\tptp-\u003edev_clk_regs.dev_clk_ns_h =\n+\t\tlibie_pci_get_mmio_addr(mmio, temp_offset);\n \ttemp_offset = le32_to_cpu(clock_offsets.phy_clk_ns_l);\n-\tptp-\u003edev_clk_regs.phy_clk_ns_l = idpf_get_reg_addr(adapter,\n-\t\t\t\t\t\t\t temp_offset);\n+\tptp-\u003edev_clk_regs.phy_clk_ns_l =\n+\t\tlibie_pci_get_mmio_addr(mmio, temp_offset);\n \ttemp_offset = le32_to_cpu(clock_offsets.phy_clk_ns_h);\n-\tptp-\u003edev_clk_regs.phy_clk_ns_h = idpf_get_reg_addr(adapter,\n-\t\t\t\t\t\t\t temp_offset);\n+\tptp-\u003edev_clk_regs.phy_clk_ns_h =\n+\t\tlibie_pci_get_mmio_addr(mmio, temp_offset);\n \ttemp_offset = le32_to_cpu(clock_offsets.cmd_sync_trigger);\n-\tptp-\u003edev_clk_regs.cmd_sync = idpf_get_reg_addr(adapter, temp_offset);\n+\tptp-\u003edev_clk_regs.cmd_sync =\n+\t\tlibie_pci_get_mmio_addr(mmio, temp_offset);\n \n cross_tstamp:\n \taccess_type = ptp-\u003eget_cross_tstamp_access;\n@@ -98,48 +98,54 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)\n \tcross_tstamp_offsets = recv_ptp_caps_msg-\u003ecross_time_offsets;\n \n \ttemp_offset = le32_to_cpu(cross_tstamp_offsets.sys_time_ns_l);\n-\tptp-\u003edev_clk_regs.sys_time_ns_l = idpf_get_reg_addr(adapter,\n-\t\t\t\t\t\t\t temp_offset);\n+\tptp-\u003edev_clk_regs.sys_time_ns_l =\n+\t\tlibie_pci_get_mmio_addr(mmio, temp_offset);\n \ttemp_offset = le32_to_cpu(cross_tstamp_offsets.sys_time_ns_h);\n-\tptp-\u003edev_clk_regs.sys_time_ns_h = idpf_get_reg_addr(adapter,\n-\t\t\t\t\t\t\t temp_offset);\n+\tptp-\u003edev_clk_regs.sys_time_ns_h =\n+\t\tlibie_pci_get_mmio_addr(mmio, temp_offset);\n \ttemp_offset = le32_to_cpu(cross_tstamp_offsets.cmd_sync_trigger);\n-\tptp-\u003edev_clk_regs.cmd_sync = idpf_get_reg_addr(adapter, temp_offset);\n+\tptp-\u003edev_clk_regs.cmd_sync =\n+\t\tlibie_pci_get_mmio_addr(mmio, temp_offset);\n \n discipline_clock:\n \taccess_type = ptp-\u003eadj_dev_clk_time_access;\n \tif (access_type != IDPF_PTP_DIRECT)\n-\t\treturn 0;\n+\t\tgoto free_resp;\n \n \tclk_adj_offsets = recv_ptp_caps_msg-\u003eclk_adj_offsets;\n \n \t/* Device clock offsets */\n \ttemp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_cmd_type);\n-\tptp-\u003edev_clk_regs.cmd = idpf_get_reg_addr(adapter, temp_offset);\n+\tptp-\u003edev_clk_regs.cmd = libie_pci_get_mmio_addr(mmio, temp_offset);\n \ttemp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_incval_l);\n-\tptp-\u003edev_clk_regs.incval_l = idpf_get_reg_addr(adapter, temp_offset);\n+\tptp-\u003edev_clk_regs.incval_l = libie_pci_get_mmio_addr(mmio, temp_offset);\n \ttemp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_incval_h);\n-\tptp-\u003edev_clk_regs.incval_h = idpf_get_reg_addr(adapter, temp_offset);\n+\tptp-\u003edev_clk_regs.incval_h = libie_pci_get_mmio_addr(mmio, temp_offset);\n \ttemp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_shadj_l);\n-\tptp-\u003edev_clk_regs.shadj_l = idpf_get_reg_addr(adapter, temp_offset);\n+\tptp-\u003edev_clk_regs.shadj_l = libie_pci_get_mmio_addr(mmio, temp_offset);\n \ttemp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_shadj_h);\n-\tptp-\u003edev_clk_regs.shadj_h = idpf_get_reg_addr(adapter, temp_offset);\n+\tptp-\u003edev_clk_regs.shadj_h = libie_pci_get_mmio_addr(mmio, temp_offset);\n \n \t/* PHY clock offsets */\n \ttemp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_cmd_type);\n-\tptp-\u003edev_clk_regs.phy_cmd = idpf_get_reg_addr(adapter, temp_offset);\n+\tptp-\u003edev_clk_regs.phy_cmd =\n+\t\tlibie_pci_get_mmio_addr(mmio, temp_offset);\n \ttemp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_incval_l);\n-\tptp-\u003edev_clk_regs.phy_incval_l = idpf_get_reg_addr(adapter,\n-\t\t\t\t\t\t\t temp_offset);\n+\tptp-\u003edev_clk_regs.phy_incval_l =\n+\t\tlibie_pci_get_mmio_addr(mmio, temp_offset);\n \ttemp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_incval_h);\n-\tptp-\u003edev_clk_regs.phy_incval_h = idpf_get_reg_addr(adapter,\n-\t\t\t\t\t\t\t temp_offset);\n+\tptp-\u003edev_clk_regs.phy_incval_h =\n+\t\tlibie_pci_get_mmio_addr(mmio, temp_offset);\n \ttemp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_shadj_l);\n-\tptp-\u003edev_clk_regs.phy_shadj_l = idpf_get_reg_addr(adapter, temp_offset);\n+\tptp-\u003edev_clk_regs.phy_shadj_l =\n+\t\tlibie_pci_get_mmio_addr(mmio, temp_offset);\n \ttemp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_shadj_h);\n-\tptp-\u003edev_clk_regs.phy_shadj_h = idpf_get_reg_addr(adapter, temp_offset);\n+\tptp-\u003edev_clk_regs.phy_shadj_h =\n+\t\tlibie_pci_get_mmio_addr(mmio, temp_offset);\n \n-\treturn 0;\n+free_resp:\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\treturn err;\n }\n \n /**\n@@ -154,28 +160,34 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)\n int idpf_ptp_get_dev_clk_time(struct idpf_adapter *adapter,\n \t\t\t struct idpf_ptp_dev_timers *dev_clk_time)\n {\n+\tstruct virtchnl2_ptp_get_dev_clk_time *get_dev_clk_time_resp;\n \tstruct virtchnl2_ptp_get_dev_clk_time get_dev_clk_time_msg;\n-\tstruct idpf_vc_xn_params xn_params = {\n-\t\t.vc_op = VIRTCHNL2_OP_PTP_GET_DEV_CLK_TIME,\n-\t\t.send_buf.iov_base = \u0026get_dev_clk_time_msg,\n-\t\t.send_buf.iov_len = sizeof(get_dev_clk_time_msg),\n-\t\t.recv_buf.iov_base = \u0026get_dev_clk_time_msg,\n-\t\t.recv_buf.iov_len = sizeof(get_dev_clk_time_msg),\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.chnl_opcode = VIRTCHNL2_OP_PTP_GET_DEV_CLK_TIME,\n \t\t.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n \t};\n-\tint reply_sz;\n+\tsize_t reply_sz;\n \tu64 dev_time;\n+\tint err;\n \n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n-\tif (reply_sz != sizeof(get_dev_clk_time_msg))\n-\t\treturn -EIO;\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params,\n+\t\t\t\t \u0026get_dev_clk_time_msg);\n+\tif (err)\n+\t\treturn err;\n \n-\tdev_time = le64_to_cpu(get_dev_clk_time_msg.dev_time_ns);\n+\treply_sz = xn_params.recv_mem.iov_len;\n+\tif (reply_sz != sizeof(*get_dev_clk_time_resp)) {\n+\t\terr = -EIO;\n+\t\tgoto free_resp;\n+\t}\n+\n+\tget_dev_clk_time_resp = xn_params.recv_mem.iov_base;\n+\tdev_time = le64_to_cpu(get_dev_clk_time_resp-\u003edev_time_ns);\n \tdev_clk_time-\u003edev_clk_time_ns = dev_time;\n \n-\treturn 0;\n+free_resp:\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\treturn err;\n }\n \n /**\n@@ -191,27 +203,29 @@ int idpf_ptp_get_dev_clk_time(struct idpf_adapter *adapter,\n int idpf_ptp_get_cross_time(struct idpf_adapter *adapter,\n \t\t\t struct idpf_ptp_dev_timers *cross_time)\n {\n-\tstruct virtchnl2_ptp_get_cross_time cross_time_msg;\n-\tstruct idpf_vc_xn_params xn_params = {\n-\t\t.vc_op = VIRTCHNL2_OP_PTP_GET_CROSS_TIME,\n-\t\t.send_buf.iov_base = \u0026cross_time_msg,\n-\t\t.send_buf.iov_len = sizeof(cross_time_msg),\n-\t\t.recv_buf.iov_base = \u0026cross_time_msg,\n-\t\t.recv_buf.iov_len = sizeof(cross_time_msg),\n+\tstruct virtchnl2_ptp_get_cross_time cross_time_send, *cross_time_recv;\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.chnl_opcode = VIRTCHNL2_OP_PTP_GET_CROSS_TIME,\n \t\t.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n \t};\n-\tint reply_sz;\n+\tint err = 0;\n \n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n-\tif (reply_sz != sizeof(cross_time_msg))\n-\t\treturn -EIO;\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params, \u0026cross_time_send);\n+\tif (err)\n+\t\treturn err;\n \n-\tcross_time-\u003edev_clk_time_ns = le64_to_cpu(cross_time_msg.dev_time_ns);\n-\tcross_time-\u003esys_time_ns = le64_to_cpu(cross_time_msg.sys_time_ns);\n+\tif (xn_params.recv_mem.iov_len != sizeof(*cross_time_recv)) {\n+\t\terr = -EIO;\n+\t\tgoto free_resp;\n+\t}\n \n-\treturn 0;\n+\tcross_time_recv = xn_params.recv_mem.iov_base;\n+\tcross_time-\u003edev_clk_time_ns = le64_to_cpu(cross_time_recv-\u003edev_time_ns);\n+\tcross_time-\u003esys_time_ns = le64_to_cpu(cross_time_recv-\u003esys_time_ns);\n+\n+free_resp:\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n+\treturn err;\n }\n \n /**\n@@ -228,23 +242,18 @@ int idpf_ptp_set_dev_clk_time(struct idpf_adapter *adapter, u64 time)\n \tstruct virtchnl2_ptp_set_dev_clk_time set_dev_clk_time_msg = {\n \t\t.dev_time_ns = cpu_to_le64(time),\n \t};\n-\tstruct idpf_vc_xn_params xn_params = {\n-\t\t.vc_op = VIRTCHNL2_OP_PTP_SET_DEV_CLK_TIME,\n-\t\t.send_buf.iov_base = \u0026set_dev_clk_time_msg,\n-\t\t.send_buf.iov_len = sizeof(set_dev_clk_time_msg),\n-\t\t.recv_buf.iov_base = \u0026set_dev_clk_time_msg,\n-\t\t.recv_buf.iov_len = sizeof(set_dev_clk_time_msg),\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.chnl_opcode = VIRTCHNL2_OP_PTP_SET_DEV_CLK_TIME,\n \t\t.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n \t};\n-\tint reply_sz;\n+\tint err;\n \n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n-\tif (reply_sz != sizeof(set_dev_clk_time_msg))\n-\t\treturn -EIO;\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params,\n+\t\t\t\t \u0026set_dev_clk_time_msg);\n+\tif (!err)\n+\t\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n \n-\treturn 0;\n+\treturn err;\n }\n \n /**\n@@ -261,23 +270,18 @@ int idpf_ptp_adj_dev_clk_time(struct idpf_adapter *adapter, s64 delta)\n \tstruct virtchnl2_ptp_adj_dev_clk_time adj_dev_clk_time_msg = {\n \t\t.delta = cpu_to_le64(delta),\n \t};\n-\tstruct idpf_vc_xn_params xn_params = {\n-\t\t.vc_op = VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_TIME,\n-\t\t.send_buf.iov_base = \u0026adj_dev_clk_time_msg,\n-\t\t.send_buf.iov_len = sizeof(adj_dev_clk_time_msg),\n-\t\t.recv_buf.iov_base = \u0026adj_dev_clk_time_msg,\n-\t\t.recv_buf.iov_len = sizeof(adj_dev_clk_time_msg),\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.chnl_opcode = VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_TIME,\n \t\t.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n \t};\n-\tint reply_sz;\n+\tint err;\n \n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n-\tif (reply_sz != sizeof(adj_dev_clk_time_msg))\n-\t\treturn -EIO;\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params,\n+\t\t\t\t \u0026adj_dev_clk_time_msg);\n+\tif (!err)\n+\t\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n \n-\treturn 0;\n+\treturn err;\n }\n \n /**\n@@ -295,23 +299,18 @@ int idpf_ptp_adj_dev_clk_fine(struct idpf_adapter *adapter, u64 incval)\n \tstruct virtchnl2_ptp_adj_dev_clk_fine adj_dev_clk_fine_msg = {\n \t\t.incval = cpu_to_le64(incval),\n \t};\n-\tstruct idpf_vc_xn_params xn_params = {\n-\t\t.vc_op = VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_FINE,\n-\t\t.send_buf.iov_base = \u0026adj_dev_clk_fine_msg,\n-\t\t.send_buf.iov_len = sizeof(adj_dev_clk_fine_msg),\n-\t\t.recv_buf.iov_base = \u0026adj_dev_clk_fine_msg,\n-\t\t.recv_buf.iov_len = sizeof(adj_dev_clk_fine_msg),\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.chnl_opcode = VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_FINE,\n \t\t.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n \t};\n-\tint reply_sz;\n+\tint err;\n \n-\treply_sz = idpf_vc_xn_exec(adapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0)\n-\t\treturn reply_sz;\n-\tif (reply_sz != sizeof(adj_dev_clk_fine_msg))\n-\t\treturn -EIO;\n+\terr = idpf_send_mb_msg_stack(adapter, \u0026xn_params,\n+\t\t\t\t \u0026adj_dev_clk_fine_msg);\n+\tif (!err)\n+\t\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n \n-\treturn 0;\n+\treturn err;\n }\n \n /**\n@@ -330,18 +329,16 @@ int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport)\n \tstruct virtchnl2_ptp_tx_tstamp_latch_caps tx_tstamp_latch_caps;\n \tstruct idpf_ptp_vport_tx_tstamp_caps *tstamp_caps;\n \tstruct idpf_ptp_tx_tstamp *ptp_tx_tstamp, *tmp;\n-\tstruct idpf_vc_xn_params xn_params = {\n-\t\t.vc_op = VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP_CAPS,\n-\t\t.send_buf.iov_base = \u0026send_tx_tstamp_caps,\n-\t\t.send_buf.iov_len = sizeof(send_tx_tstamp_caps),\n-\t\t.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN,\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.chnl_opcode = VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP_CAPS,\n \t\t.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n \t};\n \tenum idpf_ptp_access tstamp_access, get_dev_clk_access;\n \tstruct idpf_ptp *ptp = vport-\u003eadapter-\u003eptp;\n \tstruct list_head *head;\n-\tint err = 0, reply_sz;\n+\tsize_t reply_sz;\n \tu16 num_latches;\n+\tint err = 0;\n \tu32 size;\n \n \tif (!ptp)\n@@ -353,19 +350,19 @@ int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport)\n \t get_dev_clk_access == IDPF_PTP_NONE)\n \t\treturn -EOPNOTSUPP;\n \n-\trcv_tx_tstamp_caps = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);\n-\tif (!rcv_tx_tstamp_caps)\n-\t\treturn -ENOMEM;\n-\n \tsend_tx_tstamp_caps.vport_id = cpu_to_le32(vport-\u003evport_id);\n-\txn_params.recv_buf.iov_base = rcv_tx_tstamp_caps;\n \n-\treply_sz = idpf_vc_xn_exec(vport-\u003eadapter, \u0026xn_params);\n-\tif (reply_sz \u003c 0) {\n-\t\terr = reply_sz;\n+\terr = idpf_send_mb_msg_stack(vport-\u003eadapter, \u0026xn_params,\n+\t\t\t\t \u0026send_tx_tstamp_caps);\n+\tif (err)\n+\t\treturn err;\n+\n+\trcv_tx_tstamp_caps = xn_params.recv_mem.iov_base;\n+\treply_sz = xn_params.recv_mem.iov_len;\n+\tif (reply_sz \u003c sizeof(*rcv_tx_tstamp_caps)) {\n+\t\terr = -EIO;\n \t\tgoto get_tstamp_caps_out;\n \t}\n-\n \tnum_latches = le16_to_cpu(rcv_tx_tstamp_caps-\u003enum_latches);\n \tsize = struct_size(rcv_tx_tstamp_caps, tstamp_latches, num_latches);\n \tif (reply_sz != size) {\n@@ -420,7 +417,7 @@ int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport)\n \t}\n \n \tvport-\u003etx_tstamp_caps = tstamp_caps;\n-\tkfree(rcv_tx_tstamp_caps);\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n \n \treturn 0;\n \n@@ -433,7 +430,7 @@ int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport)\n \n \tkfree(tstamp_caps);\n get_tstamp_caps_out:\n-\tkfree(rcv_tx_tstamp_caps);\n+\tlibie_ctlq_release_rx_buf(\u0026xn_params.recv_mem);\n \n \treturn err;\n }\n@@ -530,9 +527,9 @@ idpf_ptp_get_tstamp_value(struct idpf_vport *vport,\n \n /**\n * idpf_ptp_get_tx_tstamp_async_handler - Async callback for getting Tx tstamps\n- * @adapter: Driver specific private structure\n- * @xn: transaction for message\n- * @ctlq_msg: received message\n+ * @ctx: adapter pointer\n+ * @mem: address and size of the response\n+ * @status: return value of the request\n *\n * Read the tstamps Tx tstamp values from a received message and put them\n * directly to the skb. The number of timestamps to read is specified by\n@@ -540,22 +537,26 @@ idpf_ptp_get_tstamp_value(struct idpf_vport *vport,\n *\n * Return: 0 on success, -errno otherwise.\n */\n-static int\n-idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,\n-\t\t\t\t struct idpf_vc_xn *xn,\n-\t\t\t\t const struct idpf_ctlq_msg *ctlq_msg)\n+static void\n+idpf_ptp_get_tx_tstamp_async_handler(void *ctx, struct kvec *mem, int status)\n {\n \tstruct virtchnl2_ptp_get_vport_tx_tstamp_latches *recv_tx_tstamp_msg;\n \tstruct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps;\n \tstruct virtchnl2_ptp_tx_tstamp_latch tstamp_latch;\n \tstruct idpf_ptp_tx_tstamp *tx_tstamp, *tmp;\n \tstruct idpf_vport *tstamp_vport = NULL;\n+\tstruct idpf_adapter *adapter = ctx;\n \tstruct list_head *head;\n \tu16 num_latches;\n \tu32 vport_id;\n-\tint err = 0;\n \n-\trecv_tx_tstamp_msg = ctlq_msg-\u003ectx.indirect.payload-\u003eva;\n+\tif (status)\n+\t\treturn;\n+\n+\trecv_tx_tstamp_msg = mem-\u003eiov_base;\n+\tif (mem-\u003eiov_len \u003c sizeof(*recv_tx_tstamp_msg))\n+\t\treturn;\n+\n \tvport_id = le32_to_cpu(recv_tx_tstamp_msg-\u003evport_id);\n \n \tidpf_for_each_vport(adapter, vport) {\n@@ -569,10 +570,13 @@ idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,\n \t}\n \n \tif (!tstamp_vport || !tstamp_vport-\u003etx_tstamp_caps)\n-\t\treturn -EINVAL;\n+\t\treturn;\n \n \ttx_tstamp_caps = tstamp_vport-\u003etx_tstamp_caps;\n \tnum_latches = le16_to_cpu(recv_tx_tstamp_msg-\u003enum_latches);\n+\tif (mem-\u003eiov_len \u003c struct_size(recv_tx_tstamp_msg, tstamp_latches,\n+\t\t\t\t num_latches))\n+\t\treturn;\n \n \tspin_lock_bh(\u0026tx_tstamp_caps-\u003elatches_lock);\n \thead = \u0026tx_tstamp_caps-\u003elatches_in_use;\n@@ -583,13 +587,13 @@ idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,\n \t\tif (!tstamp_latch.valid)\n \t\t\tcontinue;\n \n-\t\tif (list_empty(head)) {\n-\t\t\terr = -ENOBUFS;\n+\t\tif (list_empty(head))\n \t\t\tgoto unlock;\n-\t\t}\n \n \t\tlist_for_each_entry_safe(tx_tstamp, tmp, head, list_member) {\n \t\t\tif (tstamp_latch.index == tx_tstamp-\u003eidx) {\n+\t\t\t\tint err;\n+\n \t\t\t\tlist_del(\u0026tx_tstamp-\u003elist_member);\n \t\t\t\terr = idpf_ptp_get_tstamp_value(tstamp_vport,\n \t\t\t\t\t\t\t\t\u0026tstamp_latch,\n@@ -604,8 +608,6 @@ idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,\n \n unlock:\n \tspin_unlock_bh(\u0026tx_tstamp_caps-\u003elatches_lock);\n-\n-\treturn err;\n }\n \n /**\n@@ -621,15 +623,15 @@ int idpf_ptp_get_tx_tstamp(struct idpf_vport *vport)\n {\n \tstruct virtchnl2_ptp_get_vport_tx_tstamp_latches *send_tx_tstamp_msg;\n \tstruct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps;\n-\tstruct idpf_vc_xn_params xn_params = {\n-\t\t.vc_op = VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP,\n+\tstruct libie_ctlq_xn_send_params xn_params = {\n+\t\t.chnl_opcode = VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP,\n \t\t.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,\n-\t\t.async = true,\n-\t\t.async_handler = idpf_ptp_get_tx_tstamp_async_handler,\n+\t\t.resp_cb = idpf_ptp_get_tx_tstamp_async_handler,\n+\t\t.send_ctx = vport-\u003eadapter,\n \t};\n \tstruct idpf_ptp_tx_tstamp *ptp_tx_tstamp;\n-\tint reply_sz, size, msg_size;\n \tstruct list_head *head;\n+\tint size, msg_size;\n \tbool state_upd;\n \tu16 id = 0;\n \n@@ -662,11 +664,7 @@ int idpf_ptp_get_tx_tstamp(struct idpf_vport *vport)\n \tmsg_size = struct_size(send_tx_tstamp_msg, tstamp_latches, id);\n \tsend_tx_tstamp_msg-\u003evport_id = cpu_to_le32(vport-\u003evport_id);\n \tsend_tx_tstamp_msg-\u003enum_latches = cpu_to_le16(id);\n-\txn_params.send_buf.iov_base = send_tx_tstamp_msg;\n-\txn_params.send_buf.iov_len = msg_size;\n-\n-\treply_sz = idpf_vc_xn_exec(vport-\u003eadapter, \u0026xn_params);\n-\tkfree(send_tx_tstamp_msg);\n \n-\treturn min(reply_sz, 0);\n+\treturn idpf_send_mb_msg_kfree(vport-\u003eadapter, \u0026xn_params,\n+\t\t\t\t send_tx_tstamp_msg, msg_size);\n }\ndiff --git a/drivers/net/ethernet/intel/ixd/Kconfig b/drivers/net/ethernet/intel/ixd/Kconfig\nnew file mode 100644\nindex 0000000000000..0a48b3bb7bc26\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ixd/Kconfig\n@@ -0,0 +1,14 @@\n+# SPDX-License-Identifier: GPL-2.0-only\n+# Copyright (C) 2025 Intel Corporation\n+\n+config IXD\n+\ttristate \"Intel(R) Control Plane Function Support\"\n+\tdepends on PCI_MSI\n+\tselect LIBIE_CP\n+\tselect LIBIE_PCI\n+\tselect NET_DEVLINK\n+\thelp\n+\t This driver supports Intel(R) Control Plane PCI Function\n+\t of Intel E2100 and later IPUs and FNICs.\n+\t It facilitates a centralized control over multiple IDPF PFs/VFs/SFs\n+\t exposed by the same card.\ndiff --git a/drivers/net/ethernet/intel/ixd/Makefile b/drivers/net/ethernet/intel/ixd/Makefile\nnew file mode 100644\nindex 0000000000000..03760a2580b9b\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ixd/Makefile\n@@ -0,0 +1,13 @@\n+# SPDX-License-Identifier: GPL-2.0-only\n+# Copyright (C) 2025 Intel Corporation\n+\n+# Intel(R) Control Plane Function Linux Driver\n+\n+obj-$(CONFIG_IXD) += ixd.o\n+\n+ixd-y := ixd_main.o\n+ixd-y += ixd_ctlq.o\n+ixd-y += ixd_dev.o\n+ixd-y += ixd_devlink.o\n+ixd-y += ixd_lib.o\n+ixd-y += ixd_virtchnl.o\ndiff --git a/drivers/net/ethernet/intel/ixd/ixd.h b/drivers/net/ethernet/intel/ixd/ixd.h\nnew file mode 100644\nindex 0000000000000..2a09ccba13d58\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ixd/ixd.h\n@@ -0,0 +1,67 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+/* Copyright (C) 2025 Intel Corporation */\n+\n+#ifndef _IXD_H_\n+#define _IXD_H_\n+\n+#include \u003clinux/net/intel/libie/controlq.h\u003e\n+\n+#define IXD_INIT_TASK_DELAY_JIFFIES\tmsecs_to_jiffies(500)\n+\n+/**\n+ * struct ixd_adapter - Data structure representing a CPF\n+ * @cp_ctx: Control plane communication context\n+ * @init_task: Delayed initialization after reset\n+ * @init_task.init_work: Delayed initialization work\n+ * @init_task.reset_retries: How many times to check, whether reset is completed\n+ * @init_task.vc_retries: Number of retries to establish mailbox communication\n+ * @init_task.success: init_work completion status\n+ * @mbx_task: Control queue Rx handling\n+ * @xnm: virtchnl transaction manager\n+ * @asq: Send control queue info\n+ * @arq: Receive control queue info\n+ * @vc_ver: Negotiated virtchnl version\n+ * @vc_ver.major: Negotiated major virtchnl version\n+ * @vc_ver.minor: Negotiated minor virtchnl version\n+ * @caps: Negotiated virtchnl capabilities\n+ */\n+struct ixd_adapter {\n+\tstruct libie_ctlq_ctx cp_ctx;\n+\tstruct {\n+\t\tstruct delayed_work init_work;\n+\t\tu8 reset_retries;\n+\t\tu8 vc_retries;\n+\t\tbool success;\n+\t} init_task;\n+\tstruct delayed_work mbx_task;\n+\tstruct libie_ctlq_xn_manager *xnm;\n+\tstruct libie_ctlq_info *asq;\n+\tstruct libie_ctlq_info *arq;\n+\tstruct {\n+\t\tu32 major;\n+\t\tu32 minor;\n+\t} vc_ver;\n+\tstruct virtchnl2_get_capabilities caps;\n+};\n+\n+/**\n+ * ixd_to_dev - Get the corresponding device struct from an adapter\n+ * @adapter: PCI device driver-specific private data\n+ *\n+ * Return: struct device corresponding to the given adapter\n+ */\n+static inline struct device *ixd_to_dev(struct ixd_adapter *adapter)\n+{\n+\treturn \u0026adapter-\u003ecp_ctx.mmio_info.pdev-\u003edev;\n+}\n+\n+void ixd_ctlq_reg_init(struct ixd_adapter *adapter,\n+\t\t struct libie_ctlq_reg *ctlq_reg_tx,\n+\t\t struct libie_ctlq_reg *ctlq_reg_rx);\n+void ixd_trigger_reset(struct ixd_adapter *adapter);\n+bool ixd_check_reset_complete(struct ixd_adapter *adapter);\n+void ixd_init_task(struct work_struct *work);\n+int ixd_init_dflt_mbx(struct ixd_adapter *adapter);\n+void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter);\n+\n+#endif /* _IXD_H_ */\ndiff --git a/drivers/net/ethernet/intel/ixd/ixd_ctlq.c b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c\nnew file mode 100644\nindex 0000000000000..8712e10c8c504\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c\n@@ -0,0 +1,141 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/* Copyright (C) 2025 Intel Corporation */\n+\n+#include \"ixd.h\"\n+#include \"ixd_ctlq.h\"\n+#include \"ixd_virtchnl.h\"\n+\n+#define IXD_CTLQ_RX_TASK_DELAY_JIFFIES\tmsecs_to_jiffies(300)\n+\n+/**\n+ * ixd_ctlq_clean_sq - Clean the send control queue after sending the message\n+ * @adapter: The adapter that sent the messages\n+ * @force: Clean regardless of send status\n+ *\n+ * Free the libie send resources after sending the message and handling\n+ * the response.\n+ */\n+void ixd_ctlq_clean_sq(struct ixd_adapter *adapter, bool force)\n+{\n+\tlibie_ctlq_xn_send_clean(adapter-\u003easq, kfree, force);\n+}\n+\n+/**\n+ * ixd_ctlq_init_sparams - Initialize control queue send parameters\n+ * @adapter: The adapter with initialized mailbox\n+ * @sparams: Parameters to initialize\n+ * @msg_buf: DMA-mappable pointer to the message being sent\n+ * @msg_size: Message size\n+ */\n+static void ixd_ctlq_init_sparams(struct ixd_adapter *adapter,\n+\t\t\t\t struct libie_ctlq_xn_send_params *sparams,\n+\t\t\t\t void *msg_buf, size_t msg_size)\n+{\n+\t*sparams = (struct libie_ctlq_xn_send_params) {\n+\t\t.rel_tx_buf = kfree,\n+\t\t.xnm = adapter-\u003exnm,\n+\t\t.ctlq = adapter-\u003easq,\n+\t\t.timeout_ms = IXD_CTLQ_TIMEOUT,\n+\t\t.send_buf = (struct kvec) {\n+\t\t\t.iov_base = msg_buf,\n+\t\t\t.iov_len = msg_size,\n+\t\t},\n+\t};\n+}\n+\n+/**\n+ * ixd_ctlq_do_req - Perform a standard virtchnl request\n+ * @adapter: The adapter with initialized mailbox\n+ * @req: virtchnl request description\n+ *\n+ * Return: %0 if a message was sent and received a response\n+ * that was successfully handled by the custom callback,\n+ * negative error otherwise.\n+ */\n+int ixd_ctlq_do_req(struct ixd_adapter *adapter, const struct ixd_ctlq_req *req)\n+{\n+\tu8 onstack_send_buff[LIBIE_CP_TX_COPYBREAK] __aligned_largest = {};\n+\tstruct libie_ctlq_xn_send_params send_params = {};\n+\tstruct kvec *recv_mem;\n+\tvoid *send_buff;\n+\tint err;\n+\n+\tsend_buff = libie_cp_can_send_onstack(req-\u003esend_size) ?\n+\t\t \u0026onstack_send_buff : kzalloc(req-\u003esend_size, GFP_KERNEL);\n+\tif (!send_buff)\n+\t\treturn -ENOMEM;\n+\n+\tixd_ctlq_init_sparams(adapter, \u0026send_params, send_buff,\n+\t\t\t req-\u003esend_size);\n+\n+\tsend_params.chnl_opcode = req-\u003eopcode;\n+\n+\tif (req-\u003esend_buff_init)\n+\t\treq-\u003esend_buff_init(adapter, send_buff, req-\u003ectx);\n+\n+\tixd_ctlq_clean_sq(adapter, false);\n+\terr = libie_ctlq_xn_send(\u0026send_params);\n+\tif (err)\n+\t\treturn err;\n+\n+\trecv_mem = \u0026send_params.recv_mem;\n+\tif (req-\u003erecv_process)\n+\t\terr = req-\u003erecv_process(adapter, recv_mem-\u003eiov_base,\n+\t\t\t\t\trecv_mem-\u003eiov_len, req-\u003ectx);\n+\n+\tlibie_ctlq_release_rx_buf(recv_mem);\n+\n+\treturn err;\n+}\n+\n+/**\n+ * ixd_ctlq_handle_msg - Default control queue message handler\n+ * @ctx: Control plane communication context\n+ * @msg: Message received\n+ */\n+static void ixd_ctlq_handle_msg(struct libie_ctlq_ctx *ctx,\n+\t\t\t\tstruct libie_ctlq_msg *msg)\n+{\n+\tstruct ixd_adapter *adapter = pci_get_drvdata(ctx-\u003emmio_info.pdev);\n+\n+\tif (ixd_vc_can_handle_msg(msg))\n+\t\tixd_vc_recv_event_msg(adapter, msg);\n+\telse\n+\t\tdev_dbg_ratelimited(ixd_to_dev(adapter),\n+\t\t\t\t \"Received an unsupported opcode 0x%x from the CP\\n\",\n+\t\t\t\t msg-\u003echnl_opcode);\n+\n+\tlibie_ctlq_release_rx_buf(\u0026msg-\u003erecv_mem);\n+}\n+\n+/**\n+ * ixd_ctlq_recv_mb_msg - Receive a potential message over mailbox periodically\n+ * @adapter: The adapter with initialized mailbox\n+ */\n+static void ixd_ctlq_recv_mb_msg(struct ixd_adapter *adapter)\n+{\n+\tstruct libie_ctlq_xn_recv_params xn_params = {\n+\t\t.xnm = adapter-\u003exnm,\n+\t\t.ctlq = adapter-\u003earq,\n+\t\t.ctlq_msg_handler = ixd_ctlq_handle_msg,\n+\t\t.budget = LIBIE_CTLQ_MAX_XN_ENTRIES,\n+\t};\n+\n+\tlibie_ctlq_xn_recv(\u0026xn_params);\n+}\n+\n+/**\n+ * ixd_ctlq_rx_task - Periodically check for mailbox responses and events\n+ * @work: work handle\n+ */\n+void ixd_ctlq_rx_task(struct work_struct *work)\n+{\n+\tstruct ixd_adapter *adapter;\n+\n+\tadapter = container_of(work, struct ixd_adapter, mbx_task.work);\n+\n+\tqueue_delayed_work(system_dfl_wq, \u0026adapter-\u003embx_task,\n+\t\t\t IXD_CTLQ_RX_TASK_DELAY_JIFFIES);\n+\n+\tixd_ctlq_recv_mb_msg(adapter);\n+}\ndiff --git a/drivers/net/ethernet/intel/ixd/ixd_ctlq.h b/drivers/net/ethernet/intel/ixd/ixd_ctlq.h\nnew file mode 100644\nindex 0000000000000..8839f9f8f6d50\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ixd/ixd_ctlq.h\n@@ -0,0 +1,34 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+/* Copyright (C) 2025 Intel Corporation */\n+\n+#ifndef _IXD_CTLQ_H_\n+#define _IXD_CTLQ_H_\n+\n+#include \u003clinux/net/intel/virtchnl2.h\u003e\n+\n+#define IXD_CTLQ_TIMEOUT 2000\n+\n+/**\n+ * struct ixd_ctlq_req - Standard virtchnl request description\n+ * @opcode: protocol opcode, only virtchnl2 is needed for now\n+ * @send_size: required length of the send buffer\n+ * @send_buff_init: function to initialize the allocated send buffer\n+ * @recv_process: function to handle the CP response\n+ * @ctx: additional context for callbacks\n+ */\n+struct ixd_ctlq_req {\n+\tenum virtchnl2_op opcode;\n+\tsize_t send_size;\n+\tvoid (*send_buff_init)(struct ixd_adapter *adapter, void *send_buff,\n+\t\t\t void *ctx);\n+\tint (*recv_process)(struct ixd_adapter *adapter, void *recv_buff,\n+\t\t\t size_t recv_size, void *ctx);\n+\tvoid *ctx;\n+};\n+\n+void ixd_ctlq_clean_sq(struct ixd_adapter *adapter, bool force);\n+int ixd_ctlq_do_req(struct ixd_adapter *adapter,\n+\t\t const struct ixd_ctlq_req *req);\n+void ixd_ctlq_rx_task(struct work_struct *work);\n+\n+#endif /* _IXD_CTLQ_H_ */\ndiff --git a/drivers/net/ethernet/intel/ixd/ixd_dev.c b/drivers/net/ethernet/intel/ixd/ixd_dev.c\nnew file mode 100644\nindex 0000000000000..cdd5477cc1f4d\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ixd/ixd_dev.c\n@@ -0,0 +1,89 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/* Copyright (C) 2025 Intel Corporation */\n+\n+#include \"ixd.h\"\n+#include \"ixd_lan_regs.h\"\n+\n+/**\n+ * ixd_ctlq_reg_init - Initialize default mailbox registers\n+ * @adapter: PCI device driver-specific private data\n+ * @ctlq_reg_tx: Transmit queue registers info to be filled\n+ * @ctlq_reg_rx: Receive queue registers info to be filled\n+ */\n+void ixd_ctlq_reg_init(struct ixd_adapter *adapter,\n+\t\t struct libie_ctlq_reg *ctlq_reg_tx,\n+\t\t struct libie_ctlq_reg *ctlq_reg_rx)\n+{\n+\tstruct libie_mmio_info *mmio_info = \u0026adapter-\u003ecp_ctx.mmio_info;\n+\t*ctlq_reg_tx = (struct libie_ctlq_reg) {\n+\t\t.head = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQH),\n+\t\t.tail = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQT),\n+\t\t.len = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQLEN),\n+\t\t.addr_high = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQBAH),\n+\t\t.addr_low = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQBAL),\n+\t\t.len_mask = PF_FW_ATQLEN_ATQLEN_M,\n+\t\t.len_ena_mask = PF_FW_ATQLEN_ATQENABLE_M,\n+\t\t.head_mask = PF_FW_ATQH_ATQH_M,\n+\t};\n+\n+\t*ctlq_reg_rx = (struct libie_ctlq_reg) {\n+\t\t.head = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQH),\n+\t\t.tail = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQT),\n+\t\t.len = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQLEN),\n+\t\t.addr_high = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQBAH),\n+\t\t.addr_low = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQBAL),\n+\t\t.len_mask = PF_FW_ARQLEN_ARQLEN_M,\n+\t\t.len_ena_mask = PF_FW_ARQLEN_ARQENABLE_M,\n+\t\t.head_mask = PF_FW_ARQH_ARQH_M,\n+\t};\n+}\n+\n+static const struct ixd_reset_reg ixd_reset_reg = {\n+\t.rstat = PFGEN_RSTAT,\n+\t.rstat_m = PFGEN_RSTAT_PFR_STATE_M,\n+\t.rstat_ok_v = 0b01,\n+\t.rtrigger = PFGEN_CTRL,\n+\t.rtrigger_m = PFGEN_CTRL_PFSWR,\n+};\n+\n+/**\n+ * ixd_trigger_reset - Trigger PFR reset\n+ * @adapter: the device with mapped reset register\n+ */\n+void ixd_trigger_reset(struct ixd_adapter *adapter)\n+{\n+\tvoid __iomem *addr;\n+\tu32 reg_val;\n+\n+\taddr = libie_pci_get_mmio_addr(\u0026adapter-\u003ecp_ctx.mmio_info,\n+\t\t\t\t ixd_reset_reg.rtrigger);\n+\treg_val = readl(addr);\n+\twritel(reg_val | ixd_reset_reg.rtrigger_m, addr);\n+}\n+\n+/**\n+ * ixd_check_reset_complete - Check if the PFR reset is completed\n+ * @adapter: CPF being reset\n+ *\n+ * Return: %true if the register read indicates reset has been finished,\n+ *\t %false otherwise\n+ */\n+bool ixd_check_reset_complete(struct ixd_adapter *adapter)\n+{\n+\tu32 reg_val, reset_status;\n+\tvoid __iomem *addr;\n+\n+\taddr = libie_pci_get_mmio_addr(\u0026adapter-\u003ecp_ctx.mmio_info,\n+\t\t\t\t ixd_reset_reg.rstat);\n+\treg_val = readl(addr);\n+\treset_status = reg_val \u0026 ixd_reset_reg.rstat_m;\n+\n+\t/* 0xFFFFFFFF might be read if the other side hasn't cleared\n+\t * the register for us yet.\n+\t */\n+\tif (reg_val != GENMASK(31, 0) \u0026\u0026\n+\t reset_status == ixd_reset_reg.rstat_ok_v)\n+\t\treturn true;\n+\n+\treturn false;\n+}\ndiff --git a/drivers/net/ethernet/intel/ixd/ixd_devlink.c b/drivers/net/ethernet/intel/ixd/ixd_devlink.c\nnew file mode 100644\nindex 0000000000000..828132db8323e\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ixd/ixd_devlink.c\n@@ -0,0 +1,99 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/* Copyright (c) 2025, Intel Corporation. */\n+\n+#include \"ixd.h\"\n+#include \"ixd_devlink.h\"\n+\n+#define IXD_DEVLINK_INFO_LEN\t128\n+\n+/**\n+ * ixd_fill_dsn - Get the serial number for the ixd device\n+ * @adapter: adapter to query\n+ * @buf: storage buffer for the info request\n+ */\n+static void ixd_fill_dsn(struct ixd_adapter *adapter, char *buf)\n+{\n+\tu8 dsn[8];\n+\n+\t/* Copy the DSN into an array in Big Endian format */\n+\tput_unaligned_be64(pci_get_dsn(adapter-\u003ecp_ctx.mmio_info.pdev), dsn);\n+\n+\tsnprintf(buf, IXD_DEVLINK_INFO_LEN, \"%8phD\", dsn);\n+}\n+\n+/**\n+ * ixd_fill_device_name - Get the name of the underlying hardware\n+ * @adapter: adapter to query\n+ * @buf: storage buffer for the info request\n+ * @buf_size: size of the storage buffer\n+ */\n+static void ixd_fill_device_name(struct ixd_adapter *adapter, char *buf,\n+\t\t\t\t size_t buf_size)\n+{\n+\tif (adapter-\u003ecaps.device_type == cpu_to_le32(VIRTCHNL2_MEV_DEVICE))\n+\t\tsnprintf(buf, buf_size, \"%s\", \"MEV\");\n+\telse\n+\t\tsnprintf(buf, buf_size, \"%s\", \"UNKNOWN\");\n+}\n+\n+/**\n+ * ixd_devlink_info_get - .info_get devlink handler\n+ * @devlink: devlink instance structure\n+ * @req: the devlink info request\n+ * @extack: extended netdev ack structure\n+ *\n+ * Callback for the devlink .info_get operation. Reports information about the\n+ * device.\n+ *\n+ * Return: zero on success or an error code on failure.\n+ */\n+static int ixd_devlink_info_get(struct devlink *devlink,\n+\t\t\t\tstruct devlink_info_req *req,\n+\t\t\t\tstruct netlink_ext_ack *extack)\n+{\n+\tstruct ixd_adapter *adapter = devlink_priv(devlink);\n+\tchar buf[IXD_DEVLINK_INFO_LEN];\n+\tint err;\n+\n+\tixd_fill_dsn(adapter, buf);\n+\terr = devlink_info_serial_number_put(req, buf);\n+\tif (err)\n+\t\treturn err;\n+\n+\tixd_fill_device_name(adapter, buf, IXD_DEVLINK_INFO_LEN);\n+\terr = devlink_info_version_fixed_put(req, \"device.type\", buf);\n+\tif (err)\n+\t\treturn err;\n+\n+\tsnprintf(buf, sizeof(buf), \"%u.%u\",\n+\t\t adapter-\u003evc_ver.major, adapter-\u003evc_ver.minor);\n+\n+\treturn devlink_info_version_running_put(req,\n+\t\t\t\t\t\tDEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API,\n+\t\t\t\t\t\tbuf);\n+}\n+\n+static const struct devlink_ops ixd_devlink_ops = {\n+\t.info_get = ixd_devlink_info_get,\n+};\n+\n+/**\n+ * ixd_adapter_alloc - Allocate devlink and return adapter pointer\n+ * @dev: the device to allocate for\n+ *\n+ * Allocate a devlink instance for this device and return the private area as\n+ * the adapter structure.\n+ *\n+ * Return: adapter structure on success, NULL on failure\n+ */\n+struct ixd_adapter *ixd_adapter_alloc(struct device *dev)\n+{\n+\tstruct devlink *devlink;\n+\n+\tdevlink = devlink_alloc(\u0026ixd_devlink_ops, sizeof(struct ixd_adapter),\n+\t\t\t\tdev);\n+\tif (!devlink)\n+\t\treturn NULL;\n+\n+\treturn devlink_priv(devlink);\n+}\ndiff --git a/drivers/net/ethernet/intel/ixd/ixd_devlink.h b/drivers/net/ethernet/intel/ixd/ixd_devlink.h\nnew file mode 100644\nindex 0000000000000..b23a1b37aebc4\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ixd/ixd_devlink.h\n@@ -0,0 +1,50 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+/* Copyright (c) 2025, Intel Corporation. */\n+\n+#ifndef _IXD_DEVLINK_H_\n+#define _IXD_DEVLINK_H_\n+\n+#include \u003cnet/devlink.h\u003e\n+\n+#include \"ixd.h\"\n+\n+struct ixd_adapter *ixd_adapter_alloc(struct device *dev);\n+\n+/**\n+ * ixd_devlink_free - teardown the devlink\n+ * @adapter: the adapter structure to free\n+ *\n+ */\n+static inline void ixd_devlink_free(struct ixd_adapter *adapter)\n+{\n+\tstruct devlink *devlink = priv_to_devlink(adapter);\n+\n+\tdevlink_free(devlink);\n+}\n+\n+/**\n+ * ixd_devlink_unregister - Unregister devlink for this adapter.\n+ * @adapter: the adapter structure to cleanup\n+ *\n+ * Init task must be completed or cancelled beforehand.\n+ */\n+static inline void ixd_devlink_unregister(struct ixd_adapter *adapter)\n+{\n+\tif (!adapter-\u003einit_task.success)\n+\t\treturn;\n+\n+\tdevlink_unregister(priv_to_devlink(adapter));\n+}\n+\n+/**\n+ * ixd_devlink_register - Register devlink interface for this adapter\n+ * @adapter: pointer to ixd adapter structure to be associated with devlink\n+ *\n+ * Register the devlink instance associated with this adapter\n+ */\n+static inline void ixd_devlink_register(struct ixd_adapter *adapter)\n+{\n+\tdevlink_register(priv_to_devlink(adapter));\n+}\n+\n+#endif /* _IXD_DEVLINK_H_ */\ndiff --git a/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h b/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h\nnew file mode 100644\nindex 0000000000000..58e58c75981b1\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h\n@@ -0,0 +1,68 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+/* Copyright (C) 2025 Intel Corporation */\n+\n+#ifndef _IXD_LAN_REGS_H_\n+#define _IXD_LAN_REGS_H_\n+\n+/* Control Plane Function PCI ID */\n+#define IXD_DEV_ID_CPF\t\t\t0x1efe\n+\n+/* Control Queue (Mailbox) */\n+#define PF_FW_MBX_REG_LEN\t\t4096\n+#define PF_FW_MBX\t\t\t0x08400000\n+\n+#define PF_FW_ARQBAL\t\t\t(PF_FW_MBX)\n+#define PF_FW_ARQBAH\t\t\t(PF_FW_MBX + 0x4)\n+#define PF_FW_ARQLEN\t\t\t(PF_FW_MBX + 0x8)\n+#define PF_FW_ARQLEN_ARQLEN_M\t\tGENMASK(12, 0)\n+#define PF_FW_ARQLEN_ARQENABLE_S\t31\n+#define PF_FW_ARQLEN_ARQENABLE_M\tBIT(PF_FW_ARQLEN_ARQENABLE_S)\n+#define PF_FW_ARQH_ARQH_M\t\tGENMASK(12, 0)\n+#define PF_FW_ARQH\t\t\t(PF_FW_MBX + 0xC)\n+#define PF_FW_ARQT\t\t\t(PF_FW_MBX + 0x10)\n+\n+#define PF_FW_ATQBAL\t\t\t(PF_FW_MBX + 0x14)\n+#define PF_FW_ATQBAH\t\t\t(PF_FW_MBX + 0x18)\n+#define PF_FW_ATQLEN\t\t\t(PF_FW_MBX + 0x1C)\n+#define PF_FW_ATQLEN_ATQLEN_M\t\tGENMASK(9, 0)\n+#define PF_FW_ATQLEN_ATQENABLE_S\t31\n+#define PF_FW_ATQLEN_ATQENABLE_M\tBIT(PF_FW_ATQLEN_ATQENABLE_S)\n+#define PF_FW_ATQH_ATQH_M\t\tGENMASK(9, 0)\n+#define PF_FW_ATQH\t\t\t(PF_FW_MBX + 0x20)\n+#define PF_FW_ATQT\t\t\t(PF_FW_MBX + 0x24)\n+\n+/* Reset registers */\n+#define PFGEN_RTRIG_REG_LEN\t\t2048\n+#define PFGEN_RTRIG\t\t\t0x08407000\t/* Device resets */\n+#define PFGEN_RSTAT\t\t\t0x08407008\t/* PFR status */\n+#define PFGEN_RSTAT_PFR_STATE_M\t\tGENMASK(1, 0)\n+#define PFGEN_CTRL\t\t\t0x0840700C\t/* PFR trigger */\n+#define PFGEN_CTRL_PFSWR\t\tBIT(0)\n+\n+/**\n+ * struct ixd_bar_region - BAR region description\n+ * @offset: BAR region offset\n+ * @size: BAR region size\n+ */\n+struct ixd_bar_region {\n+\tresource_size_t offset;\n+\tresource_size_t size;\n+};\n+\n+/**\n+ * struct ixd_reset_reg - structure for reset registers\n+ * @rstat: offset of status in register\n+ * @rstat_m: status mask\n+ * @rstat_ok_v: value that indicates PFR completed status\n+ * @rtrigger: offset of reset trigger in register\n+ * @rtrigger_m: reset trigger mask\n+ */\n+struct ixd_reset_reg {\n+\tu32\trstat;\n+\tu32\trstat_m;\n+\tu32\trstat_ok_v;\n+\tu32\trtrigger;\n+\tu32\trtrigger_m;\n+};\n+\n+#endif /* _IXD_LAN_REGS_H_ */\ndiff --git a/drivers/net/ethernet/intel/ixd/ixd_lib.c b/drivers/net/ethernet/intel/ixd/ixd_lib.c\nnew file mode 100644\nindex 0000000000000..8311f7590666b\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ixd/ixd_lib.c\n@@ -0,0 +1,173 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/* Copyright (C) 2025 Intel Corporation */\n+\n+#include \"ixd.h\"\n+#include \"ixd_ctlq.h\"\n+#include \"ixd_devlink.h\"\n+#include \"ixd_virtchnl.h\"\n+\n+#define IXD_DFLT_MBX_Q_LEN 64\n+\n+/**\n+ * ixd_init_ctlq_create_info - Initialize control queue info for creation\n+ * @info: destination\n+ * @type: type of the queue to create\n+ * @ctlq_reg: register assigned to the control queue\n+ */\n+static void ixd_init_ctlq_create_info(struct libie_ctlq_create_info *info,\n+\t\t\t\t enum libie_ctlq_type type,\n+\t\t\t\t const struct libie_ctlq_reg *ctlq_reg)\n+{\n+\t*info = (struct libie_ctlq_create_info) {\n+\t\t.type = type,\n+\t\t.id = -1,\n+\t\t.reg = *ctlq_reg,\n+\t\t.len = IXD_DFLT_MBX_Q_LEN,\n+\t};\n+}\n+\n+/**\n+ * ixd_init_libie_xn_params - Initialize xn transaction manager creation info\n+ * @params: destination\n+ * @adapter: adapter info struct\n+ * @ctlqs: list of the managed queues to create\n+ * @num_queues: length of the queue list\n+ */\n+static void ixd_init_libie_xn_params(struct libie_ctlq_xn_init_params *params,\n+\t\t\t\t struct ixd_adapter *adapter,\n+\t\t\t\t struct libie_ctlq_create_info *ctlqs,\n+\t\t\t\t uint num_queues)\n+{\n+\t*params = (struct libie_ctlq_xn_init_params){\n+\t\t.cctlq_info = ctlqs,\n+\t\t.ctx = \u0026adapter-\u003ecp_ctx,\n+\t\t.num_qs = num_queues,\n+\t};\n+}\n+\n+/**\n+ * ixd_adapter_fill_dflt_ctlqs - Find default control queues and store them\n+ * @adapter: adapter info struct\n+ */\n+static void ixd_adapter_fill_dflt_ctlqs(struct ixd_adapter *adapter)\n+{\n+\tadapter-\u003earq = libie_find_ctlq(\u0026adapter-\u003ecp_ctx, LIBIE_CTLQ_TYPE_RX,\n+\t\t\t\t LIBIE_CTLQ_MBX_ID);\n+\tadapter-\u003easq = libie_find_ctlq(\u0026adapter-\u003ecp_ctx, LIBIE_CTLQ_TYPE_TX,\n+\t\t\t\t LIBIE_CTLQ_MBX_ID);\n+}\n+\n+/**\n+ * ixd_deinit_dflt_mbx - Deinitialize default mailbox\n+ * @adapter: adapter info struct\n+ */\n+void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter)\n+{\n+\tcancel_delayed_work_sync(\u0026adapter-\u003embx_task);\n+\n+\tif (adapter-\u003exnm)\n+\t\tlibie_ctlq_xn_shutdown(adapter-\u003exnm);\n+\n+\tif (adapter-\u003easq)\n+\t\tixd_ctlq_clean_sq(adapter, true);\n+\n+\tif (adapter-\u003exnm)\n+\t\tlibie_ctlq_xn_deinit(adapter-\u003exnm, \u0026adapter-\u003ecp_ctx);\n+\n+\tadapter-\u003earq = NULL;\n+\tadapter-\u003easq = NULL;\n+\tadapter-\u003exnm = NULL;\n+}\n+\n+/**\n+ * ixd_init_dflt_mbx - Setup default mailbox parameters and make request\n+ * @adapter: adapter info struct\n+ *\n+ * Return: %0 on success, negative errno code on failure\n+ */\n+int ixd_init_dflt_mbx(struct ixd_adapter *adapter)\n+{\n+\tstruct libie_ctlq_create_info ctlqs_info[2];\n+\tstruct libie_ctlq_xn_init_params xn_params;\n+\tstruct libie_ctlq_reg ctlq_reg_tx;\n+\tstruct libie_ctlq_reg ctlq_reg_rx;\n+\tint err;\n+\n+\tixd_ctlq_reg_init(adapter, \u0026ctlq_reg_tx, \u0026ctlq_reg_rx);\n+\tixd_init_ctlq_create_info(\u0026ctlqs_info[0], LIBIE_CTLQ_TYPE_TX,\n+\t\t\t\t \u0026ctlq_reg_tx);\n+\tixd_init_ctlq_create_info(\u0026ctlqs_info[1], LIBIE_CTLQ_TYPE_RX,\n+\t\t\t\t \u0026ctlq_reg_rx);\n+\tixd_init_libie_xn_params(\u0026xn_params, adapter, ctlqs_info,\n+\t\t\t\t ARRAY_SIZE(ctlqs_info));\n+\terr = libie_ctlq_xn_init(\u0026xn_params);\n+\tif (err)\n+\t\treturn err;\n+\tadapter-\u003exnm = xn_params.xnm;\n+\n+\tixd_adapter_fill_dflt_ctlqs(adapter);\n+\n+\tif (!adapter-\u003easq || !adapter-\u003earq) {\n+\t\tixd_deinit_dflt_mbx(adapter);\n+\t\treturn -ENOENT;\n+\t}\n+\n+\tqueue_delayed_work(system_dfl_wq, \u0026adapter-\u003embx_task, 0);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ixd_init_task - Initialize after reset\n+ * @work: init work struct\n+ */\n+void ixd_init_task(struct work_struct *work)\n+{\n+\tstruct ixd_adapter *adapter;\n+\tint err;\n+\n+\tadapter = container_of(work, struct ixd_adapter,\n+\t\t\t init_task.init_work.work);\n+\n+\tif (!ixd_check_reset_complete(adapter)) {\n+\t\tif (++adapter-\u003einit_task.reset_retries \u003c 10)\n+\t\t\tqueue_delayed_work(system_dfl_wq,\n+\t\t\t\t\t \u0026adapter-\u003einit_task.init_work,\n+\t\t\t\t\t IXD_INIT_TASK_DELAY_JIFFIES);\n+\t\telse\n+\t\t\tdev_err(ixd_to_dev(adapter),\n+\t\t\t\t\"Device reset failed. The driver was unable to contact the device's firmware. Check that the FW is running.\\n\");\n+\t\treturn;\n+\t}\n+\n+\tadapter-\u003einit_task.reset_retries = 0;\n+\terr = ixd_init_dflt_mbx(adapter);\n+\tif (err) {\n+\t\tdev_err(ixd_to_dev(adapter),\n+\t\t\t\"Failed to initialize the default mailbox: %pe\\n\",\n+\t\t\tERR_PTR(err));\n+\t\treturn;\n+\t}\n+\n+\terr = ixd_vc_dev_init(adapter);\n+\tif (!err) {\n+\t\tadapter-\u003einit_task.vc_retries = 0;\n+\t\tadapter-\u003einit_task.success = true;\n+\t\tixd_devlink_register(adapter);\n+\t\treturn;\n+\t}\n+\n+\tlibie_ctlq_xn_shutdown(adapter-\u003exnm);\n+\tixd_trigger_reset(adapter);\n+\tixd_deinit_dflt_mbx(adapter);\n+\tif (++adapter-\u003einit_task.vc_retries \u003e 5 ||\n+\t (err != -ETIMEDOUT \u0026\u0026 err != -EAGAIN \u0026\u0026 err != -EBUSY)) {\n+\t\tdev_err(ixd_to_dev(adapter),\n+\t\t\t\"Failed to establish mailbox communication with the hardware: %pe\\n\",\n+\t\t\tERR_PTR(err));\n+\t\treturn;\n+\t}\n+\n+\tqueue_delayed_work(system_dfl_wq, \u0026adapter-\u003einit_task.init_work,\n+\t\t\t IXD_INIT_TASK_DELAY_JIFFIES);\n+}\ndiff --git a/drivers/net/ethernet/intel/ixd/ixd_main.c b/drivers/net/ethernet/intel/ixd/ixd_main.c\nnew file mode 100644\nindex 0000000000000..5db992d4f9fb2\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ixd/ixd_main.c\n@@ -0,0 +1,144 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/* Copyright (C) 2025 Intel Corporation */\n+\n+#include \"ixd.h\"\n+#include \"ixd_ctlq.h\"\n+#include \"ixd_lan_regs.h\"\n+#include \"ixd_devlink.h\"\n+\n+MODULE_DESCRIPTION(\"Intel(R) Control Plane Function Device Driver\");\n+MODULE_IMPORT_NS(\"LIBIE_CP\");\n+MODULE_IMPORT_NS(\"LIBIE_PCI\");\n+MODULE_LICENSE(\"GPL\");\n+\n+/**\n+ * ixd_remove - remove a CPF PCI device\n+ * @pdev: PCI device being removed\n+ */\n+static void ixd_remove(struct pci_dev *pdev)\n+{\n+\tstruct ixd_adapter *adapter = pci_get_drvdata(pdev);\n+\n+\t/* Do not mix removal with (re)initialization */\n+\tcancel_delayed_work_sync(\u0026adapter-\u003einit_task.init_work);\n+\n+\tixd_devlink_unregister(adapter);\n+\n+\t/* Leave the device clean on exit */\n+\tif (adapter-\u003exnm)\n+\t\tlibie_ctlq_xn_shutdown(adapter-\u003exnm);\n+\tixd_trigger_reset(adapter);\n+\tixd_deinit_dflt_mbx(adapter);\n+\n+\tlibie_pci_unmap_all_mmio_regions(\u0026adapter-\u003ecp_ctx.mmio_info);\n+\tixd_devlink_free(adapter);\n+}\n+\n+/**\n+ * ixd_shutdown - shut down a CPF PCI device\n+ * @pdev: PCI device being shut down\n+ */\n+static void ixd_shutdown(struct pci_dev *pdev)\n+{\n+\tixd_remove(pdev);\n+\n+\tif (system_state == SYSTEM_POWER_OFF)\n+\t\tpci_set_power_state(pdev, PCI_D3hot);\n+}\n+\n+/**\n+ * ixd_iomap_regions - iomap PCI BARs\n+ * @adapter: adapter to map memory regions for\n+ *\n+ * Returns: %0 on success, negative on failure\n+ */\n+static int ixd_iomap_regions(struct ixd_adapter *adapter)\n+{\n+\tconst struct ixd_bar_region regions[] = {\n+\t\t{\n+\t\t\t.offset = PFGEN_RTRIG,\n+\t\t\t.size = PFGEN_RTRIG_REG_LEN,\n+\t\t},\n+\t\t{\n+\t\t\t.offset = PF_FW_MBX,\n+\t\t\t.size = PF_FW_MBX_REG_LEN,\n+\t\t},\n+\t};\n+\n+\tfor (int i = 0; i \u003c ARRAY_SIZE(regions); i++) {\n+\t\tstruct libie_mmio_info *mmio_info = \u0026adapter-\u003ecp_ctx.mmio_info;\n+\t\tbool map_ok;\n+\n+\t\tmap_ok = libie_pci_map_mmio_region(mmio_info,\n+\t\t\t\t\t\t regions[i].offset,\n+\t\t\t\t\t\t regions[i].size);\n+\t\tif (!map_ok) {\n+\t\t\tdev_err(ixd_to_dev(adapter),\n+\t\t\t\t\"Failed to map PCI device MMIO region\\n\");\n+\n+\t\t\tlibie_pci_unmap_all_mmio_regions(mmio_info);\n+\t\t\treturn -EIO;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ixd_probe - probe a CPF PCI device\n+ * @pdev: corresponding PCI device\n+ * @ent: entry in ixd_pci_tbl\n+ *\n+ * Returns: %0 on success, negative errno code on failure\n+ */\n+static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n+{\n+\tstruct ixd_adapter *adapter;\n+\tint err;\n+\n+\tadapter = ixd_adapter_alloc(\u0026pdev-\u003edev);\n+\tif (!adapter)\n+\t\treturn -ENOMEM;\n+\n+\tadapter-\u003ecp_ctx.mmio_info.pdev = pdev;\n+\tINIT_LIST_HEAD(\u0026adapter-\u003ecp_ctx.mmio_info.mmio_list);\n+\n+\terr = libie_pci_init_dev(pdev);\n+\tif (err)\n+\t\tgoto free_adapter;\n+\n+\tpci_set_drvdata(pdev, adapter);\n+\n+\terr = ixd_iomap_regions(adapter);\n+\tif (err)\n+\t\tgoto free_adapter;\n+\n+\tINIT_DELAYED_WORK(\u0026adapter-\u003einit_task.init_work,\n+\t\t\t ixd_init_task);\n+\tINIT_DELAYED_WORK(\u0026adapter-\u003embx_task, ixd_ctlq_rx_task);\n+\n+\tixd_trigger_reset(adapter);\n+\tqueue_delayed_work(system_dfl_wq, \u0026adapter-\u003einit_task.init_work,\n+\t\t\t IXD_INIT_TASK_DELAY_JIFFIES);\n+\n+\treturn 0;\n+\n+free_adapter:\n+\tixd_devlink_free(adapter);\n+\treturn err;\n+}\n+\n+static const struct pci_device_id ixd_pci_tbl[] = {\n+\t{ PCI_VDEVICE(INTEL, IXD_DEV_ID_CPF) },\n+\t{ }\n+};\n+MODULE_DEVICE_TABLE(pci, ixd_pci_tbl);\n+\n+static struct pci_driver ixd_driver = {\n+\t.name\t\t\t= KBUILD_MODNAME,\n+\t.id_table\t\t= ixd_pci_tbl,\n+\t.probe\t\t\t= ixd_probe,\n+\t.remove\t\t\t= ixd_remove,\n+\t.shutdown\t\t= ixd_shutdown,\n+};\n+module_pci_driver(ixd_driver);\ndiff --git a/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c\nnew file mode 100644\nindex 0000000000000..fc3b6d2e28c53\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c\n@@ -0,0 +1,190 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/* Copyright (C) 2025 Intel Corporation */\n+\n+#include \"ixd.h\"\n+#include \"ixd_ctlq.h\"\n+#include \"ixd_virtchnl.h\"\n+\n+/**\n+ * ixd_vc_recv_event_msg - Handle virtchnl event message\n+ * @adapter: The adapter handling the message\n+ * @ctlq_msg: Message received\n+ */\n+void ixd_vc_recv_event_msg(struct ixd_adapter *adapter,\n+\t\t\t struct libie_ctlq_msg *ctlq_msg)\n+{\n+\tint payload_size = ctlq_msg-\u003edata_len;\n+\tstruct virtchnl2_event *v2e;\n+\n+\tif (payload_size \u003c sizeof(*v2e)) {\n+\t\tdev_warn_ratelimited(ixd_to_dev(adapter),\n+\t\t\t\t \"Failed to receive valid payload for event msg (op 0x%X len %u)\\n\",\n+\t\t\t\t ctlq_msg-\u003echnl_opcode,\n+\t\t\t\t payload_size);\n+\t\treturn;\n+\t}\n+\n+\tv2e = (struct virtchnl2_event *)ctlq_msg-\u003erecv_mem.iov_base;\n+\n+\tdev_dbg(ixd_to_dev(adapter), \"Got event 0x%X from the CP\\n\",\n+\t\tle32_to_cpu(v2e-\u003eevent));\n+}\n+\n+/**\n+ * ixd_vc_can_handle_msg - Decide if an event has to be handled by virtchnl code\n+ * @ctlq_msg: Message received\n+ *\n+ * Return: %true if virtchnl code can handle the event, %false otherwise\n+ */\n+bool ixd_vc_can_handle_msg(struct libie_ctlq_msg *ctlq_msg)\n+{\n+\treturn ctlq_msg-\u003echnl_opcode == VIRTCHNL2_OP_EVENT;\n+}\n+\n+/**\n+ * ixd_handle_caps - Handle VIRTCHNL2_OP_GET_CAPS response\n+ * @adapter: The adapter for which the capabilities are being updated\n+ * @recv_buff: Buffer containing the response\n+ * @recv_size: Response buffer size\n+ * @ctx: unused\n+ *\n+ * Return: %0 if the response format is correct and was handled as expected,\n+ * negative error otherwise.\n+ */\n+static int ixd_handle_caps(struct ixd_adapter *adapter, void *recv_buff,\n+\t\t\t size_t recv_size, void *ctx)\n+{\n+\tif (recv_size \u003c sizeof(adapter-\u003ecaps))\n+\t\treturn -EBADMSG;\n+\n+\tadapter-\u003ecaps = *(typeof(adapter-\u003ecaps) *)recv_buff;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ixd_req_vc_caps - Request and save device capability\n+ * @adapter: The adapter to get the capabilities for\n+ *\n+ * Return: success or error if sending the get capability message fails\n+ */\n+static int ixd_req_vc_caps(struct ixd_adapter *adapter)\n+{\n+\tconst struct ixd_ctlq_req req = {\n+\t\t.opcode = VIRTCHNL2_OP_GET_CAPS,\n+\t\t.send_size = sizeof(struct virtchnl2_get_capabilities),\n+\t\t.ctx = NULL,\n+\t\t.send_buff_init = NULL,\n+\t\t.recv_process = ixd_handle_caps,\n+\t};\n+\n+\treturn ixd_ctlq_do_req(adapter, \u0026req);\n+}\n+\n+/**\n+ * ixd_get_vc_ver - Get version info from adapter\n+ *\n+ * Return: filled in virtchannel2 version info, ready for sending\n+ */\n+static struct virtchnl2_version_info ixd_get_vc_ver(void)\n+{\n+\treturn (struct virtchnl2_version_info) {\n+\t\t.major = cpu_to_le32(VIRTCHNL2_VERSION_MAJOR_2),\n+\t\t.minor = cpu_to_le32(VIRTCHNL2_VERSION_MINOR_0),\n+\t};\n+}\n+\n+static void ixd_fill_vc_ver(struct ixd_adapter *adapter, void *send_buff,\n+\t\t\t void *ctx)\n+{\n+\t*(struct virtchnl2_version_info *)send_buff = ixd_get_vc_ver();\n+}\n+\n+/**\n+ * ixd_handle_vc_ver - Handle VIRTCHNL2_OP_VERSION response\n+ * @adapter: The adapter for which the version is being updated\n+ * @recv_buff: Buffer containing the response\n+ * @recv_size: Response buffer size\n+ * @ctx: Unused\n+ *\n+ * Return: %0 if the response format is correct and was handled as expected,\n+ * negative error otherwise.\n+ */\n+static int ixd_handle_vc_ver(struct ixd_adapter *adapter, void *recv_buff,\n+\t\t\t size_t recv_size, void *ctx)\n+{\n+\tstruct virtchnl2_version_info need_ver = ixd_get_vc_ver();\n+\tstruct virtchnl2_version_info *recv_ver;\n+\n+\tif (recv_size \u003c sizeof(need_ver))\n+\t\treturn -EBADMSG;\n+\n+\trecv_ver = recv_buff;\n+\tif (le32_to_cpu(need_ver.major) != le32_to_cpu(recv_ver-\u003emajor) ||\n+\t le32_to_cpu(need_ver.minor) != le32_to_cpu(recv_ver-\u003eminor))\n+\t\tdev_warn(ixd_to_dev(adapter),\n+\t\t\t \"Virtchnl version does not match (expected %u.%u, received %u.%u)\\n\",\n+\t\t\t le32_to_cpu(need_ver.major),\n+\t\t\t le32_to_cpu(need_ver.minor),\n+\t\t\t le32_to_cpu(recv_ver-\u003emajor),\n+\t\t\t le32_to_cpu(recv_ver-\u003eminor));\n+\n+\tif (le32_to_cpu(need_ver.major) != le32_to_cpu(recv_ver-\u003emajor)) {\n+\t\tdev_err(ixd_to_dev(adapter),\n+\t\t\t\"Device initialization failed due to virtchnl major version mismatch\\n\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\tadapter-\u003evc_ver.major = le32_to_cpu(recv_ver-\u003emajor);\n+\tadapter-\u003evc_ver.minor = le32_to_cpu(recv_ver-\u003eminor);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ixd_req_vc_version - Request and save Virtchannel2 version\n+ * @adapter: The adapter to get the version for\n+ *\n+ * Return: success or error if sending fails or the response was not as expected\n+ */\n+static int ixd_req_vc_version(struct ixd_adapter *adapter)\n+{\n+\tconst struct ixd_ctlq_req req = {\n+\t\t.opcode = VIRTCHNL2_OP_VERSION,\n+\t\t.send_size = sizeof(struct virtchnl2_version_info),\n+\t\t.ctx = NULL,\n+\t\t.send_buff_init = ixd_fill_vc_ver,\n+\t\t.recv_process = ixd_handle_vc_ver,\n+\t};\n+\n+\treturn ixd_ctlq_do_req(adapter, \u0026req);\n+}\n+\n+/**\n+ * ixd_vc_dev_init - virtchnl device core initialization\n+ * @adapter: device information\n+ *\n+ * Return: %0 on success or error if any step of the initialization fails\n+ */\n+int ixd_vc_dev_init(struct ixd_adapter *adapter)\n+{\n+\tint err;\n+\n+\terr = ixd_req_vc_version(adapter);\n+\tif (err) {\n+\t\tdev_warn(ixd_to_dev(adapter),\n+\t\t\t \"Getting virtchnl version failed, error=%pe\\n\",\n+\t\t\t ERR_PTR(err));\n+\t\treturn err;\n+\t}\n+\n+\terr = ixd_req_vc_caps(adapter);\n+\tif (err) {\n+\t\tdev_warn(ixd_to_dev(adapter),\n+\t\t\t \"Getting virtchnl capabilities failed, error=%pe\\n\",\n+\t\t\t ERR_PTR(err));\n+\t\treturn err;\n+\t}\n+\n+\treturn err;\n+}\ndiff --git a/drivers/net/ethernet/intel/ixd/ixd_virtchnl.h b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.h\nnew file mode 100644\nindex 0000000000000..1a53da8b545c5\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.h\n@@ -0,0 +1,12 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+/* Copyright (C) 2025 Intel Corporation */\n+\n+#ifndef _IXD_VIRTCHNL_H_\n+#define _IXD_VIRTCHNL_H_\n+\n+int ixd_vc_dev_init(struct ixd_adapter *adapter);\n+bool ixd_vc_can_handle_msg(struct libie_ctlq_msg *ctlq_msg);\n+void ixd_vc_recv_event_msg(struct ixd_adapter *adapter,\n+\t\t\t struct libie_ctlq_msg *ctlq_msg);\n+\n+#endif /* _IXD_VIRTCHNL_H_ */\ndiff --git a/drivers/net/ethernet/intel/libeth/rx.c b/drivers/net/ethernet/intel/libeth/rx.c\nindex 62521a1f4ec93..0c1a565a1b3a3 100644\n--- a/drivers/net/ethernet/intel/libeth/rx.c\n+++ b/drivers/net/ethernet/intel/libeth/rx.c\n@@ -145,25 +145,29 @@ static bool libeth_rx_page_pool_params_zc(struct libeth_fq *fq,\n /**\n * libeth_rx_fq_create - create a PP with the default libeth settings\n * @fq: buffer queue struct to fill\n- * @napi: \u0026napi_struct covering this PP (no usage outside its poll loops)\n+ * @napi_dev: \u0026napi_struct for NAPI (data) queues, \u0026device for others\n *\n * Return: %0 on success, -%errno on failure.\n */\n-int libeth_rx_fq_create(struct libeth_fq *fq, struct napi_struct *napi)\n+int libeth_rx_fq_create(struct libeth_fq *fq, void *napi_dev)\n {\n+\tstruct napi_struct *napi = fq-\u003eno_napi ? NULL : napi_dev;\n \tstruct page_pool_params pp = {\n \t\t.flags\t\t= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,\n \t\t.order\t\t= LIBETH_RX_PAGE_ORDER,\n \t\t.pool_size\t= fq-\u003ecount,\n \t\t.nid\t\t= fq-\u003enid,\n-\t\t.dev\t\t= napi-\u003edev-\u003edev.parent,\n-\t\t.netdev\t\t= napi-\u003edev,\n+\t\t.dev\t\t= napi ? napi-\u003edev-\u003edev.parent : napi_dev,\n+\t\t.netdev\t\t= napi ? napi-\u003edev : NULL,\n \t\t.napi\t\t= napi,\n \t};\n \tstruct libeth_fqe *fqes;\n \tstruct page_pool *pool;\n \tint ret;\n \n+\tif (!pp.netdev \u0026\u0026 fq-\u003etype == LIBETH_FQE_MTU)\n+\t\treturn -EINVAL;\n+\n \tpp.dma_dir = fq-\u003exdp ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;\n \n \tif (!fq-\u003ehsplit)\ndiff --git a/drivers/net/ethernet/intel/libie/Kconfig b/drivers/net/ethernet/intel/libie/Kconfig\nindex 70831c7e336e9..9c5fdebb67668 100644\n--- a/drivers/net/ethernet/intel/libie/Kconfig\n+++ b/drivers/net/ethernet/intel/libie/Kconfig\n@@ -15,6 +15,14 @@ config LIBIE_ADMINQ\n \t Helper functions used by Intel Ethernet drivers for administration\n \t queue command interface (aka adminq).\n \n+config LIBIE_CP\n+\ttristate\n+\tselect LIBETH\n+\tselect LIBIE_PCI\n+\thelp\n+\t Common helper routines to communicate with the device Control Plane\n+\t using virtchnl2 or related mailbox protocols.\n+\n config LIBIE_FWLOG\n \ttristate\n \tselect LIBIE_ADMINQ\n@@ -23,3 +31,9 @@ config LIBIE_FWLOG\n \t for it. Firmware logging is using admin queue interface to communicate\n \t with the device. Debugfs is a user interface used to config logging\n \t and dump all collected logs.\n+\n+config LIBIE_PCI\n+\ttristate\n+\thelp\n+\t Helper functions for management of PCI resources belonging\n+\t to networking devices.\ndiff --git a/drivers/net/ethernet/intel/libie/Makefile b/drivers/net/ethernet/intel/libie/Makefile\nindex db57fc6780ea3..3065aa057798c 100644\n--- a/drivers/net/ethernet/intel/libie/Makefile\n+++ b/drivers/net/ethernet/intel/libie/Makefile\n@@ -9,6 +9,14 @@ obj-$(CONFIG_LIBIE_ADMINQ) \t+= libie_adminq.o\n \n libie_adminq-y\t\t\t:= adminq.o\n \n+obj-$(CONFIG_LIBIE_CP)\t\t+= libie_cp.o\n+\n+libie_cp-y\t\t\t:= controlq.o\n+\n obj-$(CONFIG_LIBIE_FWLOG) \t+= libie_fwlog.o\n \n libie_fwlog-y\t\t\t:= fwlog.o\n+\n+obj-$(CONFIG_LIBIE_PCI)\t\t+= libie_pci.o\n+\n+libie_pci-y\t\t\t:= pci.o\ndiff --git a/drivers/net/ethernet/intel/libie/controlq.c b/drivers/net/ethernet/intel/libie/controlq.c\nnew file mode 100644\nindex 0000000000000..45a49eba6a820\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/libie/controlq.c\n@@ -0,0 +1,1295 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/* Copyright (C) 2025 Intel Corporation */\n+\n+#include \u003clinux/bitfield.h\u003e\n+#include \u003cnet/libeth/rx.h\u003e\n+\n+#include \u003clinux/net/intel/libie/controlq.h\u003e\n+\n+#define LIBIE_CTLQ_DESC_QWORD0(sz)\t\t\t\\\n+\t(LIBIE_CTLQ_DESC_FLAG_BUF |\t\t\t\\\n+\t LIBIE_CTLQ_DESC_FLAG_RD |\t\t\t\\\n+\t FIELD_PREP(LIBIE_CTLQ_DESC_DATA_LEN, sz))\n+\n+/**\n+ * libie_ctlq_free_fq - free fill queue resources, including buffers\n+ * @ctlq: Rx control queue whose resources need to be freed\n+ */\n+static void libie_ctlq_free_fq(struct libie_ctlq_info *ctlq)\n+{\n+\tstruct libeth_fq fq = {\n+\t\t.fqes\t\t= ctlq-\u003erx_fqes,\n+\t\t.pp\t\t= ctlq-\u003epp,\n+\t};\n+\n+\tfor (u32 ntc = ctlq-\u003enext_to_clean; ntc != ctlq-\u003enext_to_post; ) {\n+\t\tpage_pool_put_full_netmem(fq.pp, fq.fqes[ntc].netmem, false);\n+\n+\t\tif (++ntc \u003e= ctlq-\u003ering_len)\n+\t\t\tntc = 0;\n+\t}\n+\n+\tlibeth_rx_fq_destroy(\u0026fq);\n+}\n+\n+/**\n+ * libie_ctlq_init_fq - initialize fill queue for an Rx controlq\n+ * @ctlq: control queue that needs Rx buffer allocation\n+ *\n+ * Return: %0 on success, -%errno on failure\n+ */\n+static int libie_ctlq_init_fq(struct libie_ctlq_info *ctlq)\n+{\n+\tstruct libeth_fq fq = {\n+\t\t.count\t\t= ctlq-\u003ering_len,\n+\t\t.truesize\t= LIBIE_CTLQ_MAX_BUF_LEN,\n+\t\t.nid\t\t= NUMA_NO_NODE,\n+\t\t.type\t\t= LIBETH_FQE_SHORT,\n+\t\t.hsplit\t\t= true,\n+\t\t.no_napi\t= true,\n+\t};\n+\tint err;\n+\n+\terr = libeth_rx_fq_create(\u0026fq, ctlq-\u003edev);\n+\tif (err)\n+\t\treturn err;\n+\n+\tctlq-\u003epp = fq.pp;\n+\tctlq-\u003erx_fqes = fq.fqes;\n+\tctlq-\u003etruesize = fq.truesize;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * libie_ctlq_prep_rx_desc - prepare the descriptor with a new address\n+ * @desc: descriptor to (re)initialize\n+ * @addr: physical address to put into descriptor\n+ * @mem_truesize: size of the accessible memory\n+ */\n+static void libie_ctlq_prep_rx_desc(struct libie_ctlq_desc *desc,\n+\t\t\t\t dma_addr_t addr, u32 mem_truesize)\n+{\n+\tu64 qword;\n+\n+\tqword = LIBIE_CTLQ_DESC_QWORD0(mem_truesize);\n+\tdesc-\u003eqword0 = cpu_to_le64(qword);\n+\n+\tqword = FIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_HIGH,\n+\t\t\t upper_32_bits(addr)) |\n+\t\tFIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_LOW,\n+\t\t\t lower_32_bits(addr));\n+\tdesc-\u003eqword3 = cpu_to_le64(qword);\n+}\n+\n+/**\n+ * libie_ctlq_post_rx_buffs - post buffers to descriptor ring\n+ * @ctlq: control queue that requires Rx descriptor ring to be initialized with\n+ *\t new Rx buffers\n+ *\n+ * The caller must make sure that calls to libie_ctlq_post_rx_buffs()\n+ * and libie_ctlq_recv() for each queue are either serialized\n+ * or used under ctlq-\u003elock.\n+ *\n+ * Return: %0 on success, -%ENOMEM if any buffer could not be allocated\n+ */\n+int libie_ctlq_post_rx_buffs(struct libie_ctlq_info *ctlq)\n+{\n+\tu32 ntp = ctlq-\u003enext_to_post, ntc = ctlq-\u003enext_to_clean, num_to_post;\n+\tconst struct libeth_fq_fp fq = {\n+\t\t.pp\t\t= ctlq-\u003epp,\n+\t\t.fqes\t\t= ctlq-\u003erx_fqes,\n+\t\t.truesize\t= ctlq-\u003etruesize,\n+\t\t.count\t\t= ctlq-\u003ering_len,\n+\t};\n+\tint ret = 0;\n+\n+\tnum_to_post = (ntc \u003e ntp ? 0 : ctlq-\u003ering_len) + ntc - ntp - 1;\n+\n+\twhile (num_to_post--) {\n+\t\tdma_addr_t addr;\n+\n+\t\tctlq-\u003edescs[ntp] = (struct libie_ctlq_desc) {};\n+\n+\t\taddr = libeth_rx_alloc(\u0026fq, ntp);\n+\t\tif (unlikely(addr == DMA_MAPPING_ERROR)) {\n+\t\t\tret = -ENOMEM;\n+\t\t\tgoto post_bufs;\n+\t\t}\n+\n+\t\tlibie_ctlq_prep_rx_desc(\u0026ctlq-\u003edescs[ntp], addr, fq.truesize);\n+\n+\t\tif (unlikely(++ntp == ctlq-\u003ering_len))\n+\t\t\tntp = 0;\n+\t}\n+\n+post_bufs:\n+\tif (likely(ctlq-\u003enext_to_post != ntp)) {\n+\t\tctlq-\u003enext_to_post = ntp;\n+\n+\t\tdma_wmb();\n+\t\twritel(ntp, ctlq-\u003ereg.tail);\n+\t}\n+\n+\treturn ret;\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_ctlq_post_rx_buffs, \"LIBIE_CP\");\n+\n+/**\n+ * libie_ctlq_free_tx_msgs - Free Tx control queue messages\n+ * @ctlq: Tx control queue being destroyed\n+ * @num_msgs: number of messages allocated so far\n+ */\n+static void libie_ctlq_free_tx_msgs(struct libie_ctlq_info *ctlq,\n+\t\t\t\t u32 num_msgs)\n+{\n+\tfor (u32 i = 0; i \u003c num_msgs; i++)\n+\t\tkfree(ctlq-\u003etx_msg[i]);\n+\n+\tkvfree(ctlq-\u003etx_msg);\n+}\n+\n+/**\n+ * libie_ctlq_alloc_tx_msgs - Allocate Tx control queue messages\n+ * @ctlq: Tx control queue being created\n+ *\n+ * Return: %0 on success, -%ENOMEM on allocation error\n+ */\n+static int libie_ctlq_alloc_tx_msgs(struct libie_ctlq_info *ctlq)\n+{\n+\tctlq-\u003etx_msg = kvzalloc_objs(*ctlq-\u003etx_msg, ctlq-\u003ering_len,\n+\t\t\t\t GFP_KERNEL);\n+\tif (!ctlq-\u003etx_msg)\n+\t\treturn -ENOMEM;\n+\n+\tfor (u32 i = 0; i \u003c ctlq-\u003ering_len; i++) {\n+\t\tctlq-\u003etx_msg[i] = kzalloc_obj(*ctlq-\u003etx_msg[i]);\n+\t\tif (!ctlq-\u003etx_msg[i]) {\n+\t\t\tlibie_ctlq_free_tx_msgs(ctlq, i);\n+\t\t\treturn -ENOMEM;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * libie_cp_free_desc_mem - free the previously allocated descriptor DMA memory\n+ * @dev: device information\n+ * @mem: DMA memory information\n+ */\n+static void libie_cp_free_desc_mem(struct device *dev,\n+\t\t\t\t struct libie_cp_dma_mem *mem)\n+{\n+\tdma_free_coherent(dev, mem-\u003esize, mem-\u003eva, mem-\u003epa);\n+\tmem-\u003eva = NULL;\n+}\n+\n+/**\n+ * libie_ctlq_dealloc_ring_res - free memory allocated for control queue\n+ * @ctlq: control queue that requires its ring memory to be freed\n+ *\n+ * Free the memory used by the ring, buffers and other related structures.\n+ */\n+static void libie_ctlq_dealloc_ring_res(struct libie_ctlq_info *ctlq)\n+{\n+\tstruct libie_cp_dma_mem *dma = \u0026ctlq-\u003ering_mem;\n+\n+\tif (ctlq-\u003etype == LIBIE_CTLQ_TYPE_TX)\n+\t\tlibie_ctlq_free_tx_msgs(ctlq, ctlq-\u003ering_len);\n+\telse\n+\t\tlibie_ctlq_free_fq(ctlq);\n+\n+\tlibie_cp_free_desc_mem(ctlq-\u003edev, dma);\n+}\n+\n+/**\n+ * libie_cp_alloc_desc_mem - allocate DMA memory for descriptor ring\n+ * @dev: device information\n+ * @mem: memory for DMA information to be stored\n+ * @size: size of the memory to allocate\n+ *\n+ * Return: virtual address of DMA memory or NULL.\n+ */\n+static void *libie_cp_alloc_desc_mem(struct device *dev,\n+\t\t\t\t struct libie_cp_dma_mem *mem, u32 size)\n+{\n+\tsize = LARGEST_ALIGN(size);\n+\n+\tmem-\u003eva = dma_alloc_coherent(dev, size, \u0026mem-\u003epa, GFP_KERNEL);\n+\tmem-\u003esize = size;\n+\tmem-\u003edirection = DMA_BIDIRECTIONAL;\n+\n+\treturn mem-\u003eva;\n+}\n+\n+/**\n+ * libie_ctlq_alloc_queue_res - allocate memory for descriptor ring and bufs\n+ * @ctlq: control queue that requires its ring resources to be allocated\n+ *\n+ * Return: %0 on success, -%errno on failure\n+ */\n+static int libie_ctlq_alloc_queue_res(struct libie_ctlq_info *ctlq)\n+{\n+\tsize_t size = array_size(ctlq-\u003ering_len, sizeof(*ctlq-\u003edescs));\n+\tstruct libie_cp_dma_mem *dma = \u0026ctlq-\u003ering_mem;\n+\tint err = -ENOMEM;\n+\n+\tif (!libie_cp_alloc_desc_mem(ctlq-\u003edev, dma, size))\n+\t\treturn -ENOMEM;\n+\n+\tctlq-\u003edescs = dma-\u003eva;\n+\n+\tif (ctlq-\u003etype == LIBIE_CTLQ_TYPE_TX) {\n+\t\tif (libie_ctlq_alloc_tx_msgs(ctlq))\n+\t\t\tgoto free_dma_mem;\n+\t} else {\n+\t\terr = libie_ctlq_init_fq(ctlq);\n+\t\tif (err)\n+\t\t\tgoto free_dma_mem;\n+\n+\t\terr = libie_ctlq_post_rx_buffs(ctlq);\n+\t\tif (err) {\n+\t\t\tlibie_ctlq_free_fq(ctlq);\n+\t\t\tgoto free_dma_mem;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+\n+free_dma_mem:\n+\tlibie_cp_free_desc_mem(ctlq-\u003edev, dma);\n+\n+\treturn err;\n+}\n+\n+/**\n+ * libie_ctlq_init_regs - Initialize control queue registers\n+ * @ctlq: control queue that needs to be initialized\n+ *\n+ * Initialize registers. The caller is expected to have already initialized the\n+ * descriptor ring memory and buffer memory.\n+ */\n+static void libie_ctlq_init_regs(struct libie_ctlq_info *ctlq)\n+{\n+\tu32 dword;\n+\n+\tif (ctlq-\u003etype == LIBIE_CTLQ_TYPE_RX)\n+\t\twritel(ctlq-\u003ering_len - 1, ctlq-\u003ereg.tail);\n+\telse\n+\t\twritel(0, ctlq-\u003ereg.tail);\n+\n+\twritel(0, ctlq-\u003ereg.head);\n+\twritel(lower_32_bits(ctlq-\u003ering_mem.pa), ctlq-\u003ereg.addr_low);\n+\twritel(upper_32_bits(ctlq-\u003ering_mem.pa), ctlq-\u003ereg.addr_high);\n+\n+\tdword = FIELD_PREP(LIBIE_CTLQ_MBX_ATQ_LEN, ctlq-\u003ering_len) |\n+\t\tctlq-\u003ereg.len_ena_mask;\n+\twritel(dword, ctlq-\u003ereg.len);\n+}\n+\n+/**\n+ * libie_find_ctlq - find the controlq for the given id and type\n+ * @ctx: libie CP context information\n+ * @type: type of controlq to find\n+ * @id: controlq id to find\n+ *\n+ * Return: control queue info pointer on success, NULL on failure\n+ */\n+struct libie_ctlq_info *libie_find_ctlq(struct libie_ctlq_ctx *ctx,\n+\t\t\t\t\tenum libie_ctlq_type type,\n+\t\t\t\t\tint id)\n+{\n+\tstruct libie_ctlq_info *cq;\n+\n+\tguard(spinlock)(\u0026ctx-\u003ectlqs_lock);\n+\n+\tlist_for_each_entry(cq, \u0026ctx-\u003ectlqs, list)\n+\t\tif (cq-\u003eqid == id \u0026\u0026 cq-\u003etype == type)\n+\t\t\treturn cq;\n+\n+\treturn NULL;\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_find_ctlq, \"LIBIE_CP\");\n+\n+/**\n+ * libie_ctlq_add - add one control queue\n+ * @ctx: libie CP context information\n+ * @qinfo: information required for queue creation\n+ *\n+ * Allocate and initialize a control queue and add it to the control queue list.\n+ * libie_ctlq_init() must be called prior to any calls to libie_ctlq_add.\n+ *\n+ * Return: added control queue info pointer on success, error pointer on failure\n+ */\n+static struct libie_ctlq_info *\n+libie_ctlq_add(struct libie_ctlq_ctx *ctx,\n+\t const struct libie_ctlq_create_info *qinfo)\n+{\n+\tstruct libie_ctlq_info *ctlq;\n+\tint err;\n+\n+\tif (qinfo-\u003eid != LIBIE_CTLQ_MBX_ID)\n+\t\treturn ERR_PTR(-EOPNOTSUPP);\n+\n+\tif (qinfo-\u003elen \u003e FIELD_MAX(LIBIE_CTLQ_MBX_ATQ_LEN) || !qinfo-\u003elen)\n+\t\treturn ERR_PTR(-EINVAL);\n+\n+\tctlq = kvzalloc_obj(*ctlq);\n+\tif (!ctlq)\n+\t\treturn ERR_PTR(-ENOMEM);\n+\n+\tctlq-\u003etype = qinfo-\u003etype;\n+\tctlq-\u003eqid = qinfo-\u003eid;\n+\tctlq-\u003ering_len = qinfo-\u003elen;\n+\tctlq-\u003edev = \u0026ctx-\u003emmio_info.pdev-\u003edev;\n+\tctlq-\u003ereg = qinfo-\u003ereg;\n+\n+\terr = libie_ctlq_alloc_queue_res(ctlq);\n+\tif (err) {\n+\t\tkvfree(ctlq);\n+\t\treturn ERR_PTR(err);\n+\t}\n+\n+\tlibie_ctlq_init_regs(ctlq);\n+\n+\tspin_lock_init(\u0026ctlq-\u003elock);\n+\n+\tscoped_guard(spinlock, \u0026ctx-\u003ectlqs_lock)\n+\t\tlist_add(\u0026ctlq-\u003elist, \u0026ctx-\u003ectlqs);\n+\n+\treturn ctlq;\n+}\n+\n+/**\n+ * libie_ctlq_remove - deallocate and remove specified control queue\n+ * @ctx: libie CP context information\n+ * @ctlq: specific control queue that needs to be removed\n+ */\n+static void libie_ctlq_remove(struct libie_ctlq_ctx *ctx,\n+\t\t\t struct libie_ctlq_info *ctlq)\n+{\n+\tscoped_guard(spinlock, \u0026ctx-\u003ectlqs_lock)\n+\t\tlist_del(\u0026ctlq-\u003elist);\n+\n+\tlibie_ctlq_dealloc_ring_res(ctlq);\n+\tkvfree(ctlq);\n+}\n+\n+/**\n+ * libie_ctlq_init - main initialization routine for all control queues\n+ * @ctx: libie CP context information\n+ * @qinfo: array of structs containing info for each queue to be initialized\n+ * @numq: number of queues to initialize\n+ *\n+ * This initializes queue list and adds any number and any type of control\n+ * queues. This is an all or nothing routine; if one fails, all previously\n+ * allocated queues will be destroyed.\n+ *\n+ * Please note that any control queue send/receive functions are not\n+ * softirq/NAPI safe, and therefore API can be used in process context only.\n+ *\n+ * Return: %0 on success, -%errno on failure\n+ */\n+int libie_ctlq_init(struct libie_ctlq_ctx *ctx,\n+\t\t const struct libie_ctlq_create_info *qinfo,\n+\t\t u32 numq)\n+{\n+\tINIT_LIST_HEAD(\u0026ctx-\u003ectlqs);\n+\tspin_lock_init(\u0026ctx-\u003ectlqs_lock);\n+\n+\tfor (u32 i = 0; i \u003c numq; i++) {\n+\t\tstruct libie_ctlq_info *ctlq;\n+\n+\t\tctlq = libie_ctlq_add(ctx, \u0026qinfo[i]);\n+\t\tif (IS_ERR(ctlq)) {\n+\t\t\tlibie_ctlq_deinit(ctx);\n+\t\t\treturn PTR_ERR(ctlq);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_ctlq_init, \"LIBIE_CP\");\n+\n+/**\n+ * libie_ctlq_deinit - destroy all control queues\n+ * @ctx: libie CP context information\n+ */\n+void libie_ctlq_deinit(struct libie_ctlq_ctx *ctx)\n+{\n+\tstruct libie_ctlq_info *ctlq, *tmp;\n+\n+\tlist_for_each_entry_safe(ctlq, tmp, \u0026ctx-\u003ectlqs, list)\n+\t\tlibie_ctlq_remove(ctx, ctlq);\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_ctlq_deinit, \"LIBIE_CP\");\n+\n+/**\n+ * libie_ctlq_tx_desc_from_msg - initialize a Tx descriptor from a message\n+ * @desc: descriptor to be initialized\n+ * @msg: filled control queue message\n+ */\n+static void libie_ctlq_tx_desc_from_msg(struct libie_ctlq_desc *desc,\n+\t\t\t\t\tconst struct libie_ctlq_msg *msg)\n+{\n+\tconst struct libie_cp_dma_mem *dma = \u0026msg-\u003esend_mem;\n+\tu64 qword;\n+\n+\tqword = FIELD_PREP(LIBIE_CTLQ_DESC_FLAGS, msg-\u003eflags) |\n+\t\tFIELD_PREP(LIBIE_CTLQ_DESC_INFRA_OPCODE, msg-\u003eopcode) |\n+\t\tFIELD_PREP(LIBIE_CTLQ_DESC_PFID_VFID, msg-\u003efunc_id);\n+\tdesc-\u003eqword0 = cpu_to_le64(qword);\n+\n+\tqword = FIELD_PREP(LIBIE_CTLQ_DESC_VIRTCHNL_OPCODE,\n+\t\t\t msg-\u003echnl_opcode) |\n+\t\tFIELD_PREP(LIBIE_CTLQ_DESC_VIRTCHNL_MSG_RET_VAL,\n+\t\t\t msg-\u003echnl_retval);\n+\tdesc-\u003eqword1 = cpu_to_le64(qword);\n+\n+\tqword = FIELD_PREP(LIBIE_CTLQ_DESC_MSG_PARAM0, msg-\u003eparam0) |\n+\t\tFIELD_PREP(LIBIE_CTLQ_DESC_SW_COOKIE,\n+\t\t\t msg-\u003esw_cookie) |\n+\t\tFIELD_PREP(LIBIE_CTLQ_DESC_VIRTCHNL_FLAGS,\n+\t\t\t msg-\u003evirt_flags);\n+\tdesc-\u003eqword2 = cpu_to_le64(qword);\n+\n+\tif (likely(msg-\u003edata_len)) {\n+\t\tdesc-\u003eqword0 |=\n+\t\t\tcpu_to_le64(LIBIE_CTLQ_DESC_QWORD0(msg-\u003edata_len));\n+\t\tqword = FIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_HIGH,\n+\t\t\t\t upper_32_bits(dma-\u003epa)) |\n+\t\t\tFIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_LOW,\n+\t\t\t\t lower_32_bits(dma-\u003epa));\n+\t} else {\n+\t\tqword = msg-\u003eaddr_param;\n+\t}\n+\n+\tdesc-\u003eqword3 = cpu_to_le64(qword);\n+}\n+\n+/**\n+ * libie_ctlq_send_desc_avail - get number of free descriptors on a Tx ctlq\n+ * @ctlq: specific control queue which is going be used for sending messages\n+ *\n+ * The caller must hold ctlq-\u003elock. Any dependent sending must be done\n+ * in the same critical section.\n+ *\n+ * Return: number of available descriptors/messages on a given control queue.\n+ */\n+u32 libie_ctlq_send_desc_avail(const struct libie_ctlq_info *ctlq)\n+{\n+\tu32 ntu = ctlq-\u003enext_to_use, ntc = ctlq-\u003enext_to_clean;\n+\n+\tlockdep_assert_held(\u0026ctlq-\u003elock);\n+\n+\treturn (ntc \u003e ntu ? 0 : ctlq-\u003ering_len) + ntc - ntu - 1;\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_ctlq_send_desc_avail, \"LIBIE_CP\");\n+\n+/**\n+ * libie_ctlq_send - send a message to Control Plane or Peer\n+ * @ctlq: specific control queue which is used for sending a message\n+ * @num_q_msg: number of messages present to send on @ctlq,\n+ *\t positive and no greater than the number of available descriptors\n+ *\n+ * The caller must fill in @num_q_msg Tx messages starting at ntu beforehand.\n+ *\n+ * The caller must hold ctlq-\u003elock. The intended pattern is to first check\n+ * the number of descriptors available, then fill in the messages and perform\n+ * send within a single critical section.\n+ */\n+void libie_ctlq_send(struct libie_ctlq_info *ctlq, u32 num_q_msg)\n+{\n+\tu32 ntu = ctlq-\u003enext_to_use;\n+\n+\tlockdep_assert_held(\u0026ctlq-\u003elock);\n+\n+\tfor (int i = 0; i \u003c num_q_msg; i++) {\n+\t\tstruct libie_ctlq_msg *msg = ctlq-\u003etx_msg[ntu];\n+\t\tstruct libie_ctlq_desc *desc;\n+\n+\t\tdesc = \u0026ctlq-\u003edescs[ntu];\n+\t\tlibie_ctlq_tx_desc_from_msg(desc, msg);\n+\n+\t\tif (unlikely(++ntu == ctlq-\u003ering_len))\n+\t\t\tntu = 0;\n+\t}\n+\tdma_wmb();\n+\twritel(ntu, ctlq-\u003ereg.tail);\n+\tctlq-\u003enext_to_use = ntu;\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_ctlq_send, \"LIBIE_CP\");\n+\n+/**\n+ * libie_ctlq_send_clean - cleanup the send control queue message buffers\n+ * @params: information for handling of Tx completions\n+ *\n+ * Cleanup the send buffers for the given control queue, if force is set, then\n+ * clear all the outstanding send messages irrespective of their send status,\n+ * until a zero-length message is encountered, which is either a message that\n+ * is already cleared, or a VF reset message, which is always last.\n+ * Force should be used during deinit or reset.\n+ *\n+ * Return: number of send buffers cleaned.\n+ */\n+u32 libie_ctlq_send_clean(const struct libie_ctlq_clean_params *params)\n+{\n+\tstruct libie_ctlq_info *ctlq = params-\u003ectlq;\n+\tu32 ntc, i;\n+\n+\tspin_lock(\u0026ctlq-\u003elock);\n+\tntc = ctlq-\u003enext_to_clean;\n+\n+\tfor (i = 0; i \u003c params-\u003enum_msgs; i++) {\n+\t\tstruct libie_ctlq_msg *msg = ctlq-\u003etx_msg[ntc];\n+\t\tstruct libie_ctlq_desc *desc;\n+\t\tu64 qword;\n+\n+\t\tdesc = \u0026ctlq-\u003edescs[ntc];\n+\t\tqword = le64_to_cpu(desc-\u003eqword0);\n+\n+\t\tif (!FIELD_GET(LIBIE_CTLQ_DESC_FLAG_DD, qword) \u0026\u0026\n+\t\t !(unlikely(params-\u003eforce) \u0026\u0026 msg-\u003edata_len))\n+\t\t\tbreak;\n+\n+\t\t/* This cannot be reordered and lock is taken, so no barriers */\n+\t\tdesc-\u003eqword0 = 0;\n+\n+\t\tparams-\u003erel_dma_mem(params-\u003erel_ctx, \u0026msg-\u003esend_mem);\n+\t\tmemset(msg, 0, sizeof(*msg));\n+\n+\t\tif (unlikely(++ntc == ctlq-\u003ering_len))\n+\t\t\tntc = 0;\n+\t}\n+\n+\tctlq-\u003enext_to_clean = ntc;\n+\tspin_unlock(\u0026ctlq-\u003elock);\n+\n+\treturn i;\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_ctlq_send_clean, \"LIBIE_CP\");\n+\n+/**\n+ * libie_ctlq_fill_rx_msg - fill in a message from Rx descriptor and buffer\n+ * @msg: message to be filled in\n+ * @desc: received descriptor\n+ * @rx_buf: fill queue buffer associated with the descriptor\n+ */\n+static void libie_ctlq_fill_rx_msg(struct libie_ctlq_msg *msg,\n+\t\t\t\t const struct libie_ctlq_desc *desc,\n+\t\t\t\t struct libeth_fqe *rx_buf)\n+{\n+\tu64 qword = le64_to_cpu(desc-\u003eqword0);\n+\n+\tmsg-\u003eflags = FIELD_GET(LIBIE_CTLQ_DESC_FLAGS, qword);\n+\tmsg-\u003eopcode = FIELD_GET(LIBIE_CTLQ_DESC_INFRA_OPCODE, qword);\n+\tmsg-\u003edata_len = FIELD_GET(LIBIE_CTLQ_DESC_DATA_LEN, qword);\n+\tmsg-\u003ehw_retval = FIELD_GET(LIBIE_CTLQ_DESC_HW_RETVAL, qword);\n+\n+\tqword = le64_to_cpu(desc-\u003eqword1);\n+\tmsg-\u003echnl_opcode =\n+\t\tFIELD_GET(LIBIE_CTLQ_DESC_VIRTCHNL_OPCODE, qword);\n+\tmsg-\u003echnl_retval =\n+\t\tFIELD_GET(LIBIE_CTLQ_DESC_VIRTCHNL_MSG_RET_VAL, qword);\n+\n+\tqword = le64_to_cpu(desc-\u003eqword2);\n+\tmsg-\u003eparam0 =\n+\t\tFIELD_GET(LIBIE_CTLQ_DESC_MSG_PARAM0, qword);\n+\tmsg-\u003esw_cookie =\n+\t\tFIELD_GET(LIBIE_CTLQ_DESC_SW_COOKIE, qword);\n+\tmsg-\u003evirt_flags =\n+\t\tFIELD_GET(LIBIE_CTLQ_DESC_VIRTCHNL_FLAGS, qword);\n+\n+\tif (likely(msg-\u003edata_len)) {\n+\t\tif (unlikely(msg-\u003edata_len \u003e LIBIE_CTLQ_MAX_BUF_LEN)) {\n+\t\t\tmsg-\u003edata_len = LIBIE_CTLQ_MAX_BUF_LEN;\n+\t\t\tmsg-\u003echnl_retval = U32_MAX;\n+\t\t}\n+\t\tmsg-\u003erecv_mem = (struct kvec) {\n+\t\t\t.iov_base = netmem_address(rx_buf-\u003enetmem) +\n+\t\t\t\t rx_buf-\u003eoffset,\n+\t\t\t.iov_len = msg-\u003edata_len,\n+\t\t};\n+\t\tlibeth_rx_sync_for_cpu(rx_buf, msg-\u003edata_len);\n+\t} else {\n+\t\tmsg-\u003erecv_mem = (struct kvec) {};\n+\t\tmsg-\u003eaddr_param = le64_to_cpu(desc-\u003eqword3);\n+\t\tpage_pool_put_full_netmem(netmem_get_pp(rx_buf-\u003enetmem),\n+\t\t\t\t\t rx_buf-\u003enetmem, false);\n+\t}\n+}\n+\n+/**\n+ * libie_ctlq_recv - receive control queue messages\n+ * @ctlq: control queue that needs to processed for receive\n+ * @msg: array of received control queue messages on this q;\n+ *\t needs to be pre-allocated by caller for as many messages as requested\n+ * @num_q_msg: number of messages that can be stored in msg buffer,\n+ *\t no greater than number of posted buffers\n+ *\n+ * Caller is expected to return buffers via libie_ctlq_release_rx_buf().\n+ *\n+ * The caller must make sure that calls to libie_ctlq_post_rx_buffs()\n+ * and libie_ctlq_recv() for each queue are either serialized\n+ * or used under ctlq-\u003elock.\n+ *\n+ * Return: number of messages received\n+ */\n+u32 libie_ctlq_recv(struct libie_ctlq_info *ctlq, struct libie_ctlq_msg *msg,\n+\t\t u32 num_q_msg)\n+{\n+\tu32 ntc, i;\n+\n+\tntc = ctlq-\u003enext_to_clean;\n+\n+\tfor (i = 0; i \u003c num_q_msg; i++) {\n+\t\tstruct libie_ctlq_desc *desc = \u0026ctlq-\u003edescs[ntc];\n+\t\tstruct libeth_fqe *rx_buf = \u0026ctlq-\u003erx_fqes[ntc];\n+\t\tu64 qword;\n+\n+\t\tqword = le64_to_cpu(desc-\u003eqword0);\n+\t\tif (!FIELD_GET(LIBIE_CTLQ_DESC_FLAG_DD, qword))\n+\t\t\tbreak;\n+\n+\t\tdma_rmb();\n+\n+\t\tlibie_ctlq_fill_rx_msg(\u0026msg[i], desc, rx_buf);\n+\t\tdesc-\u003eqword0 = 0;\n+\n+\t\tif (unlikely(++ntc == ctlq-\u003ering_len))\n+\t\t\tntc = 0;\n+\t}\n+\n+\tctlq-\u003enext_to_clean = ntc;\n+\n+\treturn i;\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_ctlq_recv, \"LIBIE_CP\");\n+\n+/**\n+ * libie_ctlq_xn_pop_free - get a free Xn entry from the free list\n+ * @xnm: Xn transaction manager\n+ *\n+ * Retrieve a free Xn entry from the free list.\n+ *\n+ * Return: valid Xn entry pointer or NULL if there are no free Xn entries.\n+ */\n+static struct libie_ctlq_xn *\n+libie_ctlq_xn_pop_free(struct libie_ctlq_xn_manager *xnm)\n+{\n+\tstruct libie_ctlq_xn *xn;\n+\tu32 free_idx;\n+\n+\tguard(spinlock)(\u0026xnm-\u003efree_xns_bm_lock);\n+\n+\tif (unlikely(xnm-\u003eshutdown))\n+\t\treturn NULL;\n+\n+\tfor_each_set_bit(free_idx, xnm-\u003efree_xns_bm,\n+\t\t\t LIBIE_CTLQ_MAX_XN_ENTRIES) {\n+\t\txn = \u0026xnm-\u003ering[free_idx];\n+\n+\t\t/* Torn read of the physical address is possible, the worst case\n+\t\t * scenario is a transient spurious skip. If the physical\n+\t\t * address is dirty in any way, reuse is already safe.\n+\t\t */\n+\t\tif (xn-\u003etx_msg \u0026\u0026\n+\t\t data_race(xn-\u003etx_msg-\u003esend_mem.pa) == xn-\u003esmall_dma_mem.pa)\n+\t\t\tcontinue;\n+\n+\t\tclear_bit(free_idx, xnm-\u003efree_xns_bm);\n+\n+\t\treturn xn;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+/**\n+ * __libie_ctlq_xn_push_free - unsafely push an xn entry into the free list\n+ * @xnm: Xn transaction manager\n+ * @xn: xn entry to be added into the free list\n+ *\n+ * Return: whether xnm destruction can be triggered by the caller\n+ */\n+static bool __libie_ctlq_xn_push_free(struct libie_ctlq_xn_manager *xnm,\n+\t\t\t\t struct libie_ctlq_xn *xn)\n+{\n+\txn-\u003ecookie++;\n+\tset_bit(xn-\u003eindex, xnm-\u003efree_xns_bm);\n+\n+\tif (unlikely(xnm-\u003eshutdown) \u0026\u0026\n+\t bitmap_full(xnm-\u003efree_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES))\n+\t\treturn true;\n+\n+\treturn false;\n+}\n+\n+/**\n+ * libie_ctlq_xn_push_free - push a Xn entry into the free list\n+ * @xnm: Xn transaction manager\n+ * @xn: xn entry to be added into the free list, not locked\n+ *\n+ * Safely add a used Xn entry back to the free list.\n+ */\n+static void libie_ctlq_xn_push_free(struct libie_ctlq_xn_manager *xnm,\n+\t\t\t\t struct libie_ctlq_xn *xn)\n+{\n+\tbool can_destroy;\n+\n+\tscoped_guard(spinlock, \u0026xnm-\u003efree_xns_bm_lock)\n+\t\tcan_destroy = __libie_ctlq_xn_push_free(xnm, xn);\n+\n+\tif (can_destroy)\n+\t\tcomplete(\u0026xnm-\u003ecan_destroy);\n+}\n+\n+/**\n+ * libie_ctlq_xn_deinit_dma - free the DMA memory allocated for send messages\n+ * @xnm: pointer to the transaction manager\n+ * @num_entries: number of Xn entries to free the DMA for\n+ */\n+static void libie_ctlq_xn_deinit_dma(struct libie_ctlq_xn_manager *xnm,\n+\t\t\t\t u32 num_entries)\n+{\n+\tfor (u32 i = 0; i \u003c num_entries; i++) {\n+\t\tstruct libie_ctlq_xn *xn = \u0026xnm-\u003ering[i];\n+\n+\t\tdma_pool_free(xnm-\u003esmall_buff_pool, xn-\u003esmall_dma_mem.va,\n+\t\t\t xn-\u003esmall_dma_mem.pa);\n+\t}\n+\n+\tdma_pool_destroy(xnm-\u003esmall_buff_pool);\n+}\n+\n+/**\n+ * libie_ctlq_xn_init_dma - pre-allocate DMA memory for send messages that use\n+ * stack variables\n+ * @dev: device pointer\n+ * @xnm: pointer to transaction manager\n+ *\n+ * Return: %0 on success or error if memory allocation fails\n+ */\n+static int libie_ctlq_xn_init_dma(struct device *dev,\n+\t\t\t\t struct libie_ctlq_xn_manager *xnm)\n+{\n+\tu32 i;\n+\n+\txnm-\u003esmall_buff_pool =\n+\t\tdma_pool_create(\"libie_ctlq_xn_tx\", dev, LIBIE_CP_TX_COPYBREAK,\n+\t\t\t\tLIBIE_CP_TX_COPYBREAK, 0);\n+\tif (!xnm-\u003esmall_buff_pool)\n+\t\treturn -ENOMEM;\n+\n+\tfor (i = 0; i \u003c LIBIE_CTLQ_MAX_XN_ENTRIES; i++) {\n+\t\tstruct libie_cp_dma_mem *mem = \u0026xnm-\u003ering[i].small_dma_mem;\n+\n+\t\tmem-\u003eva = dma_pool_zalloc(xnm-\u003esmall_buff_pool, GFP_KERNEL,\n+\t\t\t\t\t \u0026mem-\u003epa);\n+\t\tif (!mem-\u003eva)\n+\t\t\tgoto dealloc_dma;\n+\n+\t\tmem-\u003edirection = DMA_BIDIRECTIONAL;\n+\t\tmem-\u003esize = LIBIE_CP_TX_COPYBREAK;\n+\t}\n+\n+\treturn 0;\n+\n+dealloc_dma:\n+\tlibie_ctlq_xn_deinit_dma(xnm, i);\n+\n+\treturn -ENOMEM;\n+}\n+\n+/**\n+ * libie_ctlq_xn_process_recv - process Xn data in receive message\n+ * @params: Xn receive param information to handle a receive message\n+ * @ctlq_msg: received control queue message\n+ *\n+ * Process a control queue receive message and send a complete event\n+ * notification.\n+ *\n+ * Return: true if a message has been processed, false otherwise.\n+ */\n+static bool\n+libie_ctlq_xn_process_recv(struct libie_ctlq_xn_recv_params *params,\n+\t\t\t struct libie_ctlq_msg *ctlq_msg)\n+{\n+\tstruct libie_ctlq_xn_manager *xnm = params-\u003exnm;\n+\tstruct libie_ctlq_xn *xn;\n+\tu16 msg_cookie, xn_index;\n+\tstruct kvec *response;\n+\tint status;\n+\tu16 data;\n+\n+\tdata = ctlq_msg-\u003esw_cookie;\n+\txn_index = FIELD_GET(LIBIE_CTLQ_XN_INDEX_M, data);\n+\tmsg_cookie = FIELD_GET(LIBIE_CTLQ_XN_COOKIE_M, data);\n+\tstatus = ctlq_msg-\u003echnl_retval ? -EFAULT : 0;\n+\n+\txn = \u0026xnm-\u003ering[xn_index];\n+\tspin_lock(\u0026xn-\u003exn_lock);\n+\tif (ctlq_msg-\u003echnl_opcode != xn-\u003evirtchnl_opcode ||\n+\t msg_cookie != xn-\u003ecookie) {\n+\t\tspin_unlock(\u0026xn-\u003exn_lock);\n+\t\treturn false;\n+\t}\n+\n+\tif (xn-\u003estate != LIBIE_CTLQ_XN_ASYNC \u0026\u0026\n+\t xn-\u003estate != LIBIE_CTLQ_XN_WAITING) {\n+\t\tspin_unlock(\u0026xn-\u003exn_lock);\n+\t\treturn false;\n+\t}\n+\n+\tresponse = \u0026ctlq_msg-\u003erecv_mem;\n+\tif (xn-\u003estate == LIBIE_CTLQ_XN_ASYNC) {\n+\t\txn-\u003eresp_cb(xn-\u003esend_ctx, response, status);\n+\t\tlibie_ctlq_release_rx_buf(response);\n+\t\txn-\u003estate = LIBIE_CTLQ_XN_IDLE;\n+\t\tspin_unlock(\u0026xn-\u003exn_lock);\n+\t\tlibie_ctlq_xn_push_free(xnm, xn);\n+\n+\t\treturn true;\n+\t}\n+\n+\txn-\u003erecv_mem = *response;\n+\txn-\u003estate = status ? LIBIE_CTLQ_XN_COMPLETED_FAILED :\n+\t\t\t LIBIE_CTLQ_XN_COMPLETED_SUCCESS;\n+\n+\tcomplete(\u0026xn-\u003ecmd_completion_event);\n+\tspin_unlock(\u0026xn-\u003exn_lock);\n+\n+\treturn true;\n+}\n+\n+/**\n+ * libie_xn_check_async_timeout - Check for asynchronous message timeouts\n+ * @xnm: Xn transaction manager\n+ *\n+ * Call the corresponding callback to notify the caller about the timeout.\n+ * Iterates free_xns_bm locklessly, potential races are caught under\n+ * xn-\u003exn_lock.\n+ */\n+static void libie_xn_check_async_timeout(struct libie_ctlq_xn_manager *xnm)\n+{\n+\tu32 idx;\n+\n+\tfor_each_clear_bit(idx, xnm-\u003efree_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES) {\n+\t\tstruct libie_ctlq_xn *xn = \u0026xnm-\u003ering[idx];\n+\t\tu64 timeout_ms;\n+\n+\t\tspin_lock(\u0026xn-\u003exn_lock);\n+\n+\t\ttimeout_ms = ktime_ms_delta(ktime_get(), xn-\u003etimestamp);\n+\t\tif (xn-\u003estate != LIBIE_CTLQ_XN_ASYNC ||\n+\t\t timeout_ms \u003c xn-\u003etimeout_ms) {\n+\t\t\tspin_unlock(\u0026xn-\u003exn_lock);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\txn-\u003eresp_cb(xn-\u003esend_ctx, NULL, -ETIMEDOUT);\n+\t\txn-\u003estate = LIBIE_CTLQ_XN_IDLE;\n+\t\tspin_unlock(\u0026xn-\u003exn_lock);\n+\t\tlibie_ctlq_xn_push_free(xnm, xn);\n+\t}\n+}\n+\n+/**\n+ * libie_ctlq_xn_recv - process control queue receive message\n+ * @params: Xn receive param information to handle a receive message\n+ *\n+ * Process a receive message and update the receive queue buffer.\n+ * Also terminates async transactions for which it failed to receive a response\n+ * within a given timeframe.\n+ * Function is intended to be called periodically from a single task.\n+ *\n+ * Return: remaining budget.\n+ */\n+u32 libie_ctlq_xn_recv(struct libie_ctlq_xn_recv_params *params)\n+{\n+\tstruct libie_ctlq_msg ctlq_msg;\n+\tu32 budget = params-\u003ebudget;\n+\n+\twhile (budget \u0026\u0026 libie_ctlq_recv(params-\u003ectlq, \u0026ctlq_msg, 1)) {\n+\t\tbudget--;\n+\t\tif (!libie_ctlq_xn_process_recv(params, \u0026ctlq_msg))\n+\t\t\tparams-\u003ectlq_msg_handler(params-\u003exnm-\u003ectx, \u0026ctlq_msg);\n+\t}\n+\n+\tlibie_ctlq_post_rx_buffs(params-\u003ectlq);\n+\tlibie_xn_check_async_timeout(params-\u003exnm);\n+\n+\treturn budget;\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_recv, \"LIBIE_CP\");\n+\n+/**\n+ * libie_cp_map_dma_mem - map a given virtual address for DMA\n+ * @dev: device information\n+ * @va: virtual address to be mapped\n+ * @size: size of the memory\n+ * @direction: DMA direction either from/to device\n+ * @dma_mem: memory for DMA information to be stored\n+ *\n+ * Return: true on success, false on DMA map failure.\n+ */\n+static bool libie_cp_map_dma_mem(struct device *dev, void *va, size_t size,\n+\t\t\t\t int direction,\n+\t\t\t\t struct libie_cp_dma_mem *dma_mem)\n+{\n+\tdma_mem-\u003epa = dma_map_single(dev, va, size, direction);\n+\n+\treturn dma_mapping_error(dev, dma_mem-\u003epa) ? false : true;\n+}\n+\n+/**\n+ * libie_cp_unmap_dma_mem - unmap previously mapped DMA address\n+ * @dev: device information\n+ * @dma_mem: DMA memory information\n+ */\n+static void libie_cp_unmap_dma_mem(struct device *dev,\n+\t\t\t\t const struct libie_cp_dma_mem *dma_mem)\n+{\n+\tdma_unmap_single(dev, dma_mem-\u003epa, dma_mem-\u003esize,\n+\t\t\t dma_mem-\u003edirection);\n+}\n+\n+/**\n+ * libie_ctlq_xn_process_send - process and send a control queue message\n+ * @params: Xn send param information for sending a control queue message\n+ * @xn: Assigned Xn entry for tracking the control queue message\n+ *\n+ * Return: %0 on success, -%errno on failure.\n+ */\n+static\n+int libie_ctlq_xn_process_send(struct libie_ctlq_xn_send_params *params,\n+\t\t\t struct libie_ctlq_xn *xn)\n+{\n+\tsize_t buf_len = params-\u003esend_buf.iov_len;\n+\tstruct device *dev = params-\u003ectlq-\u003edev;\n+\tvoid *buf = params-\u003esend_buf.iov_base;\n+\tstruct libie_cp_dma_mem *dma_mem;\n+\tu16 cookie;\n+\n+\tif (!buf || !buf_len)\n+\t\treturn -EOPNOTSUPP;\n+\n+\tif (libie_cp_can_send_onstack(buf_len)) {\n+\t\tdma_mem = \u0026xn-\u003esmall_dma_mem;\n+\t\tmemcpy(dma_mem-\u003eva, buf, buf_len);\n+\t} else {\n+\t\tdma_mem = \u0026xn-\u003esend_dma_mem;\n+\t\tdma_mem-\u003eva = buf;\n+\t\tdma_mem-\u003esize = buf_len;\n+\t\tdma_mem-\u003edirection = DMA_TO_DEVICE;\n+\n+\t\tif (!libie_cp_map_dma_mem(dev, buf, buf_len, DMA_TO_DEVICE,\n+\t\t\t\t\t dma_mem))\n+\t\t\treturn -ENOMEM;\n+\t}\n+\n+\tcookie = FIELD_PREP(LIBIE_CTLQ_XN_COOKIE_M, xn-\u003ecookie) |\n+\t\t FIELD_PREP(LIBIE_CTLQ_XN_INDEX_M, xn-\u003eindex);\n+\n+\tscoped_guard(spinlock, \u0026params-\u003ectlq-\u003elock) {\n+\t\tstruct libie_ctlq_info *ctlq = params-\u003ectlq;\n+\t\tstruct libie_ctlq_msg *ctlq_msg;\n+\n+\t\tif (!libie_ctlq_send_desc_avail(ctlq)) {\n+\t\t\tif (!libie_cp_can_send_onstack(buf_len))\n+\t\t\t\tlibie_cp_unmap_dma_mem(dev, dma_mem);\n+\n+\t\t\treturn -EBUSY;\n+\t\t}\n+\n+\t\tctlq_msg = ctlq-\u003etx_msg[ctlq-\u003enext_to_use];\n+\t\txn-\u003etx_msg = dma_mem == \u0026xn-\u003esmall_dma_mem ? ctlq_msg : NULL;\n+\t\tif (params-\u003ectlq_msg)\n+\t\t\t*ctlq_msg = *params-\u003ectlq_msg;\n+\t\telse\n+\t\t\t/* Unused ctlq messages are already zeroed */\n+\t\t\tctlq_msg-\u003eopcode = LIBIE_CTLQ_SEND_MSG_TO_CP;\n+\n+\t\tctlq_msg-\u003esw_cookie = cookie;\n+\t\tctlq_msg-\u003esend_mem = *dma_mem;\n+\t\tctlq_msg-\u003edata_len = buf_len;\n+\t\tctlq_msg-\u003echnl_opcode = params-\u003echnl_opcode;\n+\t\tlibie_ctlq_send(params-\u003ectlq, 1);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * libie_ctlq_xn_send - send a control queue message, initiating a transaction\n+ * @params: Xn send param information for sending a control queue message\n+ *\n+ * Send a control queue (mailbox or config) message.\n+ * Based on the params value, the call can be completed synchronously or\n+ * asynchronously.\n+ *\n+ * Return: %0 on success, -%errno on failure.\n+ */\n+int libie_ctlq_xn_send(struct libie_ctlq_xn_send_params *params)\n+{\n+\tbool free_send = !libie_cp_can_send_onstack(params-\u003esend_buf.iov_len);\n+\tstruct libie_ctlq_xn *xn;\n+\tint ret;\n+\n+\tif (params-\u003esend_buf.iov_len \u003e LIBIE_CTLQ_MAX_BUF_LEN) {\n+\t\tret = -EINVAL;\n+\t\tgoto free_buf;\n+\t}\n+\n+\txn = libie_ctlq_xn_pop_free(params-\u003exnm);\n+\t/* no free transactions available */\n+\tif (unlikely(!xn)) {\n+\t\tret = -EAGAIN;\n+\t\tgoto free_buf;\n+\t}\n+\n+\tspin_lock(\u0026xn-\u003exn_lock);\n+\tif (xn-\u003estate == LIBIE_CTLQ_XN_SHUTDOWN) {\n+\t\tret = -ENXIO;\n+\t\tgoto unlock_xn;\n+\t}\n+\n+\txn-\u003estate = params-\u003eresp_cb ? LIBIE_CTLQ_XN_ASYNC :\n+\t\t\t\t LIBIE_CTLQ_XN_WAITING;\n+\txn-\u003evirtchnl_opcode = params-\u003echnl_opcode;\n+\n+\tif (params-\u003eresp_cb) {\n+\t\txn-\u003esend_ctx = params-\u003esend_ctx;\n+\t\txn-\u003eresp_cb = params-\u003eresp_cb;\n+\t\txn-\u003etimeout_ms = params-\u003etimeout_ms;\n+\t\txn-\u003etimestamp = ktime_get();\n+\t}\n+\n+\tret = libie_ctlq_xn_process_send(params, xn);\n+\tif (ret)\n+\t\tgoto release_xn;\n+\telse\n+\t\tfree_send = false;\n+\n+\tspin_unlock(\u0026xn-\u003exn_lock);\n+\n+\tif (params-\u003eresp_cb)\n+\t\treturn 0;\n+\n+\twait_for_completion_timeout(\u0026xn-\u003ecmd_completion_event,\n+\t\t\t\t msecs_to_jiffies(params-\u003etimeout_ms));\n+\n+\tspin_lock(\u0026xn-\u003exn_lock);\n+\tswitch (xn-\u003estate) {\n+\tcase LIBIE_CTLQ_XN_WAITING:\n+\t\tret = -ETIMEDOUT;\n+\t\tbreak;\n+\tcase LIBIE_CTLQ_XN_COMPLETED_SUCCESS:\n+\t\tparams-\u003erecv_mem = xn-\u003erecv_mem;\n+\t\tbreak;\n+\tdefault:\n+\t\tret = -EBADMSG;\n+\t\tbreak;\n+\t}\n+\n+\t/* Free the receive buffer in case of failure. On timeout, receive\n+\t * buffer is not allocated.\n+\t */\n+\tif (ret \u0026\u0026 ret != -ETIMEDOUT)\n+\t\tlibie_ctlq_release_rx_buf(\u0026xn-\u003erecv_mem);\n+\n+release_xn:\n+\txn-\u003estate = LIBIE_CTLQ_XN_IDLE;\n+\treinit_completion(\u0026xn-\u003ecmd_completion_event);\n+unlock_xn:\n+\tspin_unlock(\u0026xn-\u003exn_lock);\n+\tlibie_ctlq_xn_push_free(params-\u003exnm, xn);\n+free_buf:\n+\tif (free_send)\n+\t\tparams-\u003erel_tx_buf(params-\u003esend_buf.iov_base);\n+\n+\treturn ret;\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_send, \"LIBIE_CP\");\n+\n+/**\n+ * struct libie_ctlq_xn_rel_tx_ctx - context needed to release xn Tx message\n+ * @dev: device for which DMA was mapped\n+ * @rel_tx_buf: freeing function for non-small buffers\n+ */\n+struct libie_ctlq_xn_rel_tx_ctx {\n+\tstruct device *dev;\n+\tvoid (*rel_tx_buf)(const void *buf_va);\n+};\n+\n+/**\n+ * libie_ctlq_xn_rel_tx_buf - release xn-controlled Tx message buffer\n+ * @ctx: context, namely DMA device and freeing function\n+ * @dma_mem: DMA memory to reclaim/unmap\n+ */\n+static void libie_ctlq_xn_rel_tx_buf(const void *ctx,\n+\t\t\t\t struct libie_cp_dma_mem *dma_mem)\n+{\n+\tconst struct libie_ctlq_xn_rel_tx_ctx *rel_ctx = ctx;\n+\n+\tif (!libie_cp_can_send_onstack(dma_mem-\u003esize)) {\n+\t\tlibie_cp_unmap_dma_mem(rel_ctx-\u003edev, dma_mem);\n+\t\trel_ctx-\u003erel_tx_buf(dma_mem-\u003eva);\n+\t}\n+}\n+\n+/**\n+ * libie_ctlq_xn_send_clean - clean xn-controlled Tx messages\n+ * @ctlq: control queue to clean\n+ * @rel_tx_buf: driver callback to free the buffer\n+ * @force: clean regardless of DD\n+ *\n+ * Return: number of completed/released messages.\n+ */\n+u32 libie_ctlq_xn_send_clean(struct libie_ctlq_info *ctlq,\n+\t\t\t void (*rel_tx_buf)(const void *buf_va),\n+\t\t\t bool force)\n+{\n+\tstruct libie_ctlq_xn_rel_tx_ctx rel_ctx = {\n+\t\t.dev = ctlq-\u003edev,\n+\t\t.rel_tx_buf = rel_tx_buf,\n+\t};\n+\tstruct libie_ctlq_clean_params params = {\n+\t\t.ctlq = ctlq,\n+\t\t.force = force,\n+\t\t.num_msgs = ctlq-\u003ering_len,\n+\t\t.rel_ctx = \u0026rel_ctx,\n+\t\t.rel_dma_mem = libie_ctlq_xn_rel_tx_buf,\n+\t};\n+\n+\treturn libie_ctlq_send_clean(\u0026params);\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_send_clean, \"LIBIE_CP\");\n+\n+/**\n+ * libie_ctlq_xn_shutdown - terminate control queue transactions\n+ * @xnm: pointer to the transaction manager\n+ *\n+ * Synchronously terminate existing transactions and stop accepting new ones.\n+ * Async transactions are discarded without invoking resp_cb.\n+ */\n+void libie_ctlq_xn_shutdown(struct libie_ctlq_xn_manager *xnm)\n+{\n+\tbool must_wait = false;\n+\tu32 i;\n+\n+\t/* Should be no new clear bits after this */\n+\tspin_lock(\u0026xnm-\u003efree_xns_bm_lock);\n+\txnm-\u003eshutdown = true;\n+\n+\tfor_each_clear_bit(i, xnm-\u003efree_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES) {\n+\t\tstruct libie_ctlq_xn *xn = \u0026xnm-\u003ering[i];\n+\n+\t\tspin_lock(\u0026xn-\u003exn_lock);\n+\n+\t\tswitch (xn-\u003estate) {\n+\t\t/* if an idle xn is not free, it is about to be either\n+\t\t * freed or initialized, prevent the latter and wait\n+\t\t */\n+\t\tcase LIBIE_CTLQ_XN_IDLE:\n+\t\t\txn-\u003estate = LIBIE_CTLQ_XN_SHUTDOWN;\n+\t\t\tfallthrough;\n+\t\t/* waiting thread possibly needs a push to return the xn,\n+\t\t * transaction will be reported as timed out\n+\t\t */\n+\t\tcase LIBIE_CTLQ_XN_WAITING:\n+\t\t\tcomplete(\u0026xn-\u003ecmd_completion_event);\n+\t\t\tfallthrough;\n+\t\t/* these states will return the xn soon */\n+\t\tcase LIBIE_CTLQ_XN_COMPLETED_SUCCESS:\n+\t\tcase LIBIE_CTLQ_XN_COMPLETED_FAILED:\n+\t\tcase LIBIE_CTLQ_XN_SHUTDOWN:\n+\t\t\tmust_wait = true;\n+\t\t\tbreak;\n+\t\t/* no thread should reference async xns at this point */\n+\t\tcase LIBIE_CTLQ_XN_ASYNC:\n+\t\t\txn-\u003estate = LIBIE_CTLQ_XN_IDLE;\n+\t\t\t__libie_ctlq_xn_push_free(xnm, xn);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tspin_unlock(\u0026xn-\u003exn_lock);\n+\t}\n+\n+\tspin_unlock(\u0026xnm-\u003efree_xns_bm_lock);\n+\n+\tif (must_wait)\n+\t\twait_for_completion(\u0026xnm-\u003ecan_destroy);\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_shutdown, \"LIBIE_CP\");\n+\n+/**\n+ * libie_ctlq_xn_deinit - deallocate and free the transaction manager resources\n+ * @xnm: pointer to the transaction manager\n+ * @ctx: libie CP context information\n+ *\n+ * Rx processing must be stopped beforehand via cancelling tasks.\n+ * Tx processing must be stopped beforehand via libie_ctlq_xn_shutdown(),\n+ * all buffers must be force-cleaned from the send queue.\n+ */\n+void libie_ctlq_xn_deinit(struct libie_ctlq_xn_manager *xnm,\n+\t\t\t struct libie_ctlq_ctx *ctx)\n+{\n+\tlibie_ctlq_xn_deinit_dma(xnm, LIBIE_CTLQ_MAX_XN_ENTRIES);\n+\tkvfree(xnm);\n+\tlibie_ctlq_deinit(ctx);\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_deinit, \"LIBIE_CP\");\n+\n+/**\n+ * libie_ctlq_xn_init - initialize the Xn transaction manager\n+ * @params: Xn init param information for allocating Xn manager resources\n+ *\n+ * Return: %0 on success, -%errno on failure.\n+ */\n+int libie_ctlq_xn_init(struct libie_ctlq_xn_init_params *params)\n+{\n+\tstruct libie_ctlq_xn_manager *xnm;\n+\tint ret;\n+\n+\tret = libie_ctlq_init(params-\u003ectx, params-\u003ecctlq_info, params-\u003enum_qs);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\txnm = kvzalloc_obj(*xnm);\n+\tif (!xnm)\n+\t\tgoto ctlq_deinit;\n+\n+\tret = libie_ctlq_xn_init_dma(\u0026params-\u003ectx-\u003emmio_info.pdev-\u003edev, xnm);\n+\tif (ret)\n+\t\tgoto free_xnm;\n+\n+\tspin_lock_init(\u0026xnm-\u003efree_xns_bm_lock);\n+\tinit_completion(\u0026xnm-\u003ecan_destroy);\n+\tbitmap_fill(xnm-\u003efree_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES);\n+\n+\tfor (u32 i = 0; i \u003c LIBIE_CTLQ_MAX_XN_ENTRIES; i++) {\n+\t\tstruct libie_ctlq_xn *xn = \u0026xnm-\u003ering[i];\n+\n+\t\txn-\u003eindex = i;\n+\t\tinit_completion(\u0026xn-\u003ecmd_completion_event);\n+\t\tspin_lock_init(\u0026xn-\u003exn_lock);\n+\t}\n+\txnm-\u003ectx = params-\u003ectx;\n+\tparams-\u003exnm = xnm;\n+\n+\treturn 0;\n+\n+free_xnm:\n+\tkvfree(xnm);\n+ctlq_deinit:\n+\tlibie_ctlq_deinit(params-\u003ectx);\n+\n+\treturn -ENOMEM;\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_init, \"LIBIE_CP\");\n+\n+MODULE_DESCRIPTION(\"Control Plane communication API\");\n+MODULE_IMPORT_NS(\"LIBETH\");\n+MODULE_LICENSE(\"GPL\");\ndiff --git a/drivers/net/ethernet/intel/libie/pci.c b/drivers/net/ethernet/intel/libie/pci.c\nnew file mode 100644\nindex 0000000000000..b756c1186ce90\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/libie/pci.c\n@@ -0,0 +1,229 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/* Copyright (C) 2025 Intel Corporation */\n+\n+#include \u003clinux/net/intel/libie/pci.h\u003e\n+\n+/**\n+ * libie_find_mmio_region - find MMIO region containing a range\n+ * @mmio_list: list that contains MMIO region info\n+ * @offset: range start offset\n+ * @size: range size\n+ * @bar_idx: BAR index containing the range to search\n+ *\n+ * MMIO regions mappings are traversed from oldest to newest.\n+ *\n+ * Return: pointer to a MMIO region overlapping with the range in any way or\n+ *\t NULL if no such region is mapped.\n+ */\n+static struct libie_pci_mmio_region *\n+libie_find_mmio_region(const struct list_head *mmio_list,\n+\t\t resource_size_t offset, resource_size_t size,\n+\t\t int bar_idx)\n+{\n+\tresource_size_t end_offset = offset + size;\n+\tstruct libie_pci_mmio_region *mr;\n+\n+\tlist_for_each_entry(mr, mmio_list, list) {\n+\t\tresource_size_t mr_end = mr-\u003eoffset + mr-\u003esize;\n+\t\tresource_size_t mr_start = mr-\u003eoffset;\n+\n+\t\tif (mr-\u003ebar_idx != bar_idx)\n+\t\t\tcontinue;\n+\t\tif (offset \u003c mr_end \u0026\u0026 end_offset \u003e mr_start)\n+\t\t\treturn mr;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+/**\n+ * __libie_pci_get_mmio_addr - get the MMIO virtual address\n+ * @mmio_info: contains list of MMIO regions\n+ * @offset: register offset to find\n+ * @num_args: number of additional arguments present\n+ * @...: optional BAR index (0 by default)\n+ *\n+ * This function finds the virtual address of a register offset by iterating\n+ * through the non-linear MMIO regions that are mapped by the driver.\n+ *\n+ * The list is traversed oldest to newest, so accessing an older mapping\n+ * via this function while deleting a newer one is allowed.\n+ *\n+ * Return: valid MMIO virtual address or NULL.\n+ */\n+void __iomem *__libie_pci_get_mmio_addr(struct libie_mmio_info *mmio_info,\n+\t\t\t\t\tresource_size_t offset,\n+\t\t\t\t\tint num_args, ...)\n+{\n+\tstruct libie_pci_mmio_region *mr;\n+\tint bar_idx = 0;\n+\tva_list args;\n+\n+\tif (num_args) {\n+\t\tva_start(args, num_args);\n+\t\tbar_idx = va_arg(args, int);\n+\t\tva_end(args);\n+\t}\n+\n+\tlist_for_each_entry(mr, \u0026mmio_info-\u003emmio_list, list)\n+\t\tif (bar_idx == mr-\u003ebar_idx \u0026\u0026 offset \u003e= mr-\u003eoffset \u0026\u0026\n+\t\t offset \u003c mr-\u003eoffset + mr-\u003esize) {\n+\t\t\toffset -= mr-\u003eoffset;\n+\n+\t\t\treturn mr-\u003eaddr + offset;\n+\t\t}\n+\n+\tWARN_ONCE(true, \"Access to an unmapped MMIO region (BAR%d, offset %pa)\",\n+\t\t bar_idx, \u0026offset);\n+\n+\treturn NULL;\n+}\n+EXPORT_SYMBOL_NS_GPL(__libie_pci_get_mmio_addr, \"LIBIE_PCI\");\n+\n+/**\n+ * __libie_pci_map_mmio_region - map PCI device MMIO region\n+ * @mmio_info: struct to store the mapped MMIO region\n+ * @offset: MMIO region start offset\n+ * @size: MMIO region size\n+ * @num_args: number of additional arguments present\n+ * @...: optional BAR index (0 by default)\n+ *\n+ * Return: true if the requested address range is accessible through\n+ *\t new or existing mapping, false otherwise.\n+ */\n+bool __libie_pci_map_mmio_region(struct libie_mmio_info *mmio_info,\n+\t\t\t\t resource_size_t offset,\n+\t\t\t\t resource_size_t size, int num_args, ...)\n+{\n+\tstruct pci_dev *pdev = mmio_info-\u003epdev;\n+\tstruct libie_pci_mmio_region *mr;\n+\tresource_size_t end_offset;\n+\tvoid __iomem *va;\n+\tint bar_idx = 0;\n+\tva_list args;\n+\n+\tif (num_args) {\n+\t\tva_start(args, num_args);\n+\t\tbar_idx = va_arg(args, int);\n+\t\tva_end(args);\n+\t}\n+\n+\tif (bar_idx \u003e= PCI_STD_NUM_BARS || bar_idx \u003c 0 ||\n+\t !pci_resource_is_mem(pdev, bar_idx))\n+\t\treturn false;\n+\n+\t/* pci_iomap_range() silently maps less\n+\t * if the requested length is too big\n+\t */\n+\tif (!size || check_add_overflow(offset, size, \u0026end_offset) ||\n+\t end_offset \u003e pci_resource_len(pdev, bar_idx))\n+\t\treturn false;\n+\n+\tmr = libie_find_mmio_region(\u0026mmio_info-\u003emmio_list, offset, size,\n+\t\t\t\t bar_idx);\n+\tif (mr) {\n+\t\tpci_warn(pdev,\n+\t\t\t \"Mapping of BAR%u (offset=%llu, size=%llu) intersecting region (offset=%llu, size=%llu) already exists\\n\",\n+\t\t\t bar_idx, (unsigned long long)mr-\u003eoffset,\n+\t\t\t (unsigned long long)mr-\u003esize,\n+\t\t\t (unsigned long long)offset, (unsigned long long)size);\n+\t\treturn mr-\u003eoffset \u003c= offset \u0026\u0026\n+\t\t mr-\u003eoffset + mr-\u003esize \u003e= end_offset;\n+\t}\n+\n+\tva = pci_iomap_range(mmio_info-\u003epdev, bar_idx, offset, size);\n+\tif (!va) {\n+\t\tpci_err(pdev, \"Failed to map BAR%u region\\n\", bar_idx);\n+\t\treturn false;\n+\t}\n+\n+\tmr = kvzalloc_obj(*mr);\n+\tif (!mr) {\n+\t\tpci_iounmap(pdev, va);\n+\t\treturn false;\n+\t}\n+\n+\tmr-\u003eaddr = va;\n+\tmr-\u003eoffset = offset;\n+\tmr-\u003esize = size;\n+\tmr-\u003ebar_idx = bar_idx;\n+\n+\tlist_add_tail(\u0026mr-\u003elist, \u0026mmio_info-\u003emmio_list);\n+\n+\treturn true;\n+}\n+EXPORT_SYMBOL_NS_GPL(__libie_pci_map_mmio_region, \"LIBIE_PCI\");\n+\n+/**\n+ * libie_pci_unmap_fltr_regs - unmap selected PCI device MMIO regions\n+ * @mmio_info: contains list of MMIO regions to unmap\n+ * @fltr: returns true, if region is to be unmapped\n+ */\n+void libie_pci_unmap_fltr_regs(struct libie_mmio_info *mmio_info,\n+\t\t\t bool (*fltr)(struct libie_mmio_info *mmio_info,\n+\t\t\t\t\t struct libie_pci_mmio_region *reg))\n+{\n+\tstruct libie_pci_mmio_region *mr, *tmp;\n+\n+\tlist_for_each_entry_safe(mr, tmp, \u0026mmio_info-\u003emmio_list, list) {\n+\t\tif (!fltr(mmio_info, mr))\n+\t\t\tcontinue;\n+\t\tlist_del(\u0026mr-\u003elist);\n+\t\tpci_iounmap(mmio_info-\u003epdev, mr-\u003eaddr);\n+\t\tkvfree(mr);\n+\t}\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_pci_unmap_fltr_regs, \"LIBIE_PCI\");\n+\n+/**\n+ * libie_pci_unmap_all_mmio_regions - unmap all PCI device MMIO regions\n+ * @mmio_info: contains list of MMIO regions to unmap\n+ */\n+void libie_pci_unmap_all_mmio_regions(struct libie_mmio_info *mmio_info)\n+{\n+\tstruct libie_pci_mmio_region *mr, *tmp;\n+\n+\tlist_for_each_entry_safe(mr, tmp, \u0026mmio_info-\u003emmio_list, list) {\n+\t\tlist_del(\u0026mr-\u003elist);\n+\t\tpci_iounmap(mmio_info-\u003epdev, mr-\u003eaddr);\n+\t\tkvfree(mr);\n+\t}\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_pci_unmap_all_mmio_regions, \"LIBIE_PCI\");\n+\n+/**\n+ * libie_pci_init_dev - enable and configure the device\n+ * @pdev: PCI device information\n+ *\n+ * Enable the device, request memory regions, set 64-bit DMA mask\n+ * and coherent DMA mask, and enable bus-mastering\n+ *\n+ * Return: %0 on success, -%errno on failure.\n+ */\n+int libie_pci_init_dev(struct pci_dev *pdev)\n+{\n+\tint err;\n+\n+\terr = pcim_enable_device(pdev);\n+\tif (err)\n+\t\treturn err;\n+\n+\tfor (int bar = 0; bar \u003c PCI_STD_NUM_BARS; bar++)\n+\t\tif (pci_resource_flags(pdev, bar) \u0026 IORESOURCE_MEM) {\n+\t\t\terr = pcim_request_region(pdev, bar, pci_name(pdev));\n+\t\t\tif (err)\n+\t\t\t\treturn err;\n+\t\t}\n+\n+\terr = dma_set_mask_and_coherent(\u0026pdev-\u003edev, DMA_BIT_MASK(64));\n+\tif (err)\n+\t\treturn err;\n+\n+\tpci_set_master(pdev);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_NS_GPL(libie_pci_init_dev, \"LIBIE_PCI\");\n+\n+MODULE_DESCRIPTION(\"Common Ethernet PCI library\");\n+MODULE_LICENSE(\"GPL\");\ndiff --git a/include/linux/net/intel/libie/controlq.h b/include/linux/net/intel/libie/controlq.h\nnew file mode 100644\nindex 0000000000000..175227d4eef1e\n--- /dev/null\n+++ b/include/linux/net/intel/libie/controlq.h\n@@ -0,0 +1,436 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+/* Copyright (C) 2025 Intel Corporation */\n+\n+#ifndef __LIBIE_CONTROLQ_H\n+#define __LIBIE_CONTROLQ_H\n+\n+#include \u003clinux/dmapool.h\u003e\n+#include \u003cnet/libeth/rx.h\u003e\n+\n+#include \u003clinux/net/intel/libie/pci.h\u003e\n+#include \u003clinux/net/intel/virtchnl2.h\u003e\n+\n+/* Default mailbox control queue */\n+#define LIBIE_CTLQ_MBX_ID\t\t\t-1\n+#define LIBIE_CTLQ_MAX_BUF_LEN\t\t\tSZ_4K\n+\n+/**\n+ * enum libie_ctlq_type - control queue type\n+ * @LIBIE_CTLQ_TYPE_TX: basic Tx control queue\n+ * @LIBIE_CTLQ_TYPE_RX: basic Rx control queue\n+ */\n+enum libie_ctlq_type {\n+\tLIBIE_CTLQ_TYPE_TX = 0,\n+\tLIBIE_CTLQ_TYPE_RX = 1,\n+};\n+\n+/* Opcode used to send controlq message to the control plane */\n+#define LIBIE_CTLQ_SEND_MSG_TO_CP\t\t0x801\n+#define LIBIE_CTLQ_SEND_MSG_TO_PEER\t\t0x804\n+\n+#define LIBIE_CP_TX_COPYBREAK\t\t128\n+\n+/**\n+ * struct libie_ctlq_ctx - contains controlq info and MMIO region info\n+ * @mmio_info: MMIO region info structure\n+ * @ctlqs: list that stores all the control queues\n+ * @ctlqs_lock: lock for control queue list\n+ */\n+struct libie_ctlq_ctx {\n+\tstruct libie_mmio_info\tmmio_info;\n+\tstruct list_head\tctlqs;\n+\tspinlock_t\t\tctlqs_lock;\t/* protects the ctlqs list */\n+};\n+\n+/**\n+ * struct libie_ctlq_reg - structure representing virtual addresses of the\n+ *\t\t\t controlq registers and masks\n+ * @head: controlq head register address\n+ * @tail: controlq tail register address\n+ * @len: register address to write controlq length and enable bit\n+ * @addr_high: register address to write the upper 32b of ring physical address\n+ * @addr_low: register address to write the lower 32b of ring physical address\n+ * @len_mask: mask to read the controlq length\n+ * @len_ena_mask: mask to write the controlq enable bit\n+ * @head_mask: mask to read the head value\n+ */\n+struct libie_ctlq_reg {\n+\tvoid __iomem\t*head;\n+\tvoid __iomem\t*tail;\n+\tvoid __iomem\t*len;\n+\tvoid __iomem\t*addr_high;\n+\tvoid __iomem\t*addr_low;\n+\tu32\t\tlen_mask;\n+\tu32\t\tlen_ena_mask;\n+\tu32\t\thead_mask;\n+};\n+\n+/**\n+ * struct libie_cp_dma_mem - structure for DMA memory\n+ * @va: virtual address\n+ * @pa: physical address\n+ * @size: memory size\n+ * @direction: memory to device or device to memory\n+ */\n+struct libie_cp_dma_mem {\n+\tvoid\t\t*va;\n+\tdma_addr_t\tpa;\n+\tsize_t\t\tsize;\n+\tint\t\tdirection;\n+};\n+\n+/**\n+ * struct libie_ctlq_msg - control queue message data\n+ * @flags: refer to 'Flags sub-structure' definitions\n+ * @opcode: infrastructure message opcode\n+ * @data_len: size of the payload\n+ * @func_id: queue id for mailbox selection, 0 for default mailbox (Tx)\n+ * @hw_retval: execution status from the HW (Rx)\n+ * @chnl_opcode: virtchnl message opcode\n+ * @chnl_retval: virtchnl return value\n+ * @param0: indirect message raw parameter0\n+ * @sw_cookie: used to verify the response of the sent virtchnl message\n+ * @virt_flags: virtchnl capability flags\n+ * @addr_param: additional parameters in place of the address, given no buffer\n+ * @recv_mem: virtual address and size of the buffer that contains\n+ *\t the indirect response\n+ * @send_mem: physical and virtual address of the DMA buffer,\n+ *\t used for sending\n+ */\n+struct libie_ctlq_msg {\n+\tu16\t\t\tflags;\n+\tu16\t\t\topcode;\n+\tu16\t\t\tdata_len;\n+\tunion {\n+\t\tu16\t\tfunc_id;\n+\t\tu16\t\thw_retval;\n+\t};\n+\tu32\t\t\tchnl_opcode;\n+\tu32\t\t\tchnl_retval;\n+\tu32\t\t\tparam0;\n+\tu16\t\t\tsw_cookie;\n+\tu16\t\t\tvirt_flags;\n+\tu64\t\t\taddr_param;\n+\tunion {\n+\t\tstruct kvec\t\trecv_mem;\n+\t\tstruct libie_cp_dma_mem\tsend_mem;\n+\t};\n+};\n+\n+/**\n+ * struct libie_ctlq_create_info - control queue create information\n+ * @type: control queue type (Rx or Tx)\n+ * @id: queue offset passed as input, -1 for default mailbox\n+ * @reg: registers accessed by control queue\n+ * @len: controlq length\n+ */\n+struct libie_ctlq_create_info {\n+\tenum libie_ctlq_type\t\ttype;\n+\tint\t\t\t\tid;\n+\tstruct libie_ctlq_reg\t\treg;\n+\tu16\t\t\t\tlen;\n+};\n+\n+/**\n+ * struct libie_ctlq_info - control queue information\n+ * @list: used to add a controlq to the list of queues in libie_ctlq_ctx\n+ * @type: control queue type\n+ * @qid: queue identifier\n+ * @lock: control queue lock\n+ * @ring_mem: descriptor ring DMA memory\n+ * @descs: array of descriptors\n+ * @rx_fqes: array of controlq Rx buffers\n+ * @tx_msg: Tx messages sent to hardware\n+ * @reg: registers used by control queue\n+ * @dev: device that owns this control queue\n+ * @pp: page pool for controlq Rx buffers\n+ * @truesize: size to allocate per buffer\n+ * @next_to_clean: next descriptor to be cleaned\n+ * @next_to_use: next available slot to send buffer (Tx queue)\n+ * @next_to_post: next available slot to post buffers to (Rx queue)\n+ * @ring_len: length of the descriptor ring\n+ */\n+struct libie_ctlq_info {\n+\tstruct list_head\t\tlist;\n+\tenum libie_ctlq_type\t\ttype;\n+\tint\t\t\t\tqid;\n+\tspinlock_t\t\t\tlock;\t/* for concurrent processing */\n+\tstruct libie_cp_dma_mem\tring_mem;\n+\tstruct libie_ctlq_desc\t\t*descs;\n+\tunion {\n+\t\tstruct libeth_fqe\t*rx_fqes;\n+\t\tstruct libie_ctlq_msg\t**tx_msg;\n+\t};\n+\tstruct libie_ctlq_reg\t\treg;\n+\tstruct device\t\t\t*dev;\n+\tstruct page_pool\t\t*pp;\n+\tu32\t\t\t\ttruesize;\n+\tu32\t\t\t\tnext_to_clean;\n+\tunion {\n+\t\tu32\t\t\tnext_to_use;\n+\t\tu32\t\t\tnext_to_post;\n+\t};\n+\tu32\t\t\t\tring_len;\n+};\n+\n+#define LIBIE_CTLQ_MBX_ATQ_LEN\t\t\tGENMASK(9, 0)\n+\n+/* libie controlq descriptor qword0 details */\n+\n+/* Flags sub-structure\n+ * |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10 |11 |12 |13 |14 |15 |\n+ * |DD |CMP|ERR| * RSV * |FTYPE | *RSV* |RD |VFC|BUF| HOST_ID |\n+ */\n+#define LIBIE_CTLQ_DESC_FLAG_DD\t\tBIT(0)\n+#define LIBIE_CTLQ_DESC_FLAG_CMP\t\tBIT(1)\n+#define LIBIE_CTLQ_DESC_FLAG_ERR\t\tBIT(2)\n+#define LIBIE_CTLQ_DESC_FLAG_FTYPE_VM\t\tBIT(6)\n+#define LIBIE_CTLQ_DESC_FLAG_FTYPE_PF\t\tBIT(7)\n+#define LIBIE_CTLQ_DESC_FLAG_FTYPE\t\tGENMASK(7, 6)\n+#define LIBIE_CTLQ_DESC_FLAG_RD\t\tBIT(10)\n+#define LIBIE_CTLQ_DESC_FLAG_VFC\t\tBIT(11)\n+#define LIBIE_CTLQ_DESC_FLAG_BUF\t\tBIT(12)\n+#define LIBIE_CTLQ_DESC_FLAG_HOST_ID\t\tGENMASK(15, 13)\n+\n+#define LIBIE_CTLQ_DESC_FLAGS\t\t\tGENMASK(15, 0)\n+#define LIBIE_CTLQ_DESC_INFRA_OPCODE\t\tGENMASK_ULL(31, 16)\n+#define LIBIE_CTLQ_DESC_DATA_LEN\t\tGENMASK_ULL(47, 32)\n+#define LIBIE_CTLQ_DESC_HW_RETVAL\t\tGENMASK_ULL(63, 48)\n+\n+#define LIBIE_CTLQ_DESC_PFID_VFID\t\tGENMASK_ULL(63, 48)\n+\n+/* libie controlq descriptor qword1 details */\n+#define LIBIE_CTLQ_DESC_VIRTCHNL_OPCODE\tGENMASK(27, 0)\n+#define LIBIE_CTLQ_DESC_VIRTCHNL_DESC_TYPE\tGENMASK_ULL(31, 28)\n+#define LIBIE_CTLQ_DESC_VIRTCHNL_MSG_RET_VAL\tGENMASK_ULL(63, 32)\n+\n+/* libie controlq descriptor qword2 details */\n+#define LIBIE_CTLQ_DESC_MSG_PARAM0\t\tGENMASK_ULL(31, 0)\n+#define LIBIE_CTLQ_DESC_SW_COOKIE\t\tGENMASK_ULL(47, 32)\n+#define LIBIE_CTLQ_DESC_VIRTCHNL_FLAGS\t\tGENMASK_ULL(63, 48)\n+\n+/* libie controlq descriptor qword3 details */\n+#define LIBIE_CTLQ_DESC_DATA_ADDR_HIGH\t\tGENMASK_ULL(31, 0)\n+#define LIBIE_CTLQ_DESC_DATA_ADDR_LOW\t\tGENMASK_ULL(63, 32)\n+\n+/**\n+ * struct libie_ctlq_desc - control queue descriptor format\n+ * @qword0: flags, message opcode, data length etc\n+ * @qword1: virtchnl opcode, descriptor type and return value\n+ * @qword2: indirect message parameters\n+ * @qword3: indirect message buffer address\n+ */\n+struct libie_ctlq_desc {\n+\t__le64\t\t\tqword0;\n+\t__le64\t\t\tqword1;\n+\t__le64\t\t\tqword2;\n+\t__le64\t\t\tqword3;\n+};\n+\n+/**\n+ * struct libie_ctlq_clean_params - cleaning parameters for Tx messages\n+ * @rel_dma_mem: non-sleeping callback to put the DMA buffer after send\n+ * @rel_ctx: additional context for release callback\n+ * @ctlq: control queue information\n+ * @num_msgs: number of messages to be cleaned\n+ * @force: clean even if DD is not yet set, use only for final cleanup\n+ */\n+struct libie_ctlq_clean_params {\n+\tvoid (*rel_dma_mem)(const void *ctx, struct libie_cp_dma_mem *dma_mem);\n+\tconst void\t\t\t\t*rel_ctx;\n+\tstruct libie_ctlq_info\t\t\t*ctlq;\n+\tu16\t\t\t\t\tnum_msgs;\n+\tbool\t\t\t\t\tforce;\n+};\n+\n+/**\n+ * libie_ctlq_release_rx_buf - Release Rx buffer for a specific control queue\n+ * @rx_buf: Rx buffer to be freed\n+ *\n+ * Driver uses this function to post back the Rx buffer after the usage.\n+ */\n+static inline void libie_ctlq_release_rx_buf(struct kvec *rx_buf)\n+{\n+\tnetmem_ref netmem;\n+\n+\tif (!rx_buf-\u003eiov_base)\n+\t\treturn;\n+\n+\tnetmem = virt_to_netmem(rx_buf-\u003eiov_base);\n+\tpage_pool_put_full_netmem(netmem_get_pp(netmem), netmem, false);\n+}\n+\n+int libie_ctlq_init(struct libie_ctlq_ctx *ctx,\n+\t\t const struct libie_ctlq_create_info *qinfo, u32 numq);\n+void libie_ctlq_deinit(struct libie_ctlq_ctx *ctx);\n+\n+struct libie_ctlq_info *libie_find_ctlq(struct libie_ctlq_ctx *ctx,\n+\t\t\t\t\tenum libie_ctlq_type type,\n+\t\t\t\t\tint id);\n+\n+u32 libie_ctlq_send_desc_avail(const struct libie_ctlq_info *ctlq);\n+void libie_ctlq_send(struct libie_ctlq_info *ctlq, u32 num_q_msg);\n+u32 libie_ctlq_send_clean(const struct libie_ctlq_clean_params *params);\n+u32 libie_ctlq_recv(struct libie_ctlq_info *ctlq, struct libie_ctlq_msg *msg,\n+\t\t u32 num_q_msg);\n+\n+int libie_ctlq_post_rx_buffs(struct libie_ctlq_info *ctlq);\n+\n+/* Only 8 bits are available in descriptor for Xn index */\n+#define LIBIE_CTLQ_MAX_XN_ENTRIES\t\t256\n+#define LIBIE_CTLQ_XN_COOKIE_M\t\t\tGENMASK(15, 8)\n+#define LIBIE_CTLQ_XN_INDEX_M\t\t\tGENMASK(7, 0)\n+\n+/**\n+ * enum libie_ctlq_xn_state - Transaction state of a virtchnl message\n+ * @LIBIE_CTLQ_XN_IDLE: transaction is available to use\n+ * @LIBIE_CTLQ_XN_WAITING: waiting for transaction to complete\n+ * @LIBIE_CTLQ_XN_COMPLETED_SUCCESS: transaction completed with success\n+ * @LIBIE_CTLQ_XN_COMPLETED_FAILED: transaction completed with failure\n+ * @LIBIE_CTLQ_XN_ASYNC: asynchronous virtchnl message transaction type\n+ * @LIBIE_CTLQ_XN_SHUTDOWN: transaction cannot be used anymore\n+ */\n+enum libie_ctlq_xn_state {\n+\tLIBIE_CTLQ_XN_IDLE = 0,\n+\tLIBIE_CTLQ_XN_WAITING,\n+\tLIBIE_CTLQ_XN_COMPLETED_SUCCESS,\n+\tLIBIE_CTLQ_XN_COMPLETED_FAILED,\n+\tLIBIE_CTLQ_XN_ASYNC,\n+\tLIBIE_CTLQ_XN_SHUTDOWN,\n+};\n+\n+/**\n+ * struct libie_ctlq_xn - structure representing a virtchnl transaction entry\n+ * @resp_cb: non-sleeping callback to handle the response to an async message\n+ * @xn_lock: lock to protect the transaction entry state\n+ * @cmd_completion_event: wait until reply is received or xn is terminated\n+ * @small_dma_mem: DMA memory for copying small send buffers from stack,\n+ *\t\t is recycled when response is received or on timeout\n+ * @send_dma_mem: DMA memory of send buffer\n+ * @recv_mem: receive buffer\n+ * @send_ctx: context for callback function\n+ * @timeout_ms: Xn transaction timeout in msecs\n+ * @timestamp: timestamp to record the Xn send\n+ * @tx_msg: control queue Tx message slot to track small DMA usage\n+ * @virtchnl_opcode: virtchnl command opcode used for Xn transaction\n+ * @state: transaction state of a virtchnl message\n+ * @cookie: unique message identifier, incremented every time the slot is used\n+ * @index: index of the transaction entry\n+ */\n+struct libie_ctlq_xn {\n+\tvoid (*resp_cb)(void *ctx, struct kvec *mem, int status);\n+\tspinlock_t\t\t\txn_lock;\t/* protects state */\n+\tstruct completion\t\tcmd_completion_event;\n+\tstruct libie_cp_dma_mem\tsmall_dma_mem;\n+\tstruct libie_cp_dma_mem\tsend_dma_mem;\n+\tstruct kvec\t\t\trecv_mem;\n+\tvoid\t\t\t\t*send_ctx;\n+\tu64\t\t\t\ttimeout_ms;\n+\tktime_t\t\t\t\ttimestamp;\n+\tstruct libie_ctlq_msg\t\t*tx_msg;\n+\tu32\t\t\t\tvirtchnl_opcode;\n+\tenum libie_ctlq_xn_state\tstate;\n+\tu8\t\t\t\tcookie;\n+\tu8\t\t\t\tindex;\n+};\n+\n+/**\n+ * struct libie_ctlq_xn_manager - structure representing the array of virtchnl\n+ *\t\t\t\t transaction entries\n+ * @ctx: pointer to controlq context structure\n+ * @free_xns_bm_lock: lock to protect the free Xn entries bit map\n+ * @free_xns_bm: bitmap that represents the free Xn entries\n+ * @ring: array of Xn entries\n+ * @small_buff_pool: DMA pool for small send buffers\n+ * @can_destroy: completion, triggered by the last released transaction\n+ * @shutdown: shutdown process has been started, no new transactions allowed\n+ */\n+struct libie_ctlq_xn_manager {\n+\tstruct libie_ctlq_ctx\t*ctx;\n+\tspinlock_t\t\tfree_xns_bm_lock;\t/* get/check entries */\n+\tDECLARE_BITMAP(free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES);\n+\tstruct libie_ctlq_xn\tring[LIBIE_CTLQ_MAX_XN_ENTRIES];\n+\tstruct dma_pool\t\t*small_buff_pool;\n+\tstruct completion\tcan_destroy;\n+\tbool\t\t\tshutdown;\n+};\n+\n+/**\n+ * struct libie_ctlq_xn_send_params - structure representing send Xn entry\n+ * @resp_cb: non-sleeping callback to handle the response to an async message\n+ * @rel_tx_buf: non-sleeping callback for freeing the send buffer\n+ * @xnm: Xn manager to process Xn entries\n+ * @ctlq: send control queue information\n+ * @ctlq_msg: control queue message information\n+ * @send_buf: buffer that carries outgoing message data, buffers larger than\n+ *\t LIBIE_CP_TX_COPYBREAK bytes will always be consumed\n+ * @recv_mem: receive buffer\n+ * @send_ctx: context for callback function\n+ * @timeout_ms: virtchnl transaction timeout in msecs\n+ * @chnl_opcode: virtchnl message opcode\n+ */\n+struct libie_ctlq_xn_send_params {\n+\tvoid (*resp_cb)(void *ctx, struct kvec *mem, int status);\n+\tvoid (*rel_tx_buf)(const void *buf_va);\n+\tstruct libie_ctlq_xn_manager\t\t*xnm;\n+\tstruct libie_ctlq_info\t\t\t*ctlq;\n+\tstruct libie_ctlq_msg\t\t\t*ctlq_msg;\n+\tstruct kvec\t\t\t\tsend_buf;\n+\tstruct kvec\t\t\t\trecv_mem;\n+\tvoid\t\t\t\t\t*send_ctx;\n+\tu64\t\t\t\t\ttimeout_ms;\n+\tu32\t\t\t\t\tchnl_opcode;\n+};\n+\n+/**\n+ * libie_cp_can_send_onstack - can a message be sent using a stack variable\n+ * @size: ctlq data buffer size\n+ *\n+ * Return: %true if the message size is small enough for caller to pass\n+ *\t an on-stack buffer, %false if kmalloc is needed\n+ */\n+static inline bool libie_cp_can_send_onstack(u32 size)\n+{\n+\treturn size \u003c= LIBIE_CP_TX_COPYBREAK;\n+}\n+\n+/**\n+ * struct libie_ctlq_xn_recv_params - request to receive xn responses\n+ * @ctlq_msg_handler: handler for Rx messages with no matching xn (mandatory)\n+ * @xnm: Xn manager to process Xn entries\n+ * @ctlq: control queue information\n+ * @budget: maximum number of messages to process\n+ */\n+struct libie_ctlq_xn_recv_params {\n+\tvoid (*ctlq_msg_handler)(struct libie_ctlq_ctx *ctx,\n+\t\t\t\t struct libie_ctlq_msg *msg);\n+\tstruct libie_ctlq_xn_manager\t\t*xnm;\n+\tstruct libie_ctlq_info\t\t\t*ctlq;\n+\tu32\t\t\t\t\tbudget;\n+};\n+\n+/**\n+ * struct libie_ctlq_xn_init_params - xn transaction manager parameters\n+ * @cctlq_info: control queue information\n+ * @ctx: pointer to controlq context structure\n+ * @xnm: Xn manager to process Xn entries\n+ * @num_qs: number of control queues to be initialized\n+ */\n+struct libie_ctlq_xn_init_params {\n+\tstruct libie_ctlq_create_info\t\t*cctlq_info;\n+\tstruct libie_ctlq_ctx\t\t\t*ctx;\n+\tstruct libie_ctlq_xn_manager\t\t*xnm;\n+\tu32\t\t\t\t\tnum_qs;\n+};\n+\n+int libie_ctlq_xn_init(struct libie_ctlq_xn_init_params *params);\n+void libie_ctlq_xn_deinit(struct libie_ctlq_xn_manager *xnm,\n+\t\t\t struct libie_ctlq_ctx *ctx);\n+void libie_ctlq_xn_shutdown(struct libie_ctlq_xn_manager *xnm);\n+int libie_ctlq_xn_send(struct libie_ctlq_xn_send_params *params);\n+u32 libie_ctlq_xn_recv(struct libie_ctlq_xn_recv_params *params);\n+u32 libie_ctlq_xn_send_clean(struct libie_ctlq_info *ctlq,\n+\t\t\t void (*rel_tx_buf)(const void *buf_va),\n+\t\t\t bool force);\n+\n+#endif /* __LIBIE_CONTROLQ_H */\ndiff --git a/include/linux/net/intel/libie/pci.h b/include/linux/net/intel/libie/pci.h\nnew file mode 100644\nindex 0000000000000..effd072c55c8c\n--- /dev/null\n+++ b/include/linux/net/intel/libie/pci.h\n@@ -0,0 +1,56 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+/* Copyright (C) 2025 Intel Corporation */\n+\n+#ifndef __LIBIE_PCI_H\n+#define __LIBIE_PCI_H\n+\n+#include \u003clinux/pci.h\u003e\n+\n+/**\n+ * struct libie_pci_mmio_region - structure for MMIO region info\n+ * @list: used to add a MMIO region to the list of MMIO regions in\n+ *\t libie_mmio_info\n+ * @addr: virtual address of MMIO region start\n+ * @offset: start offset of the MMIO region\n+ * @size: size of the MMIO region\n+ * @bar_idx: BAR index to which the MMIO region belongs to\n+ */\n+struct libie_pci_mmio_region {\n+\tstruct list_head\tlist;\n+\tvoid __iomem\t\t*addr;\n+\tresource_size_t\t\toffset;\n+\tresource_size_t\t\tsize;\n+\tu16\t\t\tbar_idx;\n+};\n+\n+/**\n+ * struct libie_mmio_info - contains list of MMIO regions\n+ * @pdev: PCI device pointer\n+ * @mmio_list: list of MMIO regions\n+ */\n+struct libie_mmio_info {\n+\tstruct pci_dev\t\t*pdev;\n+\tstruct list_head\tmmio_list;\n+};\n+\n+#define libie_pci_map_mmio_region(mmio_info, offset, size, ...)\t\\\n+\t__libie_pci_map_mmio_region(mmio_info, offset, size,\t\t\\\n+\t\t\t\t COUNT_ARGS(__VA_ARGS__), ##__VA_ARGS__)\n+\n+#define libie_pci_get_mmio_addr(mmio_info, offset, ...)\t\t\\\n+\t__libie_pci_get_mmio_addr(mmio_info, offset,\t\t\t\\\n+\t\t\t\t COUNT_ARGS(__VA_ARGS__), ##__VA_ARGS__)\n+\n+bool __libie_pci_map_mmio_region(struct libie_mmio_info *mmio_info,\n+\t\t\t\t resource_size_t offset, resource_size_t size,\n+\t\t\t\t int num_args, ...);\n+void __iomem *__libie_pci_get_mmio_addr(struct libie_mmio_info *mmio_info,\n+\t\t\t\t\tresource_size_t offset,\n+\t\t\t\t\tint num_args, ...);\n+void libie_pci_unmap_all_mmio_regions(struct libie_mmio_info *mmio_info);\n+void libie_pci_unmap_fltr_regs(struct libie_mmio_info *mmio_info,\n+\t\t\t bool (*fltr)(struct libie_mmio_info *mmio_info,\n+\t\t\t\t\t struct libie_pci_mmio_region *reg));\n+int libie_pci_init_dev(struct pci_dev *pdev);\n+\n+#endif /* __LIBIE_PCI_H */\ndiff --git a/include/linux/avf/virtchnl.h b/include/linux/net/intel/virtchnl.h\nsimilarity index 100%\nrename from include/linux/avf/virtchnl.h\nrename to include/linux/net/intel/virtchnl.h\ndiff --git a/drivers/net/ethernet/intel/idpf/virtchnl2.h b/include/linux/net/intel/virtchnl2.h\nsimilarity index 100%\nrename from drivers/net/ethernet/intel/idpf/virtchnl2.h\nrename to include/linux/net/intel/virtchnl2.h\ndiff --git a/drivers/net/ethernet/intel/idpf/virtchnl2_lan_desc.h b/include/linux/net/intel/virtchnl2_lan_desc.h\nsimilarity index 100%\nrename from drivers/net/ethernet/intel/idpf/virtchnl2_lan_desc.h\nrename to include/linux/net/intel/virtchnl2_lan_desc.h\ndiff --git a/include/net/libeth/rx.h b/include/net/libeth/rx.h\nindex 5d991404845e6..0e736846c5e8a 100644\n--- a/include/net/libeth/rx.h\n+++ b/include/net/libeth/rx.h\n@@ -69,6 +69,7 @@ enum libeth_fqe_type {\n * @type: type of the buffers this queue has\n * @hsplit: flag whether header split is enabled\n * @xdp: flag indicating whether XDP is enabled\n+ * @no_napi: the queue is not a data queue and does not have NAPI\n * @buf_len: HW-writeable length per each buffer\n * @nid: ID of the closest NUMA node with memory\n */\n@@ -85,12 +86,13 @@ struct libeth_fq {\n \tenum libeth_fqe_type\ttype:2;\n \tbool\t\t\thsplit:1;\n \tbool\t\t\txdp:1;\n+\tbool\t\t\tno_napi:1;\n \n \tu32\t\t\tbuf_len;\n \tint\t\t\tnid;\n };\n \n-int libeth_rx_fq_create(struct libeth_fq *fq, struct napi_struct *napi);\n+int libeth_rx_fq_create(struct libeth_fq *fq, void *napi_dev);\n void libeth_rx_fq_destroy(struct libeth_fq *fq);\n \n /**\n"
} |
| 2/1 | 2026/08/12 21:56 | agent | patch-evaluator |
1mModel:best-expensive Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch introduces a new driver `ixd` for Intel Control Plane Function and refactors the `idpf` driver (Intel Infrastructure Data Path Function) to use common helper modules `libie_cp` and `libie_pci`. Both `ixd` and `idpf` are vendor-specific SmartNIC (Intel IPU) drivers that require physical PCIe hardware cards not emulated in standard QEMU. The changes to other drivers (`i40e`, `iavf`, `ice`) are purely `#include` path updates. Therefore, the functional changes are not reachable in virtualized environments.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). - Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed, ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU. - Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove) that are executed only during PCI hot-unplug or sysfs driver unbind operations. If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. Prefer non-static, non-inlined API entrypoint functions over internal static helper functions (which are inlined by the compiler and do not have distinct symbol addresses). 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit 70c3f5eae95ebe97c3f413cd4b978c15b52b382f
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Aug 12 21:56:24 2026 +0000
syz-cluster: applied patch under review
diff --git a/Documentation/networking/device_drivers/ethernet/index.rst b/Documentation/networking/device_drivers/ethernet/index.rst
index 786a23c84b901..d9980c84487a5 100644
--- a/Documentation/networking/device_drivers/ethernet/index.rst
+++ b/Documentation/networking/device_drivers/ethernet/index.rst
@@ -35,6 +35,7 @@ Contents:
intel/idpf
intel/igb
intel/igbvf
+ intel/ixd
intel/ixgbe
intel/ixgbevf
intel/i40e
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 0000000000000..1387626e5d20d
--- /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/Documentation/networking/devlink/index.rst b/Documentation/networking/devlink/index.rst
index 4745148fecf4f..d4a83fdcff7fe 100644
--- a/Documentation/networking/devlink/index.rst
+++ b/Documentation/networking/devlink/index.rst
@@ -87,6 +87,7 @@ parameters, info versions, and other features it supports.
ice
ionic
iosm
+ ixd
ixgbe
kvaser_pciefd
kvaser_usb
diff --git a/Documentation/networking/devlink/ixd.rst b/Documentation/networking/devlink/ixd.rst
new file mode 100644
index 0000000000000..cba4f6f650132
--- /dev/null
+++ b/Documentation/networking/devlink/ixd.rst
@@ -0,0 +1,30 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===================
+ixd devlink support
+===================
+
+This document describes the devlink features implemented by the ``ixd``
+device driver.
+
+Info versions
+=============
+
+The ``ixd`` driver reports the following versions
+
+.. list-table:: devlink info versions implemented
+ :widths: 5 5 5 90
+
+ * - Name
+ - Type
+ - Example
+ - Description
+ * - ``device.type``
+ - fixed
+ - MEV
+ - The hardware type for this device
+ * - ``fw.mgmt.api``
+ - running
+ - 2.0
+ - 2-digit version number (major.minor) of the communication channel
+ (virtchnl) used by the device.
diff --git a/MAINTAINERS b/MAINTAINERS
index e0e7fae5b92fb..0f29ea109db5d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13033,8 +13033,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/net/intel/
INTEL ETHERNET PROTOCOL DRIVER FOR RDMA
M: Tatyana Nikolova <tatyana.e.nikolova@intel.com>
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index 288fa8ce53af0..780f113986ea8 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -398,4 +398,6 @@ config IGC_LEDS
source "drivers/net/ethernet/intel/idpf/Kconfig"
+source "drivers/net/ethernet/intel/ixd/Kconfig"
+
endif # NET_VENDOR_INTEL
diff --git a/drivers/net/ethernet/intel/Makefile b/drivers/net/ethernet/intel/Makefile
index 9a37dc76aef0b..08b29f3b68011 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/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 83e780919ac97..1b6a8fbaa6485 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/net/intel/virtchnl.h>
#include <net/devlink.h>
#include <net/pkt_cls.h>
#include <net/udp_tunnel.h>
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index 59f5c1e810eb0..8dadfef2c09f6 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -1,10 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2021 Intel Corporation. */
-#include <linux/avf/virtchnl.h>
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
+#include <linux/net/intel/virtchnl.h>
#include <linux/pci.h>
#include "i40e_adminq_cmd.h"
#include "i40e_devids.h"
diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
index 26bb7bffe3610..e3d57550090ec 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/net/intel/virtchnl.h>
#include "i40e_debug.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 f558b45725c81..4e119c0502f34 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/net/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 050f8241ef5e6..dc31202b2a946 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -27,6 +27,7 @@
#include <linux/etherdevice.h>
#include <linux/socket.h>
#include <linux/jiffies.h>
+#include <linux/net/intel/virtchnl.h>
#include <net/ip6_checksum.h>
#include <net/pkt_cls.h>
#include <net/pkt_sched.h>
@@ -37,7 +38,6 @@
#include <net/net_shaper.h>
#include "iavf_type.h"
-#include <linux/avf/virtchnl.h>
#include "iavf_txrx.h"
#include "iavf_fdir.h"
#include "iavf_adv_rss.h"
diff --git a/drivers/net/ethernet/intel/iavf/iavf_common.c b/drivers/net/ethernet/intel/iavf/iavf_common.c
index 614a886bca99b..277193a97d910 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/net/intel/virtchnl.h>
#include <linux/bitfield.h>
#include "iavf_type.h"
#include "iavf_adminq.h"
diff --git a/drivers/net/ethernet/intel/iavf/iavf_prototype.h b/drivers/net/ethernet/intel/iavf/iavf_prototype.h
index 7f9f9dbf959ac..1b1f6ede39208 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_prototype.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_prototype.h
@@ -4,9 +4,10 @@
#ifndef _IAVF_PROTOTYPE_H_
#define _IAVF_PROTOTYPE_H_
+#include <linux/net/intel/virtchnl.h>
+
#include "iavf_type.h"
#include "iavf_alloc.h"
-#include <linux/avf/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_types.h b/drivers/net/ethernet/intel/iavf/iavf_types.h
index a095855122bf2..35d6d8fcca044 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/net/intel/virtchnl.h>
#include <linux/ptp_clock_kernel.h>
/* structure used to queue PTP commands for processing */
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index fc91b6665f905..db3c7015c56c4 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/net/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_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index 9f53442121955..d1d674ca644f6 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -5,13 +5,13 @@
#define _ICE_COMMON_H_
#include <linux/bitfield.h>
+#include <linux/net/intel/virtchnl.h>
#include "ice.h"
#include "ice_type.h"
#include "ice_nvm.h"
#include "ice_flex_pipe.h"
#include "ice_parser.h"
-#include <linux/avf/virtchnl.h>
#include "ice_switch.h"
#include "ice_fdir.h"
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
index 7a9c75d1d07cb..fa436b3b1eac2 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
@@ -8,9 +8,9 @@
#include <linux/hashtable.h>
#include <linux/bitmap.h>
#include <linux/mutex.h>
+#include <linux/net/intel/virtchnl.h>
#include <linux/pci.h>
#include <net/devlink.h>
-#include <linux/avf/virtchnl.h>
#include "ice_type.h"
#include "ice_flow.h"
#include "virt/fdir.h"
diff --git a/drivers/net/ethernet/intel/ice/virt/virtchnl.h b/drivers/net/ethernet/intel/ice/virt/virtchnl.h
index 71bb456e2d71a..d11789b3ae1f0 100644
--- a/drivers/net/ethernet/intel/ice/virt/virtchnl.h
+++ b/drivers/net/ethernet/intel/ice/virt/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/net/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/Kconfig b/drivers/net/ethernet/intel/idpf/Kconfig
index adab2154125ba..586df3a4afe90 100644
--- a/drivers/net/ethernet/intel/idpf/Kconfig
+++ b/drivers/net/ethernet/intel/idpf/Kconfig
@@ -6,6 +6,7 @@ config IDPF
depends on PCI_MSI
depends on PTP_1588_CLOCK_OPTIONAL
select DIMLIB
+ select LIBIE_CP
select LIBETH_XDP
help
This driver supports Intel(R) Infrastructure Data Path Function
diff --git a/drivers/net/ethernet/intel/idpf/Makefile b/drivers/net/ethernet/intel/idpf/Makefile
index 651ddee942bd8..4aaafa175ec37 100644
--- a/drivers/net/ethernet/intel/idpf/Makefile
+++ b/drivers/net/ethernet/intel/idpf/Makefile
@@ -6,8 +6,6 @@
obj-$(CONFIG_IDPF) += idpf.o
idpf-y := \
- idpf_controlq.o \
- idpf_controlq_setup.o \
idpf_dev.o \
idpf_ethtool.o \
idpf_idc.o \
diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index ec1b75f039bb2..470bc23c844c1 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -23,10 +23,10 @@ struct idpf_rss_data;
#include <linux/net/intel/iidc_rdma.h>
#include <linux/net/intel/iidc_rdma_idpf.h>
+#include <linux/net/intel/libie/controlq.h>
+#include <linux/net/intel/virtchnl2.h>
-#include "virtchnl2.h"
#include "idpf_txrx.h"
-#include "idpf_controlq.h"
#define GETMAXVAL(num_bits) GENMASK((num_bits) - 1, 0)
@@ -36,11 +36,10 @@ struct idpf_rss_data;
#define IDPF_NUM_FILTERS_PER_MSG 20
#define IDPF_NUM_DFLT_MBX_Q 2 /* includes both TX and RX */
#define IDPF_DFLT_MBX_Q_LEN 64
-#define IDPF_DFLT_MBX_ID -1
/* maximum number of times to try before resetting mailbox */
#define IDPF_MB_MAX_ERR 20
#define IDPF_NUM_CHUNKS_PER_MSG(struct_sz, chunk_sz) \
- ((IDPF_CTLQ_MAX_BUF_LEN - (struct_sz)) / (chunk_sz))
+ ((LIBIE_CTLQ_MAX_BUF_LEN - (struct_sz)) / (chunk_sz))
#define IDPF_WAIT_FOR_MARKER_TIMEO 500
#define IDPF_MAX_WAIT 500
@@ -201,8 +200,8 @@ struct idpf_vport_max_q {
* @ptp_reg_init: PTP register initialization
*/
struct idpf_reg_ops {
- void (*ctlq_reg_init)(struct idpf_adapter *adapter,
- struct idpf_ctlq_create_info *cq);
+ void (*ctlq_reg_init)(struct libie_mmio_info *mmio,
+ struct libie_ctlq_create_info *cctlq_info);
int (*intr_reg_init)(struct idpf_vport *vport,
struct idpf_q_vec_rsrc *rsrc);
void (*mb_intr_reg_init)(struct idpf_adapter *adapter);
@@ -605,8 +604,6 @@ struct idpf_vport_config {
DECLARE_BITMAP(flags, IDPF_VPORT_CONFIG_FLAGS_NBITS);
};
-struct idpf_vc_xn_manager;
-
#define idpf_for_each_vport(adapter, iter) \
for (struct idpf_vport **__##iter = &(adapter)->vports[0], \
*iter = (adapter)->max_vports ? *__##iter : NULL; \
@@ -624,7 +621,10 @@ struct idpf_vc_xn_manager;
* @state: Init state machine
* @flags: See enum idpf_flags
* @reset_reg: See struct idpf_reset_reg
- * @hw: Device access data
+ * @ctlq_ctx: controlq context
+ * @asq: Send control queue info
+ * @arq: Receive control queue info
+ * @xnm: Xn transaction manager
* @num_avail_msix: Available number of MSIX vectors
* @num_msix_entries: Number of entries in MSIX table
* @msix_entries: MSIX table
@@ -638,7 +638,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
@@ -658,7 +657,6 @@ struct idpf_vc_xn_manager;
* @stats_task: Periodic statistics retrieval task
* @stats_wq: Workqueue for statistics task
* @caps: Negotiated capabilities with device
- * @vcxn_mngr: Virtchnl transaction manager
* @dev_ops: See idpf_dev_ops
* @cdev_info: IDC core device info pointer
* @num_vfs: Number of allocated VFs through sysfs. PF does not directly talk
@@ -682,7 +680,10 @@ struct idpf_adapter {
enum idpf_state state;
DECLARE_BITMAP(flags, IDPF_FLAGS_NBITS);
struct idpf_reset_reg reset_reg;
- struct idpf_hw hw;
+ struct libie_ctlq_ctx ctlq_ctx;
+ struct libie_ctlq_info *asq;
+ struct libie_ctlq_info *arq;
+ struct libie_ctlq_xn_manager *xnm;
u16 num_avail_msix;
u16 num_msix_entries;
struct msix_entry *msix_entries;
@@ -697,7 +698,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;
@@ -720,7 +720,6 @@ struct idpf_adapter {
struct delayed_work stats_task;
struct workqueue_struct *stats_wq;
struct virtchnl2_get_capabilities caps;
- struct idpf_vc_xn_manager *vcxn_mngr;
struct idpf_dev_ops dev_ops;
struct iidc_rdma_core_dev_info *cdev_info;
@@ -872,70 +871,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_mbx_reg_addr - Get BAR0 mailbox register address
- * @adapter: private data struct
- * @reg_offset: register offset value
- *
- * Return: BAR0 mailbox register address based on register offset.
- */
-static inline void __iomem *idpf_get_mbx_reg_addr(struct idpf_adapter *adapter,
- resource_size_t reg_offset)
-{
- return adapter->hw.mbx.vaddr + reg_offset;
-}
-
-/**
- * idpf_get_rstat_reg_addr - Get BAR0 rstat register address
- * @adapter: private data struct
- * @reg_offset: register offset value
- *
- * Return: BAR0 rstat register address based on register offset.
- */
-static inline void __iomem *idpf_get_rstat_reg_addr(struct idpf_adapter *adapter,
- resource_size_t reg_offset)
-{
- reg_offset -= adapter->dev_ops.static_reg_info[1].start;
-
- return adapter->hw.rstat.vaddr + reg_offset;
-}
-
-/**
- * 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)
-{
- struct idpf_hw *hw = &adapter->hw;
-
- for (int i = 0; i < hw->num_lan_regs; i++) {
- struct idpf_mmio_reg *region = &hw->lan_regs[i];
-
- if (reg_offset >= region->addr_start &&
- reg_offset < (region->addr_start + region->addr_len)) {
- /* Convert the offset so that it is relative to the
- * start of the region. Then add the base address of
- * the region to get the final address.
- */
- reg_offset -= region->addr_start;
-
- return region->vaddr + reg_offset;
- }
- }
-
- /* It's impossible to hit this case with offsets from the CP. But if we
- * do for any other reason, the kernel will panic on that register
- * access. Might as well do it here to make it clear what's happening.
- */
- BUG();
-
- return NULL;
-}
-
/**
* idpf_is_reset_detected - check if we were reset at some point
* @adapter: driver specific private structure
@@ -944,11 +879,12 @@ static inline void __iomem *idpf_get_reg_addr(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(idpf_get_mbx_reg_addr(adapter, adapter->hw.arq->reg.len)) &
- adapter->hw.arq->reg.len_mask);
+ return !(readl(arq->reg.len) & arq->reg.len_mask);
}
/**
@@ -1048,6 +984,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_controlq.c b/drivers/net/ethernet/intel/idpf/idpf_controlq.c
deleted file mode 100644
index d2dde43269e9e..0000000000000
--- a/drivers/net/ethernet/intel/idpf/idpf_controlq.c
+++ /dev/null
@@ -1,621 +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)
- idpf_mbx_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 */
- idpf_mbx_wr32(hw, cq->reg.head, 0);
-
- /* set starting point */
- idpf_mbx_wr32(hw, cq->reg.bal, lower_32_bits(cq->desc_ring.pa));
- idpf_mbx_wr32(hw, cq->reg.bah, upper_32_bits(cq->desc_ring.pa));
- idpf_mbx_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)
-{
- spin_lock(&cq->cq_lock);
-
- /* free ring buffers and the ring itself */
- idpf_ctlq_dealloc_ring_res(hw, cq);
-
- /* Set ring_size to 0 to indicate uninitialized queue */
- cq->ring_size = 0;
-
- spin_unlock(&cq->cq_lock);
-}
-
-/**
- * idpf_ctlq_add - add one control queue
- * @hw: pointer to hardware struct
- * @qinfo: info for queue to be created
- * @cq_out: (output) double pointer to control queue to be created
- *
- * Allocate and initialize a control queue and add it to the control queue list.
- * The cq parameter will be allocated/initialized and passed back to the caller
- * if no errors occur.
- *
- * Note: idpf_ctlq_init must be called prior to any calls to idpf_ctlq_add
- */
-int idpf_ctlq_add(struct idpf_hw *hw,
- struct idpf_ctlq_create_info *qinfo,
- struct idpf_ctlq_info **cq_out)
-{
- struct idpf_ctlq_info *cq;
- bool is_rxq = false;
- int err;
-
- cq = kzalloc_obj(*cq);
- if (!cq)
- return -ENOMEM;
-
- cq->cq_type = qinfo->type;
- cq->q_id = qinfo->id;
- cq->buf_size = qinfo->buf_size;
- cq->ring_size = qinfo->len;
-
- cq->next_to_use = 0;
- cq->next_to_clean = 0;
- cq->next_to_post = cq->ring_size - 1;
-
- switch (qinfo->type) {
- case IDPF_CTLQ_TYPE_MAILBOX_RX:
- is_rxq = true;
- fallthrough;
- case IDPF_CTLQ_TYPE_MAILBOX_TX:
- err = idpf_ctlq_alloc_ring_res(hw, cq);
- break;
- default:
- err = -EBADR;
- break;
- }
-
- if (err)
- goto init_free_q;
-
- if (is_rxq) {
- idpf_ctlq_init_rxq_bufs(cq);
- } else {
- /* Allocate the array of msg pointers for TX queues */
- cq->bi.tx_msg = kzalloc_objs(struct idpf_ctlq_msg *, qinfo->len);
- if (!cq->bi.tx_msg) {
- err = -ENOMEM;
- goto init_dealloc_q_mem;
- }
- }
-
- idpf_ctlq_setup_regs(cq, qinfo);
-
- idpf_ctlq_init_regs(hw, cq, is_rxq);
-
- spin_lock_init(&cq->cq_lock);
-
- list_add(&cq->cq_list, &hw->cq_list_head);
-
- *cq_out = cq;
-
- return 0;
-
-init_dealloc_q_mem:
- /* free ring buffers and the ring itself */
- idpf_ctlq_dealloc_ring_res(hw, cq);
-init_free_q:
- kfree(cq);
-
- return err;
-}
-
-/**
- * idpf_ctlq_remove - deallocate and remove specified control queue
- * @hw: pointer to hardware struct
- * @cq: pointer to control queue to be removed
- */
-void idpf_ctlq_remove(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq)
-{
- list_del(&cq->cq_list);
- idpf_ctlq_shutdown(hw, cq);
- kfree(cq);
-}
-
-/**
- * idpf_ctlq_init - main initialization routine for all control queues
- * @hw: pointer to hardware struct
- * @num_q: number of queues to initialize
- * @q_info: array of structs containing info for each queue to be initialized
- *
- * This initializes any number and any type of control queues. This is an all
- * or nothing routine; if one fails, all previously allocated queues will be
- * destroyed. This must be called prior to using the individual add/remove
- * APIs.
- */
-int idpf_ctlq_init(struct idpf_hw *hw, u8 num_q,
- struct idpf_ctlq_create_info *q_info)
-{
- struct idpf_ctlq_info *cq, *tmp;
- int err;
- int i;
-
- INIT_LIST_HEAD(&hw->cq_list_head);
-
- for (i = 0; i < num_q; i++) {
- struct idpf_ctlq_create_info *qinfo = q_info + i;
-
- err = idpf_ctlq_add(hw, qinfo, &cq);
- if (err)
- goto init_destroy_qs;
- }
-
- return 0;
-
-init_destroy_qs:
- list_for_each_entry_safe(cq, tmp, &hw->cq_list_head, cq_list)
- idpf_ctlq_remove(hw, cq);
-
- return err;
-}
-
-/**
- * idpf_ctlq_deinit - destroy all control queues
- * @hw: pointer to hw struct
- */
-void idpf_ctlq_deinit(struct idpf_hw *hw)
-{
- struct idpf_ctlq_info *cq, *tmp;
-
- list_for_each_entry_safe(cq, tmp, &hw->cq_list_head, cq_list)
- idpf_ctlq_remove(hw, cq);
-}
-
-/**
- * idpf_ctlq_send - send command to Control Queue (CTQ)
- * @hw: pointer to hw struct
- * @cq: handle to control queue struct to send on
- * @num_q_msg: number of messages to send on control queue
- * @q_msg: pointer to array of queue messages to be sent
- *
- * The caller is expected to allocate DMAable buffers and pass them to the
- * send routine via the q_msg struct / control queue specific data struct.
- * The control queue will hold a reference to each send message until
- * the completion for that message has been cleaned.
- */
-int idpf_ctlq_send(struct idpf_hw *hw, struct idpf_ctlq_info *cq,
- u16 num_q_msg, struct idpf_ctlq_msg q_msg[])
-{
- struct idpf_ctlq_desc *desc;
- int num_desc_avail;
- int err = 0;
- int i;
-
- spin_lock(&cq->cq_lock);
-
- /* Ensure there are enough descriptors to send all messages */
- num_desc_avail = IDPF_CTLQ_DESC_UNUSED(cq);
- if (num_desc_avail == 0 || num_desc_avail < num_q_msg) {
- err = -ENOSPC;
- goto err_unlock;
- }
-
- for (i = 0; i < num_q_msg; i++) {
- struct idpf_ctlq_msg *msg = &q_msg[i];
-
- desc = IDPF_CTLQ_DESC(cq, cq->next_to_use);
-
- desc->opcode = cpu_to_le16(msg->opcode);
- desc->pfid_vfid = cpu_to_le16(msg->func_id);
-
- desc->v_opcode_dtype = cpu_to_le32(msg->cookie.mbx.chnl_opcode);
- desc->v_retval = cpu_to_le32(msg->cookie.mbx.chnl_retval);
-
- desc->flags = cpu_to_le16((msg->host_id & IDPF_HOST_ID_MASK) <<
- IDPF_CTLQ_FLAG_HOST_ID_S);
- if (msg->data_len) {
- struct idpf_dma_mem *buff = msg->ctx.indirect.payload;
-
- desc->datalen |= cpu_to_le16(msg->data_len);
- desc->flags |= cpu_to_le16(IDPF_CTLQ_FLAG_BUF);
- desc->flags |= cpu_to_le16(IDPF_CTLQ_FLAG_RD);
-
- /* Update the address values in the desc with the pa
- * value for respective buffer
- */
- desc->params.indirect.addr_high =
- cpu_to_le32(upper_32_bits(buff->pa));
- desc->params.indirect.addr_low =
- cpu_to_le32(lower_32_bits(buff->pa));
-
- memcpy(&desc->params, msg->ctx.indirect.context,
- IDPF_INDIRECT_CTX_SIZE);
- } else {
- memcpy(&desc->params, msg->ctx.direct,
- IDPF_DIRECT_CTX_SIZE);
- }
-
- /* Store buffer info */
- cq->bi.tx_msg[cq->next_to_use] = msg;
-
- (cq->next_to_use)++;
- if (cq->next_to_use == cq->ring_size)
- cq->next_to_use = 0;
- }
-
- /* Force memory write to complete before letting hardware
- * know that there are new descriptors to fetch.
- */
- dma_wmb();
-
- idpf_mbx_wr32(hw, cq->reg.tail, cq->next_to_use);
-
-err_unlock:
- spin_unlock(&cq->cq_lock);
-
- return err;
-}
-
-/**
- * idpf_ctlq_clean_sq - reclaim send descriptors on HW write back for the
- * requested queue
- * @cq: pointer to the specific Control queue
- * @clean_count: (input|output) number of descriptors to clean as input, and
- * number of descriptors actually cleaned as output
- * @msg_status: (output) pointer to msg pointer array to be populated; needs
- * to be allocated by caller
- *
- * Returns an array of message pointers associated with the cleaned
- * descriptors. The pointers are to the original ctlq_msgs sent on the cleaned
- * descriptors. The status will be returned for each; any messages that failed
- * to send will have a non-zero status. The caller is expected to free original
- * ctlq_msgs and free or reuse the DMA buffers.
- */
-int idpf_ctlq_clean_sq(struct idpf_ctlq_info *cq, u16 *clean_count,
- struct idpf_ctlq_msg *msg_status[])
-{
- struct idpf_ctlq_desc *desc;
- u16 i, num_to_clean;
- u16 ntc, desc_err;
-
- if (*clean_count == 0)
- return 0;
- if (*clean_count > cq->ring_size)
- return -EBADR;
-
- spin_lock(&cq->cq_lock);
-
- ntc = cq->next_to_clean;
-
- num_to_clean = *clean_count;
-
- for (i = 0; i < num_to_clean; i++) {
- /* Fetch next descriptor and check if marked as done */
- desc = IDPF_CTLQ_DESC(cq, ntc);
- if (!(le16_to_cpu(desc->flags) & IDPF_CTLQ_FLAG_DD))
- break;
-
- /* Ensure no other fields are read until DD flag is checked */
- dma_rmb();
-
- /* strip off FW internal code */
- desc_err = le16_to_cpu(desc->ret_val) & 0xff;
-
- msg_status[i] = cq->bi.tx_msg[ntc];
- msg_status[i]->status = desc_err;
-
- cq->bi.tx_msg[ntc] = NULL;
-
- /* Zero out any stale data */
- memset(desc, 0, sizeof(*desc));
-
- ntc++;
- if (ntc == cq->ring_size)
- ntc = 0;
- }
-
- cq->next_to_clean = ntc;
-
- spin_unlock(&cq->cq_lock);
-
- /* Return number of descriptors actually cleaned */
- *clean_count = i;
-
- return 0;
-}
-
-/**
- * idpf_ctlq_post_rx_buffs - post buffers to descriptor ring
- * @hw: pointer to hw struct
- * @cq: pointer to control queue handle
- * @buff_count: (input|output) input is number of buffers caller is trying to
- * return; output is number of buffers that were not posted
- * @buffs: array of pointers to dma mem structs to be given to hardware
- *
- * Caller uses this function to return DMA buffers to the descriptor ring after
- * consuming them; buff_count will be the number of buffers.
- *
- * Note: this function needs to be called after a receive call even
- * if there are no DMA buffers to be returned, i.e. buff_count = 0,
- * buffs = NULL to support direct commands
- */
-int idpf_ctlq_post_rx_buffs(struct idpf_hw *hw, struct idpf_ctlq_info *cq,
- u16 *buff_count, struct idpf_dma_mem **buffs)
-{
- struct idpf_ctlq_desc *desc;
- u16 ntp = cq->next_to_post;
- bool buffs_avail = false;
- u16 tbp = ntp + 1;
- int i = 0;
-
- if (*buff_count > cq->ring_size)
- return -EBADR;
-
- if (*buff_count > 0)
- buffs_avail = true;
-
- spin_lock(&cq->cq_lock);
-
- if (tbp >= cq->ring_size)
- tbp = 0;
-
- if (tbp == cq->next_to_clean)
- /* Nothing to do */
- goto post_buffs_out;
-
- /* Post buffers for as many as provided or up until the last one used */
- while (ntp != cq->next_to_clean) {
- desc = IDPF_CTLQ_DESC(cq, ntp);
-
- if (cq->bi.rx_buff[ntp])
- goto fill_desc;
- if (!buffs_avail) {
- /* If the caller hasn't given us any buffers or
- * there are none left, search the ring itself
- * for an available buffer to move to this
- * entry starting at the next entry in the ring
- */
- tbp = ntp + 1;
-
- /* Wrap ring if necessary */
- if (tbp >= cq->ring_size)
- tbp = 0;
-
- while (tbp != cq->next_to_clean) {
- if (cq->bi.rx_buff[tbp]) {
- cq->bi.rx_buff[ntp] =
- cq->bi.rx_buff[tbp];
- cq->bi.rx_buff[tbp] = NULL;
-
- /* Found a buffer, no need to
- * search anymore
- */
- break;
- }
-
- /* Wrap ring if necessary */
- tbp++;
- if (tbp >= cq->ring_size)
- tbp = 0;
- }
-
- if (tbp == cq->next_to_clean)
- goto post_buffs_out;
- } else {
- /* Give back pointer to DMA buffer */
- cq->bi.rx_buff[ntp] = buffs[i];
- i++;
-
- if (i >= *buff_count)
- buffs_avail = false;
- }
-
-fill_desc:
- desc->flags =
- cpu_to_le16(IDPF_CTLQ_FLAG_BUF | IDPF_CTLQ_FLAG_RD);
-
- /* Post buffers to descriptor */
- desc->datalen = cpu_to_le16(cq->bi.rx_buff[ntp]->size);
- desc->params.indirect.addr_high =
- cpu_to_le32(upper_32_bits(cq->bi.rx_buff[ntp]->pa));
- desc->params.indirect.addr_low =
- cpu_to_le32(lower_32_bits(cq->bi.rx_buff[ntp]->pa));
-
- ntp++;
- if (ntp == cq->ring_size)
- ntp = 0;
- }
-
-post_buffs_out:
- /* Only update tail if buffers were actually posted */
- if (cq->next_to_post != ntp) {
- if (ntp)
- /* Update next_to_post to ntp - 1 since current ntp
- * will not have a buffer
- */
- cq->next_to_post = ntp - 1;
- else
- /* Wrap to end of end ring since current ntp is 0 */
- cq->next_to_post = cq->ring_size - 1;
-
- dma_wmb();
-
- idpf_mbx_wr32(hw, cq->reg.tail, cq->next_to_post);
- }
-
- spin_unlock(&cq->cq_lock);
-
- /* return the number of buffers that were not posted */
- *buff_count = *buff_count - i;
-
- return 0;
-}
-
-/**
- * idpf_ctlq_recv - receive control queue message call back
- * @cq: pointer to control queue handle to receive on
- * @num_q_msg: (input|output) input number of messages that should be received;
- * output number of messages actually received
- * @q_msg: (output) array of received control queue messages on this q;
- * needs to be pre-allocated by caller for as many messages as requested
- *
- * Called by interrupt handler or polling mechanism. Caller is expected
- * to free buffers
- */
-int idpf_ctlq_recv(struct idpf_ctlq_info *cq, u16 *num_q_msg,
- struct idpf_ctlq_msg *q_msg)
-{
- u16 num_to_clean, ntc, flags;
- struct idpf_ctlq_desc *desc;
- int err = 0;
- u16 i;
-
- /* take the lock before we start messing with the ring */
- spin_lock(&cq->cq_lock);
-
- ntc = cq->next_to_clean;
-
- num_to_clean = *num_q_msg;
-
- for (i = 0; i < num_to_clean; i++) {
- /* Fetch next descriptor and check if marked as done */
- desc = IDPF_CTLQ_DESC(cq, ntc);
- flags = le16_to_cpu(desc->flags);
-
- if (!(flags & IDPF_CTLQ_FLAG_DD))
- break;
-
- /* Ensure no other fields are read until DD flag is checked */
- dma_rmb();
-
- q_msg[i].vmvf_type = (flags &
- (IDPF_CTLQ_FLAG_FTYPE_VM |
- IDPF_CTLQ_FLAG_FTYPE_PF)) >>
- IDPF_CTLQ_FLAG_FTYPE_S;
-
- if (flags & IDPF_CTLQ_FLAG_ERR)
- err = -EBADMSG;
-
- q_msg[i].cookie.mbx.chnl_opcode =
- le32_to_cpu(desc->v_opcode_dtype);
- q_msg[i].cookie.mbx.chnl_retval =
- le32_to_cpu(desc->v_retval);
-
- q_msg[i].opcode = le16_to_cpu(desc->opcode);
- q_msg[i].data_len = le16_to_cpu(desc->datalen);
- q_msg[i].status = le16_to_cpu(desc->ret_val);
-
- if (desc->datalen) {
- memcpy(q_msg[i].ctx.indirect.context,
- &desc->params.indirect, IDPF_INDIRECT_CTX_SIZE);
-
- /* Assign pointer to dma buffer to ctlq_msg array
- * to be given to upper layer
- */
- q_msg[i].ctx.indirect.payload = cq->bi.rx_buff[ntc];
-
- /* Zero out pointer to DMA buffer info;
- * will be repopulated by post buffers API
- */
- cq->bi.rx_buff[ntc] = NULL;
- } else {
- memcpy(q_msg[i].ctx.direct, desc->params.raw,
- IDPF_DIRECT_CTX_SIZE);
- }
-
- /* Zero out stale data in descriptor */
- memset(desc, 0, sizeof(struct idpf_ctlq_desc));
-
- ntc++;
- if (ntc == cq->ring_size)
- ntc = 0;
- }
-
- cq->next_to_clean = ntc;
-
- spin_unlock(&cq->cq_lock);
-
- *num_q_msg = i;
- if (*num_q_msg == 0)
- err = -ENOMSG;
-
- return err;
-}
diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq.h b/drivers/net/ethernet/intel/idpf/idpf_controlq.h
deleted file mode 100644
index de4ece40c2ff3..0000000000000
--- a/drivers/net/ethernet/intel/idpf/idpf_controlq.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (C) 2023 Intel Corporation */
-
-#ifndef _IDPF_CONTROLQ_H_
-#define _IDPF_CONTROLQ_H_
-
-#include <linux/slab.h>
-
-#include "idpf_controlq_api.h"
-
-/* Maximum buffer length for all control queue types */
-#define IDPF_CTLQ_MAX_BUF_LEN 4096
-
-#define IDPF_CTLQ_DESC(R, i) \
- (&(((struct idpf_ctlq_desc *)((R)->desc_ring.va))[i]))
-
-#define IDPF_CTLQ_DESC_UNUSED(R) \
- ((u16)((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->ring_size) + \
- (R)->next_to_clean - (R)->next_to_use - 1))
-
-/* Control Queue default settings */
-#define IDPF_CTRL_SQ_CMD_TIMEOUT 250 /* msecs */
-
-struct idpf_ctlq_desc {
- /* Control queue descriptor flags */
- __le16 flags;
- /* Control queue message opcode */
- __le16 opcode;
- __le16 datalen; /* 0 for direct commands */
- union {
- __le16 ret_val;
- __le16 pfid_vfid;
-#define IDPF_CTLQ_DESC_VF_ID_S 0
-#define IDPF_CTLQ_DESC_VF_ID_M (0x7FF << IDPF_CTLQ_DESC_VF_ID_S)
-#define IDPF_CTLQ_DESC_PF_ID_S 11
-#define IDPF_CTLQ_DESC_PF_ID_M (0x1F << IDPF_CTLQ_DESC_PF_ID_S)
- };
-
- /* Virtchnl message opcode and virtchnl descriptor type
- * v_opcode=[27:0], v_dtype=[31:28]
- */
- __le32 v_opcode_dtype;
- /* Virtchnl return value */
- __le32 v_retval;
- union {
- struct {
- __le32 param0;
- __le32 param1;
- __le32 param2;
- __le32 param3;
- } direct;
- struct {
- __le32 param0;
- __le16 sw_cookie;
- /* Virtchnl flags */
- __le16 v_flags;
- __le32 addr_high;
- __le32 addr_low;
- } indirect;
- u8 raw[16];
- } params;
-};
-
-/* Flags sub-structure
- * |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10 |11 |12 |13 |14 |15 |
- * |DD |CMP|ERR| * RSV * |FTYPE | *RSV* |RD |VFC|BUF| HOST_ID |
- */
-/* command flags and offsets */
-#define IDPF_CTLQ_FLAG_DD_S 0
-#define IDPF_CTLQ_FLAG_CMP_S 1
-#define IDPF_CTLQ_FLAG_ERR_S 2
-#define IDPF_CTLQ_FLAG_FTYPE_S 6
-#define IDPF_CTLQ_FLAG_RD_S 10
-#define IDPF_CTLQ_FLAG_VFC_S 11
-#define IDPF_CTLQ_FLAG_BUF_S 12
-#define IDPF_CTLQ_FLAG_HOST_ID_S 13
-
-#define IDPF_CTLQ_FLAG_DD BIT(IDPF_CTLQ_FLAG_DD_S) /* 0x1 */
-#define IDPF_CTLQ_FLAG_CMP BIT(IDPF_CTLQ_FLAG_CMP_S) /* 0x2 */
-#define IDPF_CTLQ_FLAG_ERR BIT(IDPF_CTLQ_FLAG_ERR_S) /* 0x4 */
-#define IDPF_CTLQ_FLAG_FTYPE_VM BIT(IDPF_CTLQ_FLAG_FTYPE_S) /* 0x40 */
-#define IDPF_CTLQ_FLAG_FTYPE_PF BIT(IDPF_CTLQ_FLAG_FTYPE_S + 1) /* 0x80 */
-#define IDPF_CTLQ_FLAG_RD BIT(IDPF_CTLQ_FLAG_RD_S) /* 0x400 */
-#define IDPF_CTLQ_FLAG_VFC BIT(IDPF_CTLQ_FLAG_VFC_S) /* 0x800 */
-#define IDPF_CTLQ_FLAG_BUF BIT(IDPF_CTLQ_FLAG_BUF_S) /* 0x1000 */
-
-/* Host ID is a special field that has 3b and not a 1b flag */
-#define IDPF_CTLQ_FLAG_HOST_ID_M MAKE_MASK(0x7000UL, IDPF_CTLQ_FLAG_HOST_ID_S)
-
-struct idpf_mbxq_desc {
- u8 pad[8]; /* CTLQ flags/opcode/len/retval fields */
- u32 chnl_opcode; /* avoid confusion with desc->opcode */
- u32 chnl_retval; /* ditto for desc->retval */
- u32 pf_vf_id; /* used by CP when sending to PF */
-};
-
-/* Max number of MMIO regions not including the mailbox and rstat regions in
- * the fallback case when the whole bar is mapped.
- */
-#define IDPF_MMIO_MAP_FALLBACK_MAX_REMAINING 3
-
-struct idpf_mmio_reg {
- void __iomem *vaddr;
- resource_size_t addr_start;
- resource_size_t addr_len;
-};
-
-/* Define the driver hardware struct to replace other control structs as needed
- * Align to ctlq_hw_info
- */
-struct idpf_hw {
- struct idpf_mmio_reg mbx;
- struct idpf_mmio_reg rstat;
- /* Array of remaining LAN BAR regions */
- int num_lan_regs;
- struct idpf_mmio_reg *lan_regs;
-
- struct idpf_adapter *back;
-
- /* control queue - send and receive */
- struct idpf_ctlq_info *asq;
- struct idpf_ctlq_info *arq;
-
- /* pci info */
- u16 device_id;
- u16 vendor_id;
- u16 subsystem_device_id;
- u16 subsystem_vendor_id;
- u8 revision_id;
- bool adapter_stopped;
-
- struct list_head cq_list_head;
-};
-
-int idpf_ctlq_alloc_ring_res(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq);
-
-void idpf_ctlq_dealloc_ring_res(struct idpf_hw *hw, struct idpf_ctlq_info *cq);
-
-/* prototype for functions used for dynamic memory allocation */
-void *idpf_alloc_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem,
- u64 size);
-void idpf_free_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem);
-#endif /* _IDPF_CONTROLQ_H_ */
diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h b/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h
deleted file mode 100644
index 3414c5f9a8319..0000000000000
--- a/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (C) 2023 Intel Corporation */
-
-#ifndef _IDPF_CONTROLQ_API_H_
-#define _IDPF_CONTROLQ_API_H_
-
-#include "idpf_mem.h"
-
-struct idpf_hw;
-
-/* Used for queue init, response and events */
-enum idpf_ctlq_type {
- IDPF_CTLQ_TYPE_MAILBOX_TX = 0,
- IDPF_CTLQ_TYPE_MAILBOX_RX = 1,
- IDPF_CTLQ_TYPE_CONFIG_TX = 2,
- IDPF_CTLQ_TYPE_CONFIG_RX = 3,
- IDPF_CTLQ_TYPE_EVENT_RX = 4,
- IDPF_CTLQ_TYPE_RDMA_TX = 5,
- IDPF_CTLQ_TYPE_RDMA_RX = 6,
- IDPF_CTLQ_TYPE_RDMA_COMPL = 7
-};
-
-/* Generic Control Queue Structures */
-struct idpf_ctlq_reg {
- /* used for queue tracking */
- u32 head;
- u32 tail;
- /* Below applies only to default mb (if present) */
- u32 len;
- u32 bah;
- u32 bal;
- u32 len_mask;
- u32 len_ena_mask;
- u32 head_mask;
-};
-
-/* Generic queue msg structure */
-struct idpf_ctlq_msg {
- u8 vmvf_type; /* represents the source of the message on recv */
-#define IDPF_VMVF_TYPE_VF 0
-#define IDPF_VMVF_TYPE_VM 1
-#define IDPF_VMVF_TYPE_PF 2
- u8 host_id;
- /* 3b field used only when sending a message to CP - to be used in
- * combination with target func_id to route the message
- */
-#define IDPF_HOST_ID_MASK 0x7
-
- u16 opcode;
- u16 data_len; /* data_len = 0 when no payload is attached */
- union {
- u16 func_id; /* when sending a message */
- u16 status; /* when receiving a message */
- };
- union {
- struct {
- u32 chnl_opcode;
- u32 chnl_retval;
- } mbx;
- } cookie;
- union {
-#define IDPF_DIRECT_CTX_SIZE 16
-#define IDPF_INDIRECT_CTX_SIZE 8
- /* 16 bytes of context can be provided or 8 bytes of context
- * plus the address of a DMA buffer
- */
- u8 direct[IDPF_DIRECT_CTX_SIZE];
- struct {
- u8 context[IDPF_INDIRECT_CTX_SIZE];
- struct idpf_dma_mem *payload;
- } indirect;
- struct {
- u32 rsvd;
- u16 data;
- u16 flags;
- } sw_cookie;
- } ctx;
-};
-
-/* Generic queue info structures */
-/* MB, CONFIG and EVENT q do not have extended info */
-struct idpf_ctlq_create_info {
- enum idpf_ctlq_type type;
- int id; /* absolute queue offset passed as input
- * -1 for default mailbox if present
- */
- u16 len; /* Queue length passed as input */
- u16 buf_size; /* buffer size passed as input */
- u64 base_address; /* output, HPA of the Queue start */
- struct idpf_ctlq_reg reg; /* registers accessed by ctlqs */
-
- int ext_info_size;
- void *ext_info; /* Specific to q type */
-};
-
-/* Control Queue information */
-struct idpf_ctlq_info {
- struct list_head cq_list;
-
- enum idpf_ctlq_type cq_type;
- int q_id;
- spinlock_t cq_lock; /* control queue lock */
- /* used for interrupt processing */
- u16 next_to_use;
- u16 next_to_clean;
- u16 next_to_post; /* starting descriptor to post buffers
- * to after recev
- */
-
- struct idpf_dma_mem desc_ring; /* descriptor ring memory
- * idpf_dma_mem is defined in OSdep.h
- */
- union {
- struct idpf_dma_mem **rx_buff;
- struct idpf_ctlq_msg **tx_msg;
- } bi;
-
- u16 buf_size; /* queue buffer size */
- u16 ring_size; /* Number of descriptors */
- struct idpf_ctlq_reg reg; /* registers accessed by ctlqs */
-};
-
-/**
- * enum idpf_mbx_opc - PF/VF mailbox commands
- * @idpf_mbq_opc_send_msg_to_cp: used by PF or VF to send a message to its CP
- * @idpf_mbq_opc_send_msg_to_peer_drv: used by PF or VF to send a message to
- * any peer driver
- */
-enum idpf_mbx_opc {
- idpf_mbq_opc_send_msg_to_cp = 0x0801,
- idpf_mbq_opc_send_msg_to_peer_drv = 0x0804,
-};
-
-/* API supported for control queue management */
-/* Will init all required q including default mb. "q_info" is an array of
- * create_info structs equal to the number of control queues to be created.
- */
-int idpf_ctlq_init(struct idpf_hw *hw, u8 num_q,
- struct idpf_ctlq_create_info *q_info);
-
-/* Allocate and initialize a single control queue, which will be added to the
- * control queue list; returns a handle to the created control queue
- */
-int idpf_ctlq_add(struct idpf_hw *hw,
- struct idpf_ctlq_create_info *qinfo,
- struct idpf_ctlq_info **cq);
-
-/* Deinitialize and deallocate a single control queue */
-void idpf_ctlq_remove(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq);
-
-/* Sends messages to HW and will also free the buffer*/
-int idpf_ctlq_send(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq,
- u16 num_q_msg,
- struct idpf_ctlq_msg q_msg[]);
-
-/* Receives messages and called by interrupt handler/polling
- * initiated by app/process. Also caller is supposed to free the buffers
- */
-int idpf_ctlq_recv(struct idpf_ctlq_info *cq, u16 *num_q_msg,
- struct idpf_ctlq_msg *q_msg);
-
-/* Reclaims send descriptors on HW write back */
-int idpf_ctlq_clean_sq(struct idpf_ctlq_info *cq, u16 *clean_count,
- struct idpf_ctlq_msg *msg_status[]);
-
-/* Indicate RX buffers are done being processed */
-int idpf_ctlq_post_rx_buffs(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq,
- u16 *buff_count,
- struct idpf_dma_mem **buffs);
-
-/* Will destroy all q including the default mb */
-void idpf_ctlq_deinit(struct idpf_hw *hw);
-
-#endif /* _IDPF_CONTROLQ_API_H_ */
diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c b/drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c
deleted file mode 100644
index d4d488c7cfd60..0000000000000
--- a/drivers/net/ethernet/intel/idpf/idpf_controlq_setup.c
+++ /dev/null
@@ -1,169 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (C) 2023 Intel Corporation */
-
-#include "idpf_controlq.h"
-
-/**
- * idpf_ctlq_alloc_desc_ring - Allocate Control Queue (CQ) rings
- * @hw: pointer to hw struct
- * @cq: pointer to the specific Control queue
- */
-static int idpf_ctlq_alloc_desc_ring(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq)
-{
- size_t size = cq->ring_size * sizeof(struct idpf_ctlq_desc);
-
- cq->desc_ring.va = idpf_alloc_dma_mem(hw, &cq->desc_ring, size);
- if (!cq->desc_ring.va)
- return -ENOMEM;
-
- return 0;
-}
-
-/**
- * idpf_ctlq_alloc_bufs - Allocate Control Queue (CQ) buffers
- * @hw: pointer to hw struct
- * @cq: pointer to the specific Control queue
- *
- * Allocate the buffer head for all control queues, and if it's a receive
- * queue, allocate DMA buffers
- */
-static int idpf_ctlq_alloc_bufs(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq)
-{
- int i;
-
- /* Do not allocate DMA buffers for transmit queues */
- if (cq->cq_type == IDPF_CTLQ_TYPE_MAILBOX_TX)
- return 0;
-
- /* We'll be allocating the buffer info memory first, then we can
- * allocate the mapped buffers for the event processing
- */
- cq->bi.rx_buff = kzalloc_objs(struct idpf_dma_mem *, cq->ring_size);
- if (!cq->bi.rx_buff)
- return -ENOMEM;
-
- /* allocate the mapped buffers (except for the last one) */
- for (i = 0; i < cq->ring_size - 1; i++) {
- struct idpf_dma_mem *bi;
- int num = 1; /* number of idpf_dma_mem to be allocated */
-
- cq->bi.rx_buff[i] = kzalloc_objs(struct idpf_dma_mem, num);
- if (!cq->bi.rx_buff[i])
- goto unwind_alloc_cq_bufs;
-
- bi = cq->bi.rx_buff[i];
-
- bi->va = idpf_alloc_dma_mem(hw, bi, cq->buf_size);
- if (!bi->va) {
- /* unwind will not free the failed entry */
- kfree(cq->bi.rx_buff[i]);
- goto unwind_alloc_cq_bufs;
- }
- }
-
- return 0;
-
-unwind_alloc_cq_bufs:
- /* don't try to free the one that failed... */
- i--;
- for (; i >= 0; i--) {
- idpf_free_dma_mem(hw, cq->bi.rx_buff[i]);
- kfree(cq->bi.rx_buff[i]);
- }
- kfree(cq->bi.rx_buff);
-
- return -ENOMEM;
-}
-
-/**
- * idpf_ctlq_free_desc_ring - Free Control Queue (CQ) rings
- * @hw: pointer to hw struct
- * @cq: pointer to the specific Control queue
- *
- * This assumes the posted send buffers have already been cleaned
- * and de-allocated
- */
-static void idpf_ctlq_free_desc_ring(struct idpf_hw *hw,
- struct idpf_ctlq_info *cq)
-{
- idpf_free_dma_mem(hw, &cq->desc_ring);
-}
-
-/**
- * idpf_ctlq_free_bufs - Free CQ buffer info elements
- * @hw: pointer to hw struct
- * @cq: pointer to the specific Control queue
- *
- * Free the DMA buffers for RX queues, and DMA buffer header for both RX and TX
- * queues. The upper layers are expected to manage freeing of TX DMA buffers
- */
-static void idpf_ctlq_free_bufs(struct idpf_hw *hw, struct idpf_ctlq_info *cq)
-{
- void *bi;
-
- if (cq->cq_type == IDPF_CTLQ_TYPE_MAILBOX_RX) {
- int i;
-
- /* free DMA buffers for rx queues*/
- for (i = 0; i < cq->ring_size; i++) {
- if (cq->bi.rx_buff[i]) {
- idpf_free_dma_mem(hw, cq->bi.rx_buff[i]);
- kfree(cq->bi.rx_buff[i]);
- }
- }
-
- bi = (void *)cq->bi.rx_buff;
- } else {
- bi = (void *)cq->bi.tx_msg;
- }
-
- /* free the buffer header */
- kfree(bi);
-}
-
-/**
- * idpf_ctlq_dealloc_ring_res - Free memory allocated for control queue
- * @hw: pointer to hw struct
- * @cq: pointer to the specific Control queue
- *
- * Free the memory used by the ring, buffers and other related structures
- */
-void idpf_ctlq_dealloc_ring_res(struct idpf_hw *hw, struct idpf_ctlq_info *cq)
-{
- /* free ring buffers and the ring itself */
- idpf_ctlq_free_bufs(hw, cq);
- idpf_ctlq_free_desc_ring(hw, cq);
-}
-
-/**
- * idpf_ctlq_alloc_ring_res - allocate memory for descriptor ring and bufs
- * @hw: pointer to hw struct
- * @cq: pointer to control queue struct
- *
- * Do *NOT* hold cq_lock when calling this as the memory allocation routines
- * called are not going to be atomic context safe
- */
-int idpf_ctlq_alloc_ring_res(struct idpf_hw *hw, struct idpf_ctlq_info *cq)
-{
- int err;
-
- /* allocate the ring memory */
- err = idpf_ctlq_alloc_desc_ring(hw, cq);
- if (err)
- return err;
-
- /* allocate buffers in the rings */
- err = idpf_ctlq_alloc_bufs(hw, cq);
- if (err)
- goto idpf_init_cq_free_ring;
-
- /* success! */
- return 0;
-
-idpf_init_cq_free_ring:
- idpf_free_dma_mem(hw, &cq->desc_ring);
-
- return err;
-}
diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c
index 4079a787657f1..083cf6319d262 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c
@@ -10,45 +10,32 @@
/**
* idpf_ctlq_reg_init - initialize default mailbox registers
- * @adapter: adapter structure
- * @cq: pointer to the array of create control queues
+ * @mmio: struct that contains MMIO region info
+ * @cci: struct where the register offset pointer to be copied to
*/
-static void idpf_ctlq_reg_init(struct idpf_adapter *adapter,
- struct idpf_ctlq_create_info *cq)
+static void idpf_ctlq_reg_init(struct libie_mmio_info *mmio,
+ struct libie_ctlq_create_info *cci)
{
- resource_size_t mbx_start = adapter->dev_ops.static_reg_info[0].start;
- int i;
-
- for (i = 0; i < IDPF_NUM_DFLT_MBX_Q; i++) {
- struct idpf_ctlq_create_info *ccq = cq + i;
-
- switch (ccq->type) {
- case IDPF_CTLQ_TYPE_MAILBOX_TX:
- /* set head and tail registers in our local struct */
- ccq->reg.head = PF_FW_ATQH - mbx_start;
- ccq->reg.tail = PF_FW_ATQT - mbx_start;
- ccq->reg.len = PF_FW_ATQLEN - mbx_start;
- ccq->reg.bah = PF_FW_ATQBAH - mbx_start;
- ccq->reg.bal = PF_FW_ATQBAL - mbx_start;
- 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 - mbx_start;
- ccq->reg.tail = PF_FW_ARQT - mbx_start;
- ccq->reg.len = PF_FW_ARQLEN - mbx_start;
- ccq->reg.bah = PF_FW_ARQBAH - mbx_start;
- ccq->reg.bal = PF_FW_ARQBAL - mbx_start;
- ccq->reg.len_mask = PF_FW_ARQLEN_ARQLEN_M;
- ccq->reg.len_ena_mask = PF_FW_ARQLEN_ARQENABLE_M;
- ccq->reg.head_mask = PF_FW_ARQH_ARQH_M;
- break;
- default:
- break;
- }
- }
+ struct libie_ctlq_reg *tx_reg = &cci[LIBIE_CTLQ_TYPE_TX].reg;
+ struct libie_ctlq_reg *rx_reg = &cci[LIBIE_CTLQ_TYPE_RX].reg;
+
+ tx_reg->head = libie_pci_get_mmio_addr(mmio, PF_FW_ATQH);
+ tx_reg->tail = libie_pci_get_mmio_addr(mmio, PF_FW_ATQT);
+ tx_reg->len = libie_pci_get_mmio_addr(mmio, PF_FW_ATQLEN);
+ tx_reg->addr_high = libie_pci_get_mmio_addr(mmio, PF_FW_ATQBAH);
+ tx_reg->addr_low = libie_pci_get_mmio_addr(mmio, PF_FW_ATQBAL);
+ tx_reg->len_mask = PF_FW_ATQLEN_ATQLEN_M;
+ tx_reg->len_ena_mask = PF_FW_ATQLEN_ATQENABLE_M;
+ tx_reg->head_mask = PF_FW_ATQH_ATQH_M;
+
+ rx_reg->head = libie_pci_get_mmio_addr(mmio, PF_FW_ARQH);
+ rx_reg->tail = libie_pci_get_mmio_addr(mmio, PF_FW_ARQT);
+ rx_reg->len = libie_pci_get_mmio_addr(mmio, PF_FW_ARQLEN);
+ rx_reg->addr_high = libie_pci_get_mmio_addr(mmio, PF_FW_ARQBAH);
+ rx_reg->addr_low = libie_pci_get_mmio_addr(mmio, PF_FW_ARQBAL);
+ rx_reg->len_mask = PF_FW_ARQLEN_ARQLEN_M;
+ rx_reg->len_ena_mask = PF_FW_ARQLEN_ARQENABLE_M;
+ rx_reg->head_mask = PF_FW_ARQH_ARQH_M;
}
/**
@@ -57,13 +44,14 @@ static void idpf_ctlq_reg_init(struct idpf_adapter *adapter,
*/
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;
}
@@ -78,6 +66,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, val;
u16 total_vecs;
@@ -93,14 +82,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 = ®_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;
@@ -110,22 +102,21 @@ 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);
}
/* Data vector for NOIRQ queues */
val = reg_vals[rsrc->q_vector_idxs[i] - IDPF_MBX_Q_VEC].dyn_ctl_reg;
- rsrc->noirq_dyn_ctl = idpf_get_reg_addr(adapter, val);
+ rsrc->noirq_dyn_ctl =
+ libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info, val);
val = PF_GLINT_DYN_CTL_WB_ON_ITR_M | PF_GLINT_DYN_CTL_INTENA_MSK_M |
FIELD_PREP(PF_GLINT_DYN_CTL_ITR_INDX_M, IDPF_NO_ITR_UPDATE_IDX);
@@ -143,7 +134,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_rstat_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;
}
@@ -155,11 +148,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_rstat_reg_addr(adapter, PFGEN_CTRL));
- writel(reset_reg | PFGEN_CTRL_PFSWR,
- idpf_get_rstat_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_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
index bb99d9e7c65d5..95c45f12b0f9e 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
@@ -225,7 +225,7 @@ static int idpf_add_flow_steer(struct net_device *netdev,
spin_unlock_bh(&vport_config->flow_steer_list_lock);
if (err)
- goto out;
+ goto out_free_fltr;
rule->vport_id = cpu_to_le32(vport->vport_id);
rule->count = cpu_to_le32(1);
@@ -252,17 +252,15 @@ static int idpf_add_flow_steer(struct net_device *netdev,
break;
default:
err = -EINVAL;
- goto out;
+ goto out_free_fltr;
}
err = idpf_add_del_fsteer_filters(vport->adapter, rule,
VIRTCHNL2_OP_ADD_FLOW_RULE);
- if (err)
- goto out;
-
- if (info->status != cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS)) {
- err = -EIO;
- goto out;
+ if (err) {
+ /* virtchnl2 rule is already consumed */
+ kfree(fltr);
+ return err;
}
/* Save a copy of the user's flow spec so ethtool can later retrieve it */
@@ -274,9 +272,10 @@ static int idpf_add_flow_steer(struct net_device *netdev,
user_config->num_fsteer_fltrs++;
spin_unlock_bh(&vport_config->flow_steer_list_lock);
- goto out_free_rule;
-out:
+ return 0;
+
+out_free_fltr:
kfree(fltr);
out_free_rule:
kfree(rule);
@@ -319,12 +318,7 @@ static int idpf_del_flow_steer(struct net_device *netdev,
err = idpf_add_del_fsteer_filters(vport->adapter, rule,
VIRTCHNL2_OP_DEL_FLOW_RULE);
if (err)
- goto out;
-
- if (info->status != cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS)) {
- err = -EIO;
- goto out;
- }
+ return err;
spin_lock_bh(&vport_config->flow_steer_list_lock);
list_for_each_entry_safe(f, iter,
@@ -340,8 +334,6 @@ static int idpf_del_flow_steer(struct net_device *netdev,
out_unlock:
spin_unlock_bh(&vport_config->flow_steer_list_lock);
-out:
- kfree(rule);
return err;
}
diff --git a/drivers/net/ethernet/intel/idpf/idpf_idc.c b/drivers/net/ethernet/intel/idpf/idpf_idc.c
index b7d6b08fc89e8..b6cd1c25ae5db 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_idc.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_idc.c
@@ -416,9 +416,12 @@ idpf_idc_init_msix_data(struct idpf_adapter *adapter)
int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter,
enum iidc_function_type ftype)
{
+ struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
struct iidc_rdma_core_dev_info *cdev_info;
struct iidc_rdma_priv_dev_info *privd;
- int err, i;
+ struct libie_pci_mmio_region *mr;
+ size_t num_mem_regions;
+ int err, i = 0;
adapter->cdev_info = kzalloc_obj(*cdev_info);
if (!adapter->cdev_info)
@@ -436,22 +439,31 @@ int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter,
cdev_info->rdma_protocol = IIDC_RDMA_PROTOCOL_ROCEV2;
privd->ftype = ftype;
+ num_mem_regions = list_count_nodes(&mmio->mmio_list);
+ if (num_mem_regions <= IDPF_MMIO_REG_NUM_STATIC) {
+ err = -EINVAL;
+ goto err_plug_aux_dev;
+ }
+
+ num_mem_regions -= IDPF_MMIO_REG_NUM_STATIC;
privd->mapped_mem_regions =
kzalloc_objs(struct iidc_rdma_lan_mapped_mem_region,
- adapter->hw.num_lan_regs);
+ num_mem_regions);
if (!privd->mapped_mem_regions) {
err = -ENOMEM;
goto err_plug_aux_dev;
}
- privd->num_memory_regions = cpu_to_le16(adapter->hw.num_lan_regs);
- for (i = 0; i < adapter->hw.num_lan_regs; i++) {
- privd->mapped_mem_regions[i].region_addr =
- adapter->hw.lan_regs[i].vaddr;
- privd->mapped_mem_regions[i].size =
- cpu_to_le64(adapter->hw.lan_regs[i].addr_len);
- privd->mapped_mem_regions[i].start_offset =
- cpu_to_le64(adapter->hw.lan_regs[i].addr_start);
+ privd->num_memory_regions = cpu_to_le16(num_mem_regions);
+ list_for_each_entry(mr, &mmio->mmio_list, list) {
+ if (!idpf_mmio_region_non_static(&adapter->ctlq_ctx.mmio_info,
+ mr))
+ continue;
+
+ privd->mapped_mem_regions[i].region_addr = mr->addr;
+ privd->mapped_mem_regions[i].size = cpu_to_le64(mr->size);
+ privd->mapped_mem_regions[i++].start_offset =
+ cpu_to_le64(mr->offset);
}
idpf_idc_init_msix_data(adapter);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index bb81e620c5c87..827c795afcb62 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -68,9 +68,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);
}
@@ -1109,8 +1111,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--;
@@ -1373,6 +1373,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);
@@ -1383,7 +1384,14 @@ void idpf_mbx_task(struct work_struct *work)
queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task,
usecs_to_jiffies(300));
- idpf_recv_mb_msg(adapter, adapter->hw.arq);
+ xn_params = (struct libie_ctlq_xn_recv_params) {
+ .xnm = adapter->xnm,
+ .ctlq = adapter->arq,
+ .ctlq_msg_handler = idpf_recv_event_msg,
+ .budget = LIBIE_CTLQ_MAX_XN_ENTRIES,
+ };
+
+ libie_ctlq_xn_recv(&xn_params);
}
/**
@@ -1849,15 +1857,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++) {
@@ -1920,7 +1927,7 @@ static void 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);
@@ -1934,14 +1941,11 @@ static void 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;
}
@@ -1987,7 +1991,8 @@ void idpf_vc_event_task(struct work_struct *work)
return;
func_reset:
- idpf_vc_xn_shutdown(adapter->vcxn_mngr);
+ if (adapter->xnm)
+ libie_ctlq_xn_shutdown(adapter->xnm);
drv_load:
set_bit(IDPF_HR_RESET_IN_PROG, adapter->flags);
idpf_init_hard_reset(adapter);
@@ -2570,44 +2575,6 @@ static int idpf_set_mac(struct net_device *netdev, void *p)
return err;
}
-/**
- * idpf_alloc_dma_mem - Allocate dma memory
- * @hw: pointer to hw struct
- * @mem: pointer to dma_mem struct
- * @size: size of the memory to allocate
- */
-void *idpf_alloc_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem, u64 size)
-{
- struct idpf_adapter *adapter = hw->back;
- size_t sz = ALIGN(size, 4096);
-
- /* The control queue resources are freed under a spinlock, contiguous
- * pages will avoid IOMMU remapping and the use vmap (and vunmap in
- * dma_free_*() path.
- */
- mem->va = dma_alloc_attrs(&adapter->pdev->dev, sz, &mem->pa,
- GFP_KERNEL, DMA_ATTR_FORCE_CONTIGUOUS);
- mem->size = sz;
-
- return mem->va;
-}
-
-/**
- * idpf_free_dma_mem - Free the allocated dma memory
- * @hw: pointer to hw struct
- * @mem: pointer to dma_mem struct
- */
-void idpf_free_dma_mem(struct idpf_hw *hw, struct idpf_dma_mem *mem)
-{
- struct idpf_adapter *adapter = hw->back;
-
- dma_free_attrs(&adapter->pdev->dev, mem->size,
- mem->va, mem->pa, DMA_ATTR_FORCE_CONTIGUOUS);
- mem->size = 0;
- mem->va = NULL;
- mem->pa = 0;
-}
-
static int idpf_hwtstamp_set(struct net_device *netdev,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c
index ab3c409e587bb..9840580fbe51e 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_main.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_main.c
@@ -15,6 +15,8 @@
MODULE_DESCRIPTION(DRV_SUMMARY);
MODULE_IMPORT_NS("LIBETH");
+MODULE_IMPORT_NS("LIBIE_CP");
+MODULE_IMPORT_NS("LIBIE_PCI");
MODULE_IMPORT_NS("LIBETH_XDP");
MODULE_LICENSE("GPL");
@@ -56,8 +58,16 @@ static int idpf_get_device_type(struct pci_dev *pdev)
static int idpf_dev_init(struct idpf_adapter *adapter,
const struct pci_device_id *ent)
{
+ struct libie_mmio_info *mmio_info = &adapter->ctlq_ctx.mmio_info;
int ret;
+ ret = libie_pci_init_dev(adapter->pdev);
+ if (ret)
+ return ret;
+
+ mmio_info->pdev = adapter->pdev;
+ INIT_LIST_HEAD(&mmio_info->mmio_list);
+
if (ent->class == IDPF_CLASS_NETWORK_ETHERNET_PROGIF) {
ret = idpf_get_device_type(adapter->pdev);
switch (ret) {
@@ -90,6 +100,15 @@ static int idpf_dev_init(struct idpf_adapter *adapter,
return 0;
}
+/**
+ * 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);
+}
+
/**
* idpf_remove - Device removal routine
* @pdev: PCI device information struct
@@ -151,14 +170,13 @@ 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);
mutex_destroy(&adapter->queue_lock);
mutex_destroy(&adapter->vc_buf_lock);
+ idpf_decfg_device(adapter);
pci_set_drvdata(pdev, NULL);
kfree(adapter);
}
@@ -181,46 +199,44 @@ 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)
{
- resource_size_t res_start, mbx_start, rstat_start;
+ struct libie_mmio_info *mmio_info = &adapter->ctlq_ctx.mmio_info;
struct pci_dev *pdev = adapter->pdev;
- struct idpf_hw *hw = &adapter->hw;
- struct device *dev = &pdev->dev;
- long len;
-
- res_start = pci_resource_start(pdev, 0);
+ struct resource *region;
+ bool mapped;
+ int err;
/* Map mailbox space for virtchnl communication */
- mbx_start = res_start + adapter->dev_ops.static_reg_info[0].start;
- len = resource_size(&adapter->dev_ops.static_reg_info[0]);
- hw->mbx.vaddr = devm_ioremap(dev, mbx_start, len);
- if (!hw->mbx.vaddr) {
- pci_err(pdev, "failed to allocate BAR0 mbx region\n");
-
+ region = &adapter->dev_ops.static_reg_info[0];
+ mapped = libie_pci_map_mmio_region(mmio_info, region->start,
+ resource_size(region));
+ if (!mapped) {
+ pci_err(pdev, "failed to map BAR0 mbx region\n");
return -ENOMEM;
}
- hw->mbx.addr_start = adapter->dev_ops.static_reg_info[0].start;
- hw->mbx.addr_len = len;
/* Map rstat space for resets */
- rstat_start = res_start + adapter->dev_ops.static_reg_info[1].start;
- len = resource_size(&adapter->dev_ops.static_reg_info[1]);
- hw->rstat.vaddr = devm_ioremap(dev, rstat_start, len);
- if (!hw->rstat.vaddr) {
- pci_err(pdev, "failed to allocate BAR0 rstat region\n");
+ region = &adapter->dev_ops.static_reg_info[1];
+ mapped = libie_pci_map_mmio_region(mmio_info, region->start,
+ resource_size(region));
+ if (!mapped) {
+ pci_err(pdev, "failed to map BAR0 rstat region\n");
+ libie_pci_unmap_all_mmio_regions(mmio_info);
return -ENOMEM;
}
- hw->rstat.addr_start = adapter->dev_ops.static_reg_info[1].start;
- hw->rstat.addr_len = len;
- hw->back = adapter;
+ err = pci_enable_ptm(pdev);
+ if (err)
+ pci_dbg(pdev, "PCIe PTM is not supported by PCIe bus/controller\n");
+
+ pci_set_drvdata(pdev, adapter);
return 0;
}
@@ -246,32 +262,21 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->req_rx_splitq = true;
adapter->pdev = pdev;
- err = pcim_enable_device(pdev);
- if (err)
- goto err_free;
- err = pcim_request_region(pdev, 0, pci_name(pdev));
+ err = idpf_dev_init(adapter, ent);
if (err) {
- pci_err(pdev, "pcim_request_region failed %pe\n", ERR_PTR(err));
-
+ dev_err(&pdev->dev, "Failed to initialize device (ID 0x%x): %d\n",
+ ent->device, err);
goto err_free;
}
- err = pci_enable_ptm(pdev);
- 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));
+ err = idpf_cfg_device(adapter);
if (err) {
- pci_err(pdev, "DMA configuration failed: %pe\n", ERR_PTR(err));
-
+ pci_err(pdev, "Failed to configure device specific resources: %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),
@@ -279,7 +284,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",
@@ -324,20 +329,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_dev_init(adapter, ent);
- if (err) {
- dev_err(&pdev->dev, "Unexpected dev ID 0x%x in idpf probe\n",
- ent->device);
- goto destroy_vc_event_wq;
- }
-
- err = idpf_cfg_hw(adapter);
- if (err) {
- dev_err(dev, "Failed to configure HW structure for adapter: %d\n",
- err);
- goto destroy_vc_event_wq;
- }
-
mutex_init(&adapter->vport_ctrl_lock);
mutex_init(&adapter->vector_lock);
mutex_init(&adapter->queue_lock);
@@ -356,8 +347,6 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
-destroy_vc_event_wq:
- destroy_workqueue(adapter->vc_event_wq);
err_vc_event_wq_alloc:
destroy_workqueue(adapter->stats_wq);
err_stats_wq_alloc:
@@ -366,6 +355,8 @@ 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_mem.h b/drivers/net/ethernet/intel/idpf/idpf_mem.h
deleted file mode 100644
index 2aaabdc02dd24..0000000000000
--- a/drivers/net/ethernet/intel/idpf/idpf_mem.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (C) 2023 Intel Corporation */
-
-#ifndef _IDPF_MEM_H_
-#define _IDPF_MEM_H_
-
-#include <linux/io.h>
-
-struct idpf_dma_mem {
- void *va;
- dma_addr_t pa;
- size_t size;
-};
-
-#define idpf_mbx_wr32(a, reg, value) writel((value), ((a)->mbx.vaddr + (reg)))
-#define idpf_mbx_rd32(a, reg) readl((a)->mbx.vaddr + (reg))
-#define idpf_mbx_wr64(a, reg, value) writeq((value), ((a)->mbx.vaddr + (reg)))
-#define idpf_mbx_rd64(a, reg) readq((a)->mbx.vaddr + (reg))
-
-#endif /* _IDPF_MEM_H_ */
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 99fcd8e298d64..c3ffb445297f8 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -4676,11 +4676,11 @@ int idpf_config_rss(struct idpf_vport *vport, struct idpf_rss_data *rss_data)
u32 vport_id = vport->vport_id;
int err;
- err = idpf_send_get_set_rss_key_msg(adapter, rss_data, vport_id, false);
+ err = idpf_send_set_rss_key_msg(adapter, rss_data, vport_id);
if (err)
return err;
- return idpf_send_get_set_rss_lut_msg(adapter, rss_data, vport_id, false);
+ return idpf_send_set_rss_lut_msg(adapter, rss_data, vport_id);
}
/**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
index 908dfa28674eb..93547597efd2a 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -5,6 +5,7 @@
#define _IDPF_TXRX_H_
#include <linux/dim.h>
+#include <linux/net/intel/virtchnl2_lan_desc.h>
#include <net/libeth/cache.h>
#include <net/libeth/types.h>
@@ -13,7 +14,6 @@
#include <net/xdp.h>
#include "idpf_lan_txrx.h"
-#include "virtchnl2_lan_desc.h"
#define IDPF_LARGE_MAX_Q 256
#define IDPF_MAX_Q 16
@@ -236,7 +236,7 @@ enum idpf_tx_ctx_desc_eipt_offload {
(sizeof(u16) * IDPF_RX_MAX_PTYPE_PROTO_IDS))
#define IDPF_RX_PTYPE_HDR_SZ sizeof(struct virtchnl2_get_ptype_info)
#define IDPF_RX_MAX_PTYPES_PER_BUF \
- DIV_ROUND_DOWN_ULL((IDPF_CTLQ_MAX_BUF_LEN - IDPF_RX_PTYPE_HDR_SZ), \
+ DIV_ROUND_DOWN_ULL(LIBIE_CTLQ_MAX_BUF_LEN - IDPF_RX_PTYPE_HDR_SZ, \
IDPF_RX_MAX_PTYPE_SZ)
#define IDPF_GET_PTYPE_SIZE(p) struct_size((p), proto_id, (p)->proto_id_count)
diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
index 6726084f6cfa0..b537de3592f43 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
@@ -9,45 +9,32 @@
/**
* idpf_vf_ctlq_reg_init - initialize default mailbox registers
- * @adapter: adapter structure
- * @cq: pointer to the array of create control queues
+ * @mmio: struct that contains MMIO region info
+ * @cci: struct where the register offset pointer to be copied to
*/
-static void idpf_vf_ctlq_reg_init(struct idpf_adapter *adapter,
- struct idpf_ctlq_create_info *cq)
+static void idpf_vf_ctlq_reg_init(struct libie_mmio_info *mmio,
+ struct libie_ctlq_create_info *cci)
{
- resource_size_t mbx_start = adapter->dev_ops.static_reg_info[0].start;
- int i;
-
- for (i = 0; i < IDPF_NUM_DFLT_MBX_Q; i++) {
- struct idpf_ctlq_create_info *ccq = cq + i;
-
- switch (ccq->type) {
- case IDPF_CTLQ_TYPE_MAILBOX_TX:
- /* set head and tail registers in our local struct */
- ccq->reg.head = VF_ATQH - mbx_start;
- ccq->reg.tail = VF_ATQT - mbx_start;
- ccq->reg.len = VF_ATQLEN - mbx_start;
- ccq->reg.bah = VF_ATQBAH - mbx_start;
- ccq->reg.bal = VF_ATQBAL - mbx_start;
- ccq->reg.len_mask = VF_ATQLEN_ATQLEN_M;
- ccq->reg.len_ena_mask = VF_ATQLEN_ATQENABLE_M;
- ccq->reg.head_mask = VF_ATQH_ATQH_M;
- break;
- case IDPF_CTLQ_TYPE_MAILBOX_RX:
- /* set head and tail registers in our local struct */
- ccq->reg.head = VF_ARQH - mbx_start;
- ccq->reg.tail = VF_ARQT - mbx_start;
- ccq->reg.len = VF_ARQLEN - mbx_start;
- ccq->reg.bah = VF_ARQBAH - mbx_start;
- ccq->reg.bal = VF_ARQBAL - mbx_start;
- ccq->reg.len_mask = VF_ARQLEN_ARQLEN_M;
- ccq->reg.len_ena_mask = VF_ARQLEN_ARQENABLE_M;
- ccq->reg.head_mask = VF_ARQH_ARQH_M;
- break;
- default:
- break;
- }
- }
+ struct libie_ctlq_reg *tx_reg = &cci[LIBIE_CTLQ_TYPE_TX].reg;
+ struct libie_ctlq_reg *rx_reg = &cci[LIBIE_CTLQ_TYPE_RX].reg;
+
+ tx_reg->head = libie_pci_get_mmio_addr(mmio, VF_ATQH);
+ tx_reg->tail = libie_pci_get_mmio_addr(mmio, VF_ATQT);
+ tx_reg->len = libie_pci_get_mmio_addr(mmio, VF_ATQLEN);
+ tx_reg->addr_high = libie_pci_get_mmio_addr(mmio, VF_ATQBAH);
+ tx_reg->addr_low = libie_pci_get_mmio_addr(mmio, VF_ATQBAL);
+ tx_reg->len_mask = VF_ATQLEN_ATQLEN_M;
+ tx_reg->len_ena_mask = VF_ATQLEN_ATQENABLE_M;
+ tx_reg->head_mask = VF_ATQH_ATQH_M;
+
+ rx_reg->head = libie_pci_get_mmio_addr(mmio, VF_ARQH);
+ rx_reg->tail = libie_pci_get_mmio_addr(mmio, VF_ARQT);
+ rx_reg->len = libie_pci_get_mmio_addr(mmio, VF_ARQLEN);
+ rx_reg->addr_high = libie_pci_get_mmio_addr(mmio, VF_ARQBAH);
+ rx_reg->addr_low = libie_pci_get_mmio_addr(mmio, VF_ARQBAL);
+ rx_reg->len_mask = VF_ARQLEN_ARQLEN_M;
+ rx_reg->len_ena_mask = VF_ARQLEN_ARQENABLE_M;
+ rx_reg->head_mask = VF_ARQH_ARQH_M;
}
/**
@@ -56,13 +43,14 @@ static void idpf_vf_ctlq_reg_init(struct idpf_adapter *adapter,
*/
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;
}
@@ -77,6 +65,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, val;
u16 total_vecs;
@@ -92,14 +81,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 = ®_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;
@@ -109,22 +101,21 @@ 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);
}
/* Data vector for NOIRQ queues */
val = reg_vals[rsrc->q_vector_idxs[i] - IDPF_MBX_Q_VEC].dyn_ctl_reg;
- rsrc->noirq_dyn_ctl = idpf_get_reg_addr(adapter, val);
+ rsrc->noirq_dyn_ctl =
+ libie_pci_get_mmio_addr(&adapter->ctlq_ctx.mmio_info, val);
val = VF_INT_DYN_CTLN_WB_ON_ITR_M | VF_INT_DYN_CTLN_INTENA_MSK_M |
FIELD_PREP(VF_INT_DYN_CTLN_ITR_INDX_M, IDPF_NO_ITR_UPDATE_IDX);
@@ -142,7 +133,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_rstat_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;
}
@@ -157,8 +150,7 @@ static void idpf_vf_trigger_reset(struct idpf_adapter *adapter,
/* 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_vf_reset_msg(adapter);
}
/**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 8bd6cca64c9bf..1caf527069737 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -2,26 +2,13 @@
/* Copyright (C) 2023 Intel Corporation */
#include <linux/export.h>
+#include <linux/net/intel/libie/pci.h>
#include <net/libeth/rx.h>
#include "idpf.h"
#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
@@ -82,79 +69,62 @@ 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 (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->cookie.mbx.chnl_opcode,
+ ctlq_msg->chnl_opcode,
payload_size);
- return;
+ goto free_rx_buf;
}
- v2e = (struct virtchnl2_event *)ctlq_msg->ctx.indirect.payload->va;
+ v2e = (struct virtchnl2_event *)buff->iov_base;
event = le32_to_cpu(v2e->event);
switch (event) {
case VIRTCHNL2_EVENT_LINK_CHANGE:
idpf_handle_event_link(adapter, v2e);
- return;
+ break;
default:
dev_err(&adapter->pdev->dev,
"Unknown event %d from PF\n", event);
break;
}
+
+free_rx_buf:
+ libie_ctlq_release_rx_buf(buff);
}
/**
* idpf_mb_clean - Reclaim the send mailbox queue entries
- * @adapter: driver specific private structure
* @asq: send control queue info
+ * @deinit: release all buffers before destroying the queue
*
- * Reclaim the send mailbox queue entries to be used to send further messages
- *
- * Return: 0 on success, negative on failure
+ * This is a helper function to clean the send mailbox queue entries.
*/
-static int idpf_mb_clean(struct idpf_adapter *adapter,
- struct idpf_ctlq_info *asq)
+static void idpf_mb_clean(struct libie_ctlq_info *asq, bool deinit)
{
- u16 i, num_q_msg = IDPF_DFLT_MBX_Q_LEN;
- struct idpf_ctlq_msg **q_msg;
- struct idpf_dma_mem *dma_mem;
- int err;
-
- q_msg = kzalloc_objs(struct idpf_ctlq_msg *, num_q_msg, GFP_ATOMIC);
- if (!q_msg)
- return -ENOMEM;
-
- err = idpf_ctlq_clean_sq(asq, &num_q_msg, q_msg);
- if (err)
- goto err_kfree;
-
- for (i = 0; i < num_q_msg; i++) {
- if (!q_msg[i])
- continue;
- dma_mem = q_msg[i]->ctx.indirect.payload;
- if (dma_mem)
- dma_free_coherent(&adapter->pdev->dev, dma_mem->size,
- dma_mem->va, dma_mem->pa);
- kfree(q_msg[i]);
- kfree(dma_mem);
- }
-
-err_kfree:
- kfree(q_msg);
-
- return err;
+ libie_ctlq_xn_send_clean(asq, kfree, deinit);
}
#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
@@ -188,7 +158,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.
@@ -196,530 +166,106 @@ static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,
if (!idpf_ptp_is_mb_msg(op) || !adapter->ptp->secondary_mbx.valid)
return;
- ctlq_msg->opcode = idpf_mbq_opc_send_msg_to_peer_drv;
+ ctlq_msg->opcode = LIBIE_CTLQ_SEND_MSG_TO_PEER;
ctlq_msg->func_id = adapter->ptp->secondary_mbx.peer_mbx_q_id;
- ctlq_msg->host_id = adapter->ptp->secondary_mbx.peer_id;
+ ctlq_msg->flags = FIELD_PREP(LIBIE_CTLQ_DESC_FLAG_HOST_ID,
+ adapter->ptp->secondary_mbx.peer_id);
}
#else /* !CONFIG_PTP_1588_CLOCK */
static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,
- struct idpf_ctlq_msg *ctlq_msg)
+ struct libie_ctlq_msg *ctlq_msg)
{ }
#endif /* CONFIG_PTP_1588_CLOCK */
/**
- * idpf_send_mb_msg - Send message over mailbox
+ * idpf_send_mb_msg - send mailbox message to the device control plane
* @adapter: driver specific private structure
- * @asq: control queue to send message to
- * @op: virtchnl opcode
- * @msg_size: size of the payload
- * @msg: pointer to buffer holding the payload
- * @cookie: unique SW generated cookie per message
+ * @xn_params: Xn send parameters to fill
+ * @send_buf: buffer to send
+ * @send_buf_size: size of the send buffer
*
- * Will prepare the control queue message and initiates the send api
+ * Fill the Xn parameters with the required info to send a virtchnl message.
+ * The send buffer is DMA mapped in the libie to avoid memcpy.
*
- * Return: 0 on success, negative on failure
- */
-int idpf_send_mb_msg(struct idpf_adapter *adapter, struct idpf_ctlq_info *asq,
- u32 op, u16 msg_size, u8 *msg, u16 cookie)
-{
- struct idpf_ctlq_msg *ctlq_msg;
- struct idpf_dma_mem *dma_mem;
- int err;
-
- /* If we are here and a reset is detected nothing much can be
- * done. This thread should silently abort and expected to
- * be corrected with a new run either by user or driver
- * flows after reset
- */
- if (idpf_is_reset_detected(adapter))
- return 0;
-
- err = idpf_mb_clean(adapter, asq);
- if (err)
- return err;
-
- ctlq_msg = kzalloc_obj(*ctlq_msg, GFP_ATOMIC);
- if (!ctlq_msg)
- return -ENOMEM;
-
- dma_mem = kzalloc_obj(*dma_mem, GFP_ATOMIC);
- if (!dma_mem) {
- err = -ENOMEM;
- goto dma_mem_error;
- }
-
- ctlq_msg->opcode = idpf_mbq_opc_send_msg_to_cp;
- ctlq_msg->func_id = 0;
-
- idpf_prepare_ptp_mb_msg(adapter, op, ctlq_msg);
-
- ctlq_msg->data_len = msg_size;
- ctlq_msg->cookie.mbx.chnl_opcode = op;
- ctlq_msg->cookie.mbx.chnl_retval = 0;
- dma_mem->size = IDPF_CTLQ_MAX_BUF_LEN;
- dma_mem->va = dma_alloc_coherent(&adapter->pdev->dev, dma_mem->size,
- &dma_mem->pa, GFP_ATOMIC);
- if (!dma_mem->va) {
- err = -ENOMEM;
- goto dma_alloc_error;
- }
-
- /* It's possible we're just sending an opcode but no buffer */
- if (msg && msg_size)
- memcpy(dma_mem->va, msg, msg_size);
- ctlq_msg->ctx.indirect.payload = dma_mem;
- ctlq_msg->ctx.sw_cookie.data = cookie;
-
- err = idpf_ctlq_send(&adapter->hw, asq, 1, ctlq_msg);
- if (err)
- goto send_error;
-
- return 0;
-
-send_error:
- dma_free_coherent(&adapter->pdev->dev, dma_mem->size, dma_mem->va,
- dma_mem->pa);
-dma_alloc_error:
- kfree(dma_mem);
-dma_mem_error:
- kfree(ctlq_msg);
-
- return err;
-}
-
-/* API for virtchnl "transaction" support ("xn" for short). */
-
-/**
- * idpf_vc_xn_lock - Request exclusive access to vc transaction
- * @xn: struct idpf_vc_xn* to access
- */
-#define idpf_vc_xn_lock(xn) \
- spin_lock(&(xn)->lock)
-
-/**
- * idpf_vc_xn_unlock - Release exclusive access to vc transaction
- * @xn: struct idpf_vc_xn* to access
- */
-#define idpf_vc_xn_unlock(xn) \
- spin_unlock(&(xn)->lock)
-
-/**
- * idpf_vc_xn_release_bufs - Release reference to reply buffer(s) and
- * reset the transaction state.
- * @xn: struct idpf_vc_xn to update
- */
-static void idpf_vc_xn_release_bufs(struct idpf_vc_xn *xn)
-{
- xn->reply.iov_base = NULL;
- xn->reply.iov_len = 0;
-
- if (xn->state != IDPF_VC_XN_SHUTDOWN)
- xn->state = IDPF_VC_XN_IDLE;
-}
-
-/**
- * idpf_vc_xn_init - Initialize virtchnl transaction object
- * @vcxn_mngr: pointer to vc transaction manager struct
- */
-static void idpf_vc_xn_init(struct idpf_vc_xn_manager *vcxn_mngr)
-{
- int i;
-
- spin_lock_init(&vcxn_mngr->xn_bm_lock);
-
- for (i = 0; i < ARRAY_SIZE(vcxn_mngr->ring); i++) {
- struct idpf_vc_xn *xn = &vcxn_mngr->ring[i];
-
- xn->state = IDPF_VC_XN_IDLE;
- xn->idx = i;
- idpf_vc_xn_release_bufs(xn);
- spin_lock_init(&xn->lock);
- init_completion(&xn->completed);
- }
-
- bitmap_fill(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN);
-}
-
-/**
- * idpf_vc_xn_shutdown - Uninitialize virtchnl transaction object
- * @vcxn_mngr: pointer to vc transaction manager struct
+ * Cleanup the mailbox queue entries of the previously sent message to
+ * unmap and release the buffer.
*
- * All waiting threads will be woken-up and their transaction aborted. Further
- * operations on that object will fail.
+ * Return: 0 if the request was successful, -%EBUSY if reset is detected
+ * or Tx control queue is full, other negative error code on failure.
*/
-void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr)
+int idpf_send_mb_msg(struct idpf_adapter *adapter,
+ struct libie_ctlq_xn_send_params *xn_params,
+ void *send_buf, size_t send_buf_size)
{
- int i;
+ struct libie_ctlq_msg ctlq_msg = {};
- spin_lock_bh(&vcxn_mngr->xn_bm_lock);
- bitmap_zero(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN);
- spin_unlock_bh(&vcxn_mngr->xn_bm_lock);
+ if (idpf_is_reset_detected(adapter)) {
+ if (!libie_cp_can_send_onstack(send_buf_size))
+ kfree(send_buf);
- for (i = 0; i < ARRAY_SIZE(vcxn_mngr->ring); i++) {
- struct idpf_vc_xn *xn = &vcxn_mngr->ring[i];
-
- idpf_vc_xn_lock(xn);
- xn->state = IDPF_VC_XN_SHUTDOWN;
- idpf_vc_xn_release_bufs(xn);
- idpf_vc_xn_unlock(xn);
- complete_all(&xn->completed);
+ return -EBUSY;
}
-}
-/**
- * idpf_vc_xn_pop_free - Pop a free transaction from free list
- * @vcxn_mngr: transaction manager to pop from
- *
- * Returns NULL if no free transactions
- */
-static
-struct idpf_vc_xn *idpf_vc_xn_pop_free(struct idpf_vc_xn_manager *vcxn_mngr)
-{
- struct idpf_vc_xn *xn = NULL;
- unsigned long free_idx;
-
- 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;
+ idpf_prepare_ptp_mb_msg(adapter, xn_params->chnl_opcode, &ctlq_msg);
+ xn_params->ctlq_msg = ctlq_msg.opcode ? &ctlq_msg : NULL;
- clear_bit(free_idx, vcxn_mngr->free_xn_bm);
- xn = &vcxn_mngr->ring[free_idx];
- xn->salt = vcxn_mngr->salt++;
+ xn_params->send_buf.iov_base = send_buf;
+ xn_params->send_buf.iov_len = send_buf_size;
+ xn_params->xnm = adapter->xnm;
+ xn_params->ctlq = xn_params->ctlq ? xn_params->ctlq : adapter->asq;
+ xn_params->rel_tx_buf = kfree;
-do_unlock:
- spin_unlock_bh(&vcxn_mngr->xn_bm_lock);
+ idpf_mb_clean(xn_params->ctlq, false);
- return xn;
-}
-
-/**
- * idpf_vc_xn_push_free - Push a free transaction to free list
- * @vcxn_mngr: transaction manager to push to
- * @xn: transaction to push
- */
-static void idpf_vc_xn_push_free(struct idpf_vc_xn_manager *vcxn_mngr,
- struct idpf_vc_xn *xn)
-{
- idpf_vc_xn_release_bufs(xn);
- spin_lock_bh(&vcxn_mngr->xn_bm_lock);
- set_bit(xn->idx, vcxn_mngr->free_xn_bm);
- spin_unlock_bh(&vcxn_mngr->xn_bm_lock);
+ return libie_ctlq_xn_send(xn_params);
}
/**
- * idpf_vc_xn_exec - Perform a send/recv virtchnl transaction
- * @adapter: driver specific private structure with vcxn_mngr
- * @params: parameters for this particular transaction including
- * -vc_op: virtchannel operation to send
- * -send_buf: kvec iov for send buf and len
- * -recv_buf: kvec iov for recv buf and len (ignored if NULL)
- * -timeout_ms: timeout waiting for a reply (milliseconds)
- * -async: don't wait for message reply, will lose caller context
- * -async_handler: callback to handle async replies
+ * idpf_send_mb_msg_kfree - send mailbox message and free the send buffer
+ * @adapter: driver specific private structure
+ * @xn_params: Xn send parameters to fill
+ * @send_buf: buffer to send, can be released with kfree()
+ * @send_buf_size: size of the send buffer
*
- * @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 = ¶ms->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
+ * libie_cp functions consume only buffers above certain size,
+ * smaller buffers are assumed to be on the stack. However, for some
+ * commands with variable message size it makes sense to always use kzalloc(),
+ * which means we have to free smaller buffers ourselves.
*
- * 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
+ * Return: 0 if no unexpected errors were encountered,
+ * negative error code otherwise.
*/
-static int
-idpf_vc_xn_forward_reply(struct idpf_adapter *adapter,
- const struct idpf_ctlq_msg *ctlq_msg)
+int idpf_send_mb_msg_kfree(struct idpf_adapter *adapter,
+ struct libie_ctlq_xn_send_params *xn_params,
+ void *send_buf, size_t send_buf_size)
{
- const void *payload = NULL;
- size_t payload_size = 0;
- struct idpf_vc_xn *xn;
- u16 msg_info;
- int err = 0;
- u16 xn_idx;
- u16 salt;
-
- msg_info = ctlq_msg->ctx.sw_cookie.data;
- xn_idx = FIELD_GET(IDPF_VC_XN_IDX_M, msg_info);
- if (xn_idx >= ARRAY_SIZE(adapter->vcxn_mngr->ring)) {
- dev_err_ratelimited(&adapter->pdev->dev, "Out of bounds cookie received: %02x\n",
- xn_idx);
- return -EINVAL;
- }
- xn = &adapter->vcxn_mngr->ring[xn_idx];
- idpf_vc_xn_lock(xn);
- salt = FIELD_GET(IDPF_VC_XN_SALT_M, msg_info);
- if (xn->salt != salt) {
- dev_err_ratelimited(&adapter->pdev->dev, "Transaction salt does not match (exp:%d@%02x(%d) != got:%d@%02x)\n",
- xn->vc_op, xn->salt, xn->state,
- ctlq_msg->cookie.mbx.chnl_opcode, salt);
- idpf_vc_xn_unlock(xn);
- return -EINVAL;
- }
-
- switch (xn->state) {
- case IDPF_VC_XN_WAITING:
- /* success */
- break;
- case IDPF_VC_XN_IDLE:
- dev_err_ratelimited(&adapter->pdev->dev, "Unexpected or belated VC reply (op %d)\n",
- ctlq_msg->cookie.mbx.chnl_opcode);
- err = -EINVAL;
- goto out_unlock;
- case IDPF_VC_XN_SHUTDOWN:
- /* ENXIO is a bit special here as the recv msg loop uses that
- * know if it should stop trying to clean the ring if we lost
- * the virtchnl. We need to stop playing with registers and
- * yield.
- */
- err = -ENXIO;
- goto out_unlock;
- case IDPF_VC_XN_ASYNC:
- /* Set reply_sz from the actual payload so that async_handler
- * can evaluate the response.
- */
- xn->reply_sz = ctlq_msg->data_len;
- err = idpf_vc_xn_forward_async(adapter, xn, ctlq_msg);
- idpf_vc_xn_unlock(xn);
- return err;
- default:
- dev_err_ratelimited(&adapter->pdev->dev, "Overwriting VC reply (op %d)\n",
- ctlq_msg->cookie.mbx.chnl_opcode);
- err = -EBUSY;
- goto out_unlock;
- }
-
- if (ctlq_msg->cookie.mbx.chnl_opcode != xn->vc_op) {
- dev_err_ratelimited(&adapter->pdev->dev, "Message opcode does not match transaction opcode (msg: %d) (xn: %d)\n",
- ctlq_msg->cookie.mbx.chnl_opcode, xn->vc_op);
- xn->reply_sz = 0;
- xn->state = IDPF_VC_XN_COMPLETED_FAILED;
- err = -EINVAL;
- goto out_unlock;
- }
+ int err = idpf_send_mb_msg(adapter, xn_params, send_buf, send_buf_size);
- 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);
+ if (libie_cp_can_send_onstack(send_buf_size))
+ kfree(send_buf);
return err;
}
/**
- * idpf_recv_mb_msg - Receive message over mailbox
+ * idpf_send_vf_reset_msg - send one way VF reset message
* @adapter: driver specific private structure
- * @arq: control queue to receive message from
- *
- * Will receive control queue message and posts the receive buffer.
- *
- * Return: 0 on success and negative on failure.
*/
-int idpf_recv_mb_msg(struct idpf_adapter *adapter, struct idpf_ctlq_info *arq)
+void idpf_send_vf_reset_msg(struct idpf_adapter *adapter)
{
- 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;
- }
+ struct libie_ctlq_info *ctlq = adapter->asq;
- 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);
+ /* Forcefully claim send queue slot */
+ idpf_mb_clean(ctlq, true);
- post_err = idpf_ctlq_post_rx_buffs(&adapter->hw, arq,
- &num_recv, &dma_mem);
+ scoped_guard(spinlock, &ctlq->lock) {
+ *ctlq->tx_msg[ctlq->next_to_use] = (struct libie_ctlq_msg) {
+ .opcode = LIBIE_CTLQ_SEND_MSG_TO_CP,
+ .chnl_opcode = VIRTCHNL2_OP_RESET_VF,
+ };
- /* If post failed clear the only buffer we supplied */
- if (post_err) {
- if (dma_mem)
- dma_free_coherent(&adapter->pdev->dev,
- dma_mem->size, dma_mem->va,
- dma_mem->pa);
- break;
- }
-
- /* virtchnl trying to shutdown, stop cleaning */
- if (err == -ENXIO)
- break;
+ libie_ctlq_send(adapter->asq, 1);
}
-
- return err;
}
struct idpf_chunked_msg_params {
@@ -767,45 +313,43 @@ struct idpf_queue_set *idpf_alloc_queue_set(struct idpf_adapter *adapter,
static int idpf_send_chunked_msg(struct idpf_adapter *adapter,
const struct idpf_chunked_msg_params *params)
{
- struct idpf_vc_xn_params xn_params = {
- .vc_op = params->vc_op,
+ struct libie_ctlq_xn_send_params xn_params = {
.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = params->vc_op,
};
const void *pos = params->chunks;
- u32 num_chunks, num_msgs, buf_sz;
- void *buf __free(kfree) = NULL;
u32 totqs = params->num_chunks;
u32 vid = params->vport_id;
+ u32 num_chunks, num_msgs;
- num_chunks = min(IDPF_NUM_CHUNKS_PER_MSG(params->config_sz,
- params->chunk_sz), totqs);
+ num_chunks = IDPF_NUM_CHUNKS_PER_MSG(params->config_sz,
+ params->chunk_sz);
num_msgs = DIV_ROUND_UP(totqs, num_chunks);
- buf_sz = params->config_sz + num_chunks * params->chunk_sz;
- buf = kzalloc(buf_sz, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- xn_params.send_buf.iov_base = buf;
-
for (u32 i = 0; i < num_msgs; i++) {
- ssize_t reply_sz;
+ u32 buf_sz;
+ void *buf;
+ int err;
- memset(buf, 0, buf_sz);
- xn_params.send_buf.iov_len = buf_sz;
+ num_chunks = min(num_chunks, totqs);
+ buf_sz = params->config_sz + num_chunks * params->chunk_sz;
+ buf = kzalloc(buf_sz, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- if (params->prepare_msg(vid, buf, pos, num_chunks) != buf_sz)
+ if (params->prepare_msg(vid, buf, pos, num_chunks) != buf_sz) {
+ kfree(buf);
return -EINVAL;
+ }
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, buf, buf_sz);
+ if (err)
+ return err;
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+ xn_params.recv_mem = (struct kvec) {};
pos += num_chunks * params->chunk_sz;
totqs -= num_chunks;
-
- num_chunks = min(num_chunks, totqs);
- buf_sz = params->config_sz + num_chunks * params->chunk_sz;
}
return 0;
@@ -880,11 +424,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);
@@ -894,24 +441,23 @@ static int idpf_send_ver_msg(struct idpf_adapter *adapter)
vvi.minor = cpu_to_le32(IDPF_VIRTCHNL_VERSION_MINOR);
}
- xn_params.vc_op = VIRTCHNL2_OP_VERSION;
- xn_params.send_buf.iov_base = &vvi;
- xn_params.send_buf.iov_len = sizeof(vvi);
- xn_params.recv_buf = xn_params.send_buf;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &vvi);
+ if (err)
+ return err;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- if (reply_sz < sizeof(vvi))
- return -EIO;
+ if (xn_params.recv_mem.iov_len < sizeof(*vvi_recv)) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
- major = le32_to_cpu(vvi.major);
- minor = le32_to_cpu(vvi.minor);
+ vvi_recv = xn_params.recv_mem.iov_base;
+ major = le32_to_cpu(vvi_recv->major);
+ minor = le32_to_cpu(vvi_recv->minor);
if (major > IDPF_VIRTCHNL_VERSION_MAJOR) {
dev_warn(&adapter->pdev->dev, "Virtchnl major version greater than supported\n");
- return -EINVAL;
+ err = -EINVAL;
+ goto free_rx_buf;
}
if (major == IDPF_VIRTCHNL_VERSION_MAJOR &&
@@ -929,6 +475,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;
}
@@ -941,9 +490,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 |
@@ -1003,143 +555,154 @@ 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 = ∩︀
- 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_stack(adapter, &xn_params, &caps);
+ if (err)
+ return err;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- if (reply_sz < sizeof(adapter->caps))
- return -EIO;
+ if (xn_params.recv_mem.iov_len < sizeof(adapter->caps)) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
- return 0;
+ memcpy(&adapter->caps, xn_params.recv_mem.iov_base,
+ sizeof(adapter->caps));
+
+free_rx_buf:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
+ return err;
+}
+
+/**
+ * idpf_mmio_region_non_static - Check if region is not static
+ * @mmio_info: PCI resources info
+ * @reg: region to check
+ *
+ * Return: %true if region can be received though virtchnl command,
+ * %false if region is related to mailbox or resetting
+ */
+bool idpf_mmio_region_non_static(struct libie_mmio_info *mmio_info,
+ struct libie_pci_mmio_region *reg)
+{
+ struct idpf_adapter *adapter =
+ container_of(mmio_info, struct idpf_adapter,
+ ctlq_ctx.mmio_info);
+
+ for (uint i = 0; i < IDPF_MMIO_REG_NUM_STATIC; i++) {
+ if (reg->bar_idx == 0 &&
+ reg->offset == adapter->dev_ops.static_reg_info[i].start)
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * idpf_decfg_lan_memory_regions - Unmap non-static memory regions
+ * @adapter: Driver specific private structure
+ */
+static void idpf_decfg_lan_memory_regions(struct idpf_adapter *adapter)
+{
+ libie_pci_unmap_fltr_regs(&adapter->ctlq_ctx.mmio_info,
+ idpf_mmio_region_non_static);
}
/**
- * idpf_send_get_lan_memory_regions - Send virtchnl get LAN memory regions msg
+ * idpf_cfg_lan_memory_regions - Get (via virtchnl) and map LAN memory regions
* @adapter: Driver specific private struct
*
* Return: 0 on success or error code on failure.
*/
-static int idpf_send_get_lan_memory_regions(struct idpf_adapter *adapter)
+static int idpf_cfg_lan_memory_regions(struct idpf_adapter *adapter)
{
- struct virtchnl2_get_lan_memory_regions *rcvd_regions __free(kfree);
- struct idpf_vc_xn_params xn_params = {
- .vc_op = VIRTCHNL2_OP_GET_LAN_MEMORY_REGIONS,
- .recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN,
- .send_buf.iov_len =
- sizeof(struct virtchnl2_get_lan_memory_regions) +
- sizeof(struct virtchnl2_mem_region),
+ struct virtchnl2_get_lan_memory_regions *send_regions, *rcvd_regions;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = VIRTCHNL2_OP_GET_LAN_MEMORY_REGIONS,
.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
};
- int num_regions, size;
- struct idpf_hw *hw;
- ssize_t reply_sz;
+ size_t send_sz, reply_sz, size;
+ int num_regions;
int err = 0;
- rcvd_regions = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
- if (!rcvd_regions)
+ send_sz = sizeof(struct virtchnl2_get_lan_memory_regions) +
+ sizeof(struct virtchnl2_mem_region);
+ send_regions = kzalloc(send_sz, GFP_KERNEL);
+ if (!send_regions)
return -ENOMEM;
- xn_params.recv_buf.iov_base = rcvd_regions;
- rcvd_regions->num_memory_regions = cpu_to_le16(1);
- xn_params.send_buf.iov_base = rcvd_regions;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
+ send_regions->num_memory_regions = cpu_to_le16(1);
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, send_regions,
+ send_sz);
+ if (err)
+ return err;
+ rcvd_regions = xn_params.recv_mem.iov_base;
+ reply_sz = xn_params.recv_mem.iov_len;
+ if (reply_sz < sizeof(*rcvd_regions)) {
+ err = -EIO;
+ goto rel_rx_buf;
+ }
num_regions = le16_to_cpu(rcvd_regions->num_memory_regions);
size = struct_size(rcvd_regions, mem_reg, num_regions);
- if (reply_sz < size)
- return -EIO;
-
- if (size > IDPF_CTLQ_MAX_BUF_LEN)
- return -EINVAL;
-
- hw = &adapter->hw;
- hw->lan_regs = kzalloc_objs(*hw->lan_regs, num_regions);
- if (!hw->lan_regs)
- return -ENOMEM;
+ if (reply_sz < size) {
+ err = -EIO;
+ goto rel_rx_buf;
+ }
for (int i = 0; i < num_regions; i++) {
- hw->lan_regs[i].addr_len =
- le64_to_cpu(rcvd_regions->mem_reg[i].size);
- hw->lan_regs[i].addr_start =
- le64_to_cpu(rcvd_regions->mem_reg[i].start_offset);
+ struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
+ resource_size_t offset, len;
+
+ offset = le64_to_cpu(rcvd_regions->mem_reg[i].start_offset);
+ len = le64_to_cpu(rcvd_regions->mem_reg[i].size);
+ if (len && !libie_pci_map_mmio_region(mmio, offset, len)) {
+ idpf_decfg_lan_memory_regions(adapter);
+ err = -EIO;
+ goto rel_rx_buf;
+ }
}
- hw->num_lan_regs = num_regions;
+
+rel_rx_buf:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
return err;
}
/**
- * idpf_calc_remaining_mmio_regs - calculate MMIO regions outside mbx and rstat
+ * idpf_map_remaining_mmio_regs - map MMIO regions outside mbx and rstat
* @adapter: Driver specific private structure
*
- * Called when idpf_send_get_lan_memory_regions is not supported. This will
+ * Called when idpf_cfg_lan_memory_regions is not supported. This will
* calculate the offsets and sizes for the regions before, in between, and
- * after the mailbox and rstat MMIO mappings.
+ * after the mailbox and rstat MMIO mappings, and map those ranges.
*
* Return: 0 on success or error code on failure.
*/
-static int idpf_calc_remaining_mmio_regs(struct idpf_adapter *adapter)
+static int idpf_map_remaining_mmio_regs(struct idpf_adapter *adapter)
{
struct resource *rstat_reg = &adapter->dev_ops.static_reg_info[1];
struct resource *mbx_reg = &adapter->dev_ops.static_reg_info[0];
- struct idpf_hw *hw = &adapter->hw;
-
- hw->num_lan_regs = IDPF_MMIO_MAP_FALLBACK_MAX_REMAINING;
- hw->lan_regs = kzalloc_objs(*hw->lan_regs, hw->num_lan_regs);
- if (!hw->lan_regs)
- return -ENOMEM;
+ struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
+ resource_size_t reg_start, size;
+ bool ok = true;
/* Region preceding mailbox */
- hw->lan_regs[0].addr_start = 0;
- hw->lan_regs[0].addr_len = mbx_reg->start;
- /* Region between mailbox and rstat */
- hw->lan_regs[1].addr_start = mbx_reg->end + 1;
- hw->lan_regs[1].addr_len = rstat_reg->start -
- hw->lan_regs[1].addr_start;
- /* Region after rstat */
- hw->lan_regs[2].addr_start = rstat_reg->end + 1;
- hw->lan_regs[2].addr_len = pci_resource_len(adapter->pdev, 0) -
- hw->lan_regs[2].addr_start;
-
- return 0;
-}
+ size = mbx_reg->start;
+ ok &= !size || libie_pci_map_mmio_region(mmio, 0, size);
-/**
- * idpf_map_lan_mmio_regs - map remaining LAN BAR regions
- * @adapter: Driver specific private structure
- *
- * Return: 0 on success or error code on failure.
- */
-static int idpf_map_lan_mmio_regs(struct idpf_adapter *adapter)
-{
- struct pci_dev *pdev = adapter->pdev;
- struct idpf_hw *hw = &adapter->hw;
- resource_size_t res_start;
-
- res_start = pci_resource_start(pdev, 0);
-
- for (int i = 0; i < hw->num_lan_regs; i++) {
- resource_size_t start;
- long len;
+ /* Region between mailbox and rstat */
+ reg_start = mbx_reg->end + 1;
+ size = rstat_reg->start - reg_start;
+ ok &= !size || libie_pci_map_mmio_region(mmio, reg_start, size);
- len = hw->lan_regs[i].addr_len;
- if (!len)
- continue;
- start = hw->lan_regs[i].addr_start + res_start;
+ /* Region after rstat */
+ reg_start = rstat_reg->end + 1;
+ size = pci_resource_len(adapter->pdev, 0) - reg_start;
+ ok &= !size || libie_pci_map_mmio_region(mmio, reg_start, size);
- hw->lan_regs[i].vaddr = devm_ioremap(&pdev->dev, start, len);
- if (!hw->lan_regs[i].vaddr) {
- pci_err(pdev, "failed to allocate BAR0 region\n");
- return -ENOMEM;
- }
+ if (!ok) {
+ idpf_decfg_lan_memory_regions(adapter);
+ return -ENOMEM;
}
return 0;
@@ -1160,24 +723,43 @@ int idpf_add_del_fsteer_filters(struct idpf_adapter *adapter,
struct virtchnl2_flow_rule_add_del *rule,
enum virtchnl2_op opcode)
{
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = opcode,
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ };
+ struct virtchnl2_flow_rule_add_del *rx_rule;
int rule_count = le32_to_cpu(rule->count);
- struct idpf_vc_xn_params xn_params = {};
- ssize_t reply_sz;
+ size_t send_sz;
+ int err;
if (opcode != VIRTCHNL2_OP_ADD_FLOW_RULE &&
- opcode != VIRTCHNL2_OP_DEL_FLOW_RULE)
+ opcode != VIRTCHNL2_OP_DEL_FLOW_RULE) {
+ kfree(rule);
return -EINVAL;
+ }
+
+ send_sz = struct_size(rule, rule_info, rule_count);
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, rule, send_sz);
+ if (err)
+ return err;
+
+ if (xn_params.recv_mem.iov_len < send_sz) {
+ err = -EIO;
+ goto rel_rx;
+ }
- xn_params.vc_op = opcode;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.async = false;
- xn_params.send_buf.iov_base = rule;
- xn_params.send_buf.iov_len = struct_size(rule, rule_info, rule_count);
- xn_params.recv_buf.iov_base = rule;
- xn_params.recv_buf.iov_len = struct_size(rule, rule_info, rule_count);
+ rx_rule = xn_params.recv_mem.iov_base;
+ for (int i = 0; i < rule_count; i++) {
+ if (rx_rule->rule_info[i].status !=
+ cpu_to_le32(VIRTCHNL2_FLOW_RULE_SUCCESS)) {
+ err = -EIO;
+ goto rel_rx;
+ }
+ }
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- return reply_sz < 0 ? reply_sz : 0;
+rel_rx:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+ return err;
}
/**
@@ -1414,7 +996,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) {
@@ -1424,7 +1006,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:
@@ -1436,8 +1019,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;
@@ -1450,8 +1033,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;
@@ -1551,21 +1134,19 @@ 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);
- 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);
@@ -1582,38 +1163,35 @@ 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]) {
- 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 free_vport_params;
+ goto rel_buf;
}
}
- xn_params.vc_op = VIRTCHNL2_OP_CREATE_VPORT;
- xn_params.send_buf.iov_base = vport_msg;
- xn_params.send_buf.iov_len = buf_size;
- xn_params.recv_buf.iov_base = adapter->vport_params_recvd[idx];
- xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0) {
- err = reply_sz;
- goto free_vport_params;
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, vport_msg,
+ sizeof(*vport_msg));
+ if (err) {
+ kfree(adapter->vport_params_recvd[idx]);
+ adapter->vport_params_recvd[idx] = NULL;
+ return err;
}
+ 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;
- kfree(adapter->vport_params_reqd[idx]);
- adapter->vport_params_reqd[idx] = NULL;
+rel_buf:
+ kfree(vport_msg);
return err;
}
@@ -1673,19 +1251,22 @@ int idpf_check_supported_desc_ids(struct idpf_vport *vport)
*/
int idpf_send_destroy_vport_msg(struct idpf_adapter *adapter, u32 vport_id)
{
- struct idpf_vc_xn_params xn_params = {};
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_DESTROY_VPORT,
+ };
struct virtchnl2_vport v_id;
- ssize_t reply_sz;
+ int err;
v_id.vport_id = cpu_to_le32(vport_id);
- xn_params.vc_op = VIRTCHNL2_OP_DESTROY_VPORT;
- xn_params.send_buf.iov_base = &v_id;
- xn_params.send_buf.iov_len = sizeof(v_id);
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &v_id);
+ if (err)
+ return err;
+
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return reply_sz < 0 ? reply_sz : 0;
+ return 0;
}
/**
@@ -1697,19 +1278,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_stack(adapter, &xn_params, &v_id);
+ if (err)
+ return err;
+
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return reply_sz < 0 ? reply_sz : 0;
+ return 0;
}
/**
@@ -1721,19 +1305,22 @@ int idpf_send_enable_vport_msg(struct idpf_adapter *adapter, u32 vport_id)
*/
int idpf_send_disable_vport_msg(struct idpf_adapter *adapter, u32 vport_id)
{
- struct idpf_vc_xn_params xn_params = {};
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_DISABLE_VPORT,
+ };
struct virtchnl2_vport v_id;
- ssize_t reply_sz;
+ int err;
v_id.vport_id = cpu_to_le32(vport_id);
- xn_params.vc_op = VIRTCHNL2_OP_DISABLE_VPORT;
- xn_params.send_buf.iov_base = &v_id;
- xn_params.send_buf.iov_len = sizeof(v_id);
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &v_id);
+ if (err)
+ return err;
+
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return reply_sz < 0 ? reply_sz : 0;
+ return 0;
}
/**
@@ -2572,11 +2159,14 @@ int idpf_send_delete_queues_msg(struct idpf_adapter *adapter,
struct idpf_queue_id_reg_info *chunks,
u32 vport_id)
{
- struct virtchnl2_del_ena_dis_queues *eq __free(kfree) = NULL;
- struct idpf_vc_xn_params xn_params = {};
- ssize_t reply_sz;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_DEL_QUEUES,
+ };
+ struct virtchnl2_del_ena_dis_queues *eq;
+ ssize_t buf_size;
u16 num_chunks;
- int buf_size;
+ int err;
num_chunks = chunks->num_chunks;
buf_size = struct_size(eq, chunks.chunks, num_chunks);
@@ -2591,13 +2181,13 @@ int idpf_send_delete_queues_msg(struct idpf_adapter *adapter,
idpf_convert_reg_to_queue_chunks(eq->chunks.chunks, chunks->queue_chunks,
num_chunks);
- xn_params.vc_op = VIRTCHNL2_OP_DEL_QUEUES;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.send_buf.iov_base = eq;
- xn_params.send_buf.iov_len = buf_size;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, eq, buf_size);
+ if (err)
+ return err;
- return reply_sz < 0 ? reply_sz : 0;
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
+ return 0;
}
/**
@@ -2635,15 +2225,14 @@ int idpf_send_add_queues_msg(struct idpf_adapter *adapter,
struct idpf_q_vec_rsrc *rsrc,
u32 vport_id)
{
- struct virtchnl2_add_queues *vc_msg __free(kfree) = NULL;
- struct idpf_vc_xn_params xn_params = {};
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_ADD_QUEUES,
+ };
+ struct virtchnl2_add_queues *vc_msg;
struct virtchnl2_add_queues aq = {};
- ssize_t reply_sz;
- int size;
-
- vc_msg = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
- if (!vc_msg)
- return -ENOMEM;
+ size_t size;
+ int err;
aq.vport_id = cpu_to_le32(vport_id);
aq.num_tx_q = cpu_to_le16(rsrc->num_txq);
@@ -2651,29 +2240,38 @@ int idpf_send_add_queues_msg(struct idpf_adapter *adapter,
aq.num_rx_q = cpu_to_le16(rsrc->num_rxq);
aq.num_rx_bufq = cpu_to_le16(rsrc->num_bufq);
- xn_params.vc_op = VIRTCHNL2_OP_ADD_QUEUES;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.send_buf.iov_base = &aq;
- xn_params.send_buf.iov_len = sizeof(aq);
- xn_params.recv_buf.iov_base = vc_msg;
- xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &aq);
+ if (err)
+ return err;
+
+ vc_msg = xn_params.recv_mem.iov_base;
+ if (xn_params.recv_mem.iov_len < sizeof(*vc_msg)) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
/* compare vc_msg num queues with vport num queues */
if (le16_to_cpu(vc_msg->num_tx_q) != rsrc->num_txq ||
le16_to_cpu(vc_msg->num_rx_q) != rsrc->num_rxq ||
le16_to_cpu(vc_msg->num_tx_complq) != rsrc->num_complq ||
- le16_to_cpu(vc_msg->num_rx_bufq) != rsrc->num_bufq)
- return -EINVAL;
+ le16_to_cpu(vc_msg->num_rx_bufq) != rsrc->num_bufq) {
+ err = -EINVAL;
+ goto free_rx_buf;
+ }
size = struct_size(vc_msg, chunks.chunks,
le16_to_cpu(vc_msg->chunks.num_chunks));
- if (reply_sz < size)
- return -EIO;
+ if (xn_params.recv_mem.iov_len < size) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
+
+ err = idpf_vport_init_queue_reg_chunks(vport_config, &vc_msg->chunks);
+
+free_rx_buf:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return idpf_vport_init_queue_reg_chunks(vport_config, &vc_msg->chunks);
+ return err;
}
/**
@@ -2685,49 +2283,51 @@ int idpf_send_add_queues_msg(struct idpf_adapter *adapter,
*/
int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors)
{
- struct virtchnl2_alloc_vectors *rcvd_vec __free(kfree) = NULL;
- struct idpf_vc_xn_params xn_params = {};
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_ALLOC_VECTORS,
+ };
+ struct virtchnl2_alloc_vectors *rcvd_vec;
struct virtchnl2_alloc_vectors ac = {};
- ssize_t reply_sz;
u16 num_vchunks;
- int size;
+ int size, err;
ac.num_vectors = cpu_to_le16(num_vectors);
- rcvd_vec = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
- if (!rcvd_vec)
- return -ENOMEM;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &ac);
+ if (err)
+ return err;
- xn_params.vc_op = VIRTCHNL2_OP_ALLOC_VECTORS;
- xn_params.send_buf.iov_base = ∾
- xn_params.send_buf.iov_len = sizeof(ac);
- xn_params.recv_buf.iov_base = rcvd_vec;
- xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
+ rcvd_vec = xn_params.recv_mem.iov_base;
+ if (xn_params.recv_mem.iov_len < sizeof(*rcvd_vec)) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
num_vchunks = le16_to_cpu(rcvd_vec->vchunks.num_vchunks);
size = struct_size(rcvd_vec, vchunks.vchunks, num_vchunks);
- if (reply_sz < size)
- return -EIO;
-
- if (size > IDPF_CTLQ_MAX_BUF_LEN)
- return -EINVAL;
+ if (xn_params.recv_mem.iov_len < size) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
kfree(adapter->req_vec_chunks);
adapter->req_vec_chunks = kmemdup(rcvd_vec, size, GFP_KERNEL);
- if (!adapter->req_vec_chunks)
- return -ENOMEM;
+ if (!adapter->req_vec_chunks) {
+ err = -ENOMEM;
+ goto free_rx_buf;
+ }
if (le16_to_cpu(adapter->req_vec_chunks->num_vectors) < num_vectors) {
kfree(adapter->req_vec_chunks);
adapter->req_vec_chunks = NULL;
- return -EINVAL;
+ err = -EINVAL;
}
- return 0;
+free_rx_buf:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
+ return err;
}
/**
@@ -2739,24 +2339,28 @@ int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors)
int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter)
{
struct virtchnl2_alloc_vectors *ac = adapter->req_vec_chunks;
- struct virtchnl2_vector_chunks *vcs = &ac->vchunks;
- struct idpf_vc_xn_params xn_params = {};
- ssize_t reply_sz;
- int buf_size;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_DEALLOC_VECTORS,
+ };
+ struct virtchnl2_vector_chunks *vcs;
+ int buf_size, err;
- buf_size = struct_size(vcs, vchunks, le16_to_cpu(vcs->num_vchunks));
+ buf_size = struct_size(&ac->vchunks, vchunks,
+ le16_to_cpu(ac->vchunks.num_vchunks));
+ vcs = kmemdup(&ac->vchunks, buf_size, GFP_KERNEL);
+ if (!vcs)
+ return -ENOMEM;
- xn_params.vc_op = VIRTCHNL2_OP_DEALLOC_VECTORS;
- xn_params.send_buf.iov_base = vcs;
- xn_params.send_buf.iov_len = buf_size;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, vcs, buf_size);
+ if (err)
+ return err;
kfree(adapter->req_vec_chunks);
adapter->req_vec_chunks = NULL;
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
return 0;
}
@@ -2780,18 +2384,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_stack(adapter, &xn_params, &svi);
+ if (err)
+ return err;
+
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
+ return 0;
}
/**
@@ -2804,10 +2412,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 */
@@ -2816,65 +2428,65 @@ 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_stack(np->adapter, &xn_params, &stats_msg);
+ if (err)
+ return err;
+
+ if (xn_params.recv_mem.iov_len < sizeof(*stats_recv)) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
- 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;
+ stats_recv = xn_params.recv_mem.iov_base;
spin_lock_bh(&np->stats_lock);
- netstats->rx_packets = le64_to_cpu(stats_msg.rx_unicast) +
- le64_to_cpu(stats_msg.rx_multicast) +
- le64_to_cpu(stats_msg.rx_broadcast);
- netstats->tx_packets = le64_to_cpu(stats_msg.tx_unicast) +
- le64_to_cpu(stats_msg.tx_multicast) +
- le64_to_cpu(stats_msg.tx_broadcast);
- netstats->rx_bytes = le64_to_cpu(stats_msg.rx_bytes);
- netstats->tx_bytes = le64_to_cpu(stats_msg.tx_bytes);
- netstats->rx_errors = le64_to_cpu(stats_msg.rx_errors);
- netstats->tx_errors = le64_to_cpu(stats_msg.tx_errors);
- netstats->rx_dropped = le64_to_cpu(stats_msg.rx_discards);
- netstats->tx_dropped = le64_to_cpu(stats_msg.tx_discards);
-
- port_stats->vport_stats = stats_msg;
+ netstats->rx_packets = le64_to_cpu(stats_recv->rx_unicast) +
+ le64_to_cpu(stats_recv->rx_multicast) +
+ le64_to_cpu(stats_recv->rx_broadcast);
+ netstats->tx_packets = le64_to_cpu(stats_recv->tx_unicast) +
+ le64_to_cpu(stats_recv->tx_multicast) +
+ le64_to_cpu(stats_recv->tx_broadcast);
+ netstats->rx_bytes = le64_to_cpu(stats_recv->rx_bytes);
+ netstats->tx_bytes = le64_to_cpu(stats_recv->tx_bytes);
+ netstats->rx_errors = le64_to_cpu(stats_recv->rx_errors);
+ netstats->tx_errors = le64_to_cpu(stats_recv->tx_errors);
+ netstats->rx_dropped = le64_to_cpu(stats_recv->rx_discards);
+ netstats->tx_dropped = le64_to_cpu(stats_recv->tx_discards);
+
+ port_stats->vport_stats = *stats_recv;
spin_unlock_bh(&np->stats_lock);
- return 0;
+free_rx_buf:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+
+ return err;
}
/**
- * idpf_send_get_set_rss_lut_msg - Send virtchnl get or set RSS lut message
+ * idpf_send_set_rss_lut_msg - Send virtchnl set RSS lut message
* @adapter: adapter pointer used to send virtchnl message
* @rss_data: pointer to RSS key and lut info
* @vport_id: vport identifier used while preparing the virtchnl message
- * @get: flag to set or get RSS look up table
*
- * When rxhash is disabled, RSS LUT will be configured with zeros. If rxhash
+ * When rxhash is disabled, RSS LUT will be configured with zeros. If rxhash
* is enabled, the LUT values stored in driver's soft copy will be used to setup
* the HW.
*
* Return: 0 on success, negative on failure.
*/
-int idpf_send_get_set_rss_lut_msg(struct idpf_adapter *adapter,
- struct idpf_rss_data *rss_data,
- u32 vport_id, bool get)
+int idpf_send_set_rss_lut_msg(struct idpf_adapter *adapter,
+ struct idpf_rss_data *rss_data, u32 vport_id)
{
- struct virtchnl2_rss_lut *recv_rl __free(kfree) = NULL;
- struct virtchnl2_rss_lut *rl __free(kfree) = NULL;
- struct idpf_vc_xn_params xn_params = {};
- int buf_size, lut_buf_size;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_SET_RSS_LUT,
+ };
+ struct virtchnl2_rss_lut *rl;
struct idpf_vport *vport;
- ssize_t reply_sz;
+ int buf_size, i, err;
bool rxhash_ena;
- int i;
vport = idpf_vid_to_vport(adapter, vport_id);
if (!vport)
@@ -2888,76 +2500,36 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_adapter *adapter,
return -ENOMEM;
rl->vport_id = cpu_to_le32(vport_id);
+ rl->lut_entries = cpu_to_le16(rss_data->rss_lut_size);
+ for (i = 0; i < rss_data->rss_lut_size; i++)
+ rl->lut[i] = rxhash_ena ? cpu_to_le32(rss_data->rss_lut[i]) : 0;
- xn_params.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 {
- rl->lut_entries = cpu_to_le16(rss_data->rss_lut_size);
- for (i = 0; i < rss_data->rss_lut_size; i++)
- rl->lut[i] = rxhash_ena ?
- cpu_to_le32(rss_data->rss_lut[i]) : 0;
-
- xn_params.vc_op = VIRTCHNL2_OP_SET_RSS_LUT;
- }
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- if (!get)
- return 0;
- if (reply_sz < sizeof(struct virtchnl2_rss_lut))
- return -EIO;
-
- lut_buf_size = le16_to_cpu(recv_rl->lut_entries) * sizeof(u32);
- if (reply_sz < lut_buf_size)
- return -EIO;
-
- /* size didn't change, we can reuse existing lut buf */
- if (rss_data->rss_lut_size == le16_to_cpu(recv_rl->lut_entries))
- goto do_memcpy;
-
- rss_data->rss_lut_size = le16_to_cpu(recv_rl->lut_entries);
- kfree(rss_data->rss_lut);
-
- rss_data->rss_lut = kzalloc(lut_buf_size, GFP_KERNEL);
- if (!rss_data->rss_lut) {
- rss_data->rss_lut_size = 0;
- return -ENOMEM;
- }
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, rl, buf_size);
+ if (err)
+ return err;
-do_memcpy:
- memcpy(rss_data->rss_lut, recv_rl->lut, rss_data->rss_lut_size);
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return 0;
+ return err;
}
/**
- * idpf_send_get_set_rss_key_msg - Send virtchnl get or set RSS key message
+ * idpf_send_set_rss_key_msg - Send virtchnl set RSS key message
* @adapter: adapter pointer used to send virtchnl message
* @rss_data: pointer to RSS key and lut info
* @vport_id: vport identifier used while preparing the virtchnl message
- * @get: flag to set or get RSS look up table
*
* Return: 0 on success, negative on failure
*/
-int idpf_send_get_set_rss_key_msg(struct idpf_adapter *adapter,
- struct idpf_rss_data *rss_data,
- u32 vport_id, bool get)
+int idpf_send_set_rss_key_msg(struct idpf_adapter *adapter,
+ struct idpf_rss_data *rss_data, u32 vport_id)
{
- 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 = VIRTCHNL2_OP_SET_RSS_KEY,
+ };
+ struct virtchnl2_rss_key *rk;
+ int i, buf_size, err;
buf_size = struct_size(rk, key_flex, rss_data->rss_key_size);
rk = kzalloc(buf_size, GFP_KERNEL);
@@ -2965,54 +2537,17 @@ 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 {
- 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];
+ 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;
-
- key_size = min_t(u16, NETDEV_RSS_KEY_LEN,
- le16_to_cpu(recv_rk->key_len));
- if (reply_sz < key_size)
- return -EIO;
-
- /* key len didn't change, reuse existing buf */
- if (rss_data->rss_key_size == key_size)
- goto do_memcpy;
-
- rss_data->rss_key_size = key_size;
- kfree(rss_data->rss_key);
- rss_data->rss_key = kzalloc(key_size, GFP_KERNEL);
- if (!rss_data->rss_key) {
- rss_data->rss_key_size = 0;
- return -ENOMEM;
- }
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, rk, buf_size);
+ if (err)
+ return err;
-do_memcpy:
- memcpy(rss_data->rss_key, recv_rk->key_flex, rss_data->rss_key_size);
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return 0;
+ return err;
}
/**
@@ -3189,60 +2724,63 @@ static void idpf_parse_protocol_ids(struct virtchnl2_ptype *ptype,
*/
static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)
{
- struct virtchnl2_get_ptype_info *get_ptype_info __free(kfree) = NULL;
- struct virtchnl2_get_ptype_info *ptype_info __free(kfree) = NULL;
- struct libeth_rx_pt *singleq_pt_lkup __free(kfree) = NULL;
- struct libeth_rx_pt *splitq_pt_lkup __free(kfree) = NULL;
- struct idpf_vc_xn_params xn_params = {};
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_GET_PTYPE_INFO,
+ };
+ struct virtchnl2_get_ptype_info *get_ptype_info;
+ struct virtchnl2_get_ptype_info *ptype_info;
+ int err = 0, max_ptype = IDPF_RX_MAX_PTYPE;
+ int buf_size = sizeof(*get_ptype_info);
+ struct libeth_rx_pt *singleq_pt_lkup;
+ struct libeth_rx_pt *splitq_pt_lkup;
int ptypes_recvd = 0, ptype_offset;
- u32 max_ptype = IDPF_RX_MAX_PTYPE;
u16 next_ptype_id = 0;
- ssize_t reply_sz;
singleq_pt_lkup = kzalloc_objs(*singleq_pt_lkup, IDPF_RX_MAX_BASE_PTYPE);
if (!singleq_pt_lkup)
return -ENOMEM;
splitq_pt_lkup = kzalloc_objs(*splitq_pt_lkup, max_ptype);
- if (!splitq_pt_lkup)
- return -ENOMEM;
-
- get_ptype_info = kzalloc_obj(*get_ptype_info);
- if (!get_ptype_info)
- return -ENOMEM;
+ if (!splitq_pt_lkup) {
+ err = -ENOMEM;
+ goto free_singleq;
+ }
- ptype_info = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
- if (!ptype_info)
- return -ENOMEM;
+ while (next_ptype_id < max_ptype) {
+ u16 num_ptypes;
- xn_params.vc_op = VIRTCHNL2_OP_GET_PTYPE_INFO;
- xn_params.send_buf.iov_base = get_ptype_info;
- xn_params.send_buf.iov_len = sizeof(*get_ptype_info);
- xn_params.recv_buf.iov_base = ptype_info;
- xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
+ get_ptype_info = kzalloc(buf_size, GFP_KERNEL);
+ if (!get_ptype_info) {
+ err = -ENOMEM;
+ goto free_splitq;
+ }
- while (next_ptype_id < max_ptype) {
get_ptype_info->start_ptype_id = cpu_to_le16(next_ptype_id);
if ((next_ptype_id + IDPF_RX_MAX_PTYPES_PER_BUF) > max_ptype)
- get_ptype_info->num_ptypes =
- cpu_to_le16(max_ptype - next_ptype_id);
+ num_ptypes = max_ptype - next_ptype_id;
else
- get_ptype_info->num_ptypes =
- cpu_to_le16(IDPF_RX_MAX_PTYPES_PER_BUF);
-
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
-
+ num_ptypes = IDPF_RX_MAX_PTYPES_PER_BUF;
+
+ get_ptype_info->num_ptypes = cpu_to_le16(num_ptypes);
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params,
+ get_ptype_info, buf_size);
+ if (err)
+ goto free_splitq;
+
+ ptype_info = xn_params.recv_mem.iov_base;
+ if (xn_params.recv_mem.iov_len < sizeof(*ptype_info)) {
+ err = -EIO;
+ goto free_rx_buf;
+ }
ptypes_recvd += le16_to_cpu(ptype_info->num_ptypes);
- if (ptypes_recvd > max_ptype)
- return -EINVAL;
-
- next_ptype_id = le16_to_cpu(get_ptype_info->start_ptype_id) +
- le16_to_cpu(get_ptype_info->num_ptypes);
+ if (ptypes_recvd > max_ptype) {
+ err = -EINVAL;
+ goto free_rx_buf;
+ }
+ next_ptype_id = next_ptype_id + num_ptypes;
ptype_offset = IDPF_RX_PTYPE_HDR_SZ;
for (u16 i = 0; i < le16_to_cpu(ptype_info->num_ptypes); i++) {
@@ -3252,19 +2790,28 @@ static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)
ptype = (struct virtchnl2_ptype *)
((u8 *)ptype_info + ptype_offset);
+ if (xn_params.recv_mem.iov_len <
+ ptype_offset + sizeof(struct virtchnl2_ptype)) {
+ err = -EINVAL;
+ goto free_rx_buf;
+ }
pt_10 = le16_to_cpu(ptype->ptype_id_10);
pt_8 = ptype->ptype_id_8;
ptype_offset += IDPF_GET_PTYPE_SIZE(ptype);
- if (ptype_offset > IDPF_CTLQ_MAX_BUF_LEN)
- return -EINVAL;
+ if (xn_params.recv_mem.iov_len < ptype_offset) {
+ err = -EINVAL;
+ goto free_rx_buf;
+ }
/* 0xFFFF indicates end of ptypes */
if (pt_10 == IDPF_INVALID_PTYPE_ID)
goto out;
- if (pt_10 >= max_ptype)
- return -EINVAL;
+ if (pt_10 >= max_ptype) {
+ err = -EINVAL;
+ goto free_rx_buf;
+ }
idpf_parse_protocol_ids(ptype, &rx_pt);
idpf_finalize_ptype_lookup(&rx_pt);
@@ -3278,13 +2825,24 @@ static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)
if (!singleq_pt_lkup[pt_8].outer_ip)
singleq_pt_lkup[pt_8] = rx_pt;
}
+
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+ xn_params.recv_mem = (struct kvec) {};
}
out:
- adapter->splitq_pt_lkup = no_free_ptr(splitq_pt_lkup);
- adapter->singleq_pt_lkup = no_free_ptr(singleq_pt_lkup);
+ adapter->splitq_pt_lkup = splitq_pt_lkup;
+ adapter->singleq_pt_lkup = singleq_pt_lkup;
+ splitq_pt_lkup = NULL;
+ singleq_pt_lkup = NULL;
+free_rx_buf:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+free_splitq:
+ kfree(splitq_pt_lkup);
+free_singleq:
+ kfree(singleq_pt_lkup);
- return 0;
+ return err;
}
/**
@@ -3312,40 +2870,23 @@ static void idpf_rel_rx_pt_lkup(struct idpf_adapter *adapter)
int idpf_send_ena_dis_loopback_msg(struct idpf_adapter *adapter, u32 vport_id,
bool loopback_ena)
{
- struct idpf_vc_xn_params xn_params = {};
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = VIRTCHNL2_OP_LOOPBACK,
+ };
struct virtchnl2_loopback loopback;
- ssize_t reply_sz;
+ int err;
loopback.vport_id = cpu_to_le32(vport_id);
loopback.enable = loopback_ena;
- xn_params.vc_op = VIRTCHNL2_OP_LOOPBACK;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.send_buf.iov_base = &loopback;
- xn_params.send_buf.iov_len = sizeof(loopback);
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
-
- return reply_sz < 0 ? reply_sz : 0;
-}
-
-/**
- * idpf_find_ctlq - Given a type and id, find ctlq info
- * @hw: hardware struct
- * @type: type of ctrlq to find
- * @id: ctlq id to find
- *
- * Returns pointer to found ctlq info struct, NULL otherwise.
- */
-static struct idpf_ctlq_info *idpf_find_ctlq(struct idpf_hw *hw,
- enum idpf_ctlq_type type, int id)
-{
- struct idpf_ctlq_info *cq, *tmp;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &loopback);
+ if (err)
+ return err;
- list_for_each_entry_safe(cq, tmp, &hw->cq_list_head, cq_list)
- if (cq->q_id == id && cq->cq_type == type)
- return cq;
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return NULL;
+ return 0;
}
/**
@@ -3356,42 +2897,49 @@ static struct idpf_ctlq_info *idpf_find_ctlq(struct idpf_hw *hw,
*/
int idpf_init_dflt_mbx(struct idpf_adapter *adapter)
{
- struct idpf_ctlq_create_info ctlq_info[] = {
+ struct libie_ctlq_ctx *ctx = &adapter->ctlq_ctx;
+ struct libie_ctlq_create_info ctlq_info[] = {
{
- .type = IDPF_CTLQ_TYPE_MAILBOX_TX,
- .id = IDPF_DFLT_MBX_ID,
+ .type = LIBIE_CTLQ_TYPE_TX,
+ .id = LIBIE_CTLQ_MBX_ID,
.len = IDPF_DFLT_MBX_Q_LEN,
- .buf_size = IDPF_CTLQ_MAX_BUF_LEN
},
{
- .type = IDPF_CTLQ_TYPE_MAILBOX_RX,
- .id = IDPF_DFLT_MBX_ID,
+ .type = LIBIE_CTLQ_TYPE_RX,
+ .id = LIBIE_CTLQ_MBX_ID,
.len = IDPF_DFLT_MBX_Q_LEN,
- .buf_size = IDPF_CTLQ_MAX_BUF_LEN
}
};
- struct idpf_hw *hw = &adapter->hw;
+ struct libie_ctlq_xn_init_params params = {
+ .num_qs = IDPF_NUM_DFLT_MBX_Q,
+ .cctlq_info = ctlq_info,
+ .ctx = ctx,
+ };
int err;
- adapter->dev_ops.reg_ops.ctlq_reg_init(adapter, ctlq_info);
+ adapter->dev_ops.reg_ops.ctlq_reg_init(&ctx->mmio_info,
+ params.cctlq_info);
- err = idpf_ctlq_init(hw, IDPF_NUM_DFLT_MBX_Q, ctlq_info);
+ err = libie_ctlq_xn_init(¶ms);
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) {
+ adapter->asq = NULL;
+ adapter->arq = NULL;
+ libie_ctlq_xn_deinit(params.xnm, ctx);
return -ENOENT;
}
+ adapter->xnm = params.xnm;
adapter->state = __IDPF_VER_CHECK;
+ queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task, 0);
+
return 0;
}
@@ -3401,12 +2949,18 @@ 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);
+ idpf_mb_intr_rel_irq(adapter);
+ cancel_delayed_work_sync(&adapter->mbx_task);
+
+ if (adapter->xnm) {
+ libie_ctlq_xn_shutdown(adapter->xnm);
+ idpf_mb_clean(adapter->asq, true);
+ libie_ctlq_xn_deinit(adapter->xnm, &adapter->ctlq_ctx);
}
- adapter->hw.arq = NULL;
- adapter->hw.asq = NULL;
+
+ adapter->arq = NULL;
+ adapter->asq = NULL;
+ adapter->xnm = NULL;
}
/**
@@ -3419,8 +2973,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;
}
@@ -3435,15 +2987,10 @@ static int idpf_vport_params_buf_alloc(struct idpf_adapter *adapter)
{
u16 num_max_vports = idpf_get_max_vports(adapter);
- adapter->vport_params_reqd = kzalloc_objs(*adapter->vport_params_reqd,
- num_max_vports);
- if (!adapter->vport_params_reqd)
- return -ENOMEM;
-
adapter->vport_params_recvd = kzalloc_objs(*adapter->vport_params_recvd,
num_max_vports);
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)
@@ -3484,15 +3031,6 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
u16 num_max_vports;
int err = 0;
- if (!adapter->vcxn_mngr) {
- adapter->vcxn_mngr = kzalloc_obj(*adapter->vcxn_mngr);
- if (!adapter->vcxn_mngr) {
- err = -ENOMEM;
- goto init_failed;
- }
- }
- idpf_vc_xn_init(adapter->vcxn_mngr);
-
while (adapter->state != __IDPF_INIT_SW) {
switch (adapter->state) {
case __IDPF_VER_CHECK:
@@ -3531,34 +3069,29 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
}
if (idpf_is_cap_ena(adapter, IDPF_OTHER_CAPS, VIRTCHNL2_CAP_LAN_MEMORY_REGIONS)) {
- err = idpf_send_get_lan_memory_regions(adapter);
+ err = idpf_cfg_lan_memory_regions(adapter);
if (err) {
- dev_err(&adapter->pdev->dev, "Failed to get LAN memory regions: %d\n",
+ dev_err(&adapter->pdev->dev, "Failed to configure LAN memory regions: %d\n",
err);
return -EINVAL;
}
} else {
/* Fallback to mapping the remaining regions of the entire BAR */
- err = idpf_calc_remaining_mmio_regs(adapter);
+ err = idpf_map_remaining_mmio_regs(adapter);
if (err) {
- dev_err(&adapter->pdev->dev, "Failed to allocate BAR0 region(s): %d\n",
+ dev_err(&adapter->pdev->dev, "Failed to configure BAR0 region(s): %d\n",
err);
- return -ENOMEM;
+ return err;
}
}
- err = idpf_map_lan_mmio_regs(adapter);
- if (err) {
- dev_err(&adapter->pdev->dev, "Failed to map BAR0 region(s): %d\n",
- err);
- return -ENOMEM;
- }
-
pci_sriov_set_totalvfs(adapter->pdev, idpf_get_max_vfs(adapter));
num_max_vports = idpf_get_max_vports(adapter);
adapter->vports = kzalloc_objs(*adapter->vports, num_max_vports);
- if (!adapter->vports)
- return -ENOMEM;
+ if (!adapter->vports) {
+ err = -ENOMEM;
+ goto decfg_regions;
+ }
if (!adapter->netdevs) {
adapter->netdevs = kzalloc_objs(struct net_device *,
@@ -3630,6 +3163,8 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
err_netdev_alloc:
kfree(adapter->vports);
adapter->vports = NULL;
+decfg_regions:
+ idpf_decfg_lan_memory_regions(adapter);
return err;
init_failed:
@@ -3647,8 +3182,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);
+ libie_ctlq_xn_shutdown(adapter->xnm);
set_bit(IDPF_HR_DRV_LOAD, adapter->flags);
queue_delayed_work(adapter->vc_event_wq, &adapter->vc_event_task,
msecs_to_jiffies(task_delay));
@@ -3663,7 +3197,6 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
*/
void idpf_vc_core_deinit(struct idpf_adapter *adapter)
{
- struct idpf_hw *hw = &adapter->hw;
bool remove_in_prog;
if (!test_bit(IDPF_VC_CORE_INIT, adapter->flags))
@@ -3672,7 +3205,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);
+ libie_ctlq_xn_shutdown(adapter->xnm);
idpf_ptp_release(adapter);
idpf_deinit_task(adapter);
@@ -3681,19 +3214,17 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)
idpf_intr_rel(adapter);
if (remove_in_prog)
- idpf_vc_xn_shutdown(adapter->vcxn_mngr);
+ libie_ctlq_xn_shutdown(adapter->xnm);
cancel_delayed_work_sync(&adapter->serv_task);
cancel_delayed_work_sync(&adapter->mbx_task);
idpf_vport_params_buf_rel(adapter);
- kfree(hw->lan_regs);
- hw->lan_regs = NULL;
-
kfree(adapter->vports);
adapter->vports = NULL;
+ idpf_decfg_lan_memory_regions(adapter);
clear_bit(IDPF_VC_CORE_INIT, adapter->flags);
}
@@ -4220,9 +3751,9 @@ static void idpf_set_mac_type(const u8 *default_mac_addr,
/**
* idpf_mac_filter_async_handler - Async callback for mac filters
- * @adapter: private data struct
- * @xn: transaction for message
- * @ctlq_msg: received message
+ * @ctx: controlq context structure
+ * @buff: response buffer pointer and size
+ * @status: async call return value
*
* In some scenarios driver can't sleep and wait for a reply (e.g.: stack is
* holding rtnl_lock) when adding a new mac filter. It puts us in a difficult
@@ -4230,13 +3761,14 @@ static void idpf_set_mac_type(const u8 *default_mac_addr,
* ultimately do is remove it from our list of mac filters and report the
* error.
*/
-static int idpf_mac_filter_async_handler(struct idpf_adapter *adapter,
- struct idpf_vc_xn *xn,
- const struct idpf_ctlq_msg *ctlq_msg)
+static void idpf_mac_filter_async_handler(void *ctx,
+ struct kvec *buff,
+ int status)
{
struct virtchnl2_mac_addr_list *ma_list;
struct idpf_vport_config *vport_config;
struct virtchnl2_mac_addr *mac_addr;
+ struct idpf_adapter *adapter = ctx;
struct idpf_mac_filter *f, *tmp;
struct list_head *ma_list_head;
struct idpf_vport *vport;
@@ -4244,18 +3776,18 @@ static int idpf_mac_filter_async_handler(struct idpf_adapter *adapter,
int i;
/* if success we're done, we're only here if something bad happened */
- if (!ctlq_msg->cookie.mbx.chnl_retval)
- return 0;
+ if (!status || status == -ETIMEDOUT)
+ return;
+ ma_list = buff->iov_base;
/* make sure at least struct is there */
- if (xn->reply_sz < sizeof(*ma_list))
+ if (buff->iov_len < sizeof(*ma_list))
goto invalid_payload;
- ma_list = ctlq_msg->ctx.indirect.payload->va;
mac_addr = ma_list->mac_addr_list;
num_entries = le16_to_cpu(ma_list->num_mac_addr);
/* we should have received a buffer at least this big */
- if (xn->reply_sz < struct_size(ma_list, mac_addr_list, num_entries))
+ if (buff->iov_len < struct_size(ma_list, mac_addr_list, num_entries))
goto invalid_payload;
vport = idpf_vid_to_vport(adapter, le32_to_cpu(ma_list->vport_id));
@@ -4275,16 +3807,13 @@ static int idpf_mac_filter_async_handler(struct idpf_adapter *adapter,
if (ether_addr_equal(mac_addr[i].addr, f->macaddr))
list_del(&f->list);
spin_unlock_bh(&vport_config->mac_filter_list_lock);
- dev_err_ratelimited(&adapter->pdev->dev, "Received error sending MAC filter request (op %d)\n",
- xn->vc_op);
-
- return 0;
+ dev_err_ratelimited(&adapter->pdev->dev, "Received error %d on sending MAC filter request\n",
+ status);
+ return;
invalid_payload:
- dev_err_ratelimited(&adapter->pdev->dev, "Received invalid MAC filter payload (op %d) (len %zd)\n",
- xn->vc_op, xn->reply_sz);
-
- return -EINVAL;
+ dev_err_ratelimited(&adapter->pdev->dev, "Received invalid MAC filter payload (len %zd)\n",
+ buff->iov_len);
}
/**
@@ -4303,19 +3832,21 @@ int idpf_add_del_mac_filters(struct idpf_adapter *adapter,
const u8 *default_mac_addr, u32 vport_id,
bool add, bool async)
{
- struct virtchnl2_mac_addr_list *ma_list __free(kfree) = NULL;
struct virtchnl2_mac_addr *mac_addr __free(kfree) = NULL;
- struct idpf_vc_xn_params xn_params = {};
+ struct libie_ctlq_xn_send_params xn_params = {
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ .chnl_opcode = add ? VIRTCHNL2_OP_ADD_MAC_ADDR :
+ VIRTCHNL2_OP_DEL_MAC_ADDR,
+ };
+ struct virtchnl2_mac_addr_list *ma_list;
u32 num_msgs, total_filters = 0;
struct idpf_mac_filter *f;
- ssize_t reply_sz;
- int i = 0, k;
+ int i = 0;
- xn_params.vc_op = add ? VIRTCHNL2_OP_ADD_MAC_ADDR :
- VIRTCHNL2_OP_DEL_MAC_ADDR;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.async = async;
- xn_params.async_handler = idpf_mac_filter_async_handler;
+ if (async) {
+ xn_params.resp_cb = idpf_mac_filter_async_handler;
+ xn_params.send_ctx = adapter;
+ }
spin_lock_bh(&vport_config->mac_filter_list_lock);
@@ -4370,32 +3901,31 @@ int idpf_add_del_mac_filters(struct idpf_adapter *adapter,
*/
num_msgs = DIV_ROUND_UP(total_filters, IDPF_NUM_FILTERS_PER_MSG);
- for (i = 0, k = 0; i < num_msgs; i++) {
- u32 entries_size, buf_size, num_entries;
+ for (u32 i = 0, k = 0; i < num_msgs; i++) {
+ u32 entries_size, num_entries;
+ size_t buf_size;
+ int err;
num_entries = min_t(u32, total_filters,
IDPF_NUM_FILTERS_PER_MSG);
entries_size = sizeof(struct virtchnl2_mac_addr) * num_entries;
buf_size = struct_size(ma_list, mac_addr_list, num_entries);
- if (!ma_list || num_entries != IDPF_NUM_FILTERS_PER_MSG) {
- kfree(ma_list);
- ma_list = kzalloc(buf_size, GFP_ATOMIC);
- if (!ma_list)
- return -ENOMEM;
- } else {
- memset(ma_list, 0, buf_size);
- }
+ ma_list = kzalloc(buf_size, GFP_ATOMIC);
+ if (!ma_list)
+ return -ENOMEM;
ma_list->vport_id = cpu_to_le32(vport_id);
ma_list->num_mac_addr = cpu_to_le16(num_entries);
memcpy(ma_list->mac_addr_list, &mac_addr[k], entries_size);
- xn_params.send_buf.iov_base = ma_list;
- xn_params.send_buf.iov_len = buf_size;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
+ err = idpf_send_mb_msg_kfree(adapter, &xn_params, ma_list,
+ buf_size);
+ if (err)
+ return err;
+
+ if (!async)
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
k += num_entries;
total_filters -= num_entries;
@@ -4404,6 +3934,26 @@ int idpf_add_del_mac_filters(struct idpf_adapter *adapter,
return 0;
}
+/**
+ * idpf_promiscuous_async_handler - async callback for promiscuous mode
+ * @ctx: controlq context structure
+ * @buff: response buffer pointer and size
+ * @status: async call return value
+ *
+ * Nobody is waiting for the promiscuous virtchnl message response. Print
+ * an error message if something went wrong and return.
+ */
+static void idpf_promiscuous_async_handler(void *ctx,
+ struct kvec *buff,
+ int status)
+{
+ struct idpf_adapter *adapter = ctx;
+
+ if (status)
+ dev_err_ratelimited(&adapter->pdev->dev, "Failed to set promiscuous mode: %d\n",
+ status);
+}
+
/**
* idpf_set_promiscuous - set promiscuous and send message to mailbox
* @adapter: Driver specific private structure
@@ -4418,9 +3968,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))
@@ -4431,15 +3985,7 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter,
vpi.vport_id = cpu_to_le32(vport_id);
vpi.flags = cpu_to_le16(flags);
- xn_params.vc_op = VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.send_buf.iov_base = &vpi;
- xn_params.send_buf.iov_len = sizeof(vpi);
- /* setting promiscuous is only ever done asynchronously */
- xn_params.async = true;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
-
- return reply_sz < 0 ? reply_sz : 0;
+ return idpf_send_mb_msg_stack(adapter, &xn_params, &vpi);
}
/**
@@ -4448,7 +3994,7 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter,
* @send_msg: message to send
* @msg_size: size of message to send
* @recv_msg: message to populate on reception of response
- * @recv_len: length of message copied into recv_msg or 0 on error
+ * @recv_len: on input, maximum response size; on success, actual response size
*
* Return: 0 on success or error code on failure.
*/
@@ -4457,26 +4003,39 @@ int idpf_idc_rdma_vc_send_sync(struct iidc_rdma_core_dev_info *cdev_info,
u8 *recv_msg, u16 *recv_len)
{
struct idpf_adapter *adapter = pci_get_drvdata(cdev_info->pdev);
- struct idpf_vc_xn_params xn_params = { };
- ssize_t reply_sz;
- u16 recv_size;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = VIRTCHNL2_OP_RDMA,
+ .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+ };
+ u8 on_stack_buf[LIBIE_CP_TX_COPYBREAK];
+ void *send_buf;
+ int err;
- if (!recv_msg || !recv_len || msg_size > IDPF_CTLQ_MAX_BUF_LEN)
+ if (!recv_msg || !recv_len || msg_size > LIBIE_CTLQ_MAX_BUF_LEN)
return -EINVAL;
- recv_size = min_t(u16, *recv_len, IDPF_CTLQ_MAX_BUF_LEN);
- *recv_len = 0;
- xn_params.vc_op = VIRTCHNL2_OP_RDMA;
- xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
- xn_params.send_buf.iov_base = send_msg;
- xn_params.send_buf.iov_len = msg_size;
- xn_params.recv_buf.iov_base = recv_msg;
- xn_params.recv_buf.iov_len = recv_size;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- *recv_len = reply_sz;
+ if (!libie_cp_can_send_onstack(msg_size)) {
+ send_buf = kzalloc(msg_size, GFP_KERNEL);
+ if (!send_buf)
+ return -ENOMEM;
+ } else {
+ send_buf = on_stack_buf;
+ }
- return 0;
+ memcpy(send_buf, send_msg, msg_size);
+ err = idpf_send_mb_msg(adapter, &xn_params, send_buf, msg_size);
+ if (err)
+ return err;
+
+ if (xn_params.recv_mem.iov_len > *recv_len) {
+ err = -EINVAL;
+ goto rel_buf;
+ }
+
+ *recv_len = xn_params.recv_mem.iov_len;
+ memcpy(recv_msg, xn_params.recv_mem.iov_base, *recv_len);
+rel_buf:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+ return err;
}
EXPORT_SYMBOL_GPL(idpf_idc_rdma_vc_send_sync);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
index 9b1c9c86f6eac..5d27805ff40fb 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
@@ -4,89 +4,9 @@
#ifndef _IDPF_VIRTCHNL_H_
#define _IDPF_VIRTCHNL_H_
-#include "virtchnl2.h"
+#include <linux/net/intel/virtchnl2.h>
#define IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC (60 * 1000)
-#define IDPF_VC_XN_IDX_M GENMASK(7, 0)
-#define IDPF_VC_XN_SALT_M GENMASK(15, 8)
-#define IDPF_VC_XN_RING_LEN U8_MAX
-
-/**
- * enum idpf_vc_xn_state - Virtchnl transaction status
- * @IDPF_VC_XN_IDLE: not expecting a reply, ready to be used
- * @IDPF_VC_XN_WAITING: expecting a reply, not yet received
- * @IDPF_VC_XN_COMPLETED_SUCCESS: a reply was expected and received, buffer
- * updated
- * @IDPF_VC_XN_COMPLETED_FAILED: a reply was expected and received, but there
- * was an error, buffer not updated
- * @IDPF_VC_XN_SHUTDOWN: transaction object cannot be used, VC torn down
- * @IDPF_VC_XN_ASYNC: transaction sent asynchronously and doesn't have the
- * return context; a callback may be provided to handle
- * return
- */
-enum idpf_vc_xn_state {
- IDPF_VC_XN_IDLE = 1,
- IDPF_VC_XN_WAITING,
- IDPF_VC_XN_COMPLETED_SUCCESS,
- IDPF_VC_XN_COMPLETED_FAILED,
- IDPF_VC_XN_SHUTDOWN,
- IDPF_VC_XN_ASYNC,
-};
-
-struct idpf_vc_xn;
-/* Callback for asynchronous messages */
-typedef int (*async_vc_cb) (struct idpf_adapter *, struct idpf_vc_xn *,
- const struct idpf_ctlq_msg *);
-
-/**
- * struct idpf_vc_xn - Data structure representing virtchnl transactions
- * @completed: virtchnl event loop uses that to signal when a reply is
- * available, uses kernel completion API
- * @lock: protects the transaction state fields below
- * @state: virtchnl event loop stores the data below, protected by @lock
- * @reply_sz: Original size of reply, may be > reply_buf.iov_len; it will be
- * truncated on its way to the receiver thread according to
- * reply_buf.iov_len.
- * @reply: Reference to the buffer(s) where the reply data should be written
- * to. May be 0-length (then NULL address permitted) if the reply data
- * should be ignored.
- * @async_handler: if sent asynchronously, a callback can be provided to handle
- * the reply when it's received
- * @vc_op: corresponding opcode sent with this transaction
- * @idx: index used as retrieval on reply receive, used for cookie
- * @salt: changed every message to make unique, used for cookie
- */
-struct idpf_vc_xn {
- struct completion completed;
- spinlock_t lock;
- enum idpf_vc_xn_state state;
- size_t reply_sz;
- struct kvec reply;
- async_vc_cb async_handler;
- u32 vc_op;
- u8 idx;
- u8 salt;
-};
-
-/**
- * struct idpf_vc_xn_params - Parameters for executing transaction
- * @send_buf: kvec for send buffer
- * @recv_buf: kvec for recv buffer, may be NULL, must then have zero length
- * @timeout_ms: timeout to wait for reply
- * @async: send message asynchronously, will not wait on completion
- * @async_handler: If sent asynchronously, optional callback handler. The user
- * must be careful when using async handlers as the memory for
- * the recv_buf _cannot_ be on stack if this is async.
- * @vc_op: virtchnl op to send
- */
-struct idpf_vc_xn_params {
- struct kvec send_buf;
- struct kvec recv_buf;
- int timeout_ms;
- bool async;
- async_vc_cb async_handler;
- u32 vc_op;
-};
struct idpf_adapter;
struct idpf_netdev_priv;
@@ -96,8 +16,6 @@ struct idpf_vport_max_q;
struct idpf_vport_config;
struct idpf_vport_user_config_data;
-ssize_t idpf_vc_xn_exec(struct idpf_adapter *adapter,
- const struct idpf_vc_xn_params *params);
int idpf_init_dflt_mbx(struct idpf_adapter *adapter);
void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter);
int idpf_vc_core_init(struct idpf_adapter *adapter);
@@ -124,9 +42,35 @@ bool idpf_sideband_action_ena(struct idpf_vport *vport,
struct ethtool_rx_flow_spec *fsp);
unsigned int idpf_fsteer_max_rules(struct idpf_vport *vport);
-int idpf_recv_mb_msg(struct idpf_adapter *adapter, struct idpf_ctlq_info *arq);
-int idpf_send_mb_msg(struct idpf_adapter *adapter, struct idpf_ctlq_info *asq,
- u32 op, u16 msg_size, u8 *msg, u16 cookie);
+void idpf_recv_event_msg(struct libie_ctlq_ctx *ctx,
+ struct libie_ctlq_msg *ctlq_msg);
+int idpf_send_mb_msg(struct idpf_adapter *adapter,
+ struct libie_ctlq_xn_send_params *xn_params,
+ void *send_buf, size_t send_buf_size);
+int idpf_send_mb_msg_kfree(struct idpf_adapter *adapter,
+ struct libie_ctlq_xn_send_params *xn_params,
+ void *send_buf, size_t send_buf_size);
+void idpf_send_vf_reset_msg(struct idpf_adapter *adapter);
+bool idpf_mmio_region_non_static(struct libie_mmio_info *mmio_info,
+ struct libie_pci_mmio_region *reg);
+
+/**
+ * idpf_send_mb_msg_stack - send a mailbox message from an on-stack buffer
+ * @adapter: driver specific private structure
+ * @xn_params: Xn send parameters to fill
+ * @ptr: pointer to the on-stack message object to send
+ *
+ * Send size is deduced based on the pointer type.
+ *
+ * Return: %0 on success, -%errno on failure.
+ */
+#define idpf_send_mb_msg_stack(adapter, xn_params, ptr) \
+({ \
+ typeof(ptr) __ptr = (ptr); \
+ \
+ static_assert(sizeof(*__ptr) <= LIBIE_CP_TX_COPYBREAK); \
+ idpf_send_mb_msg(adapter, xn_params, __ptr, sizeof(*__ptr)); \
+})
struct idpf_queue_ptr {
enum virtchnl2_queue_type type;
@@ -208,13 +152,10 @@ int idpf_send_ena_dis_loopback_msg(struct idpf_adapter *adapter, u32 vport_id,
int idpf_send_get_stats_msg(struct idpf_netdev_priv *np,
struct idpf_port_stats *port_stats);
int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs);
-int idpf_send_get_set_rss_key_msg(struct idpf_adapter *adapter,
- struct idpf_rss_data *rss_data,
- u32 vport_id, bool get);
-int idpf_send_get_set_rss_lut_msg(struct idpf_adapter *adapter,
- struct idpf_rss_data *rss_data,
- u32 vport_id, bool get);
-void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr);
+int idpf_send_set_rss_key_msg(struct idpf_adapter *adapter,
+ struct idpf_rss_data *rss_data, u32 vport_id);
+int idpf_send_set_rss_lut_msg(struct idpf_adapter *adapter,
+ struct idpf_rss_data *rss_data, u32 vport_id);
int idpf_idc_rdma_vc_send_sync(struct iidc_rdma_core_dev_info *cdev_info,
u8 *send_msg, u16 msg_size,
u8 *recv_msg, u16 *recv_len);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c
index d9bcc3f61c658..14dba40a993f7 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,33 +23,33 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)
VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK_MB |
VIRTCHNL2_CAP_PTP_TX_TSTAMPS_MB)
};
- struct idpf_vc_xn_params xn_params = {
- .vc_op = VIRTCHNL2_OP_PTP_GET_CAPS,
- .send_buf.iov_base = &send_ptp_caps_msg,
- .send_buf.iov_len = sizeof(send_ptp_caps_msg),
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = VIRTCHNL2_OP_PTP_GET_CAPS,
.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
};
struct virtchnl2_ptp_cross_time_reg_offsets cross_tstamp_offsets;
+ struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
struct virtchnl2_ptp_clk_adj_reg_offsets clk_adj_offsets;
struct virtchnl2_ptp_clk_reg_offsets clock_offsets;
+ struct virtchnl2_ptp_get_caps *recv_ptp_caps_msg;
struct idpf_ptp_secondary_mbx *scnd_mbx;
struct idpf_ptp *ptp = adapter->ptp;
enum idpf_ptp_access access_type;
u32 temp_offset;
- int reply_sz;
+ size_t reply_sz;
+ int err;
- recv_ptp_caps_msg = kzalloc_obj(struct virtchnl2_ptp_get_caps);
- if (!recv_ptp_caps_msg)
- return -ENOMEM;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &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);
@@ -76,19 +75,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, 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, 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, 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, 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, temp_offset);
cross_tstamp:
access_type = ptp->get_cross_tstamp_access;
@@ -98,48 +98,54 @@ int idpf_ptp_get_caps(struct idpf_adapter *adapter)
cross_tstamp_offsets = recv_ptp_caps_msg->cross_time_offsets;
temp_offset = le32_to_cpu(cross_tstamp_offsets.sys_time_ns_l);
- ptp->dev_clk_regs.sys_time_ns_l = idpf_get_reg_addr(adapter,
- temp_offset);
+ ptp->dev_clk_regs.sys_time_ns_l =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(cross_tstamp_offsets.sys_time_ns_h);
- ptp->dev_clk_regs.sys_time_ns_h = idpf_get_reg_addr(adapter,
- temp_offset);
+ ptp->dev_clk_regs.sys_time_ns_h =
+ libie_pci_get_mmio_addr(mmio, temp_offset);
temp_offset = le32_to_cpu(cross_tstamp_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, temp_offset);
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;
/* 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, temp_offset);
- return 0;
+free_resp:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+ return err;
}
/**
@@ -154,28 +160,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_stack(adapter, &xn_params,
+ &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;
}
/**
@@ -191,27 +203,29 @@ int idpf_ptp_get_dev_clk_time(struct idpf_adapter *adapter,
int idpf_ptp_get_cross_time(struct idpf_adapter *adapter,
struct idpf_ptp_dev_timers *cross_time)
{
- struct virtchnl2_ptp_get_cross_time cross_time_msg;
- struct idpf_vc_xn_params xn_params = {
- .vc_op = VIRTCHNL2_OP_PTP_GET_CROSS_TIME,
- .send_buf.iov_base = &cross_time_msg,
- .send_buf.iov_len = sizeof(cross_time_msg),
- .recv_buf.iov_base = &cross_time_msg,
- .recv_buf.iov_len = sizeof(cross_time_msg),
+ struct virtchnl2_ptp_get_cross_time cross_time_send, *cross_time_recv;
+ struct libie_ctlq_xn_send_params xn_params = {
+ .chnl_opcode = VIRTCHNL2_OP_PTP_GET_CROSS_TIME,
.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
};
- int reply_sz;
+ int err = 0;
- reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
- if (reply_sz < 0)
- return reply_sz;
- if (reply_sz != sizeof(cross_time_msg))
- return -EIO;
+ err = idpf_send_mb_msg_stack(adapter, &xn_params, &cross_time_send);
+ if (err)
+ return err;
- cross_time->dev_clk_time_ns = le64_to_cpu(cross_time_msg.dev_time_ns);
- cross_time->sys_time_ns = le64_to_cpu(cross_time_msg.sys_time_ns);
+ if (xn_params.recv_mem.iov_len != sizeof(*cross_time_recv)) {
+ err = -EIO;
+ goto free_resp;
+ }
- return 0;
+ cross_time_recv = xn_params.recv_mem.iov_base;
+ cross_time->dev_clk_time_ns = le64_to_cpu(cross_time_recv->dev_time_ns);
+ cross_time->sys_time_ns = le64_to_cpu(cross_time_recv->sys_time_ns);
+
+free_resp:
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
+ return err;
}
/**
@@ -228,23 +242,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_stack(adapter, &xn_params,
+ &set_dev_clk_time_msg);
+ if (!err)
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return 0;
+ return err;
}
/**
@@ -261,23 +270,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_stack(adapter, &xn_params,
+ &adj_dev_clk_time_msg);
+ if (!err)
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return 0;
+ return err;
}
/**
@@ -295,23 +299,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_stack(adapter, &xn_params,
+ &adj_dev_clk_fine_msg);
+ if (!err)
+ libie_ctlq_release_rx_buf(&xn_params.recv_mem);
- return 0;
+ return err;
}
/**
@@ -330,18 +329,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)
@@ -353,19 +350,19 @@ int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport)
get_dev_clk_access == IDPF_PTP_NONE)
return -EOPNOTSUPP;
- rcv_tx_tstamp_caps = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
- if (!rcv_tx_tstamp_caps)
- return -ENOMEM;
-
send_tx_tstamp_caps.vport_id = cpu_to_le32(vport->vport_id);
- xn_params.recv_buf.iov_base = rcv_tx_tstamp_caps;
- reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
- if (reply_sz < 0) {
- err = reply_sz;
+ err = idpf_send_mb_msg_stack(vport->adapter, &xn_params,
+ &send_tx_tstamp_caps);
+ if (err)
+ return err;
+
+ rcv_tx_tstamp_caps = xn_params.recv_mem.iov_base;
+ reply_sz = xn_params.recv_mem.iov_len;
+ if (reply_sz < sizeof(*rcv_tx_tstamp_caps)) {
+ err = -EIO;
goto get_tstamp_caps_out;
}
-
num_latches = le16_to_cpu(rcv_tx_tstamp_caps->num_latches);
size = struct_size(rcv_tx_tstamp_caps, tstamp_latches, num_latches);
if (reply_sz != size) {
@@ -420,7 +417,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;
@@ -433,7 +430,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;
}
@@ -530,9 +527,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
@@ -540,22 +537,26 @@ idpf_ptp_get_tstamp_value(struct idpf_vport *vport,
*
* Return: 0 on success, -errno otherwise.
*/
-static int
-idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,
- struct idpf_vc_xn *xn,
- const struct idpf_ctlq_msg *ctlq_msg)
+static void
+idpf_ptp_get_tx_tstamp_async_handler(void *ctx, struct kvec *mem, int status)
{
struct virtchnl2_ptp_get_vport_tx_tstamp_latches *recv_tx_tstamp_msg;
struct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps;
struct virtchnl2_ptp_tx_tstamp_latch tstamp_latch;
struct idpf_ptp_tx_tstamp *tx_tstamp, *tmp;
struct idpf_vport *tstamp_vport = NULL;
+ struct idpf_adapter *adapter = ctx;
struct list_head *head;
u16 num_latches;
u32 vport_id;
- int err = 0;
- recv_tx_tstamp_msg = ctlq_msg->ctx.indirect.payload->va;
+ if (status)
+ return;
+
+ recv_tx_tstamp_msg = mem->iov_base;
+ if (mem->iov_len < sizeof(*recv_tx_tstamp_msg))
+ return;
+
vport_id = le32_to_cpu(recv_tx_tstamp_msg->vport_id);
idpf_for_each_vport(adapter, vport) {
@@ -569,10 +570,13 @@ idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,
}
if (!tstamp_vport || !tstamp_vport->tx_tstamp_caps)
- return -EINVAL;
+ return;
tx_tstamp_caps = tstamp_vport->tx_tstamp_caps;
num_latches = le16_to_cpu(recv_tx_tstamp_msg->num_latches);
+ if (mem->iov_len < struct_size(recv_tx_tstamp_msg, tstamp_latches,
+ num_latches))
+ return;
spin_lock_bh(&tx_tstamp_caps->latches_lock);
head = &tx_tstamp_caps->latches_in_use;
@@ -583,13 +587,13 @@ idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,
if (!tstamp_latch.valid)
continue;
- if (list_empty(head)) {
- err = -ENOBUFS;
+ if (list_empty(head))
goto unlock;
- }
list_for_each_entry_safe(tx_tstamp, tmp, head, list_member) {
if (tstamp_latch.index == tx_tstamp->idx) {
+ int err;
+
list_del(&tx_tstamp->list_member);
err = idpf_ptp_get_tstamp_value(tstamp_vport,
&tstamp_latch,
@@ -604,8 +608,6 @@ idpf_ptp_get_tx_tstamp_async_handler(struct idpf_adapter *adapter,
unlock:
spin_unlock_bh(&tx_tstamp_caps->latches_lock);
-
- return err;
}
/**
@@ -621,15 +623,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;
@@ -662,11 +664,7 @@ int idpf_ptp_get_tx_tstamp(struct idpf_vport *vport)
msg_size = struct_size(send_tx_tstamp_msg, tstamp_latches, id);
send_tx_tstamp_msg->vport_id = cpu_to_le32(vport->vport_id);
send_tx_tstamp_msg->num_latches = cpu_to_le16(id);
- xn_params.send_buf.iov_base = send_tx_tstamp_msg;
- xn_params.send_buf.iov_len = msg_size;
-
- reply_sz = idpf_vc_xn_exec(vport->adapter, &xn_params);
- kfree(send_tx_tstamp_msg);
- return min(reply_sz, 0);
+ return idpf_send_mb_msg_kfree(vport->adapter, &xn_params,
+ send_tx_tstamp_msg, msg_size);
}
diff --git a/drivers/net/ethernet/intel/ixd/Kconfig b/drivers/net/ethernet/intel/ixd/Kconfig
new file mode 100644
index 0000000000000..0a48b3bb7bc26
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/Kconfig
@@ -0,0 +1,14 @@
+# 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 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.
+ 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 0000000000000..03760a2580b9b
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/Makefile
@@ -0,0 +1,13 @@
+# 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
+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.h b/drivers/net/ethernet/intel/ixd/ixd.h
new file mode 100644
index 0000000000000..2a09ccba13d58
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2025 Intel Corporation */
+
+#ifndef _IXD_H_
+#define _IXD_H_
+
+#include <linux/net/intel/libie/controlq.h>
+
+#define IXD_INIT_TASK_DELAY_JIFFIES msecs_to_jiffies(500)
+
+/**
+ * struct ixd_adapter - Data structure representing a CPF
+ * @cp_ctx: Control plane communication context
+ * @init_task: Delayed initialization after reset
+ * @init_task.init_work: Delayed initialization work
+ * @init_task.reset_retries: How many times to check, whether reset is completed
+ * @init_task.vc_retries: Number of retries to establish mailbox communication
+ * @init_task.success: init_work completion status
+ * @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
+ * @vc_ver.major: Negotiated major virtchnl version
+ * @vc_ver.minor: Negotiated minor 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;
+ bool success;
+ } 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;
+};
+
+/**
+ * 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->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_ctlq.c b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
new file mode 100644
index 0000000000000..8712e10c8c504
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_ctlq.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include "ixd.h"
+#include "ixd_ctlq.h"
+#include "ixd_virtchnl.h"
+
+#define IXD_CTLQ_RX_TASK_DELAY_JIFFIES msecs_to_jiffies(300)
+
+/**
+ * ixd_ctlq_clean_sq - Clean the send control queue after sending the message
+ * @adapter: The adapter that sent the messages
+ * @force: Clean regardless of send status
+ *
+ * Free the libie send resources after sending the message and handling
+ * the response.
+ */
+void ixd_ctlq_clean_sq(struct ixd_adapter *adapter, bool force)
+{
+ libie_ctlq_xn_send_clean(adapter->asq, kfree, force);
+}
+
+/**
+ * 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)
+{
+ u8 onstack_send_buff[LIBIE_CP_TX_COPYBREAK] __aligned_largest = {};
+ struct libie_ctlq_xn_send_params send_params = {};
+ 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);
+
+ ixd_ctlq_clean_sq(adapter, false);
+ 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);
+
+ libie_ctlq_release_rx_buf(recv_mem);
+
+ return err;
+}
+
+/**
+ * ixd_ctlq_handle_msg - Default control queue message handler
+ * @ctx: Control plane communication context
+ * @msg: Message received
+ */
+static void ixd_ctlq_handle_msg(struct libie_ctlq_ctx *ctx,
+ struct libie_ctlq_msg *msg)
+{
+ struct ixd_adapter *adapter = pci_get_drvdata(ctx->mmio_info.pdev);
+
+ if (ixd_vc_can_handle_msg(msg))
+ ixd_vc_recv_event_msg(adapter, msg);
+ else
+ dev_dbg_ratelimited(ixd_to_dev(adapter),
+ "Received an unsupported opcode 0x%x from the CP\n",
+ msg->chnl_opcode);
+
+ libie_ctlq_release_rx_buf(&msg->recv_mem);
+}
+
+/**
+ * ixd_ctlq_recv_mb_msg - Receive a potential message over mailbox periodically
+ * @adapter: The adapter with initialized mailbox
+ */
+static void ixd_ctlq_recv_mb_msg(struct ixd_adapter *adapter)
+{
+ struct libie_ctlq_xn_recv_params xn_params = {
+ .xnm = adapter->xnm,
+ .ctlq = adapter->arq,
+ .ctlq_msg_handler = ixd_ctlq_handle_msg,
+ .budget = LIBIE_CTLQ_MAX_XN_ENTRIES,
+ };
+
+ libie_ctlq_xn_recv(&xn_params);
+}
+
+/**
+ * ixd_ctlq_rx_task - Periodically check for mailbox responses and events
+ * @work: work handle
+ */
+void ixd_ctlq_rx_task(struct work_struct *work)
+{
+ struct ixd_adapter *adapter;
+
+ adapter = container_of(work, struct ixd_adapter, mbx_task.work);
+
+ queue_delayed_work(system_dfl_wq, &adapter->mbx_task,
+ IXD_CTLQ_RX_TASK_DELAY_JIFFIES);
+
+ 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 0000000000000..8839f9f8f6d50
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_ctlq.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2025 Intel Corporation */
+
+#ifndef _IXD_CTLQ_H_
+#define _IXD_CTLQ_H_
+
+#include <linux/net/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;
+};
+
+void ixd_ctlq_clean_sq(struct ixd_adapter *adapter, bool force);
+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_dev.c b/drivers/net/ethernet/intel/ixd/ixd_dev.c
new file mode 100644
index 0000000000000..cdd5477cc1f4d
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_dev.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include "ixd.h"
+#include "ixd_lan_regs.h"
+
+/**
+ * ixd_ctlq_reg_init - Initialize default mailbox registers
+ * @adapter: PCI device driver-specific private data
+ * @ctlq_reg_tx: Transmit queue registers info to be filled
+ * @ctlq_reg_rx: Receive queue registers info to be filled
+ */
+void ixd_ctlq_reg_init(struct ixd_adapter *adapter,
+ struct libie_ctlq_reg *ctlq_reg_tx,
+ struct libie_ctlq_reg *ctlq_reg_rx)
+{
+ struct libie_mmio_info *mmio_info = &adapter->cp_ctx.mmio_info;
+ *ctlq_reg_tx = (struct libie_ctlq_reg) {
+ .head = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQH),
+ .tail = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQT),
+ .len = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQLEN),
+ .addr_high = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQBAH),
+ .addr_low = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQBAL),
+ .len_mask = PF_FW_ATQLEN_ATQLEN_M,
+ .len_ena_mask = PF_FW_ATQLEN_ATQENABLE_M,
+ .head_mask = PF_FW_ATQH_ATQH_M,
+ };
+
+ *ctlq_reg_rx = (struct libie_ctlq_reg) {
+ .head = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQH),
+ .tail = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQT),
+ .len = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQLEN),
+ .addr_high = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQBAH),
+ .addr_low = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQBAL),
+ .len_mask = PF_FW_ARQLEN_ARQLEN_M,
+ .len_ena_mask = PF_FW_ARQLEN_ARQENABLE_M,
+ .head_mask = PF_FW_ARQH_ARQH_M,
+ };
+}
+
+static const struct ixd_reset_reg ixd_reset_reg = {
+ .rstat = PFGEN_RSTAT,
+ .rstat_m = PFGEN_RSTAT_PFR_STATE_M,
+ .rstat_ok_v = 0b01,
+ .rtrigger = PFGEN_CTRL,
+ .rtrigger_m = PFGEN_CTRL_PFSWR,
+};
+
+/**
+ * ixd_trigger_reset - Trigger PFR reset
+ * @adapter: the device with mapped reset register
+ */
+void ixd_trigger_reset(struct ixd_adapter *adapter)
+{
+ void __iomem *addr;
+ u32 reg_val;
+
+ addr = libie_pci_get_mmio_addr(&adapter->cp_ctx.mmio_info,
+ ixd_reset_reg.rtrigger);
+ reg_val = readl(addr);
+ writel(reg_val | ixd_reset_reg.rtrigger_m, addr);
+}
+
+/**
+ * ixd_check_reset_complete - Check if the PFR reset is completed
+ * @adapter: CPF being reset
+ *
+ * Return: %true if the register read indicates reset has been finished,
+ * %false otherwise
+ */
+bool ixd_check_reset_complete(struct ixd_adapter *adapter)
+{
+ u32 reg_val, reset_status;
+ void __iomem *addr;
+
+ addr = libie_pci_get_mmio_addr(&adapter->cp_ctx.mmio_info,
+ ixd_reset_reg.rstat);
+ reg_val = readl(addr);
+ reset_status = reg_val & ixd_reset_reg.rstat_m;
+
+ /* 0xFFFFFFFF might be read if the other side hasn't cleared
+ * the register for us yet.
+ */
+ if (reg_val != GENMASK(31, 0) &&
+ reset_status == ixd_reset_reg.rstat_ok_v)
+ return true;
+
+ return false;
+}
diff --git a/drivers/net/ethernet/intel/ixd/ixd_devlink.c b/drivers/net/ethernet/intel/ixd/ixd_devlink.c
new file mode 100644
index 0000000000000..828132db8323e
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_devlink.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025, Intel Corporation. */
+
+#include "ixd.h"
+#include "ixd_devlink.h"
+
+#define IXD_DEVLINK_INFO_LEN 128
+
+/**
+ * ixd_fill_dsn - Get the serial number for the ixd device
+ * @adapter: adapter to query
+ * @buf: storage buffer for the info request
+ */
+static void ixd_fill_dsn(struct ixd_adapter *adapter, char *buf)
+{
+ u8 dsn[8];
+
+ /* Copy the DSN into an array in Big Endian format */
+ put_unaligned_be64(pci_get_dsn(adapter->cp_ctx.mmio_info.pdev), dsn);
+
+ snprintf(buf, IXD_DEVLINK_INFO_LEN, "%8phD", dsn);
+}
+
+/**
+ * ixd_fill_device_name - Get the name of the underlying hardware
+ * @adapter: adapter to query
+ * @buf: storage buffer for the info request
+ * @buf_size: size of the storage buffer
+ */
+static void ixd_fill_device_name(struct ixd_adapter *adapter, char *buf,
+ size_t buf_size)
+{
+ if (adapter->caps.device_type == cpu_to_le32(VIRTCHNL2_MEV_DEVICE))
+ snprintf(buf, buf_size, "%s", "MEV");
+ else
+ snprintf(buf, buf_size, "%s", "UNKNOWN");
+}
+
+/**
+ * ixd_devlink_info_get - .info_get devlink handler
+ * @devlink: devlink instance structure
+ * @req: the devlink info request
+ * @extack: extended netdev ack structure
+ *
+ * Callback for the devlink .info_get operation. Reports information about the
+ * device.
+ *
+ * Return: zero on success or an error code on failure.
+ */
+static int ixd_devlink_info_get(struct devlink *devlink,
+ struct devlink_info_req *req,
+ struct netlink_ext_ack *extack)
+{
+ struct ixd_adapter *adapter = devlink_priv(devlink);
+ char buf[IXD_DEVLINK_INFO_LEN];
+ int err;
+
+ ixd_fill_dsn(adapter, buf);
+ err = devlink_info_serial_number_put(req, buf);
+ if (err)
+ return err;
+
+ ixd_fill_device_name(adapter, buf, IXD_DEVLINK_INFO_LEN);
+ err = devlink_info_version_fixed_put(req, "device.type", buf);
+ if (err)
+ return err;
+
+ snprintf(buf, sizeof(buf), "%u.%u",
+ adapter->vc_ver.major, adapter->vc_ver.minor);
+
+ return devlink_info_version_running_put(req,
+ DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API,
+ 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 0000000000000..b23a1b37aebc4
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_devlink.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2025, Intel Corporation. */
+
+#ifndef _IXD_DEVLINK_H_
+#define _IXD_DEVLINK_H_
+
+#include <net/devlink.h>
+
+#include "ixd.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 for this adapter.
+ * @adapter: the adapter structure to cleanup
+ *
+ * Init task must be completed or cancelled beforehand.
+ */
+static inline void ixd_devlink_unregister(struct ixd_adapter *adapter)
+{
+ if (!adapter->init_task.success)
+ return;
+
+ 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_lan_regs.h b/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h
new file mode 100644
index 0000000000000..58e58c75981b1
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_lan_regs.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2025 Intel Corporation */
+
+#ifndef _IXD_LAN_REGS_H_
+#define _IXD_LAN_REGS_H_
+
+/* Control Plane Function PCI ID */
+#define IXD_DEV_ID_CPF 0x1efe
+
+/* Control Queue (Mailbox) */
+#define PF_FW_MBX_REG_LEN 4096
+#define PF_FW_MBX 0x08400000
+
+#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
+ * @offset: BAR region offset
+ * @size: BAR region size
+ */
+struct ixd_bar_region {
+ resource_size_t offset;
+ 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 0000000000000..8311f7590666b
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_lib.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include "ixd.h"
+#include "ixd_ctlq.h"
+#include "ixd_devlink.h"
+#include "ixd_virtchnl.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 libie_ctlq_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)
+{
+ adapter->arq = libie_find_ctlq(&adapter->cp_ctx, LIBIE_CTLQ_TYPE_RX,
+ LIBIE_CTLQ_MBX_ID);
+ adapter->asq = libie_find_ctlq(&adapter->cp_ctx, LIBIE_CTLQ_TYPE_TX,
+ LIBIE_CTLQ_MBX_ID);
+}
+
+/**
+ * ixd_deinit_dflt_mbx - Deinitialize default mailbox
+ * @adapter: adapter info struct
+ */
+void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter)
+{
+ cancel_delayed_work_sync(&adapter->mbx_task);
+
+ if (adapter->xnm)
+ libie_ctlq_xn_shutdown(adapter->xnm);
+
+ if (adapter->asq)
+ ixd_ctlq_clean_sq(adapter, true);
+
+ if (adapter->xnm)
+ libie_ctlq_xn_deinit(adapter->xnm, &adapter->cp_ctx);
+
+ adapter->arq = NULL;
+ adapter->asq = NULL;
+ adapter->xnm = NULL;
+}
+
+/**
+ * ixd_init_dflt_mbx - Setup default mailbox parameters and make request
+ * @adapter: adapter info struct
+ *
+ * Return: %0 on success, negative errno code on failure
+ */
+int ixd_init_dflt_mbx(struct ixd_adapter *adapter)
+{
+ struct libie_ctlq_create_info ctlqs_info[2];
+ struct libie_ctlq_xn_init_params xn_params;
+ struct libie_ctlq_reg ctlq_reg_tx;
+ struct libie_ctlq_reg ctlq_reg_rx;
+ int err;
+
+ ixd_ctlq_reg_init(adapter, &ctlq_reg_tx, &ctlq_reg_rx);
+ ixd_init_ctlq_create_info(&ctlqs_info[0], LIBIE_CTLQ_TYPE_TX,
+ &ctlq_reg_tx);
+ ixd_init_ctlq_create_info(&ctlqs_info[1], LIBIE_CTLQ_TYPE_RX,
+ &ctlq_reg_rx);
+ ixd_init_libie_xn_params(&xn_params, adapter, ctlqs_info,
+ ARRAY_SIZE(ctlqs_info));
+ err = libie_ctlq_xn_init(&xn_params);
+ if (err)
+ return err;
+ adapter->xnm = xn_params.xnm;
+
+ ixd_adapter_fill_dflt_ctlqs(adapter);
+
+ if (!adapter->asq || !adapter->arq) {
+ ixd_deinit_dflt_mbx(adapter);
+ return -ENOENT;
+ }
+
+ queue_delayed_work(system_dfl_wq, &adapter->mbx_task, 0);
+
+ return 0;
+}
+
+/**
+ * ixd_init_task - Initialize after reset
+ * @work: init work struct
+ */
+void ixd_init_task(struct work_struct *work)
+{
+ struct ixd_adapter *adapter;
+ int err;
+
+ adapter = container_of(work, struct ixd_adapter,
+ init_task.init_work.work);
+
+ if (!ixd_check_reset_complete(adapter)) {
+ if (++adapter->init_task.reset_retries < 10)
+ queue_delayed_work(system_dfl_wq,
+ &adapter->init_task.init_work,
+ IXD_INIT_TASK_DELAY_JIFFIES);
+ 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));
+ return;
+ }
+
+ err = ixd_vc_dev_init(adapter);
+ if (!err) {
+ adapter->init_task.vc_retries = 0;
+ adapter->init_task.success = true;
+ ixd_devlink_register(adapter);
+ return;
+ }
+
+ libie_ctlq_xn_shutdown(adapter->xnm);
+ ixd_trigger_reset(adapter);
+ ixd_deinit_dflt_mbx(adapter);
+ if (++adapter->init_task.vc_retries > 5 ||
+ (err != -ETIMEDOUT && err != -EAGAIN && err != -EBUSY)) {
+ dev_err(ixd_to_dev(adapter),
+ "Failed to establish mailbox communication with the hardware: %pe\n",
+ ERR_PTR(err));
+ return;
+ }
+
+ queue_delayed_work(system_dfl_wq, &adapter->init_task.init_work,
+ IXD_INIT_TASK_DELAY_JIFFIES);
+}
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 0000000000000..5db992d4f9fb2
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_main.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#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");
+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);
+
+ /* 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 */
+ if (adapter->xnm)
+ libie_ctlq_xn_shutdown(adapter->xnm);
+ ixd_trigger_reset(adapter);
+ ixd_deinit_dflt_mbx(adapter);
+
+ libie_pci_unmap_all_mmio_regions(&adapter->cp_ctx.mmio_info);
+ ixd_devlink_free(adapter);
+}
+
+/**
+ * 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->cp_ctx.mmio_info;
+ 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 = ixd_adapter_alloc(&pdev->dev);
+ if (!adapter)
+ return -ENOMEM;
+
+ 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)
+ goto free_adapter;
+
+ pci_set_drvdata(pdev, adapter);
+
+ err = ixd_iomap_regions(adapter);
+ if (err)
+ goto free_adapter;
+
+ 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_dfl_wq, &adapter->init_task.init_work,
+ IXD_INIT_TASK_DELAY_JIFFIES);
+
+ return 0;
+
+free_adapter:
+ ixd_devlink_free(adapter);
+ 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);
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 0000000000000..fc3b6d2e28c53
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c
@@ -0,0 +1,190 @@
+// 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) ||
+ le32_to_cpu(need_ver.minor) != le32_to_cpu(recv_ver->minor))
+ dev_warn(ixd_to_dev(adapter),
+ "Virtchnl version does not match (expected %u.%u, received %u.%u)\n",
+ le32_to_cpu(need_ver.major),
+ le32_to_cpu(need_ver.minor),
+ le32_to_cpu(recv_ver->major),
+ le32_to_cpu(recv_ver->minor));
+
+ if (le32_to_cpu(need_ver.major) != le32_to_cpu(recv_ver->major)) {
+ dev_err(ixd_to_dev(adapter),
+ "Device initialization failed due to virtchnl major version mismatch\n");
+ 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 0000000000000..1a53da8b545c5
--- /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_ */
diff --git a/drivers/net/ethernet/intel/libeth/rx.c b/drivers/net/ethernet/intel/libeth/rx.c
index 62521a1f4ec93..0c1a565a1b3a3 100644
--- a/drivers/net/ethernet/intel/libeth/rx.c
+++ b/drivers/net/ethernet/intel/libeth/rx.c
@@ -145,25 +145,29 @@ 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;
struct page_pool *pool;
int ret;
+ if (!pp.netdev && fq->type == LIBETH_FQE_MTU)
+ return -EINVAL;
+
pp.dma_dir = fq->xdp ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
if (!fq->hsplit)
diff --git a/drivers/net/ethernet/intel/libie/Kconfig b/drivers/net/ethernet/intel/libie/Kconfig
index 70831c7e336e9..9c5fdebb67668 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_FWLOG
tristate
select LIBIE_ADMINQ
@@ -23,3 +31,9 @@ config LIBIE_FWLOG
for it. Firmware logging is using admin queue interface to communicate
with the device. Debugfs is a user interface used to config logging
and dump all collected logs.
+
+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 db57fc6780ea3..3065aa057798c 100644
--- a/drivers/net/ethernet/intel/libie/Makefile
+++ b/drivers/net/ethernet/intel/libie/Makefile
@@ -9,6 +9,14 @@ 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_FWLOG) += libie_fwlog.o
libie_fwlog-y := fwlog.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 0000000000000..45a49eba6a820
--- /dev/null
+++ b/drivers/net/ethernet/intel/libie/controlq.c
@@ -0,0 +1,1295 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include <linux/bitfield.h>
+#include <net/libeth/rx.h>
+
+#include <linux/net/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 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_prep_rx_desc - prepare 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_prep_rx_desc(struct libie_ctlq_desc *desc,
+ dma_addr_t addr, u32 mem_truesize)
+{
+ u64 qword;
+
+ 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 each queue 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;
+
+ ctlq->descs[ntp] = (struct libie_ctlq_desc) {};
+
+ addr = libeth_rx_alloc(&fq, ntp);
+ if (unlikely(addr == DMA_MAPPING_ERROR)) {
+ ret = -ENOMEM;
+ goto post_bufs;
+ }
+
+ libie_ctlq_prep_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;
+
+ dma_wmb();
+ 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 = kvzalloc_objs(*ctlq->tx_msg, ctlq->ring_len,
+ GFP_KERNEL);
+ if (!ctlq->tx_msg)
+ return -ENOMEM;
+
+ for (u32 i = 0; i < ctlq->ring_len; i++) {
+ ctlq->tx_msg[i] = kzalloc_obj(*ctlq->tx_msg[i]);
+ if (!ctlq->tx_msg[i]) {
+ libie_ctlq_free_tx_msgs(ctlq, i);
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * libie_cp_free_desc_mem - free the previously allocated descriptor DMA memory
+ * @dev: device information
+ * @mem: DMA memory information
+ */
+static void libie_cp_free_desc_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_desc_mem(ctlq->dev, dma);
+}
+
+/**
+ * libie_cp_alloc_desc_mem - allocate DMA memory for descriptor ring
+ * @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_desc_mem(struct device *dev,
+ struct libie_cp_dma_mem *mem, u32 size)
+{
+ size = LARGEST_ALIGN(size);
+
+ mem->va = dma_alloc_coherent(dev, size, &mem->pa, GFP_KERNEL);
+ mem->size = size;
+ mem->direction = DMA_BIDIRECTIONAL;
+
+ 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_desc_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_desc_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 == LIBIE_CTLQ_TYPE_RX)
+ writel(ctlq->ring_len - 1, ctlq->reg.tail);
+ else
+ writel(0, 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: libie CP context information
+ * @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 libie_ctlq_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: libie CP context information
+ * @qinfo: information required for queue creation
+ *
+ * Allocate and initialize a control queue and add it to the control queue list.
+ * 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;
+ int err;
+
+ if (qinfo->id != LIBIE_CTLQ_MBX_ID)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ if (qinfo->len > FIELD_MAX(LIBIE_CTLQ_MBX_ATQ_LEN) || !qinfo->len)
+ return ERR_PTR(-EINVAL);
+
+ ctlq = kvzalloc_obj(*ctlq);
+ 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;
+
+ err = libie_ctlq_alloc_queue_res(ctlq);
+ if (err) {
+ kvfree(ctlq);
+ return ERR_PTR(err);
+ }
+
+ 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 CP 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 CP 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.
+ *
+ * Please note that any control queue send/receive functions are not
+ * softirq/NAPI safe, and therefore API can be used in process context only.
+ *
+ * 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_desc_avail - get number of free descriptors on a Tx ctlq
+ * @ctlq: specific control queue which is going be used for sending messages
+ *
+ * The caller must hold ctlq->lock. Any dependent sending must be done
+ * in the same critical section.
+ *
+ * Return: number of available descriptors/messages on a given control queue.
+ */
+u32 libie_ctlq_send_desc_avail(const struct libie_ctlq_info *ctlq)
+{
+ u32 ntu = ctlq->next_to_use, ntc = ctlq->next_to_clean;
+
+ lockdep_assert_held(&ctlq->lock);
+
+ return (ntc > ntu ? 0 : ctlq->ring_len) + ntc - ntu - 1;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_send_desc_avail, "LIBIE_CP");
+
+/**
+ * libie_ctlq_send - send a message to Control Plane or Peer
+ * @ctlq: specific control queue which is used for sending a message
+ * @num_q_msg: number of messages present to send on @ctlq,
+ * positive and no greater than the number of available descriptors
+ *
+ * The caller must fill in @num_q_msg Tx messages starting at ntu beforehand.
+ *
+ * The caller must hold ctlq->lock. The intended pattern is to first check
+ * the number of descriptors available, then fill in the messages and perform
+ * send within a single critical section.
+ */
+void libie_ctlq_send(struct libie_ctlq_info *ctlq, u32 num_q_msg)
+{
+ u32 ntu = ctlq->next_to_use;
+
+ lockdep_assert_held(&ctlq->lock);
+
+ for (int i = 0; i < num_q_msg; i++) {
+ struct libie_ctlq_msg *msg = ctlq->tx_msg[ntu];
+ 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;
+ }
+ dma_wmb();
+ writel(ntu, ctlq->reg.tail);
+ ctlq->next_to_use = ntu;
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_send, "LIBIE_CP");
+
+/**
+ * libie_ctlq_send_clean - cleanup the send control queue message buffers
+ * @params: information for handling of Tx completions
+ *
+ * Cleanup the send buffers for the given control queue, if force is set, then
+ * clear all the outstanding send messages irrespective of their send status,
+ * until a zero-length message is encountered, which is either a message that
+ * is already cleared, or a VF reset message, which is always last.
+ * Force should be used during deinit or reset.
+ *
+ * Return: number of send buffers cleaned.
+ */
+u32 libie_ctlq_send_clean(const struct libie_ctlq_clean_params *params)
+{
+ struct libie_ctlq_info *ctlq = params->ctlq;
+ 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) &&
+ !(unlikely(params->force) && msg->data_len))
+ break;
+
+ /* This cannot be reordered and lock is taken, so no barriers */
+ desc->qword0 = 0;
+
+ params->rel_dma_mem(params->rel_ctx, &msg->send_mem);
+ memset(msg, 0, sizeof(*msg));
+
+ 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_send_clean, "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)) {
+ if (unlikely(msg->data_len > LIBIE_CTLQ_MAX_BUF_LEN)) {
+ msg->data_len = LIBIE_CTLQ_MAX_BUF_LEN;
+ msg->chnl_retval = U32_MAX;
+ }
+ msg->recv_mem = (struct kvec) {
+ .iov_base = netmem_address(rx_buf->netmem) +
+ rx_buf->offset,
+ .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 messages
+ * @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,
+ * no greater than number of posted buffers
+ *
+ * Caller is expected to return buffers via libie_ctlq_release_rx_buf().
+ *
+ * The caller must make sure that calls to libie_ctlq_post_rx_buffs()
+ * and libie_ctlq_recv() for each queue 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++) {
+ 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();
+
+ libie_ctlq_fill_rx_msg(&msg[i], desc, rx_buf);
+ desc->qword0 = 0;
+
+ if (unlikely(++ntc == ctlq->ring_len))
+ ntc = 0;
+ }
+
+ ctlq->next_to_clean = ntc;
+
+ return i;
+}
+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;
+
+ for_each_set_bit(free_idx, xnm->free_xns_bm,
+ LIBIE_CTLQ_MAX_XN_ENTRIES) {
+ xn = &xnm->ring[free_idx];
+
+ /* Torn read of the physical address is possible, the worst case
+ * scenario is a transient spurious skip. If the physical
+ * address is dirty in any way, reuse is already safe.
+ */
+ if (xn->tx_msg &&
+ data_race(xn->tx_msg->send_mem.pa) == xn->small_dma_mem.pa)
+ continue;
+
+ clear_bit(free_idx, xnm->free_xns_bm);
+
+ return xn;
+ }
+
+ return NULL;
+}
+
+/**
+ * __libie_ctlq_xn_push_free - unsafely push an xn entry into the free list
+ * @xnm: Xn transaction manager
+ * @xn: xn entry to be added into the free list
+ *
+ * Return: whether xnm destruction can be triggered by the caller
+ */
+static bool __libie_ctlq_xn_push_free(struct libie_ctlq_xn_manager *xnm,
+ struct libie_ctlq_xn *xn)
+{
+ xn->cookie++;
+ set_bit(xn->index, xnm->free_xns_bm);
+
+ if (unlikely(xnm->shutdown) &&
+ bitmap_full(xnm->free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES))
+ return true;
+
+ return false;
+}
+
+/**
+ * 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)
+{
+ bool can_destroy;
+
+ scoped_guard(spinlock, &xnm->free_xns_bm_lock)
+ can_destroy = __libie_ctlq_xn_push_free(xnm, xn);
+
+ if (can_destroy)
+ complete(&xnm->can_destroy);
+}
+
+/**
+ * libie_ctlq_xn_deinit_dma - free the DMA memory allocated for send messages
+ * @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 libie_ctlq_xn_manager *xnm,
+ u32 num_entries)
+{
+ for (u32 i = 0; i < num_entries; i++) {
+ struct libie_ctlq_xn *xn = &xnm->ring[i];
+
+ dma_pool_free(xnm->small_buff_pool, xn->small_dma_mem.va,
+ xn->small_dma_mem.pa);
+ }
+
+ dma_pool_destroy(xnm->small_buff_pool);
+}
+
+/**
+ * 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;
+
+ xnm->small_buff_pool =
+ dma_pool_create("libie_ctlq_xn_tx", dev, LIBIE_CP_TX_COPYBREAK,
+ LIBIE_CP_TX_COPYBREAK, 0);
+ if (!xnm->small_buff_pool)
+ return -ENOMEM;
+
+ for (i = 0; i < LIBIE_CTLQ_MAX_XN_ENTRIES; i++) {
+ struct libie_cp_dma_mem *mem = &xnm->ring[i].small_dma_mem;
+
+ mem->va = dma_pool_zalloc(xnm->small_buff_pool, GFP_KERNEL,
+ &mem->pa);
+ if (!mem->va)
+ goto dealloc_dma;
+
+ mem->direction = DMA_BIDIRECTIONAL;
+ mem->size = LIBIE_CP_TX_COPYBREAK;
+ }
+
+ return 0;
+
+dealloc_dma:
+ libie_ctlq_xn_deinit_dma(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];
+ spin_lock(&xn->xn_lock);
+ if (ctlq_msg->chnl_opcode != xn->virtchnl_opcode ||
+ msg_cookie != xn->cookie) {
+ spin_unlock(&xn->xn_lock);
+ return false;
+ }
+
+ 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);
+ libie_ctlq_release_rx_buf(response);
+ 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.
+ * Iterates free_xns_bm locklessly, potential races are caught under
+ * xn->xn_lock.
+ */
+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.
+ * Also terminates async transactions for which it failed to receive a response
+ * within a given timeframe.
+ * Function is intended to be called periodically from a single task.
+ *
+ * Return: remaining budget.
+ */
+u32 libie_ctlq_xn_recv(struct libie_ctlq_xn_recv_params *params)
+{
+ struct libie_ctlq_msg ctlq_msg;
+ u32 budget = params->budget;
+
+ while (budget && libie_ctlq_recv(params->ctlq, &ctlq_msg, 1)) {
+ budget--;
+ if (!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 budget;
+}
+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;
+
+ if (!buf || !buf_len)
+ return -EOPNOTSUPP;
+
+ if (libie_cp_can_send_onstack(buf_len)) {
+ dma_mem = &xn->small_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, ¶ms->ctlq->lock) {
+ struct libie_ctlq_info *ctlq = params->ctlq;
+ struct libie_ctlq_msg *ctlq_msg;
+
+ if (!libie_ctlq_send_desc_avail(ctlq)) {
+ if (!libie_cp_can_send_onstack(buf_len))
+ libie_cp_unmap_dma_mem(dev, dma_mem);
+
+ return -EBUSY;
+ }
+
+ ctlq_msg = ctlq->tx_msg[ctlq->next_to_use];
+ xn->tx_msg = dma_mem == &xn->small_dma_mem ? ctlq_msg : NULL;
+ if (params->ctlq_msg)
+ *ctlq_msg = *params->ctlq_msg;
+ else
+ /* Unused ctlq messages are already zeroed */
+ ctlq_msg->opcode = LIBIE_CTLQ_SEND_MSG_TO_CP;
+
+ ctlq_msg->sw_cookie = cookie;
+ ctlq_msg->send_mem = *dma_mem;
+ ctlq_msg->data_len = buf_len;
+ ctlq_msg->chnl_opcode = params->chnl_opcode;
+ libie_ctlq_send(params->ctlq, 1);
+ }
+
+ return 0;
+}
+
+/**
+ * libie_ctlq_xn_send - send a control queue message, initiating a transaction
+ * @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);
+ if (xn->state == LIBIE_CTLQ_XN_SHUTDOWN) {
+ ret = -ENXIO;
+ goto unlock_xn;
+ }
+
+ xn->state = params->resp_cb ? LIBIE_CTLQ_XN_ASYNC :
+ LIBIE_CTLQ_XN_WAITING;
+ 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)
+ 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);
+unlock_xn:
+ 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");
+
+/**
+ * struct libie_ctlq_xn_rel_tx_ctx - context needed to release xn Tx message
+ * @dev: device for which DMA was mapped
+ * @rel_tx_buf: freeing function for non-small buffers
+ */
+struct libie_ctlq_xn_rel_tx_ctx {
+ struct device *dev;
+ void (*rel_tx_buf)(const void *buf_va);
+};
+
+/**
+ * libie_ctlq_xn_rel_tx_buf - release xn-controlled Tx message buffer
+ * @ctx: context, namely DMA device and freeing function
+ * @dma_mem: DMA memory to reclaim/unmap
+ */
+static void libie_ctlq_xn_rel_tx_buf(const void *ctx,
+ struct libie_cp_dma_mem *dma_mem)
+{
+ const struct libie_ctlq_xn_rel_tx_ctx *rel_ctx = ctx;
+
+ if (!libie_cp_can_send_onstack(dma_mem->size)) {
+ libie_cp_unmap_dma_mem(rel_ctx->dev, dma_mem);
+ rel_ctx->rel_tx_buf(dma_mem->va);
+ }
+}
+
+/**
+ * libie_ctlq_xn_send_clean - clean xn-controlled Tx messages
+ * @ctlq: control queue to clean
+ * @rel_tx_buf: driver callback to free the buffer
+ * @force: clean regardless of DD
+ *
+ * Return: number of completed/released messages.
+ */
+u32 libie_ctlq_xn_send_clean(struct libie_ctlq_info *ctlq,
+ void (*rel_tx_buf)(const void *buf_va),
+ bool force)
+{
+ struct libie_ctlq_xn_rel_tx_ctx rel_ctx = {
+ .dev = ctlq->dev,
+ .rel_tx_buf = rel_tx_buf,
+ };
+ struct libie_ctlq_clean_params params = {
+ .ctlq = ctlq,
+ .force = force,
+ .num_msgs = ctlq->ring_len,
+ .rel_ctx = &rel_ctx,
+ .rel_dma_mem = libie_ctlq_xn_rel_tx_buf,
+ };
+
+ return libie_ctlq_send_clean(¶ms);
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_send_clean, "LIBIE_CP");
+
+/**
+ * libie_ctlq_xn_shutdown - terminate control queue transactions
+ * @xnm: pointer to the transaction manager
+ *
+ * Synchronously terminate existing transactions and stop accepting new ones.
+ * Async transactions are discarded without invoking resp_cb.
+ */
+void libie_ctlq_xn_shutdown(struct libie_ctlq_xn_manager *xnm)
+{
+ 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);
+
+ switch (xn->state) {
+ /* if an idle xn is not free, it is about to be either
+ * freed or initialized, prevent the latter and wait
+ */
+ case LIBIE_CTLQ_XN_IDLE:
+ xn->state = LIBIE_CTLQ_XN_SHUTDOWN;
+ fallthrough;
+ /* waiting thread possibly needs a push to return the xn,
+ * transaction will be reported as timed out
+ */
+ case LIBIE_CTLQ_XN_WAITING:
+ complete(&xn->cmd_completion_event);
+ fallthrough;
+ /* these states will return the xn soon */
+ case LIBIE_CTLQ_XN_COMPLETED_SUCCESS:
+ case LIBIE_CTLQ_XN_COMPLETED_FAILED:
+ case LIBIE_CTLQ_XN_SHUTDOWN:
+ must_wait = true;
+ break;
+ /* no thread should reference async xns at this point */
+ case LIBIE_CTLQ_XN_ASYNC:
+ xn->state = LIBIE_CTLQ_XN_IDLE;
+ __libie_ctlq_xn_push_free(xnm, xn);
+ break;
+ }
+
+ spin_unlock(&xn->xn_lock);
+ }
+
+ spin_unlock(&xnm->free_xns_bm_lock);
+
+ if (must_wait)
+ wait_for_completion(&xnm->can_destroy);
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_shutdown, "LIBIE_CP");
+
+/**
+ * libie_ctlq_xn_deinit - deallocate and free the transaction manager resources
+ * @xnm: pointer to the transaction manager
+ * @ctx: libie CP context information
+ *
+ * Rx processing must be stopped beforehand via cancelling tasks.
+ * Tx processing must be stopped beforehand via libie_ctlq_xn_shutdown(),
+ * all buffers must be force-cleaned from the send queue.
+ */
+void libie_ctlq_xn_deinit(struct libie_ctlq_xn_manager *xnm,
+ struct libie_ctlq_ctx *ctx)
+{
+ libie_ctlq_xn_deinit_dma(xnm, LIBIE_CTLQ_MAX_XN_ENTRIES);
+ kvfree(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 = kvzalloc_obj(*xnm);
+ if (!xnm)
+ goto ctlq_deinit;
+
+ ret = libie_ctlq_xn_init_dma(¶ms->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:
+ kvfree(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/drivers/net/ethernet/intel/libie/pci.c b/drivers/net/ethernet/intel/libie/pci.c
new file mode 100644
index 0000000000000..b756c1186ce90
--- /dev/null
+++ b/drivers/net/ethernet/intel/libie/pci.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2025 Intel Corporation */
+
+#include <linux/net/intel/libie/pci.h>
+
+/**
+ * libie_find_mmio_region - find MMIO region containing a range
+ * @mmio_list: list that contains MMIO region info
+ * @offset: range start offset
+ * @size: range size
+ * @bar_idx: BAR index containing the range to search
+ *
+ * MMIO regions mappings are traversed from oldest to newest.
+ *
+ * Return: pointer to a MMIO region overlapping with the range in any way or
+ * NULL if no such region is mapped.
+ */
+static struct libie_pci_mmio_region *
+libie_find_mmio_region(const struct list_head *mmio_list,
+ resource_size_t offset, resource_size_t size,
+ int bar_idx)
+{
+ resource_size_t end_offset = offset + size;
+ struct libie_pci_mmio_region *mr;
+
+ list_for_each_entry(mr, mmio_list, list) {
+ resource_size_t mr_end = mr->offset + mr->size;
+ resource_size_t mr_start = mr->offset;
+
+ if (mr->bar_idx != bar_idx)
+ continue;
+ if (offset < mr_end && end_offset > mr_start)
+ return mr;
+ }
+
+ return NULL;
+}
+
+/**
+ * __libie_pci_get_mmio_addr - get the MMIO virtual address
+ * @mmio_info: contains list of MMIO regions
+ * @offset: register offset to find
+ * @num_args: number of additional arguments present
+ * @...: optional BAR index (0 by default)
+ *
+ * This function finds the virtual address of a register offset by iterating
+ * through the non-linear MMIO regions that are mapped by the driver.
+ *
+ * The list is traversed oldest to newest, so accessing an older mapping
+ * via this function while deleting a newer one is allowed.
+ *
+ * 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;
+ }
+
+ WARN_ONCE(true, "Access to an unmapped MMIO region (BAR%d, offset %pa)",
+ bar_idx, &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
+ * @...: optional BAR index (0 by default)
+ *
+ * Return: true if the requested address range is accessible through
+ * new or existing mapping, false otherwise.
+ */
+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 end_offset;
+ 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);
+ }
+
+ if (bar_idx >= PCI_STD_NUM_BARS || bar_idx < 0 ||
+ !pci_resource_is_mem(pdev, bar_idx))
+ return false;
+
+ /* pci_iomap_range() silently maps less
+ * if the requested length is too big
+ */
+ if (!size || check_add_overflow(offset, size, &end_offset) ||
+ end_offset > pci_resource_len(pdev, bar_idx))
+ return false;
+
+ mr = libie_find_mmio_region(&mmio_info->mmio_list, offset, size,
+ bar_idx);
+ if (mr) {
+ pci_warn(pdev,
+ "Mapping of BAR%u (offset=%llu, size=%llu) intersecting region (offset=%llu, size=%llu) already exists\n",
+ bar_idx, (unsigned long long)mr->offset,
+ (unsigned long long)mr->size,
+ (unsigned long long)offset, (unsigned long long)size);
+ return mr->offset <= offset &&
+ mr->offset + mr->size >= end_offset;
+ }
+
+ va = pci_iomap_range(mmio_info->pdev, bar_idx, offset, size);
+ if (!va) {
+ pci_err(pdev, "Failed to map BAR%u region\n", bar_idx);
+ return false;
+ }
+
+ mr = kvzalloc_obj(*mr);
+ if (!mr) {
+ pci_iounmap(pdev, 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_fltr_regs - unmap selected PCI device MMIO regions
+ * @mmio_info: contains list of MMIO regions to unmap
+ * @fltr: returns true, if region is to be unmapped
+ */
+void libie_pci_unmap_fltr_regs(struct libie_mmio_info *mmio_info,
+ bool (*fltr)(struct libie_mmio_info *mmio_info,
+ struct libie_pci_mmio_region *reg))
+{
+ struct libie_pci_mmio_region *mr, *tmp;
+
+ list_for_each_entry_safe(mr, tmp, &mmio_info->mmio_list, list) {
+ if (!fltr(mmio_info, mr))
+ continue;
+ list_del(&mr->list);
+ pci_iounmap(mmio_info->pdev, mr->addr);
+ kvfree(mr);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(libie_pci_unmap_fltr_regs, "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) {
+ list_del(&mr->list);
+ pci_iounmap(mmio_info->pdev, mr->addr);
+ kvfree(mr);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(libie_pci_unmap_all_mmio_regions, "LIBIE_PCI");
+
+/**
+ * libie_pci_init_dev - enable and configure the device
+ * @pdev: PCI device information
+ *
+ * Enable the device, request memory regions, set 64-bit DMA mask
+ * and coherent DMA mask, and enable bus-mastering
+ *
+ * Return: %0 on success, -%errno on failure.
+ */
+int libie_pci_init_dev(struct pci_dev *pdev)
+{
+ int err;
+
+ err = pcim_enable_device(pdev);
+ if (err)
+ return err;
+
+ for (int bar = 0; bar < PCI_STD_NUM_BARS; bar++)
+ if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
+ err = pcim_request_region(pdev, bar, pci_name(pdev));
+ if (err)
+ return err;
+ }
+
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (err)
+ return err;
+
+ pci_set_master(pdev);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(libie_pci_init_dev, "LIBIE_PCI");
+
+MODULE_DESCRIPTION("Common Ethernet PCI library");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/net/intel/libie/controlq.h b/include/linux/net/intel/libie/controlq.h
new file mode 100644
index 0000000000000..175227d4eef1e
--- /dev/null
+++ b/include/linux/net/intel/libie/controlq.h
@@ -0,0 +1,436 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2025 Intel Corporation */
+
+#ifndef __LIBIE_CONTROLQ_H
+#define __LIBIE_CONTROLQ_H
+
+#include <linux/dmapool.h>
+#include <net/libeth/rx.h>
+
+#include <linux/net/intel/libie/pci.h>
+#include <linux/net/intel/virtchnl2.h>
+
+/* Default mailbox control queue */
+#define LIBIE_CTLQ_MBX_ID -1
+#define LIBIE_CTLQ_MAX_BUF_LEN SZ_4K
+
+/**
+ * enum libie_ctlq_type - control queue type
+ * @LIBIE_CTLQ_TYPE_TX: basic Tx control queue
+ * @LIBIE_CTLQ_TYPE_RX: basic Rx control queue
+ */
+enum libie_ctlq_type {
+ LIBIE_CTLQ_TYPE_TX = 0,
+ 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
+
+#define LIBIE_CP_TX_COPYBREAK 128
+
+/**
+ * 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
+ * @direction: memory to device or device to memory
+ */
+struct libie_cp_dma_mem {
+ void *va;
+ dma_addr_t pa;
+ size_t size;
+ int direction;
+};
+
+/**
+ * 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 mailbox selection, 0 for default mailbox (Tx)
+ * @hw_retval: execution status from the HW (Rx)
+ * @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 libie_ctlq_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: descriptor ring DMA memory
+ * @descs: array of descriptors
+ * @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_clean: next descriptor to be cleaned
+ * @next_to_use: next available slot to send buffer (Tx queue)
+ * @next_to_post: next available slot to post buffers to (Rx queue)
+ * @ring_len: length of the descriptor ring
+ */
+struct libie_ctlq_info {
+ struct list_head list;
+ enum libie_ctlq_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)
+
+/* libie controlq descriptor qword0 details */
+
+/* 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 |
+ */
+#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;
+};
+
+/**
+ * struct libie_ctlq_clean_params - cleaning parameters for Tx messages
+ * @rel_dma_mem: non-sleeping callback to put the DMA buffer after send
+ * @rel_ctx: additional context for release callback
+ * @ctlq: control queue information
+ * @num_msgs: number of messages to be cleaned
+ * @force: clean even if DD is not yet set, use only for final cleanup
+ */
+struct libie_ctlq_clean_params {
+ void (*rel_dma_mem)(const void *ctx, struct libie_cp_dma_mem *dma_mem);
+ const void *rel_ctx;
+ struct libie_ctlq_info *ctlq;
+ u16 num_msgs;
+ bool force;
+};
+
+/**
+ * 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 libie_ctlq_type type,
+ int id);
+
+u32 libie_ctlq_send_desc_avail(const struct libie_ctlq_info *ctlq);
+void libie_ctlq_send(struct libie_ctlq_info *ctlq, u32 num_q_msg);
+u32 libie_ctlq_send_clean(const struct libie_ctlq_clean_params *params);
+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);
+
+/* 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
+ * @LIBIE_CTLQ_XN_SHUTDOWN: transaction cannot be used anymore
+ */
+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,
+ LIBIE_CTLQ_XN_SHUTDOWN,
+};
+
+/**
+ * struct libie_ctlq_xn - structure representing a virtchnl transaction entry
+ * @resp_cb: non-sleeping callback to handle the response to an async message
+ * @xn_lock: lock to protect the transaction entry state
+ * @cmd_completion_event: wait until reply is received or xn is terminated
+ * @small_dma_mem: DMA memory for copying small send buffers from stack,
+ * is recycled when response is received or on timeout
+ * @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
+ * @tx_msg: control queue Tx message slot to track small DMA usage
+ * @virtchnl_opcode: virtchnl command opcode used for Xn transaction
+ * @state: transaction state of a virtchnl message
+ * @cookie: unique message identifier, incremented every time the slot is used
+ * @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 completion cmd_completion_event;
+ struct libie_cp_dma_mem small_dma_mem;
+ struct libie_cp_dma_mem send_dma_mem;
+ struct kvec recv_mem;
+ void *send_ctx;
+ u64 timeout_ms;
+ ktime_t timestamp;
+ struct libie_ctlq_msg *tx_msg;
+ 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
+ * @small_buff_pool: DMA pool for small send buffers
+ * @can_destroy: completion, triggered by the last released transaction
+ * @shutdown: shutdown process has been started, no new transactions allowed
+ */
+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 dma_pool *small_buff_pool;
+ struct completion can_destroy;
+ bool shutdown;
+};
+
+/**
+ * struct libie_ctlq_xn_send_params - structure representing send Xn entry
+ * @resp_cb: non-sleeping callback to handle the response to an async message
+ * @rel_tx_buf: non-sleeping callback for freeing the send buffer
+ * @xnm: Xn manager to process Xn entries
+ * @ctlq: send control queue information
+ * @ctlq_msg: control queue message information
+ * @send_buf: buffer that carries outgoing message data, buffers larger than
+ * LIBIE_CP_TX_COPYBREAK bytes will always be consumed
+ * @recv_mem: receive buffer
+ * @send_ctx: context for callback 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 - request to receive xn responses
+ * @ctlq_msg_handler: handler for Rx messages with no matching xn (mandatory)
+ * @xnm: Xn manager to process Xn entries
+ * @ctlq: control queue information
+ * @budget: maximum number of messages to process
+ */
+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;
+ u32 budget;
+};
+
+/**
+ * struct libie_ctlq_xn_init_params - xn transaction manager parameters
+ * @cctlq_info: control queue information
+ * @ctx: pointer to controlq context structure
+ * @xnm: Xn manager to process Xn entries
+ * @num_qs: number of control queues to be 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);
+void libie_ctlq_xn_shutdown(struct libie_ctlq_xn_manager *xnm);
+int libie_ctlq_xn_send(struct libie_ctlq_xn_send_params *params);
+u32 libie_ctlq_xn_recv(struct libie_ctlq_xn_recv_params *params);
+u32 libie_ctlq_xn_send_clean(struct libie_ctlq_info *ctlq,
+ void (*rel_tx_buf)(const void *buf_va),
+ bool force);
+
+#endif /* __LIBIE_CONTROLQ_H */
diff --git a/include/linux/net/intel/libie/pci.h b/include/linux/net/intel/libie/pci.h
new file mode 100644
index 0000000000000..effd072c55c8c
--- /dev/null
+++ b/include/linux/net/intel/libie/pci.h
@@ -0,0 +1,56 @@
+/* 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 offset,
+ int num_args, ...);
+void libie_pci_unmap_all_mmio_regions(struct libie_mmio_info *mmio_info);
+void libie_pci_unmap_fltr_regs(struct libie_mmio_info *mmio_info,
+ bool (*fltr)(struct libie_mmio_info *mmio_info,
+ struct libie_pci_mmio_region *reg));
+int libie_pci_init_dev(struct pci_dev *pdev);
+
+#endif /* __LIBIE_PCI_H */
diff --git a/include/linux/avf/virtchnl.h b/include/linux/net/intel/virtchnl.h
similarity index 100%
rename from include/linux/avf/virtchnl.h
rename to include/linux/net/intel/virtchnl.h
diff --git a/drivers/net/ethernet/intel/idpf/virtchnl2.h b/include/linux/net/intel/virtchnl2.h
similarity index 100%
rename from drivers/net/ethernet/intel/idpf/virtchnl2.h
rename to include/linux/net/intel/virtchnl2.h
diff --git a/drivers/net/ethernet/intel/idpf/virtchnl2_lan_desc.h b/include/linux/net/intel/virtchnl2_lan_desc.h
similarity index 100%
rename from drivers/net/ethernet/intel/idpf/virtchnl2_lan_desc.h
rename to include/linux/net/intel/virtchnl2_lan_desc.h
diff --git a/include/net/libeth/rx.h b/include/net/libeth/rx.h
index 5d991404845e6..0e736846c5e8a 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);
/**
|
| 3/2 | 2026/08/12 21:56 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 126764 output: 22 thoughts: 1314 Thoughts: **Fuzzing Potential: Examining the Kernel Patch** Okay, so I'm looking at this patch series and need to determine its fuzzing potential. It's introducing a new driver, `ixd`, for Intel's Control Plane Function, and reorganizing some existing code by moving headers and adding `libie_cp` and `libie_pci` modules, also modifying `idpf` to use the new libraries. My initial thought is to assess if these changes introduce any new, fuzzable attack surfaces. First, the `ixd` driver. It's a PCI driver, which is a promising start for fuzzing. The provided PCI ID points to an "Intel(R) Control Plane PCI Function," which immediately triggers a question: is this virtualized or physical hardware? The description mentions "Intel E2100 and later IPUs and FNICs." IPUs (Infrastructure Processing Units) are, essentially, SmartNICs. The documentation does point out drivers that *require* physical hardware are not emulated in standard QEMU. Thinking about it, are SmartNIC drivers like `ixd` emulated? Ah, but then I remember the patch also modifies `idpf`. That one's already in the kernel, and that means it has been vetted for fuzzing before, but I'll double-check it. Looking at the `idpf` driver itself, it's described as "Intel(R) Infrastructure Data Path Function Linux Driver." Wait... is `idpf` also a virtual function or related? I should check its location in `drivers/net/ethernet/intel/idpf/`. Okay, the `idpf` driver is also using `libie_cp` and `libie_pci`, which further confirms that they are related to some kind of communication and PCI resource management. Let's see if this could be fuzzed in a QEMU environment. Intel VF drivers (like `iavf`) are usually fine, but `idpf` is related to Intel IPUs, making it a bit dubious. The key question is whether they strictly require physical hardware. The prompt does state that drivers needing *physical* hardware (SmartNICs and GPUs) that aren't emulated in QEMU should be flagged. This suggests `idpf` or `ixd` might fall into that category. So, the question remains: is `idpf` emulated in QEMU? I don't have direct access to QEMU's source right now, but I can assume that `idpf` is not a standard driver, given its specific use. Then I get another idea: is `idpf` actually a SmartNIC driver? The description indicates it's part of an IPU (SmartNICs). `ixd` is explicitly a "Control Plane Function of Intel E2100 and later IPUs" - so it's *definitely* a SmartNIC driver. Similarly, `idpf`'s "Infrastructure Data Path Function" is tied to Intel IPUs as well. I need to make sure `idpf` is being treated as a network card by the kernel. Let's check where `idpf` and `ixd` are in the source tree: in `drivers/net/ethernet/intel/idpf/` and `drivers/net/ethernet/intel/ixd/` respectively. Since I don't see any of them as a part of the standard set of ethernet drivers, I am going to assume they are more specialized and likely require specific hardware. Here's a key point: if they *do* require physical PCIe cards not emulated in QEMU, they might be out. But wait, syzkaller *can* fuzz PCI drivers using `syz_pci_vpci`... If the PCI ID is added to syzkaller's descriptions, or if it's a virtual device, they can be emulated. Syzkaller's `syz_pci_vpci` can essentially fuzz *any* PCI driver by faking PCI config space and MMIO accesses. But the prompt explicitly rules out vendor-specific PCIe switch/SmartNIC/GPU drivers that aren't emulated in standard QEMU. That's a direct indication I shouldn't treat these as fuzzed unless they can work without the actual device. Okay, let's go back and verify the assumption. Is `idpf` and `ixd` are considered SmartNIC drivers? "Intel(R) Control Plane PCI Function of Intel E2100 and later IPUs and FNICs" - IPU = SmartNIC. The "Infrastructure Data Path Function" is also for IPUs. Now I am sure. So, both `ixd` and `idpf` are SmartNIC drivers. I'd better check |
| 4/2 | 2026/08/12 21:56 | tool | grepper |
0mArgs:{
"Expression": "idpf",
"PathPrefix": ""
}Results: {
"Output": "\nFull output is too long, showing 500 out of 10201 lines.\nUse more precise expression if possible.\n\nDocumentation/networking/device_drivers/ethernet/index.rst=8=Contents:\n--\nDocumentation/networking/device_drivers/ethernet/index.rst-34- intel/fm10k\nDocumentation/networking/device_drivers/ethernet/index.rst:35: intel/idpf\nDocumentation/networking/device_drivers/ethernet/index.rst-36- intel/igb\n--\nDocumentation/networking/device_drivers/ethernet/intel/idpf.rst-3-==========================================================================\nDocumentation/networking/device_drivers/ethernet/intel/idpf.rst:4:idpf Linux* Base Driver for the Intel(R) Infrastructure Data Path Function\nDocumentation/networking/device_drivers/ethernet/intel/idpf.rst-5-==========================================================================\nDocumentation/networking/device_drivers/ethernet/intel/idpf.rst-6-\nDocumentation/networking/device_drivers/ethernet/intel/idpf.rst:7:Intel idpf Linux driver.\nDocumentation/networking/device_drivers/ethernet/intel/idpf.rst-8-Copyright(C) 2023 Intel Corporation.\n--\nDocumentation/networking/device_drivers/ethernet/intel/idpf.rst-11-\nDocumentation/networking/device_drivers/ethernet/intel/idpf.rst:12:The idpf driver serves as both the Physical Function (PF) and Virtual Function\nDocumentation/networking/device_drivers/ethernet/intel/idpf.rst-13-(VF) driver for the Intel(R) Infrastructure Data Path Function.\n--\nDocumentation/networking/device_drivers/ethernet/intel/idpf.rst=133=helpful to optimize performance in VMs.\n--\nDocumentation/networking/device_drivers/ethernet/intel/idpf.rst-138-\nDocumentation/networking/device_drivers/ethernet/intel/idpf.rst:139: - Configure as many Rx/Tx queues in the VM as available. (See the idpf driver\nDocumentation/networking/device_drivers/ethernet/intel/idpf.rst-140- documentation for the number of queues supported.) For example::\n--\ndrivers/infiniband/hw/irdma/ig3rdma_if.c-4-#include \"main.h\"\ndrivers/infiniband/hw/irdma/ig3rdma_if.c:5:#include \u003clinux/net/intel/iidc_rdma_idpf.h\u003e\ndrivers/infiniband/hw/irdma/ig3rdma_if.c-6-#include \"ig3rdma_hw.h\"\n--\ndrivers/infiniband/hw/irdma/ig3rdma_if.c=19=int ig3rdma_vchnl_send_sync(struct irdma_sc_dev *dev, u8 *msg, u16 len,\n--\ndrivers/infiniband/hw/irdma/ig3rdma_if.c-24-\ndrivers/infiniband/hw/irdma/ig3rdma_if.c:25:\tret = idpf_idc_rdma_vc_send_sync(cdev_info, msg, len, recv_msg,\ndrivers/infiniband/hw/irdma/ig3rdma_if.c-26-\t\t\t\t\t recv_len);\n--\ndrivers/infiniband/hw/irdma/ig3rdma_if.c=71=static void ig3rdma_request_reset(struct irdma_pci_f *rf)\n--\ndrivers/infiniband/hw/irdma/ig3rdma_if.c-73-\tibdev_warn(\u0026rf-\u003eiwdev-\u003eibdev, \"Requesting a reset\\n\");\ndrivers/infiniband/hw/irdma/ig3rdma_if.c:74:\tidpf_idc_request_reset(rf-\u003ecdev, IIDC_FUNC_RESET);\ndrivers/infiniband/hw/irdma/ig3rdma_if.c-75-}\n--\ndrivers/infiniband/hw/irdma/ig3rdma_if.c=168=static int ig3rdma_core_probe(struct auxiliary_device *aux_dev,\n--\ndrivers/infiniband/hw/irdma/ig3rdma_if.c-190-\ndrivers/infiniband/hw/irdma/ig3rdma_if.c:191:\terr = idpf_idc_vport_dev_ctrl(cdev_info, true);\ndrivers/infiniband/hw/irdma/ig3rdma_if.c-192-\tif (err)\n--\ndrivers/infiniband/hw/irdma/ig3rdma_if.c=207=static void ig3rdma_core_remove(struct auxiliary_device *aux_dev)\n--\ndrivers/infiniband/hw/irdma/ig3rdma_if.c-213-\ndrivers/infiniband/hw/irdma/ig3rdma_if.c:214:\tidpf_idc_vport_dev_ctrl(cdev_info, false);\ndrivers/infiniband/hw/irdma/ig3rdma_if.c-215-\tirdma_ctrl_deinit_hw(rf);\n--\ndrivers/infiniband/hw/irdma/ig3rdma_if.c=220=static const struct auxiliary_device_id ig3rdma_core_auxiliary_id_table[] = {\ndrivers/infiniband/hw/irdma/ig3rdma_if.c:221:\t{.name = \"idpf.8086.rdma.core\", },\ndrivers/infiniband/hw/irdma/ig3rdma_if.c-222-\t{},\n--\ndrivers/infiniband/hw/irdma/main.c-3-#include \"main.h\"\ndrivers/infiniband/hw/irdma/main.c:4:#include \u003clinux/net/intel/iidc_rdma_idpf.h\u003e\ndrivers/infiniband/hw/irdma/main.c-5-\n--\ndrivers/infiniband/hw/irdma/main.c=139=static const struct auxiliary_device_id ig3rdma_vport_auxiliary_id_table[] = {\ndrivers/infiniband/hw/irdma/main.c:140:\t{.name = \"idpf.8086.rdma.vdev\", },\ndrivers/infiniband/hw/irdma/main.c-141-\t{},\n--\ndrivers/net/ethernet/intel/Kconfig=391=config IGC_LEDS\n--\ndrivers/net/ethernet/intel/Kconfig-398-\ndrivers/net/ethernet/intel/Kconfig:399:source \"drivers/net/ethernet/intel/idpf/Kconfig\"\ndrivers/net/ethernet/intel/Kconfig-400-\n--\ndrivers/net/ethernet/intel/Makefile=20=obj-$(CONFIG_ICE) += ice/\ndrivers/net/ethernet/intel/Makefile:21:obj-$(CONFIG_IDPF) += idpf/\ndrivers/net/ethernet/intel/Makefile-22-obj-$(CONFIG_IXD) += ixd/\n--\ndrivers/net/ethernet/intel/idpf/Kconfig=4=config IDPF\n--\ndrivers/net/ethernet/intel/idpf/Kconfig-15-\t To compile this driver as a module, choose M here. The module\ndrivers/net/ethernet/intel/idpf/Kconfig:16:\t will be called idpf.\ndrivers/net/ethernet/intel/idpf/Kconfig-17-\n--\ndrivers/net/ethernet/intel/idpf/Kconfig=20=config IDPF_SINGLEQ\ndrivers/net/ethernet/intel/idpf/Kconfig:21:\tbool \"idpf singleq support\"\ndrivers/net/ethernet/intel/idpf/Kconfig-22-\thelp\n--\ndrivers/net/ethernet/intel/idpf/Makefile-5-\ndrivers/net/ethernet/intel/idpf/Makefile:6:obj-$(CONFIG_IDPF) += idpf.o\ndrivers/net/ethernet/intel/idpf/Makefile-7-\ndrivers/net/ethernet/intel/idpf/Makefile:8:idpf-y := \\\ndrivers/net/ethernet/intel/idpf/Makefile:9:\tidpf_dev.o\t\t\\\ndrivers/net/ethernet/intel/idpf/Makefile:10:\tidpf_ethtool.o\t\t\\\ndrivers/net/ethernet/intel/idpf/Makefile:11:\tidpf_idc.o\t\t\\\ndrivers/net/ethernet/intel/idpf/Makefile:12:\tidpf_lib.o\t\t\\\ndrivers/net/ethernet/intel/idpf/Makefile:13:\tidpf_main.o\t\t\\\ndrivers/net/ethernet/intel/idpf/Makefile:14:\tidpf_txrx.o\t\t\\\ndrivers/net/ethernet/intel/idpf/Makefile:15:\tidpf_virtchnl.o \t\\\ndrivers/net/ethernet/intel/idpf/Makefile:16:\tidpf_vf_dev.o\ndrivers/net/ethernet/intel/idpf/Makefile-17-\ndrivers/net/ethernet/intel/idpf/Makefile:18:idpf-$(CONFIG_IDPF_SINGLEQ)\t+= idpf_singleq_txrx.o\ndrivers/net/ethernet/intel/idpf/Makefile-19-\ndrivers/net/ethernet/intel/idpf/Makefile:20:idpf-$(CONFIG_PTP_1588_CLOCK)\t+= idpf_ptp.o\ndrivers/net/ethernet/intel/idpf/Makefile:21:idpf-$(CONFIG_PTP_1588_CLOCK)\t+= idpf_virtchnl_ptp.o\ndrivers/net/ethernet/intel/idpf/Makefile-22-\ndrivers/net/ethernet/intel/idpf/Makefile:23:idpf-y\t\t\t\t+= xdp.o\ndrivers/net/ethernet/intel/idpf/Makefile:24:idpf-y\t\t\t\t+= xsk.o\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-7-/* Forward declaration */\ndrivers/net/ethernet/intel/idpf/idpf.h:8:struct idpf_adapter;\ndrivers/net/ethernet/intel/idpf/idpf.h:9:struct idpf_vport;\ndrivers/net/ethernet/intel/idpf/idpf.h:10:struct idpf_vport_max_q;\ndrivers/net/ethernet/intel/idpf/idpf.h:11:struct idpf_q_vec_rsrc;\ndrivers/net/ethernet/intel/idpf/idpf.h:12:struct idpf_rss_data;\ndrivers/net/ethernet/intel/idpf/idpf.h-13-\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-24-#include \u003clinux/net/intel/iidc_rdma.h\u003e\ndrivers/net/ethernet/intel/idpf/idpf.h:25:#include \u003clinux/net/intel/iidc_rdma_idpf.h\u003e\ndrivers/net/ethernet/intel/idpf/idpf.h-26-#include \u003clinux/net/intel/libie/controlq.h\u003e\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-28-\ndrivers/net/ethernet/intel/idpf/idpf.h:29:#include \"idpf_txrx.h\"\ndrivers/net/ethernet/intel/idpf/idpf.h-30-\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-55-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:56: * struct idpf_mac_filter\ndrivers/net/ethernet/intel/idpf/idpf.h-57- * @list: list member field\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-61- */\ndrivers/net/ethernet/intel/idpf/idpf.h:62:struct idpf_mac_filter {\ndrivers/net/ethernet/intel/idpf/idpf.h-63-\tstruct list_head list;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-69-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:70: * enum idpf_state - State machine to handle bring up\ndrivers/net/ethernet/intel/idpf/idpf.h-71- * @__IDPF_VER_CHECK: Negotiate virtchnl version\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-75- */\ndrivers/net/ethernet/intel/idpf/idpf.h:76:enum idpf_state {\ndrivers/net/ethernet/intel/idpf/idpf.h-77-\t__IDPF_VER_CHECK,\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-83-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:84: * enum idpf_flags - Hard reset causes.\ndrivers/net/ethernet/intel/idpf/idpf.h-85- * @IDPF_HR_FUNC_RESET: Hard reset when TxRx timeout\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-92- */\ndrivers/net/ethernet/intel/idpf/idpf.h:93:enum idpf_flags {\ndrivers/net/ethernet/intel/idpf/idpf.h-94-\tIDPF_HR_FUNC_RESET,\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-103-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:104: * enum idpf_cap_field - Offsets into capabilities struct for specific caps\ndrivers/net/ethernet/intel/idpf/idpf.h-105- * @IDPF_BASE_CAPS: generic base capabilities\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-116- */\ndrivers/net/ethernet/intel/idpf/idpf.h:117:enum idpf_cap_field {\ndrivers/net/ethernet/intel/idpf/idpf.h-118-\tIDPF_BASE_CAPS\t\t= -1,\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-133-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:134: * enum idpf_vport_state - Current vport state\ndrivers/net/ethernet/intel/idpf/idpf.h-135- * @IDPF_VPORT_UP: Vport is up\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-137- */\ndrivers/net/ethernet/intel/idpf/idpf.h:138:enum idpf_vport_state {\ndrivers/net/ethernet/intel/idpf/idpf.h-139-\tIDPF_VPORT_UP,\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-143-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:144: * struct idpf_netdev_priv - Struct to store vport back pointer\ndrivers/net/ethernet/intel/idpf/idpf.h-145- * @adapter: Adapter back pointer\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-151- * @tx_max_bufs: Max buffers that can be transmitted with scatter-gather\ndrivers/net/ethernet/intel/idpf/idpf.h:152: * @state: See enum idpf_vport_state\ndrivers/net/ethernet/intel/idpf/idpf.h-153- * @netstats: Packet and byte stats\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-155- */\ndrivers/net/ethernet/intel/idpf/idpf.h:156:struct idpf_netdev_priv {\ndrivers/net/ethernet/intel/idpf/idpf.h:157:\tstruct idpf_adapter *adapter;\ndrivers/net/ethernet/intel/idpf/idpf.h:158:\tstruct idpf_vport *vport;\ndrivers/net/ethernet/intel/idpf/idpf.h-159-\tu32 vport_id;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-169-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:170: * struct idpf_reset_reg - Reset register offsets/masks\ndrivers/net/ethernet/intel/idpf/idpf.h-171- * @rstat: Reset status register\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-173- */\ndrivers/net/ethernet/intel/idpf/idpf.h:174:struct idpf_reset_reg {\ndrivers/net/ethernet/intel/idpf/idpf.h-175-\tvoid __iomem *rstat;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-179-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:180: * struct idpf_vport_max_q - Queue limits\ndrivers/net/ethernet/intel/idpf/idpf.h-181- * @max_rxq: Maximum number of RX queues supported\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-185- */\ndrivers/net/ethernet/intel/idpf/idpf.h:186:struct idpf_vport_max_q {\ndrivers/net/ethernet/intel/idpf/idpf.h-187-\tu16 max_rxq;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-193-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:194: * struct idpf_reg_ops - Device specific register operation function pointers\ndrivers/net/ethernet/intel/idpf/idpf.h-195- * @ctlq_reg_init: Mailbox control queue register initialization\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-201- */\ndrivers/net/ethernet/intel/idpf/idpf.h:202:struct idpf_reg_ops {\ndrivers/net/ethernet/intel/idpf/idpf.h-203-\tvoid (*ctlq_reg_init)(struct libie_mmio_info *mmio,\ndrivers/net/ethernet/intel/idpf/idpf.h-204-\t\t\t struct libie_ctlq_create_info *cctlq_info);\ndrivers/net/ethernet/intel/idpf/idpf.h:205:\tint (*intr_reg_init)(struct idpf_vport *vport,\ndrivers/net/ethernet/intel/idpf/idpf.h:206:\t\t\t struct idpf_q_vec_rsrc *rsrc);\ndrivers/net/ethernet/intel/idpf/idpf.h:207:\tvoid (*mb_intr_reg_init)(struct idpf_adapter *adapter);\ndrivers/net/ethernet/intel/idpf/idpf.h:208:\tvoid (*reset_reg_init)(struct idpf_adapter *adapter);\ndrivers/net/ethernet/intel/idpf/idpf.h:209:\tvoid (*trigger_reset)(struct idpf_adapter *adapter,\ndrivers/net/ethernet/intel/idpf/idpf.h:210:\t\t\t enum idpf_flags trig_cause);\ndrivers/net/ethernet/intel/idpf/idpf.h:211:\tvoid (*ptp_reg_init)(const struct idpf_adapter *adapter);\ndrivers/net/ethernet/intel/idpf/idpf.h-212-};\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-220-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:221: * struct idpf_dev_ops - Device specific operations\ndrivers/net/ethernet/intel/idpf/idpf.h-222- * @reg_ops: Register operations\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-225- */\ndrivers/net/ethernet/intel/idpf/idpf.h:226:struct idpf_dev_ops {\ndrivers/net/ethernet/intel/idpf/idpf.h:227:\tstruct idpf_reg_ops reg_ops;\ndrivers/net/ethernet/intel/idpf/idpf.h-228-\ndrivers/net/ethernet/intel/idpf/idpf.h:229:\tint (*idc_init)(struct idpf_adapter *adapter);\ndrivers/net/ethernet/intel/idpf/idpf.h-230-\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-235-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:236: * enum idpf_vport_reset_cause - Vport soft reset causes\ndrivers/net/ethernet/intel/idpf/idpf.h-237- * @IDPF_SR_Q_CHANGE: Soft reset queue change\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-241- */\ndrivers/net/ethernet/intel/idpf/idpf.h:242:enum idpf_vport_reset_cause {\ndrivers/net/ethernet/intel/idpf/idpf.h-243-\tIDPF_SR_Q_CHANGE,\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-249-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:250: * enum idpf_vport_flags - Vport flags\ndrivers/net/ethernet/intel/idpf/idpf.h-251- * @IDPF_VPORT_DEL_QUEUES: To send delete queues message\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-253- */\ndrivers/net/ethernet/intel/idpf/idpf.h:254:enum idpf_vport_flags {\ndrivers/net/ethernet/intel/idpf/idpf.h-255-\tIDPF_VPORT_DEL_QUEUES,\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-259-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:260: * struct idpf_tstamp_stats - Tx timestamp statistics\ndrivers/net/ethernet/intel/idpf/idpf.h-261- * @stats_sync: See struct u64_stats_sync\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-266- */\ndrivers/net/ethernet/intel/idpf/idpf.h:267:struct idpf_tstamp_stats {\ndrivers/net/ethernet/intel/idpf/idpf.h-268-\tstruct u64_stats_sync stats_sync;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-273-\ndrivers/net/ethernet/intel/idpf/idpf.h:274:struct idpf_port_stats {\ndrivers/net/ethernet/intel/idpf/idpf.h-275-\tstruct u64_stats_sync stats_sync;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-286-\ndrivers/net/ethernet/intel/idpf/idpf.h:287:struct idpf_fsteer_fltr {\ndrivers/net/ethernet/intel/idpf/idpf.h-288-\tstruct list_head list;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-292-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:293: * struct idpf_q_vec_rsrc - handle for queue and vector resources\ndrivers/net/ethernet/intel/idpf/idpf.h-294- * @dev: device pointer for DMA mapping\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-321- */\ndrivers/net/ethernet/intel/idpf/idpf.h:322:struct idpf_q_vec_rsrc {\ndrivers/net/ethernet/intel/idpf/idpf.h-323-\tstruct device\t\t*dev;\ndrivers/net/ethernet/intel/idpf/idpf.h:324:\tstruct idpf_q_vector\t*q_vectors;\ndrivers/net/ethernet/intel/idpf/idpf.h-325-\tu16\t\t\t*q_vector_idxs;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-330-\ndrivers/net/ethernet/intel/idpf/idpf.h:331:\tstruct idpf_txq_group\t*txq_grps;\ndrivers/net/ethernet/intel/idpf/idpf.h-332-\tu32\t\t\ttxq_desc_count;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-341-\tu32\t\t\trxq_model;\ndrivers/net/ethernet/intel/idpf/idpf.h:342:\tstruct idpf_rxq_group\t*rxq_grps;\ndrivers/net/ethernet/intel/idpf/idpf.h-343-\tu16\t\t\tnum_rxq;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-351-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:352: * struct idpf_vport - Handle for netdevices and queue resources\ndrivers/net/ethernet/intel/idpf/idpf.h-353- * @dflt_qv_rsrc: contains default queue and vector resources\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-362- *\t associated netdev.\ndrivers/net/ethernet/intel/idpf/idpf.h:363: * @flags: See enum idpf_vport_flags\ndrivers/net/ethernet/intel/idpf/idpf.h-364- * @compln_clean_budget: Work budget for completion clean\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-380- */\ndrivers/net/ethernet/intel/idpf/idpf.h:381:struct idpf_vport {\ndrivers/net/ethernet/intel/idpf/idpf.h:382:\tstruct idpf_q_vec_rsrc dflt_qv_rsrc;\ndrivers/net/ethernet/intel/idpf/idpf.h:383:\tstruct idpf_tx_queue **txqs;\ndrivers/net/ethernet/intel/idpf/idpf.h-384-\tu16 num_txq;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-390-\ndrivers/net/ethernet/intel/idpf/idpf.h:391:\tstruct idpf_adapter *adapter;\ndrivers/net/ethernet/intel/idpf/idpf.h-392-\tstruct net_device *netdev;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-403-\ndrivers/net/ethernet/intel/idpf/idpf.h:404:\tstruct idpf_port_stats port_stats;\ndrivers/net/ethernet/intel/idpf/idpf.h-405-\tbool default_vport;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-408-\ndrivers/net/ethernet/intel/idpf/idpf.h:409:\tstruct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps;\ndrivers/net/ethernet/intel/idpf/idpf.h-410-\tstruct kernel_hwtstamp_config tstamp_config;\ndrivers/net/ethernet/intel/idpf/idpf.h-411-\tstruct work_struct tstamp_task;\ndrivers/net/ethernet/intel/idpf/idpf.h:412:\tstruct idpf_tstamp_stats tstamp_stats;\ndrivers/net/ethernet/intel/idpf/idpf.h-413-};\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-415-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:416: * enum idpf_user_flags\ndrivers/net/ethernet/intel/idpf/idpf.h-417- * @__IDPF_USER_FLAG_HSPLIT: header split state\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-421- */\ndrivers/net/ethernet/intel/idpf/idpf.h:422:enum idpf_user_flags {\ndrivers/net/ethernet/intel/idpf/idpf.h-423-\t__IDPF_USER_FLAG_HSPLIT = 0U,\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-430-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:431: * struct idpf_rss_data - Associated RSS data\ndrivers/net/ethernet/intel/idpf/idpf.h-432- * @rss_key_size: Size of RSS hash key\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-436- */\ndrivers/net/ethernet/intel/idpf/idpf.h:437:struct idpf_rss_data {\ndrivers/net/ethernet/intel/idpf/idpf.h-438-\tu16 rss_key_size;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-444-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:445: * struct idpf_q_coalesce - User defined coalescing configuration values for\ndrivers/net/ethernet/intel/idpf/idpf.h-446- *\t\t\t a single queue.\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-453- */\ndrivers/net/ethernet/intel/idpf/idpf.h:454:struct idpf_q_coalesce {\ndrivers/net/ethernet/intel/idpf/idpf.h-455-\tu32 tx_intr_mode;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-461-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:462: * struct idpf_vport_user_config_data - User defined configuration values for\ndrivers/net/ethernet/intel/idpf/idpf.h-463- *\t\t\t\t\teach vport.\ndrivers/net/ethernet/intel/idpf/idpf.h:464: * @rss_data: See struct idpf_rss_data\ndrivers/net/ethernet/intel/idpf/idpf.h-465- * @q_coalesce: Array of per queue coalescing data\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-479- */\ndrivers/net/ethernet/intel/idpf/idpf.h:480:struct idpf_vport_user_config_data {\ndrivers/net/ethernet/intel/idpf/idpf.h:481:\tstruct idpf_rss_data rss_data;\ndrivers/net/ethernet/intel/idpf/idpf.h:482:\tstruct idpf_q_coalesce *q_coalesce;\ndrivers/net/ethernet/intel/idpf/idpf.h-483-\tu16 num_req_tx_qs;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-494-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:495: * enum idpf_vport_config_flags - Vport config flags\ndrivers/net/ethernet/intel/idpf/idpf.h-496- * @IDPF_VPORT_REG_NETDEV: Register netdev\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-499- */\ndrivers/net/ethernet/intel/idpf/idpf.h:500:enum idpf_vport_config_flags {\ndrivers/net/ethernet/intel/idpf/idpf.h-501-\tIDPF_VPORT_REG_NETDEV,\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-506-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:507: * struct idpf_avail_queue_info\ndrivers/net/ethernet/intel/idpf/idpf.h-508- * @avail_rxq: Available RX queues\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-514- */\ndrivers/net/ethernet/intel/idpf/idpf.h:515:struct idpf_avail_queue_info {\ndrivers/net/ethernet/intel/idpf/idpf.h-516-\tu16 avail_rxq;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-522-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:523: * struct idpf_vector_info - Utility structure to pass function arguments as a\ndrivers/net/ethernet/intel/idpf/idpf.h-524- *\t\t\t structure\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-530- */\ndrivers/net/ethernet/intel/idpf/idpf.h:531:struct idpf_vector_info {\ndrivers/net/ethernet/intel/idpf/idpf.h-532-\tu16 num_req_vecs;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-538-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:539: * struct idpf_vector_lifo - Stack to maintain vector indexes used for vector\ndrivers/net/ethernet/intel/idpf/idpf.h-540- *\t\t\t distribution algorithm\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-554- */\ndrivers/net/ethernet/intel/idpf/idpf.h:555:struct idpf_vector_lifo {\ndrivers/net/ethernet/intel/idpf/idpf.h-556-\tu16 top;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-562-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:563: * struct idpf_queue_id_reg_chunk - individual queue ID and register chunk\ndrivers/net/ethernet/intel/idpf/idpf.h-564- * @qtail_reg_start: queue tail register offset\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-569- */\ndrivers/net/ethernet/intel/idpf/idpf.h:570:struct idpf_queue_id_reg_chunk {\ndrivers/net/ethernet/intel/idpf/idpf.h-571-\tu64 qtail_reg_start;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-578-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:579: * struct idpf_queue_id_reg_info - queue ID and register chunk info received\ndrivers/net/ethernet/intel/idpf/idpf.h-580- *\t\t\t\t over the mailbox\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-583- */\ndrivers/net/ethernet/intel/idpf/idpf.h:584:struct idpf_queue_id_reg_info {\ndrivers/net/ethernet/intel/idpf/idpf.h-585-\tu16 num_chunks;\ndrivers/net/ethernet/intel/idpf/idpf.h:586:\tstruct idpf_queue_id_reg_chunk *queue_chunks;\ndrivers/net/ethernet/intel/idpf/idpf.h-587-};\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-589-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:590: * struct idpf_vport_config - Vport configuration data\ndrivers/net/ethernet/intel/idpf/idpf.h:591: * @user_config: see struct idpf_vport_user_config_data\ndrivers/net/ethernet/intel/idpf/idpf.h-592- * @max_q: Maximum possible queues\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-595- * @flow_steer_list_lock: Lock to protect fsteer filters\ndrivers/net/ethernet/intel/idpf/idpf.h:596: * @flags: See enum idpf_vport_config_flags\ndrivers/net/ethernet/intel/idpf/idpf.h-597- */\ndrivers/net/ethernet/intel/idpf/idpf.h:598:struct idpf_vport_config {\ndrivers/net/ethernet/intel/idpf/idpf.h:599:\tstruct idpf_vport_user_config_data user_config;\ndrivers/net/ethernet/intel/idpf/idpf.h:600:\tstruct idpf_vport_max_q max_q;\ndrivers/net/ethernet/intel/idpf/idpf.h:601:\tstruct idpf_queue_id_reg_info qid_reg_info;\ndrivers/net/ethernet/intel/idpf/idpf.h-602-\tspinlock_t mac_filter_list_lock;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-606-\ndrivers/net/ethernet/intel/idpf/idpf.h:607:#define idpf_for_each_vport(adapter, iter) \\\ndrivers/net/ethernet/intel/idpf/idpf.h:608:\tfor (struct idpf_vport **__##iter = \u0026(adapter)-\u003evports[0], \\\ndrivers/net/ethernet/intel/idpf/idpf.h-609-\t *iter = (adapter)-\u003emax_vports ? *__##iter : NULL; \\\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-614-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:615: * struct idpf_adapter - Device data struct generated on probe\ndrivers/net/ethernet/intel/idpf/idpf.h-616- * @pdev: PCI device struct given on probe\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-621- * @state: Init state machine\ndrivers/net/ethernet/intel/idpf/idpf.h:622: * @flags: See enum idpf_flags\ndrivers/net/ethernet/intel/idpf/idpf.h:623: * @reset_reg: See struct idpf_reset_reg\ndrivers/net/ethernet/intel/idpf/idpf.h-624- * @ctlq_ctx: controlq context\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-659- * @caps: Negotiated capabilities with device\ndrivers/net/ethernet/intel/idpf/idpf.h:660: * @dev_ops: See idpf_dev_ops\ndrivers/net/ethernet/intel/idpf/idpf.h-661- * @cdev_info: IDC core device info pointer\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-672- */\ndrivers/net/ethernet/intel/idpf/idpf.h:673:struct idpf_adapter {\ndrivers/net/ethernet/intel/idpf/idpf.h-674-\tstruct pci_dev *pdev;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-679-\tu32 mb_wait_count;\ndrivers/net/ethernet/intel/idpf/idpf.h:680:\tenum idpf_state state;\ndrivers/net/ethernet/intel/idpf/idpf.h-681-\tDECLARE_BITMAP(flags, IDPF_FLAGS_NBITS);\ndrivers/net/ethernet/intel/idpf/idpf.h:682:\tstruct idpf_reset_reg reset_reg;\ndrivers/net/ethernet/intel/idpf/idpf.h-683-\tstruct libie_ctlq_ctx ctlq_ctx;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-692-\tstruct virtchnl2_alloc_vectors *req_vec_chunks;\ndrivers/net/ethernet/intel/idpf/idpf.h:693:\tstruct idpf_q_vector mb_vector;\ndrivers/net/ethernet/intel/idpf/idpf.h:694:\tstruct idpf_vector_lifo vector_stack;\ndrivers/net/ethernet/intel/idpf/idpf.h-695-\tirqreturn_t (*irq_mb_handler)(int irq, void *data);\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-697-\tu32 tx_timeout_count;\ndrivers/net/ethernet/intel/idpf/idpf.h:698:\tstruct idpf_avail_queue_info avail_queues;\ndrivers/net/ethernet/intel/idpf/idpf.h:699:\tstruct idpf_vport **vports;\ndrivers/net/ethernet/intel/idpf/idpf.h-700-\tstruct net_device **netdevs;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-706-\ndrivers/net/ethernet/intel/idpf/idpf.h:707:\tstruct idpf_vport_config **vport_config;\ndrivers/net/ethernet/intel/idpf/idpf.h-708-\tu16 max_vports;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-723-\ndrivers/net/ethernet/intel/idpf/idpf.h:724:\tstruct idpf_dev_ops dev_ops;\ndrivers/net/ethernet/intel/idpf/idpf.h-725-\tstruct iidc_rdma_core_dev_info *cdev_info;\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-735-\ndrivers/net/ethernet/intel/idpf/idpf.h:736:\tstruct idpf_ptp *ptp;\ndrivers/net/ethernet/intel/idpf/idpf.h-737-};\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-739-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:740: * idpf_is_queue_model_split - check if queue model is split\ndrivers/net/ethernet/intel/idpf/idpf.h-741- * @q_model: queue model single or split\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-744- */\ndrivers/net/ethernet/intel/idpf/idpf.h:745:static inline int idpf_is_queue_model_split(u16 q_model)\ndrivers/net/ethernet/intel/idpf/idpf.h-746-{\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-750-\ndrivers/net/ethernet/intel/idpf/idpf.h:751:static inline bool idpf_xdp_enabled(const struct idpf_vport *vport)\ndrivers/net/ethernet/intel/idpf/idpf.h-752-{\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-755-\ndrivers/net/ethernet/intel/idpf/idpf.h:756:#define idpf_is_cap_ena(adapter, field, flag) \\\ndrivers/net/ethernet/intel/idpf/idpf.h:757:\tidpf_is_capability_ena(adapter, false, field, flag)\ndrivers/net/ethernet/intel/idpf/idpf.h:758:#define idpf_is_cap_ena_all(adapter, field, flag) \\\ndrivers/net/ethernet/intel/idpf/idpf.h:759:\tidpf_is_capability_ena(adapter, true, field, flag)\ndrivers/net/ethernet/intel/idpf/idpf.h-760-\ndrivers/net/ethernet/intel/idpf/idpf.h:761:bool idpf_is_capability_ena(struct idpf_adapter *adapter, bool all,\ndrivers/net/ethernet/intel/idpf/idpf.h:762:\t\t\t enum idpf_cap_field field, u64 flag);\ndrivers/net/ethernet/intel/idpf/idpf.h-763-\ndrivers/net/ethernet/intel/idpf/idpf.h-764-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:765: * idpf_is_rdma_cap_ena - Determine if RDMA is supported\ndrivers/net/ethernet/intel/idpf/idpf.h-766- * @adapter: private data struct\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-769- */\ndrivers/net/ethernet/intel/idpf/idpf.h:770:static inline bool idpf_is_rdma_cap_ena(struct idpf_adapter *adapter)\ndrivers/net/ethernet/intel/idpf/idpf.h-771-{\ndrivers/net/ethernet/intel/idpf/idpf.h:772:\treturn idpf_is_cap_ena(adapter, IDPF_OTHER_CAPS, VIRTCHNL2_CAP_RDMA);\ndrivers/net/ethernet/intel/idpf/idpf.h-773-}\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-816-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:817: * idpf_get_reserved_vecs - Get reserved vectors\ndrivers/net/ethernet/intel/idpf/idpf.h-818- * @adapter: private data struct\ndrivers/net/ethernet/intel/idpf/idpf.h-819- */\ndrivers/net/ethernet/intel/idpf/idpf.h:820:static inline u16 idpf_get_reserved_vecs(struct idpf_adapter *adapter)\ndrivers/net/ethernet/intel/idpf/idpf.h-821-{\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-825-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:826: * idpf_get_reserved_rdma_vecs - Get reserved RDMA vectors\ndrivers/net/ethernet/intel/idpf/idpf.h-827- * @adapter: private data struct\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-830- */\ndrivers/net/ethernet/intel/idpf/idpf.h:831:static inline u16 idpf_get_reserved_rdma_vecs(struct idpf_adapter *adapter)\ndrivers/net/ethernet/intel/idpf/idpf.h-832-{\n--\ndrivers/net/ethernet/intel/idpf/idpf.h-836-/**\ndrivers/net/ethernet/intel/idpf/idpf.h:837: * idpf_get_default_vports - Get default number of vports\ndrivers/net/ethernet/intel/idpf/idpf.h-838- * @adapter: private data struct\ndrivers/net/ethernet/intel/idpf/idpf.h-839- */\ndrivers/net/ethernet/intel/idpf/idpf.h:840:static inline u16 idpf_get_default_vports(struct idpf_adapter *adapter)\ndrivers/net/ethernet/intel/idpf/idpf.h-841-{\n--\n\n"
} |
| 5/2 | 2026/08/12 21:56 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 141545 output: 24 thoughts: 912 Thoughts: **My Assessment of the Fuzzing Worthiness** Okay, let's break this down. I'm looking at a patch that seems to touch the `idpf` driver, which is a virtual or physical function driver for the Intel Infrastructure Data Path Function. It's a PCI driver, so my initial thought is, "Syzkaller could potentially handle this." After all, Syzkaller's `syz_pci_vpci` is designed to fuzz PCI drivers by manipulating PCI config space and MMIO. However, I need to consider the constraints of the task. The prompt explicitly tells me to return `WorthFuzzing=false` under specific circumstances. Specifically, if the patch *only* contains code in vendor-specific PCIe switch, SmartNIC, or GPU drivers that require physical PCIe hardware not emulated in standard QEMU. That's the crux of the issue. Now, `idpf` is an Intel Infrastructure Data Path Function driver, often used with Intel's IPUs (Infrastructure Processing Units), which are essentially SmartNICs. I'm pretty sure standard QEMU doesn't emulate these. I need to keep in mind, however, the ixd driver, which is also an IPU-related driver, the Intel Control Plane Function of Intel E2100 and later IPUs and FNICs. My first instinct was to check if Syzkaller already fuzzed `idpf`, but unfortunately, I can't use the provided tools to search the Syzkaller descriptions directory, even though I'd *love* to see if someone else has already put in the work, because that would change my answer. Given my tool restrictions, I have to re-evaluate the prompt's criteria: Is `ixd` considered a SmartNIC driver? Yes, it's for the Control Plane Function of those very IPUs. Is it vendor-specific? Absolutely; it's Intel-specific hardware. Does it require special hardware not emulated in standard QEMU? Yes, that's almost certainly the case with Intel IPUs. Now, the patch modifies `drivers/net/ethernet/intel/libie/`. That also makes me concerned. `libie` is a helper library for Intel Ethernet drivers, and while I haven't explicitly confirmed it, it *likely* means that both `idpf` and `ixd` depend on `libie`. If the patch *only* involves changes to `idpf`, `ixd`, and this supporting `libie` code, it falls squarely into the "not worth fuzzing" category because it involves SmartNIC-specific components not emulated in standard QEMU. In summary, I have no way to determine if this is worth fuzzing without additional information. |
| 6/2 | 2026/08/12 21:57 | tool | grepper |
0mArgs:{
"Expression": "libie_cp",
"PathPrefix": ""
}Results: {
"Output": "drivers/net/ethernet/intel/idpf/idpf_virtchnl.c=196=int idpf_send_mb_msg(struct idpf_adapter *adapter,\n--\ndrivers/net/ethernet/intel/idpf/idpf_virtchnl.c-202-\tif (idpf_is_reset_detected(adapter)) {\ndrivers/net/ethernet/intel/idpf/idpf_virtchnl.c:203:\t\tif (!libie_cp_can_send_onstack(send_buf_size))\ndrivers/net/ethernet/intel/idpf/idpf_virtchnl.c-204-\t\t\tkfree(send_buf);\n--\ndrivers/net/ethernet/intel/idpf/idpf_virtchnl.c-229- *\ndrivers/net/ethernet/intel/idpf/idpf_virtchnl.c:230: * libie_cp functions consume only buffers above certain size,\ndrivers/net/ethernet/intel/idpf/idpf_virtchnl.c-231- * smaller buffers are assumed to be on the stack. However, for some\n--\ndrivers/net/ethernet/intel/idpf/idpf_virtchnl.c=238=int idpf_send_mb_msg_kfree(struct idpf_adapter *adapter,\n--\ndrivers/net/ethernet/intel/idpf/idpf_virtchnl.c-243-\ndrivers/net/ethernet/intel/idpf/idpf_virtchnl.c:244:\tif (libie_cp_can_send_onstack(send_buf_size))\ndrivers/net/ethernet/intel/idpf/idpf_virtchnl.c-245-\t\tkfree(send_buf);\n--\ndrivers/net/ethernet/intel/idpf/idpf_virtchnl.c=4001=int idpf_idc_rdma_vc_send_sync(struct iidc_rdma_core_dev_info *cdev_info,\n--\ndrivers/net/ethernet/intel/idpf/idpf_virtchnl.c-4016-\ndrivers/net/ethernet/intel/idpf/idpf_virtchnl.c:4017:\tif (!libie_cp_can_send_onstack(msg_size)) {\ndrivers/net/ethernet/intel/idpf/idpf_virtchnl.c-4018-\t\tsend_buf = kzalloc(msg_size, GFP_KERNEL);\n--\ndrivers/net/ethernet/intel/ixd/ixd_ctlq.c=55=int ixd_ctlq_do_req(struct ixd_adapter *adapter, const struct ixd_ctlq_req *req)\n--\ndrivers/net/ethernet/intel/ixd/ixd_ctlq.c-62-\ndrivers/net/ethernet/intel/ixd/ixd_ctlq.c:63:\tsend_buff = libie_cp_can_send_onstack(req-\u003esend_size) ?\ndrivers/net/ethernet/intel/ixd/ixd_ctlq.c-64-\t\t \u0026onstack_send_buff : kzalloc(req-\u003esend_size, GFP_KERNEL);\n--\ndrivers/net/ethernet/intel/libie/Makefile=10=libie_adminq-y\t\t\t:= adminq.o\ndrivers/net/ethernet/intel/libie/Makefile-11-\ndrivers/net/ethernet/intel/libie/Makefile:12:obj-$(CONFIG_LIBIE_CP)\t\t+= libie_cp.o\ndrivers/net/ethernet/intel/libie/Makefile-13-\ndrivers/net/ethernet/intel/libie/Makefile:14:libie_cp-y\t\t\t:= controlq.o\ndrivers/net/ethernet/intel/libie/Makefile-15-\n--\ndrivers/net/ethernet/intel/libie/controlq.c=158=static int libie_ctlq_alloc_tx_msgs(struct libie_ctlq_info *ctlq)\n--\ndrivers/net/ethernet/intel/libie/controlq.c-176-/**\ndrivers/net/ethernet/intel/libie/controlq.c:177: * libie_cp_free_desc_mem - free the previously allocated descriptor DMA memory\ndrivers/net/ethernet/intel/libie/controlq.c-178- * @dev: device information\n--\ndrivers/net/ethernet/intel/libie/controlq.c-180- */\ndrivers/net/ethernet/intel/libie/controlq.c:181:static void libie_cp_free_desc_mem(struct device *dev,\ndrivers/net/ethernet/intel/libie/controlq.c:182:\t\t\t\t struct libie_cp_dma_mem *mem)\ndrivers/net/ethernet/intel/libie/controlq.c-183-{\n--\ndrivers/net/ethernet/intel/libie/controlq.c=194=static void libie_ctlq_dealloc_ring_res(struct libie_ctlq_info *ctlq)\ndrivers/net/ethernet/intel/libie/controlq.c-195-{\ndrivers/net/ethernet/intel/libie/controlq.c:196:\tstruct libie_cp_dma_mem *dma = \u0026ctlq-\u003ering_mem;\ndrivers/net/ethernet/intel/libie/controlq.c-197-\n--\ndrivers/net/ethernet/intel/libie/controlq.c-202-\ndrivers/net/ethernet/intel/libie/controlq.c:203:\tlibie_cp_free_desc_mem(ctlq-\u003edev, dma);\ndrivers/net/ethernet/intel/libie/controlq.c-204-}\n--\ndrivers/net/ethernet/intel/libie/controlq.c-206-/**\ndrivers/net/ethernet/intel/libie/controlq.c:207: * libie_cp_alloc_desc_mem - allocate DMA memory for descriptor ring\ndrivers/net/ethernet/intel/libie/controlq.c-208- * @dev: device information\n--\ndrivers/net/ethernet/intel/libie/controlq.c-213- */\ndrivers/net/ethernet/intel/libie/controlq.c:214:static void *libie_cp_alloc_desc_mem(struct device *dev,\ndrivers/net/ethernet/intel/libie/controlq.c:215:\t\t\t\t struct libie_cp_dma_mem *mem, u32 size)\ndrivers/net/ethernet/intel/libie/controlq.c-216-{\n--\ndrivers/net/ethernet/intel/libie/controlq.c=232=static int libie_ctlq_alloc_queue_res(struct libie_ctlq_info *ctlq)\n--\ndrivers/net/ethernet/intel/libie/controlq.c-234-\tsize_t size = array_size(ctlq-\u003ering_len, sizeof(*ctlq-\u003edescs));\ndrivers/net/ethernet/intel/libie/controlq.c:235:\tstruct libie_cp_dma_mem *dma = \u0026ctlq-\u003ering_mem;\ndrivers/net/ethernet/intel/libie/controlq.c-236-\tint err = -ENOMEM;\ndrivers/net/ethernet/intel/libie/controlq.c-237-\ndrivers/net/ethernet/intel/libie/controlq.c:238:\tif (!libie_cp_alloc_desc_mem(ctlq-\u003edev, dma, size))\ndrivers/net/ethernet/intel/libie/controlq.c-239-\t\treturn -ENOMEM;\n--\ndrivers/net/ethernet/intel/libie/controlq.c-260-free_dma_mem:\ndrivers/net/ethernet/intel/libie/controlq.c:261:\tlibie_cp_free_desc_mem(ctlq-\u003edev, dma);\ndrivers/net/ethernet/intel/libie/controlq.c-262-\n--\ndrivers/net/ethernet/intel/libie/controlq.c=433=static void libie_ctlq_tx_desc_from_msg(struct libie_ctlq_desc *desc,\n--\ndrivers/net/ethernet/intel/libie/controlq.c-435-{\ndrivers/net/ethernet/intel/libie/controlq.c:436:\tconst struct libie_cp_dma_mem *dma = \u0026msg-\u003esend_mem;\ndrivers/net/ethernet/intel/libie/controlq.c-437-\tu64 qword;\n--\ndrivers/net/ethernet/intel/libie/controlq.c=774=static int libie_ctlq_xn_init_dma(struct device *dev,\n--\ndrivers/net/ethernet/intel/libie/controlq.c-785-\tfor (i = 0; i \u003c LIBIE_CTLQ_MAX_XN_ENTRIES; i++) {\ndrivers/net/ethernet/intel/libie/controlq.c:786:\t\tstruct libie_cp_dma_mem *mem = \u0026xnm-\u003ering[i].small_dma_mem;\ndrivers/net/ethernet/intel/libie/controlq.c-787-\n--\ndrivers/net/ethernet/intel/libie/controlq.c=925=EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_recv, \"LIBIE_CP\");\n--\ndrivers/net/ethernet/intel/libie/controlq.c-927-/**\ndrivers/net/ethernet/intel/libie/controlq.c:928: * libie_cp_map_dma_mem - map a given virtual address for DMA\ndrivers/net/ethernet/intel/libie/controlq.c-929- * @dev: device information\n--\ndrivers/net/ethernet/intel/libie/controlq.c-936- */\ndrivers/net/ethernet/intel/libie/controlq.c:937:static bool libie_cp_map_dma_mem(struct device *dev, void *va, size_t size,\ndrivers/net/ethernet/intel/libie/controlq.c-938-\t\t\t\t int direction,\ndrivers/net/ethernet/intel/libie/controlq.c:939:\t\t\t\t struct libie_cp_dma_mem *dma_mem)\ndrivers/net/ethernet/intel/libie/controlq.c-940-{\n--\ndrivers/net/ethernet/intel/libie/controlq.c-946-/**\ndrivers/net/ethernet/intel/libie/controlq.c:947: * libie_cp_unmap_dma_mem - unmap previously mapped DMA address\ndrivers/net/ethernet/intel/libie/controlq.c-948- * @dev: device information\n--\ndrivers/net/ethernet/intel/libie/controlq.c-950- */\ndrivers/net/ethernet/intel/libie/controlq.c:951:static void libie_cp_unmap_dma_mem(struct device *dev,\ndrivers/net/ethernet/intel/libie/controlq.c:952:\t\t\t\t const struct libie_cp_dma_mem *dma_mem)\ndrivers/net/ethernet/intel/libie/controlq.c-953-{\n--\ndrivers/net/ethernet/intel/libie/controlq.c=966=int libie_ctlq_xn_process_send(struct libie_ctlq_xn_send_params *params,\n--\ndrivers/net/ethernet/intel/libie/controlq.c-971-\tvoid *buf = params-\u003esend_buf.iov_base;\ndrivers/net/ethernet/intel/libie/controlq.c:972:\tstruct libie_cp_dma_mem *dma_mem;\ndrivers/net/ethernet/intel/libie/controlq.c-973-\tu16 cookie;\n--\ndrivers/net/ethernet/intel/libie/controlq.c-977-\ndrivers/net/ethernet/intel/libie/controlq.c:978:\tif (libie_cp_can_send_onstack(buf_len)) {\ndrivers/net/ethernet/intel/libie/controlq.c-979-\t\tdma_mem = \u0026xn-\u003esmall_dma_mem;\n--\ndrivers/net/ethernet/intel/libie/controlq.c-986-\ndrivers/net/ethernet/intel/libie/controlq.c:987:\t\tif (!libie_cp_map_dma_mem(dev, buf, buf_len, DMA_TO_DEVICE,\ndrivers/net/ethernet/intel/libie/controlq.c-988-\t\t\t\t\t dma_mem))\n--\ndrivers/net/ethernet/intel/libie/controlq.c-999-\t\tif (!libie_ctlq_send_desc_avail(ctlq)) {\ndrivers/net/ethernet/intel/libie/controlq.c:1000:\t\t\tif (!libie_cp_can_send_onstack(buf_len))\ndrivers/net/ethernet/intel/libie/controlq.c:1001:\t\t\t\tlibie_cp_unmap_dma_mem(dev, dma_mem);\ndrivers/net/ethernet/intel/libie/controlq.c-1002-\n--\ndrivers/net/ethernet/intel/libie/controlq.c=1034=int libie_ctlq_xn_send(struct libie_ctlq_xn_send_params *params)\ndrivers/net/ethernet/intel/libie/controlq.c-1035-{\ndrivers/net/ethernet/intel/libie/controlq.c:1036:\tbool free_send = !libie_cp_can_send_onstack(params-\u003esend_buf.iov_len);\ndrivers/net/ethernet/intel/libie/controlq.c-1037-\tstruct libie_ctlq_xn *xn;\n--\ndrivers/net/ethernet/intel/libie/controlq.c=1131=static void libie_ctlq_xn_rel_tx_buf(const void *ctx,\ndrivers/net/ethernet/intel/libie/controlq.c:1132:\t\t\t\t struct libie_cp_dma_mem *dma_mem)\ndrivers/net/ethernet/intel/libie/controlq.c-1133-{\n--\ndrivers/net/ethernet/intel/libie/controlq.c-1135-\ndrivers/net/ethernet/intel/libie/controlq.c:1136:\tif (!libie_cp_can_send_onstack(dma_mem-\u003esize)) {\ndrivers/net/ethernet/intel/libie/controlq.c:1137:\t\tlibie_cp_unmap_dma_mem(rel_ctx-\u003edev, dma_mem);\ndrivers/net/ethernet/intel/libie/controlq.c-1138-\t\trel_ctx-\u003erel_tx_buf(dma_mem-\u003eva);\n--\ninclude/linux/net/intel/libie/controlq.h=57=struct libie_ctlq_reg {\n--\ninclude/linux/net/intel/libie/controlq.h-68-/**\ninclude/linux/net/intel/libie/controlq.h:69: * struct libie_cp_dma_mem - structure for DMA memory\ninclude/linux/net/intel/libie/controlq.h-70- * @va: virtual address\n--\ninclude/linux/net/intel/libie/controlq.h-74- */\ninclude/linux/net/intel/libie/controlq.h:75:struct libie_cp_dma_mem {\ninclude/linux/net/intel/libie/controlq.h-76-\tvoid\t\t*va;\n--\ninclude/linux/net/intel/libie/controlq.h=100=struct libie_ctlq_msg {\n--\ninclude/linux/net/intel/libie/controlq.h-115-\t\tstruct kvec\t\trecv_mem;\ninclude/linux/net/intel/libie/controlq.h:116:\t\tstruct libie_cp_dma_mem\tsend_mem;\ninclude/linux/net/intel/libie/controlq.h-117-\t};\n--\ninclude/linux/net/intel/libie/controlq.h=153=struct libie_ctlq_info {\n--\ninclude/linux/net/intel/libie/controlq.h-157-\tspinlock_t\t\t\tlock;\t/* for concurrent processing */\ninclude/linux/net/intel/libie/controlq.h:158:\tstruct libie_cp_dma_mem\tring_mem;\ninclude/linux/net/intel/libie/controlq.h-159-\tstruct libie_ctlq_desc\t\t*descs;\n--\ninclude/linux/net/intel/libie/controlq.h=238=struct libie_ctlq_clean_params {\ninclude/linux/net/intel/libie/controlq.h:239:\tvoid (*rel_dma_mem)(const void *ctx, struct libie_cp_dma_mem *dma_mem);\ninclude/linux/net/intel/libie/controlq.h-240-\tconst void\t\t\t\t*rel_ctx;\n--\ninclude/linux/net/intel/libie/controlq.h=320=struct libie_ctlq_xn {\n--\ninclude/linux/net/intel/libie/controlq.h-323-\tstruct completion\t\tcmd_completion_event;\ninclude/linux/net/intel/libie/controlq.h:324:\tstruct libie_cp_dma_mem\tsmall_dma_mem;\ninclude/linux/net/intel/libie/controlq.h:325:\tstruct libie_cp_dma_mem\tsend_dma_mem;\ninclude/linux/net/intel/libie/controlq.h-326-\tstruct kvec\t\t\trecv_mem;\n--\ninclude/linux/net/intel/libie/controlq.h=372=struct libie_ctlq_xn_send_params {\n--\ninclude/linux/net/intel/libie/controlq.h-385-/**\ninclude/linux/net/intel/libie/controlq.h:386: * libie_cp_can_send_onstack - can a message be sent using a stack variable\ninclude/linux/net/intel/libie/controlq.h-387- * @size: ctlq data buffer size\n--\ninclude/linux/net/intel/libie/controlq.h-391- */\ninclude/linux/net/intel/libie/controlq.h:392:static inline bool libie_cp_can_send_onstack(u32 size)\ninclude/linux/net/intel/libie/controlq.h-393-{\n"
} |
| 7/2 | 2026/08/12 21:57 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 147878 output: 28 thoughts: 3070 Thoughts: **Analysis of Patch for WorthFuzzing Determination** Okay, so I've been tasked with evaluating a patch and deciding if it's worth fuzzing, based on some specific criteria. Let's break this down. The patch touches files in `drivers/net/ethernet/intel/libie/`, `drivers/net/ethernet/intel/ixd/`, `drivers/net/ethernet/intel/idpf/`, and a few other Intel Ethernet drivers. The critical part is determining if `idpf` and `ixd` are SmartNIC drivers that, according to the prompt, should not be fuzzed by the tools I have available. Initially, I looked into whether `idpf` and `ixd` are SmartNIC drivers. Based on the Kconfig files, and by the descriptions of what the drivers provide, it seems very clear that both `idpf` (Intel Infrastructure Data Path Function) and `ixd` (Intel Control Plane Function) are indeed SmartNIC drivers, specifically designed for Intel IPUs (Infrastructure Processing Units). The prompt explicitly says to return `WorthFuzzing=false` for any code in vendor-specific PCIe switch, SmartNIC, or GPU drivers that require physical PCIe hardware not emulated in standard QEMU. That is, drivers that are not going to be properly emulated. This is because standard QEMU doesn't emulate the specifics of IPUs. Now, I considered syzkaller and its `syz_pci_vpci` capability, which can fuzz PCI drivers by faking the PCI config space. However, the prompt clearly states that even though it might be possible to fuzz these drivers, it is not recommended for SmartNIC drivers that require physical hardware. This is likely because fuzzing them with faked PCI config space is going to hit initialization failures and false positives and not generate useful results. After reviewing all the files modified by the patch, I can tell that there are some library updates too. I noticed the `libeth` library is updated, and this library is used by `idpf`, `ixd`, `ice`, `iavf`. It looks like most of the patch is about updating file paths and library versions. Therefore, because the changes include modifications to `idpf` and `ixd`, and because I've confirmed they are Intel SmartNIC drivers and the prompt gives the explicit instruction, I must return `WorthFuzzing=false` for this patch. Even though there are other driver updates, the initial criteria are met. |
| 8/2 | 2026/08/12 21:57 | tool | grepper |
0mArgs:{
"Expression": "libeth_rx_fq_create",
"PathPrefix": ""
}Results: {
"Output": "drivers/net/ethernet/intel/iavf/iavf_txrx.c=768=int iavf_setup_rx_descriptors(struct iavf_ring *rx_ring)\n--\ndrivers/net/ethernet/intel/iavf/iavf_txrx.c-776-\ndrivers/net/ethernet/intel/iavf/iavf_txrx.c:777:\tret = libeth_rx_fq_create(\u0026fq, \u0026rx_ring-\u003eq_vector-\u003enapi);\ndrivers/net/ethernet/intel/iavf/iavf_txrx.c-778-\tif (ret)\n--\ndrivers/net/ethernet/intel/ice/ice_base.c=607=static int ice_rxq_pp_create(struct ice_rx_ring *rq)\n--\ndrivers/net/ethernet/intel/ice/ice_base.c-617-\ndrivers/net/ethernet/intel/ice/ice_base.c:618:\terr = libeth_rx_fq_create(\u0026fq, \u0026rq-\u003eq_vector-\u003enapi);\ndrivers/net/ethernet/intel/ice/ice_base.c-619-\tif (err)\n--\ndrivers/net/ethernet/intel/ice/ice_base.c-636-\ndrivers/net/ethernet/intel/ice/ice_base.c:637:\terr = libeth_rx_fq_create(\u0026fq, \u0026rq-\u003eq_vector-\u003enapi);\ndrivers/net/ethernet/intel/ice/ice_base.c-638-\tif (err)\n--\ndrivers/net/ethernet/intel/idpf/idpf_txrx.c=553=static int idpf_rx_hdr_buf_alloc_all(struct idpf_buf_queue *bufq)\n--\ndrivers/net/ethernet/intel/idpf/idpf_txrx.c-562-\ndrivers/net/ethernet/intel/idpf/idpf_txrx.c:563:\tret = libeth_rx_fq_create(\u0026fq, \u0026bufq-\u003eq_vector-\u003enapi);\ndrivers/net/ethernet/intel/idpf/idpf_txrx.c-564-\tif (ret)\n--\ndrivers/net/ethernet/intel/idpf/idpf_txrx.c=695=static int idpf_rx_bufs_init_singleq(struct idpf_rx_queue *rxq)\n--\ndrivers/net/ethernet/intel/idpf/idpf_txrx.c-704-\ndrivers/net/ethernet/intel/idpf/idpf_txrx.c:705:\tret = libeth_rx_fq_create(\u0026fq, \u0026rxq-\u003eq_vector-\u003enapi);\ndrivers/net/ethernet/intel/idpf/idpf_txrx.c-706-\tif (ret)\n--\ndrivers/net/ethernet/intel/idpf/idpf_txrx.c=751=static int idpf_rx_bufs_init(struct idpf_buf_queue *bufq,\n--\ndrivers/net/ethernet/intel/idpf/idpf_txrx.c-767-\ndrivers/net/ethernet/intel/idpf/idpf_txrx.c:768:\tret = libeth_rx_fq_create(\u0026fq, \u0026bufq-\u003eq_vector-\u003enapi);\ndrivers/net/ethernet/intel/idpf/idpf_txrx.c-769-\tif (ret)\n--\ndrivers/net/ethernet/intel/libeth/rx.c=116=static bool libeth_rx_page_pool_params_zc(struct libeth_fq *fq,\n--\ndrivers/net/ethernet/intel/libeth/rx.c-145-/**\ndrivers/net/ethernet/intel/libeth/rx.c:146: * libeth_rx_fq_create - create a PP with the default libeth settings\ndrivers/net/ethernet/intel/libeth/rx.c-147- * @fq: buffer queue struct to fill\n--\ndrivers/net/ethernet/intel/libeth/rx.c-151- */\ndrivers/net/ethernet/intel/libeth/rx.c:152:int libeth_rx_fq_create(struct libeth_fq *fq, void *napi_dev)\ndrivers/net/ethernet/intel/libeth/rx.c-153-{\n--\ndrivers/net/ethernet/intel/libeth/rx.c-205-}\ndrivers/net/ethernet/intel/libeth/rx.c:206:EXPORT_SYMBOL_GPL(libeth_rx_fq_create);\ndrivers/net/ethernet/intel/libeth/rx.c-207-\n--\ndrivers/net/ethernet/intel/libie/controlq.c=41=static int libie_ctlq_init_fq(struct libie_ctlq_info *ctlq)\n--\ndrivers/net/ethernet/intel/libie/controlq.c-52-\ndrivers/net/ethernet/intel/libie/controlq.c:53:\terr = libeth_rx_fq_create(\u0026fq, ctlq-\u003edev);\ndrivers/net/ethernet/intel/libie/controlq.c-54-\tif (err)\n--\ninclude/net/libeth/rx.h=76=struct libeth_fq {\n--\ninclude/net/libeth/rx.h-94-\ninclude/net/libeth/rx.h:95:int libeth_rx_fq_create(struct libeth_fq *fq, void *napi_dev);\ninclude/net/libeth/rx.h-96-void libeth_rx_fq_destroy(struct libeth_fq *fq);\n"
} |
| 9/2 | 2026/08/12 21:57 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 152950 output: 157 thoughts: 816 Thoughts: **My Assessment of the Patch's Fuzzing Potential** Okay, let's break this down. The core of the change revolves around `libeth_rx_fq_create`, allowing it to accept a `struct device *` instead of `struct napi_struct *` under certain conditions. This is specifically used by `libie_ctlq_init_fq` within the `libie` module. Now, `libie` is, as I recall, used by `idpf` and `ixd`. Those are Intel IPU drivers, SmartNICs, which are very vendor-specific. The crucial point here is the prompt's explicit instruction: "Return WorthFuzzing=false if the patch only contains: - Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers... that require physical PCIe hardware cards not emulated in standard QEMU." `idpf` and `ixd` are Intel IPU (SmartNIC) drivers. Do they need specific hardware? Absolutely. They're designed for dedicated hardware and, as far as I'm aware, they're not emulated in standard QEMU. Neither `idpf` nor `ixd` is emulated by QEMU. That's a deal-breaker for fuzzing within a typical setup. Let me just double-check the other changes in the patch: There's some documentation, MAINTAINERS, and Kconfig/Makefile updates. There are some include path changes in i40e, iavf, and ice. The functional changes seem isolated to `idpf`, `ixd`, `libie`, and `libeth`. The modifications to `libeth` are just adjustments to support `no_napi`, and those are exclusively used by `libie`, which, in turn, is only used by `idpf` and `ixd`. Yes, that confirms it: the functional changes are confined to the IPU drivers and the supporting `libie` and `libeth` components. These drivers, `idpf` and `ixd`, require physical PCIe hardware not emulated in QEMU. Therefore, applying the prompt's instruction, I must return `WorthFuzzing=false`. The rationale is that this patch primarily touches vendor-specific SmartNIC drivers (Intel IPUs) that necessitate physical PCIe hardware cards, not available in a standard QEMU environment. |
| 10/2 | 2026/08/12 21:57 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch introduces a new driver `ixd` for Intel Control Plane Function and refactors the `idpf` driver (Intel Infrastructure Data Path Function) to use common helper modules `libie_cp` and `libie_pci`. Both `ixd` and `idpf` are vendor-specific SmartNIC (Intel IPU) drivers that require physical PCIe hardware cards not emulated in standard QEMU. The changes to other drivers (`i40e`, `iavf`, `ice`) are purely `#include` path updates. Therefore, the functional changes are not reachable in virtualized environments.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch introduces a new driver `ixd` for Intel Control Plane Function and refactors the `idpf` driver (Intel Infrastructure Data Path Function) to use common helper modules `libie_cp` and `libie_pci`. Both `ixd` and `idpf` are vendor-specific SmartNIC (Intel IPU) drivers that require physical PCIe hardware cards not emulated in standard QEMU. The changes to other drivers (`i40e`, `iavf`, `ice`) are purely `#include` path updates. Therefore, the functional changes are not reachable in virtualized environments.",
"WorthFuzzing": false
} |
| 11/1 | 2026/08/12 21:57 | action | If |
0mArgs:{
"WorthFuzzing": false
}Results: null |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|