On Thu, 2019-09-26 at 20:30 +0300, Leon Romanovsky wrote: > On Thu, Sep 26, 2019 at 09:45:03AM -0700, Jeff Kirsher wrote: > > From: Mustafa Ismail > > > > 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 > > Signed-off-by: Shiraz Saleem > > Signed-off-by: Jeff Kirsher > > --- > > 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.h > > > > diff --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 > > +#include > > +#include > > +#include > > +#include > > +#include "main.h" > > +#include "i40iw_hw.h" > > +#include > > + > > +/** > > + * 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. Who is the "we" in this context? I am sure that all the Linux distributions would strongly disagree with this stance. Whether or not you support out-of-tree drivers, they do exist and this code would ensure that if a "out-of-tree" driver is loaded, the driver will do a sanity check to ensure the RDMA driver will work.