On Thu, Sep 26, 2019 at 09:45:03AM -0700, Jeff Kirsher wrote: > From: Mustafa Ismail <mustafa.ismail@xxxxxxxxx> > > 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 <mustafa.ismail@xxxxxxxxx> > Signed-off-by: Shiraz Saleem <shiraz.saleem@xxxxxxxxx> > Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@xxxxxxxxx> > --- > 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 <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