Re: [RFC 04/20] RDMA/irdma: Add driver framework definitions
From: Leon Romanovsky <leon@kernel.org>
Date: 2019-09-26 17:30:53
Also in:
linux-rdma
On Thu, Sep 26, 2019 at 09:45:03AM -0700, Jeff Kirsher wrote:
quoted hunk ↗ jump to hunk
From: Mustafa Ismail <redacted> Register irdma as a platform driver capable of supporting platform devices from multi-generation RDMA capable Intel HW. Establish the interface with all supported netdev peer devices and initialize HW. Signed-off-by: Mustafa Ismail <redacted> Signed-off-by: Shiraz Saleem <redacted> Signed-off-by: Jeff Kirsher <redacted> --- drivers/infiniband/hw/irdma/i40iw_if.c | 270 +++++++++++ drivers/infiniband/hw/irdma/irdma_if.c | 436 +++++++++++++++++ drivers/infiniband/hw/irdma/main.c | 531 ++++++++++++++++++++ drivers/infiniband/hw/irdma/main.h | 639 +++++++++++++++++++++++++ 4 files changed, 1876 insertions(+) create mode 100644 drivers/infiniband/hw/irdma/i40iw_if.c create mode 100644 drivers/infiniband/hw/irdma/irdma_if.c create mode 100644 drivers/infiniband/hw/irdma/main.c create mode 100644 drivers/infiniband/hw/irdma/main.hdiff --git a/drivers/infiniband/hw/irdma/i40iw_if.c b/drivers/infiniband/hw/irdma/i40iw_if.c new file mode 100644 index 000000000000..3cddb091acfb --- /dev/null +++ b/drivers/infiniband/hw/irdma/i40iw_if.c@@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB +/* Copyright (c) 2019, Intel Corporation. */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <net/addrconf.h> +#include "main.h" +#include "i40iw_hw.h" +#include <linux/net/intel/i40e_client.h> + +/** + * i40iw_request_reset - Request a reset + * @rf: RDMA PCI function + * + */ +void i40iw_request_reset(struct irdma_pci_f *rf) +{ + struct i40e_info *ldev = (struct i40e_info *)rf->ldev.if_ldev; + + ldev->ops->request_reset(ldev, rf->ldev.if_client, 1); +} + +/** + * i40iw_open - client interface operation open for iwarp/uda device + * @ldev: LAN device information + * @client: iwarp client information, provided during registration + * + * Called by the LAN driver during the processing of client register + * Create device resources, set up queues, pble and hmc objects and + * register the device with the ib verbs interface + * Return 0 if successful, otherwise return error + */ +static int i40iw_open(struct i40e_info *ldev, struct i40e_client *client) +{ + struct irdma_l2params l2params = {}; + struct irdma_device *iwdev = NULL; + struct irdma_handler *hdl = NULL; + struct irdma_priv_ldev *pldev; + u16 last_qset = IRDMA_NO_QSET; + struct irdma_sc_dev *dev; + struct irdma_pci_f *rf; + int err_code = -EIO; + u16 qset; + int i; + + hdl = irdma_find_handler(ldev->pcidev); + if (hdl) + return 0; + + hdl = kzalloc((sizeof(*hdl) + sizeof(*iwdev)), GFP_KERNEL); + if (!hdl) + return -ENOMEM; + + iwdev = (struct irdma_device *)((u8 *)hdl + sizeof(*hdl)); + + iwdev->param_wq = alloc_ordered_workqueue("l2params", WQ_MEM_RECLAIM); + if (!iwdev->param_wq) + goto error; + + rf = &hdl->rf; + rf->hdl = hdl; + dev = &rf->sc_dev; + dev->back_dev = rf; + rf->rdma_ver = IRDMA_GEN_1; + hdl->platform_dev = ldev->platform_dev; + irdma_init_rf_config_params(rf); + rf->init_hw = i40iw_init_hw; + rf->hw.hw_addr = ldev->hw_addr; + rf->pdev = ldev->pcidev; + rf->netdev = ldev->netdev; + dev->pci_rev = rf->pdev->revision; + iwdev->rf = rf; + iwdev->hdl = hdl; + iwdev->ldev = &rf->ldev; + iwdev->init_state = INITIAL_STATE; + iwdev->rcv_wnd = IRDMA_CM_DEFAULT_RCV_WND_SCALED; + iwdev->rcv_wscale = IRDMA_CM_DEFAULT_RCV_WND_SCALE; + iwdev->netdev = ldev->netdev; + iwdev->create_ilq = true; + iwdev->vsi_num = 0; + + pldev = &rf->ldev; + hdl->ldev = pldev; + pldev->if_client = client; + pldev->if_ldev = ldev; + pldev->fn_num = ldev->fid; + pldev->ftype = ldev->ftype; + pldev->pf_vsi_num = 0; + pldev->msix_count = ldev->msix_count; + pldev->msix_entries = ldev->msix_entries; + + if (irdma_ctrl_init_hw(rf)) + goto error; + + l2params.mtu = + (ldev->params.mtu) ? ldev->params.mtu : IRDMA_DEFAULT_MTU; + for (i = 0; i < I40E_CLIENT_MAX_USER_PRIORITY; i++) { + qset = ldev->params.qos.prio_qos[i].qs_handle; + l2params.up2tc[i] = ldev->params.qos.prio_qos[i].tc; + l2params.qs_handle_list[i] = qset; + if (last_qset == IRDMA_NO_QSET) + last_qset = qset; + else if ((qset != last_qset) && (qset != IRDMA_NO_QSET)) + iwdev->dcb = true; + } + + if (irdma_rt_init_hw(rf, iwdev, &l2params)) { + irdma_deinit_ctrl_hw(rf); + goto error; + } + + irdma_add_handler(hdl); + return 0; +error: + kfree(hdl); + return err_code; +} + +/** + * i40iw_l2params_worker - worker for l2 params change + * @work: work pointer for l2 params + */ +static void i40iw_l2params_worker(struct work_struct *work) +{ + struct l2params_work *dwork = + container_of(work, struct l2params_work, work); + struct irdma_device *iwdev = dwork->iwdev; + + irdma_change_l2params(&iwdev->vsi, &dwork->l2params); + atomic_dec(&iwdev->params_busy); + kfree(work); +} + +/** + * i40iw_l2param_change - handle qs handles for QoS and MSS change + * @ldev: LAN device information + * @client: client for parameter change + * @params: new parameters from L2 + */ +static void i40iw_l2param_change(struct i40e_info *ldev, + struct i40e_client *client, + struct i40e_params *params) +{ + struct irdma_l2params *l2params; + struct l2params_work *work; + struct irdma_device *iwdev; + struct irdma_handler *hdl; + int i; + + hdl = irdma_find_handler(ldev->pcidev); + if (!hdl) + return; + + iwdev = (struct irdma_device *)((u8 *)hdl + sizeof(*hdl)); + + if (atomic_read(&iwdev->params_busy)) + return; + work = kzalloc(sizeof(*work), GFP_KERNEL); + if (!work) + return; + + atomic_inc(&iwdev->params_busy);
Changing parameters through workqueue and perform locking with atomic_t, exciting. Please do proper locking scheme and better to avoid workqueue at all. <...>
+/* client interface functions */
+static const struct i40e_client_ops i40e_ops = {
+ .open = i40iw_open,
+ .close = i40iw_close,
+ .l2_param_change = i40iw_l2param_change
+};
+
+static struct i40e_client i40iw_client = {
+ .name = "irdma",
+ .ops = &i40e_ops,
+ .version.major = I40E_CLIENT_VERSION_MAJOR,
+ .version.minor = I40E_CLIENT_VERSION_MINOR,
+ .version.build = I40E_CLIENT_VERSION_BUILD,
+ .type = I40E_CLIENT_IWARP,
+};
+
+int i40iw_probe(struct platform_device *pdev)
+{
+ struct i40e_peer_dev_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct i40e_info *ldev;
+
+ if (!pdata)
+ return -EINVAL;
+
+ ldev = pdata->ldev;
+
+ if (ldev->version.major != I40E_CLIENT_VERSION_MAJOR ||
+ ldev->version.minor != I40E_CLIENT_VERSION_MINOR) {
+ pr_err("version mismatch:\n");
+ pr_err("expected major ver %d, caller specified major ver %d\n",
+ I40E_CLIENT_VERSION_MAJOR, ldev->version.major);
+ pr_err("expected minor ver %d, caller specified minor ver %d\n",
+ I40E_CLIENT_VERSION_MINOR, ldev->version.minor);
+ return -EINVAL;
+ }This is can't be in upstream code, we don't support out-of-tree modules, everything else will have proper versions. Thanks