@@ -10,6 +10,7 @@ idpf-y := \
idpf_controlq_setup.o \
idpf_dev.o \
idpf_ethtool.o \
+ idpf_idc.o \
idpf_lib.o \
idpf_main.o \
idpf_txrx.o \
@@ -17,6 +17,7 @@ struct idpf_vport_max_q;
#include <linux/sctp.h>
#include <linux/ethtool_netlink.h>
#include <net/gro.h>
+#include <linux/net/intel/idc_rdma.h>
#include "virtchnl2.h"
#include "idpf_txrx.h"
@@ -203,6 +204,8 @@ struct idpf_reg_ops {
*/
struct idpf_dev_ops {
struct idpf_reg_ops reg_ops;
+
+ int (*idc_init)(struct idpf_adapter *adapter);
};
/**
@@ -580,6 +583,7 @@ struct idpf_adapter {
struct idpf_vc_xn_manager *vcxn_mngr;
struct idpf_dev_ops dev_ops;
+ struct idc_rdma_core_dev_info *cdev_info;
int num_vfs;
bool crc_enable;
bool req_tx_splitq;
@@ -854,5 +858,9 @@ int idpf_sriov_configure(struct pci_dev *pdev, int num_vfs);
u8 idpf_vport_get_hsplit(const struct idpf_vport *vport);
bool idpf_vport_set_hsplit(const struct idpf_vport *vport, u8 val);
+int idpf_idc_init(struct idpf_adapter *adapter);
+int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter,
+ enum idc_function_type ftype);
+void idpf_idc_deinit_core_aux_device(struct idc_rdma_core_dev_info *cdev_info);
#endif /* !_IDPF_H_ */
@@ -143,6 +143,15 @@ static void idpf_trigger_reset(struct idpf_adapter *adapter,
idpf_get_reg_addr(adapter, PFGEN_CTRL));
}
+/**
+ * idpf_idc_register - register for IDC callbacks
+ * @adapter: Driver specific private structure
+ */
+static int idpf_idc_register(struct idpf_adapter *adapter)
+{
+ return idpf_idc_init_aux_core_dev(adapter, IDC_FUNCTION_TYPE_PF);
+}
+
/**
* idpf_reg_ops_init - Initialize register API function pointers
* @adapter: Driver specific private structure
@@ -163,4 +172,6 @@ static void idpf_reg_ops_init(struct idpf_adapter *adapter)
void idpf_dev_ops_init(struct idpf_adapter *adapter)
{
idpf_reg_ops_init(adapter);
+
+ adapter->dev_ops.idc_init = idpf_idc_register;
}
new file mode 100644
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2022 Intel Corporation */
+
+#include "idpf.h"
+#include "idpf_virtchnl.h"
+
+static DEFINE_IDA(idpf_idc_ida);
+
+#define IDPF_IDC_MAX_ADEV_NAME_LEN 15
+
+/**
+ * idpf_idc_init - Called to initialize IDC
+ * @adapter: driver private data structure
+ */
+int idpf_idc_init(struct idpf_adapter *adapter)
+{
+ int err;
+
+ if (!idpf_is_rdma_cap_ena(adapter) ||
+ !adapter->dev_ops.idc_init)
+ return 0;
+
+ err = adapter->dev_ops.idc_init(adapter);
+ if (err)
+ dev_err(&adapter->pdev->dev, "failed to initialize idc: %d\n",
+ err);
+
+ return err;
+}
+
+/**
+ * idpf_core_adev_release - function to be mapped to aux dev's release op
+ * @dev: pointer to device to free
+ */
+static void idpf_core_adev_release(struct device *dev)
+{
+ struct idc_rdma_core_auxiliary_dev *iadev;
+
+ iadev = container_of(dev, struct idc_rdma_core_auxiliary_dev, adev.dev);
+ kfree(iadev);
+ iadev = NULL;
+}
+
+/* idpf_plug_core_aux_dev - allocate and register an Auxiliary device
+ * @cdev_info: idc core device info pointer
+ */
+static int idpf_plug_core_aux_dev(struct idc_rdma_core_dev_info *cdev_info)
+{
+ struct idc_rdma_core_auxiliary_dev *iadev;
+ char name[IDPF_IDC_MAX_ADEV_NAME_LEN];
+ struct auxiliary_device *adev;
+ int err;
+
+ iadev = (struct idc_rdma_core_auxiliary_dev *)
+ kzalloc(sizeof(*iadev), GFP_KERNEL);
+ if (!iadev)
+ return -ENOMEM;
+
+ adev = &iadev->adev;
+ cdev_info->adev = adev;
+ iadev->cdev_info = cdev_info;
+
+ adev->id = ida_alloc(&idpf_idc_ida, GFP_KERNEL);
+ if (adev->id < 0) {
+ pr_err("failed to allocate unique device ID for Auxiliary driver\n");
+ err = -ENOMEM;
+ goto err_ida_alloc;
+ }
+ adev->dev.release = idpf_core_adev_release;
+ adev->dev.parent = &cdev_info->pdev->dev;
+ sprintf(name, "%04x.rdma.core", cdev_info->pdev->vendor);
+ adev->name = name;
+
+ err = auxiliary_device_init(adev);
+ if (err)
+ goto err_aux_dev_init;
+
+ err = auxiliary_device_add(adev);
+ if (err)
+ goto err_aux_dev_add;
+
+ return 0;
+
+err_aux_dev_add:
+ cdev_info->adev = NULL;
+ auxiliary_device_uninit(adev);
+err_aux_dev_init:
+ ida_free(&idpf_idc_ida, adev->id);
+err_ida_alloc:
+ kfree(iadev);
+
+ return err;
+}
+
+/* idpf_unplug_aux_dev - unregister and free an Auxiliary device
+ * @adev: auxiliary device struct
+ */
+static void idpf_unplug_aux_dev(struct auxiliary_device *adev)
+{
+ auxiliary_device_delete(adev);
+ auxiliary_device_uninit(adev);
+
+ ida_free(&idpf_idc_ida, adev->id);
+}
+
+/**
+ * idpf_idc_vport_dev_ctrl - Called by an Auxiliary Driver
+ * @cdev_info: idc core device info pointer
+ * @up: RDMA core driver status
+ *
+ * This callback function is accessed by an Auxiliary Driver to indicate
+ * whether core driver is ready to support vport driver load or if vport
+ * drivers need to be taken down.
+ */
+static int
+idpf_idc_vport_dev_ctrl(struct idc_rdma_core_dev_info *cdev_info,
+ bool up)
+{
+ return -EOPNOTSUPP;
+}
+
+/**
+ * idpf_idc_request_reset - Called by an Auxiliary Driver
+ * @cdev_info: idc core device info pointer
+ * @reset_type: function, core or other
+ *
+ * This callback function is accessed by an Auxiliary Driver to request a reset
+ * on the Auxiliary Device
+ */
+static int
+idpf_idc_request_reset(struct idc_rdma_core_dev_info *cdev_info,
+ enum idc_rdma_reset_type __always_unused reset_type)
+{
+ return -EOPNOTSUPP;
+}
+
+/* Implemented by the Auxiliary Device and called by the Auxiliary Driver */
+static const struct idc_rdma_core_ops idc_ops = {
+ .vport_dev_ctrl = idpf_idc_vport_dev_ctrl,
+ .request_reset = idpf_idc_request_reset,
+ .vc_send_sync = idpf_idc_rdma_vc_send_sync,
+};
+
+/**
+ * idpf_idc_init_msix_data - initialize MSIX data for the cdev_info structure
+ * @adapter: driver private data structure
+ */
+static void
+idpf_idc_init_msix_data(struct idpf_adapter *adapter)
+{
+ struct idc_rdma_core_dev_info *cdev_info;
+
+ if (!adapter->rdma_msix_entries)
+ return;
+
+ cdev_info = adapter->cdev_info;
+
+ cdev_info->msix_entries = adapter->rdma_msix_entries;
+ cdev_info->msix_count = adapter->num_rdma_msix_entries;
+}
+
+/**
+ * idpf_idc_init_aux_core_dev - initialize Auxiliary Device(s)
+ * @adapter: driver private data structure
+ * @ftype: PF or VF
+ */
+int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter,
+ enum idc_function_type ftype)
+{
+ struct idc_rdma_core_dev_info *cdev_info;
+ int err;
+
+ adapter->cdev_info = (struct idc_rdma_core_dev_info *)
+ kzalloc(sizeof(struct idc_rdma_core_dev_info), GFP_KERNEL);
+ if (!adapter->cdev_info)
+ return -ENOMEM;
+
+ cdev_info = adapter->cdev_info;
+ cdev_info->pdev = adapter->pdev;
+ cdev_info->ops = &idc_ops;
+ cdev_info->rdma_protocol = IDC_RDMA_PROTOCOL_ROCEV2;
+ cdev_info->ftype = ftype;
+
+ idpf_idc_init_msix_data(adapter);
+
+ err = idpf_plug_core_aux_dev(cdev_info);
+ if (err)
+ goto err_plug_aux_dev;
+
+ return 0;
+
+err_plug_aux_dev:
+ kfree(cdev_info);
+ adapter->cdev_info = NULL;
+
+ return err;
+}
+
+/**
+ * idpf_idc_deinit_core_aux_device - de-initialize Auxiliary Device(s)
+ * @cdev_info: idc core device info pointer
+ */
+void idpf_idc_deinit_core_aux_device(struct idc_rdma_core_dev_info *cdev_info)
+{
+ if (!cdev_info)
+ return;
+
+ idpf_unplug_aux_dev(cdev_info->adev);
+
+ kfree(cdev_info->mapped_mem_regions);
+ kfree(cdev_info);
+}
@@ -1861,6 +1861,10 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter)
unlock_mutex:
mutex_unlock(&adapter->vport_ctrl_lock);
+ /* Wait until all vports are created to init RDMA CORE AUX */
+ if (!err)
+ err = idpf_idc_init(adapter);
+
return err;
}
@@ -141,6 +141,15 @@ static void idpf_vf_trigger_reset(struct idpf_adapter *adapter,
idpf_send_mb_msg(adapter, VIRTCHNL2_OP_RESET_VF, 0, NULL, 0);
}
+/**
+ * idpf_idc_vf_register - register for IDC callbacks
+ * @adapter: Driver specific private structure
+ */
+static int idpf_idc_vf_register(struct idpf_adapter *adapter)
+{
+ return idpf_idc_init_aux_core_dev(adapter, IDC_FUNCTION_TYPE_VF);
+}
+
/**
* idpf_vf_reg_ops_init - Initialize register API function pointers
* @adapter: Driver specific private structure
@@ -161,4 +170,6 @@ static void idpf_vf_reg_ops_init(struct idpf_adapter *adapter)
void idpf_vf_dev_ops_init(struct idpf_adapter *adapter)
{
idpf_vf_reg_ops_init(adapter);
+
+ adapter->dev_ops.idc_init = idpf_idc_vf_register;
}
@@ -893,6 +893,7 @@ static int idpf_send_get_caps_msg(struct idpf_adapter *adapter)
caps.other_caps =
cpu_to_le64(VIRTCHNL2_CAP_SRIOV |
+ VIRTCHNL2_CAP_RDMA |
VIRTCHNL2_CAP_MACFILTER |
VIRTCHNL2_CAP_SPLITQ_QSCHED |
VIRTCHNL2_CAP_PROMISC |
@@ -3090,6 +3091,7 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)
idpf_vc_xn_shutdown(adapter->vcxn_mngr);
idpf_deinit_task(adapter);
+ idpf_idc_deinit_core_aux_device(adapter->cdev_info);
idpf_intr_rel(adapter);
cancel_delayed_work_sync(&adapter->serv_task);
@@ -3732,3 +3734,18 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter,
return reply_sz < 0 ? reply_sz : 0;
}
+
+/**
+ * idpf_idc_rdma_vc_send_sync - virtchnl send callback for IDC registered drivers
+ * @cdev_info: idc core device info pointer
+ * @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
+ */
+int idpf_idc_rdma_vc_send_sync(struct idc_rdma_core_dev_info *cdev_info,
+ u8 *send_msg, u16 msg_size,
+ u8 *recv_msg, u16 *recv_len)
+{
+ return -EOPNOTSUPP;
+}
@@ -66,5 +66,8 @@ int idpf_send_get_stats_msg(struct idpf_vport *vport);
int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs);
int idpf_send_get_set_rss_key_msg(struct idpf_vport *vport, bool get);
int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get);
+int idpf_idc_rdma_vc_send_sync(struct idc_rdma_core_dev_info *cdev_info,
+ u8 *send_msg, u16 msg_size,
+ u8 *recv_msg, u16 *recv_len);
#endif /* _IDPF_VIRTCHNL_H_ */