On 2/12/2020 1:14 PM, 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 | 228 ++++++++++ > drivers/infiniband/hw/irdma/irdma_if.c | 424 ++++++++++++++++++ > drivers/infiniband/hw/irdma/main.c | 572 ++++++++++++++++++++++++ > drivers/infiniband/hw/irdma/main.h | 595 +++++++++++++++++++++++++ > 4 files changed, 1819 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..5e69b16a2658 > --- /dev/null > +++ b/drivers/infiniband/hw/irdma/i40iw_if.c > @@ -0,0 +1,228 @@ > +// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB > +/* Copyright (c) 2015 - 2019 Intel Corporation */ > +#include <linux/module.h> > +#include <linux/moduleparam.h> > +#include <linux/netdevice.h> > +#include <linux/etherdevice.h> > +#include <linux/net/intel/i40e_client.h> > +#include <net/addrconf.h> > +#include "main.h" > +#include "i40iw_hw.h" > + > +/** > + * i40iw_request_reset - Request a reset > + * @rf: RDMA PCI function > + * > + */ > +static void i40iw_request_reset(struct irdma_pci_f *rf) > +{ > + struct i40e_info *ldev = 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_device *iwdev = NULL; > + struct irdma_handler *hdl = NULL; > + struct irdma_priv_ldev *pldev; > + struct irdma_sc_dev *dev; > + struct irdma_pci_f *rf; > + struct irdma_l2params l2params = {}; > + int err = -EIO; > + int i; > + u16 qset; > + u16 last_qset = IRDMA_NO_QSET; > + > + hdl = irdma_find_handler(ldev->pcidev); > + if (hdl) > + return 0; > + > + hdl = kzalloc(sizeof(*hdl), GFP_KERNEL); > + if (!hdl) > + return -ENOMEM; > + > + rf = &hdl->rf; > + rf->hdl = hdl; > + dev = &rf->sc_dev; > + dev->back_dev = rf; > + rf->rdma_ver = IRDMA_GEN_1; > + hdl->vdev = ldev->vdev; > + irdma_init_rf_config_params(rf); > + rf->gen_ops.init_hw = i40iw_init_hw; > + rf->gen_ops.request_reset = i40iw_request_reset; > + rf->hw.hw_addr = ldev->hw_addr; > + rf->pdev = ldev->pcidev; > + rf->netdev = ldev->netdev; > + dev->pci_rev = rf->pdev->revision; > + > + 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)) { > + err = -EIO; > + goto err_ctrl_init; > + } > + > + iwdev = ib_alloc_device(irdma_device, ibdev); > + if (!iwdev) { > + err = -ENOMEM; > + goto err_ib_alloc; > + } > + > + 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; > + > + 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)) { > + err = -EIO; > + goto err_rt_init; > + } > + > + err = irdma_ib_register_device(iwdev); > + if (err) > + goto err_ibreg; > + > + irdma_add_handler(hdl); > + dev_dbg(rfdev_to_dev(dev), "INIT: Gen1 VSI open success ldev=%p\n", > + ldev); > + > + return 0; > + > +err_ibreg: > + irdma_rt_deinit_hw(iwdev); > +err_rt_init: > + ib_dealloc_device(&iwdev->ibdev); > +err_ib_alloc: > + irdma_ctrl_deinit_hw(rf); > +err_ctrl_init: > + kfree(hdl); > + > + return err; > +} > + > +/** > + * i40iw_l2param_change - handle 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 irdma_device *iwdev; > + > + iwdev = irdma_get_device(ldev->netdev); > + if (!iwdev) > + return; > + > + if (iwdev->vsi.mtu != params->mtu) { > + l2params.mtu_changed = true; > + l2params.mtu = params->mtu; > + } > + irdma_change_l2params(&iwdev->vsi, &l2params); > + irdma_put_device(iwdev); > +} > + > +/** > + * i40iw_close - client interface operation close for iwarp/uda device > + * @ldev: lan device information > + * @client: client to close > + * @reset: flag to indicate close on reset > + * > + * Called by the lan driver during the processing of client unregister > + * Destroy and clean up the driver resources > + */ > +static void i40iw_close(struct i40e_info *ldev, struct i40e_client *client, > + bool reset) > +{ > + struct irdma_handler *hdl; > + struct irdma_pci_f *rf; > + struct irdma_device *iwdev; > + > + hdl = irdma_find_handler(ldev->pcidev); > + if (!hdl) > + return; > + > + rf = &hdl->rf; > + iwdev = list_first_entry_or_null(&rf->vsi_dev_list, struct irdma_device, > + list); > + if (reset) > + iwdev->reset = true; > + > + irdma_ib_unregister_device(iwdev); > + irdma_deinit_rf(rf); > + pr_debug("INIT: Gen1 VSI close complete ldev=%p\n", ldev); > +} > + > +/* 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, > + .type = I40E_CLIENT_IWARP, > +}; > + > +int i40iw_probe(struct virtbus_device *vdev) > +{ > + struct i40e_virtbus_device *i40e_vdev = > + container_of(vdev, struct i40e_virtbus_device, vdev); > + struct i40e_info *ldev = i40e_vdev->ldev; > + > + ldev->client = &i40iw_client; > + > + return ldev->ops->client_device_register(ldev); > +} > + > +int i40iw_remove(struct virtbus_device *vdev) > +{ > + struct i40e_virtbus_device *i40e_vdev = > + container_of(vdev, struct i40e_virtbus_device, vdev); > + struct i40e_info *ldev = i40e_vdev->ldev; > + > + ldev->ops->client_device_unregister(ldev); > + > + return 0; > +} > diff --git a/drivers/infiniband/hw/irdma/irdma_if.c b/drivers/infiniband/hw/irdma/irdma_if.c > new file mode 100644 > index 000000000000..b538801ca0b9 > --- /dev/null > +++ b/drivers/infiniband/hw/irdma/irdma_if.c > @@ -0,0 +1,424 @@ > +// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB > +/* Copyright (c) 2019 Intel Corporation */ > +#include <linux/module.h> > +#include <linux/moduleparam.h> > +#include <linux/net/intel/iidc.h> > +#include "main.h" > +#include "ws.h" > +#include "icrdma_hw.h" > + > +/** > + * irdma_lan_register_qset - Register qset with LAN driver > + * @vsi: vsi structure > + * @tc_node: Traffic class node > + */ > +static enum irdma_status_code irdma_lan_register_qset(struct irdma_sc_vsi *vsi, > + struct irdma_ws_node *tc_node) > +{ > + struct irdma_device *iwdev = vsi->back_vsi; > + struct iidc_peer_dev *ldev = iwdev->ldev->if_ldev; > + struct iidc_res rdma_qset_res = {}; > + int ret; > + > + rdma_qset_res.cnt_req = 1; > + rdma_qset_res.res_type = IIDC_RDMA_QSETS_TXSCHED; > + rdma_qset_res.res[0].res.qsets.qs_handle = tc_node->qs_handle; > + rdma_qset_res.res[0].res.qsets.tc = tc_node->traffic_class; > + rdma_qset_res.res[0].res.qsets.vsi_id = vsi->vsi_idx; > + ret = ldev->ops->alloc_res(ldev, &rdma_qset_res, 0); > + if (ret) { > + dev_dbg(rfdev_to_dev(vsi->dev), > + "WS: LAN alloc_res for rdma qset failed.\n"); > + return IRDMA_ERR_NO_MEMORY; > + } > + > + tc_node->l2_sched_node_id = rdma_qset_res.res[0].res.qsets.teid; > + vsi->qos[tc_node->user_pri].l2_sched_node_id = > + rdma_qset_res.res[0].res.qsets.teid; > + > + return 0; > +} > + > +/** > + * irdma_lan_unregister_qset - Unregister qset with LAN driver > + * @vsi: vsi structure > + * @tc_node: Traffic class node > + */ > +static void irdma_lan_unregister_qset(struct irdma_sc_vsi *vsi, > + struct irdma_ws_node *tc_node) > +{ > + struct irdma_device *iwdev = vsi->back_vsi; > + struct iidc_peer_dev *ldev = iwdev->ldev->if_ldev; > + struct iidc_res rdma_qset_res = {}; > + > + rdma_qset_res.res_allocated = 1; > + rdma_qset_res.res_type = IIDC_RDMA_QSETS_TXSCHED; > + rdma_qset_res.res[0].res.qsets.vsi_id = vsi->vsi_idx; > + rdma_qset_res.res[0].res.qsets.teid = tc_node->l2_sched_node_id; > + rdma_qset_res.res[0].res.qsets.qs_handle = tc_node->qs_handle; > + > + if (ldev->ops->free_res(ldev, &rdma_qset_res)) > + dev_dbg(rfdev_to_dev(vsi->dev), > + "WS: LAN free_res for rdma qset failed.\n"); > +} > + > +/** > + * irdma_prep_tc_change - Prepare for TC changes > + * @ldev: Peer device structure > + */ > +static void irdma_prep_tc_change(struct iidc_peer_dev *ldev) > +{ > + struct irdma_device *iwdev; > + > + iwdev = irdma_get_device(ldev->netdev); > + if (!iwdev) > + return; > + > + if (iwdev->vsi.tc_change_pending) > + goto done; > + > + iwdev->vsi.tc_change_pending = true; > + irdma_sc_suspend_resume_qps(&iwdev->vsi, IRDMA_OP_SUSPEND); > + > + /* Wait for all qp's to suspend */ > + wait_event_timeout(iwdev->suspend_wq, > + !atomic_read(&iwdev->vsi.qp_suspend_reqs), > + IRDMA_EVENT_TIMEOUT); > + irdma_ws_reset(&iwdev->vsi); > +done: > + irdma_put_device(iwdev); > +} > + > +static void irdma_log_invalid_mtu(u16 mtu, struct irdma_sc_dev *dev) > +{ > + if (mtu < IRDMA_MIN_MTU_IPV4) > + dev_warn(rfdev_to_dev(dev), > + "MTU setting [%d] too low for RDMA traffic. Minimum MTU is 576 for IPv4\n", > + mtu); > + else if (mtu < IRDMA_MIN_MTU_IPV6) > + dev_warn(rfdev_to_dev(dev), > + "MTU setting [%d] too low for RDMA traffic. Minimum MTU is 1280 for IPv6\\n", > + mtu); > +} > + > +/** > + * irdma_event_handler - Called by LAN driver to notify events > + * @ldev: Peer device structure > + * @event: event from LAN driver > + */ > +static void irdma_event_handler(struct iidc_peer_dev *ldev, > + struct iidc_event *event) > +{ > + struct irdma_l2params l2params = {}; > + struct irdma_device *iwdev; > + int i; > + > + iwdev = irdma_get_device(ldev->netdev); > + if (!iwdev) > + return; > + > + if (*event->type & BIT(IIDC_EVENT_LINK_CHANGE)) { > + dev_dbg(rfdev_to_dev(&iwdev->rf->sc_dev), > + "CLNT: LINK_CHANGE event\n"); > + } else if (*event->type & BIT(IIDC_EVENT_MTU_CHANGE)) { > + dev_dbg(rfdev_to_dev(&iwdev->rf->sc_dev), > + "CLNT: new MTU = %d\n", event->info.mtu); > + if (iwdev->vsi.mtu != event->info.mtu) { > + l2params.mtu = event->info.mtu; > + l2params.mtu_changed = true; > + irdma_log_invalid_mtu(l2params.mtu, &iwdev->rf->sc_dev); > + irdma_change_l2params(&iwdev->vsi, &l2params); > + } > + } else if (*event->type & BIT(IIDC_EVENT_TC_CHANGE)) { > + if (!iwdev->vsi.tc_change_pending) > + goto done; > + > + l2params.tc_changed = true; > + dev_dbg(rfdev_to_dev(&iwdev->rf->sc_dev), "CLNT: TC Change\n"); > + iwdev->dcb = event->info.port_qos.num_tc > 1 ? true : false; > + > + for (i = 0; i < IIDC_MAX_USER_PRIORITY; ++i) > + l2params.up2tc[i] = event->info.port_qos.up2tc[i]; > + irdma_change_l2params(&iwdev->vsi, &l2params); > + } else if (*event->type & BIT(IIDC_EVENT_API_CHANGE)) { > + dev_dbg(rfdev_to_dev(&iwdev->rf->sc_dev), > + "CLNT: API_CHANGE\n"); > + } > + > +done: > + irdma_put_device(iwdev); > +} > + > +/** > + * irdma_open - client interface operation open for RDMA device > + * @ldev: LAN device information > + * > + * Called by the LAN driver during the processing of client > + * register. > + */ > +static int irdma_open(struct iidc_peer_dev *ldev) > +{ > + struct irdma_handler *hdl; > + struct irdma_device *iwdev; > + struct irdma_sc_dev *dev; > + struct iidc_event events = {}; > + struct irdma_pci_f *rf; > + struct irdma_priv_ldev *pldev; > + struct irdma_l2params l2params = {}; > + int i, ret; > + > + hdl = irdma_find_handler(ldev->pdev); > + if (!hdl) > + return -ENODEV; > + > + rf = &hdl->rf; > + if (rf->init_state != CEQ0_CREATED) > + return -EINVAL; > + > + iwdev = ib_alloc_device(irdma_device, ibdev); > + if (!iwdev) > + return -ENOMEM; > + > + pldev = &rf->ldev; > + pldev->pf_vsi_num = ldev->pf_vsi_num; > + dev = &hdl->rf.sc_dev; > + > + iwdev->hdl = hdl; > + iwdev->rf = rf; > + iwdev->ldev = &rf->ldev; > + iwdev->push_mode = 0; > + 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; > + if (rf->protocol_used == IRDMA_ROCE_PROTOCOL_ONLY) { > + iwdev->roce_mode = true; > + iwdev->create_ilq = false; > + } > + l2params.mtu = ldev->netdev->mtu; > + l2params.num_tc = ldev->initial_qos_info.num_tc; > + l2params.num_apps = ldev->initial_qos_info.num_apps; > + l2params.vsi_prio_type = ldev->initial_qos_info.vsi_priority_type; > + l2params.vsi_rel_bw = ldev->initial_qos_info.vsi_relative_bw; > + for (i = 0; i < l2params.num_tc; i++) { > + l2params.tc_info[i].egress_virt_up = > + ldev->initial_qos_info.tc_info[i].egress_virt_up; > + l2params.tc_info[i].ingress_virt_up = > + ldev->initial_qos_info.tc_info[i].ingress_virt_up; > + l2params.tc_info[i].prio_type = > + ldev->initial_qos_info.tc_info[i].prio_type; > + l2params.tc_info[i].rel_bw = > + ldev->initial_qos_info.tc_info[i].rel_bw; > + l2params.tc_info[i].tc_ctx = > + ldev->initial_qos_info.tc_info[i].tc_ctx; > + } > + for (i = 0; i < IIDC_MAX_USER_PRIORITY; i++) > + l2params.up2tc[i] = ldev->initial_qos_info.up2tc[i]; > + > + iwdev->vsi_num = ldev->pf_vsi_num; > + ldev->ops->update_vsi_filter(ldev, IIDC_RDMA_FILTER_BOTH, true); > + > + if (irdma_rt_init_hw(rf, iwdev, &l2params)) { > + ib_dealloc_device(&iwdev->ibdev); > + return -EIO; > + } > + > + ret = irdma_ib_register_device(iwdev); > + if (ret) { > + irdma_rt_deinit_hw(iwdev); > + ib_dealloc_device(&iwdev->ibdev); > + return ret; > + } > + > + events.reporter = ldev; > + set_bit(IIDC_EVENT_LINK_CHANGE, events.type); > + set_bit(IIDC_EVENT_MTU_CHANGE, events.type); > + set_bit(IIDC_EVENT_TC_CHANGE, events.type); > + set_bit(IIDC_EVENT_API_CHANGE, events.type); > + > + ldev->ops->reg_for_notification(ldev, &events); > + dev_dbg(rfdev_to_dev(dev), > + "INIT: Gen2 VSI[%d] open success ldev=%p\n", ldev->pf_vsi_num, > + ldev); > + > + return 0; > +} > + > +/** > + * irdma_close - client interface operation close for iwarp/uda device > + * @ldev: LAN device information > + * @reason: reason for closing > + * > + * Called by the LAN driver during the processing of client > + * unregister Destroy and clean up the driver resources > + */ > +static void irdma_close(struct iidc_peer_dev *ldev, > + enum iidc_close_reason reason) > +{ > + struct irdma_handler *hdl; > + struct irdma_device *iwdev; > + struct irdma_pci_f *rf; > + > + hdl = irdma_find_handler(ldev->pdev); > + if (!hdl) > + return; > + > + rf = &hdl->rf; > + iwdev = list_first_entry_or_null(&rf->vsi_dev_list, struct irdma_device, > + list); > + if (!iwdev) > + return; > + > + if (reason == IIDC_REASON_GLOBR_REQ || reason == IIDC_REASON_CORER_REQ || > + reason == IIDC_REASON_PFR_REQ || rf->reset) { > + iwdev->reset = true; > + rf->reset = true; > + } > + > + irdma_ib_unregister_device(iwdev); > + ldev->ops->update_vsi_filter(ldev, IIDC_RDMA_FILTER_BOTH, false); > + if (rf->reset) > + schedule_delayed_work(&rf->rst_work, rf->rst_to * HZ); > + > + pr_debug("INIT: Gen2 VSI[%d] close complete ldev=%p\n", > + ldev->pf_vsi_num, ldev); > +} > + > +/** > + * irdma_remove - GEN_2 device remove() > + * @vdev: virtbus device > + * > + * Called on module unload. > + */ > +int irdma_remove(struct virtbus_device *vdev) > +{ > + struct iidc_virtbus_object *vo = > + container_of(vdev, struct iidc_virtbus_object, vdev); > + struct iidc_peer_dev *ldev = vo->peer_dev; > + struct irdma_handler *hdl; > + > + hdl = irdma_find_handler(ldev->pdev); > + if (!hdl) > + return 0; > + > + cancel_delayed_work_sync(&hdl->rf.rst_work); > + ldev->ops->peer_unregister(ldev); > + > + irdma_deinit_rf(&hdl->rf); > + pr_debug("INIT: Gen2 device remove success ldev=%p\n", ldev); > + > + return 0; > +} > + > +static const struct iidc_peer_ops irdma_peer_ops = { > + .close = irdma_close, > + .event_handler = irdma_event_handler, > + .open = irdma_open, > + .prep_tc_change = irdma_prep_tc_change, > +}; > + > +static struct iidc_peer_drv irdma_peer_drv = { > + .driver_id = IIDC_PEER_RDMA_DRIVER, > + .name = KBUILD_MODNAME, > +}; > + > +/** > + * icrdma_request_reset - Request a reset > + * @rf: RDMA PCI function > + */ > +static void icrdma_request_reset(struct irdma_pci_f *rf) > +{ > + struct iidc_peer_dev *ldev = rf->ldev.if_ldev; > + > + dev_warn(rfdev_to_dev(&rf->sc_dev), "Requesting a a reset\n"); > + ldev->ops->request_reset(ldev, IIDC_PEER_PFR); > +} > + > +/** > + * irdma_probe - GEN_2 device probe() > + * @vdev: virtbus device > + * > + * Create device resources, set up queues, pble and hmc objects. > + * Return 0 if successful, otherwise return error > + */ > +int irdma_probe(struct virtbus_device *vdev) > +{ > + struct iidc_virtbus_object *vo = > + container_of(vdev, struct iidc_virtbus_object, vdev); > + struct iidc_peer_dev *ldev = vo->peer_dev; > + struct irdma_handler *hdl; > + struct irdma_pci_f *rf; > + struct irdma_sc_dev *dev; > + struct irdma_priv_ldev *pldev; > + int err; > + > + hdl = irdma_find_handler(ldev->pdev); > + if (hdl) > + return -EBUSY; > + > + hdl = kzalloc(sizeof(*hdl), GFP_KERNEL); > + if (!hdl) > + return -ENOMEM; > + > + rf = &hdl->rf; > + pldev = &rf->ldev; > + hdl->ldev = pldev; > + hdl->vdev = vdev; > + rf->hdl = hdl; > + dev = &rf->sc_dev; > + dev->back_dev = rf; > + rf->gen_ops.init_hw = icrdma_init_hw; > + rf->gen_ops.request_reset = icrdma_request_reset; > + rf->gen_ops.register_qset = irdma_lan_register_qset; > + rf->gen_ops.unregister_qset = irdma_lan_unregister_qset; > + pldev->if_ldev = ldev; > + rf->rdma_ver = IRDMA_GEN_2; > + irdma_init_rf_config_params(rf); > + INIT_DELAYED_WORK(&rf->rst_work, irdma_reset_task); > + dev->pci_rev = ldev->pdev->revision; > + rf->default_vsi.vsi_idx = ldev->pf_vsi_num; > + /* save information from ldev to priv_ldev*/ > + pldev->fn_num = PCI_FUNC(ldev->pdev->devfn); > + rf->hw.hw_addr = ldev->hw_addr; > + rf->pdev = ldev->pdev; > + rf->netdev = ldev->netdev; > + pldev->ftype = ldev->ftype; > + pldev->msix_count = ldev->msix_count; > + pldev->msix_entries = ldev->msix_entries; > + irdma_add_handler(hdl); > + if (irdma_ctrl_init_hw(rf)) { > + err = -EIO; > + goto err_ctrl_init; > + } > + ldev->peer_ops = &irdma_peer_ops; > + ldev->peer_drv = &irdma_peer_drv; > + err = ldev->ops->peer_register(ldev); > + if (err) > + goto err_peer_reg; > + > + dev_dbg(rfdev_to_dev(dev), > + "INIT: Gen2 device probe success ldev=%p\n", ldev); > + > + return 0; > + > +err_peer_reg: > + irdma_ctrl_deinit_hw(rf); > +err_ctrl_init: > + irdma_del_handler(rf->hdl); > + kfree(rf->hdl); > + > + return err; > +} > + > +/* > + * irdma_lan_vsi_ready - check to see if lan reset done > + * @vdev: virtbus device > + */ > +bool irdma_lan_vsi_ready(struct virtbus_device *vdev) > +{ > + struct iidc_virtbus_object *vo = > + container_of(vdev, struct iidc_virtbus_object, vdev); > + struct iidc_peer_dev *ldev = vo->peer_dev; > + > + return ldev->ops->is_vsi_ready(ldev) ? true : false; > +} > diff --git a/drivers/infiniband/hw/irdma/main.c b/drivers/infiniband/hw/irdma/main.c > new file mode 100644 > index 000000000000..aa7f2b2f496b > --- /dev/null > +++ b/drivers/infiniband/hw/irdma/main.c > @@ -0,0 +1,572 @@ > +// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB > +/* Copyright (c) 2015 - 2019 Intel Corporation */ > +#include "main.h" > + > +bool irdma_upload_context; > + > +MODULE_ALIAS("i40iw"); > +MODULE_AUTHOR("Intel Corporation, <e1000-rdma@xxxxxxxxxxxxxxxxxxxxx>"); > +MODULE_DESCRIPTION("Intel(R) Ethernet Protocol Driver for RDMA"); > +MODULE_LICENSE("Dual BSD/GPL"); > + > +LIST_HEAD(irdma_handlers); > +DEFINE_SPINLOCK(irdma_handler_lock); > + > +static struct notifier_block irdma_inetaddr_notifier = { > + .notifier_call = irdma_inetaddr_event > +}; > + > +static struct notifier_block irdma_inetaddr6_notifier = { > + .notifier_call = irdma_inet6addr_event > +}; > + > +static struct notifier_block irdma_net_notifier = { > + .notifier_call = irdma_net_event > +}; > + > +static struct notifier_block irdma_netdevice_notifier = { > + .notifier_call = irdma_netdevice_event > +}; > + > +/** > + * set_protocol_used - set protocol_used against HW generation and roce_ena flag > + * @rf: RDMA PCI function > + * @roce_ena: RoCE enabled flag > + */ > +static void set_protocol_used(struct irdma_pci_f *rf, bool roce_ena) > +{ > + switch (rf->rdma_ver) { > + case IRDMA_GEN_2: > + rf->protocol_used = roce_ena ? IRDMA_ROCE_PROTOCOL_ONLY : > + IRDMA_IWARP_PROTOCOL_ONLY; > + break; > + case IRDMA_GEN_1: > + rf->protocol_used = IRDMA_IWARP_PROTOCOL_ONLY; > + break; > + } > +} > + > +void irdma_init_rf_config_params(struct irdma_pci_f *rf) > +{ > + struct irdma_dl_priv *dl_priv; > + > + rf->rsrc_profile = IRDMA_HMC_PROFILE_DEFAULT; > + dl_priv = dev_get_drvdata(&rf->hdl->vdev->dev); > + rf->limits_sel = dl_priv->limits_sel; > + set_protocol_used(rf, dl_priv->roce_ena); > + rf->rst_to = IRDMA_RST_TIMEOUT_HZ; > +} > + > +/* > + * irdma_deinit_rf - Clean up resources allocated for RF > + * @rf: RDMA PCI function > + */ > +void irdma_deinit_rf(struct irdma_pci_f *rf) > +{ > + irdma_ctrl_deinit_hw(rf); > + irdma_del_handler(rf->hdl); > + kfree(rf->hdl); > +} > + > +/** > + * irdma_find_ice_handler - find a handler given a client info > + * @pdev: pointer to pci dev info > + */ > +struct irdma_handler *irdma_find_handler(struct pci_dev *pdev) > +{ > + struct irdma_handler *hdl; > + unsigned long flags; > + > + spin_lock_irqsave(&irdma_handler_lock, flags); > + list_for_each_entry (hdl, &irdma_handlers, list) { > + if (hdl->rf.pdev->devfn == pdev->devfn && > + hdl->rf.pdev->bus->number == pdev->bus->number) { > + spin_unlock_irqrestore(&irdma_handler_lock, flags); > + return hdl; > + } > + } > + spin_unlock_irqrestore(&irdma_handler_lock, flags); > + > + return NULL; > +} > + > +/** > + * irdma_add_handler - add a handler to the list > + * @hdl: handler to be added to the handler list > + */ > +void irdma_add_handler(struct irdma_handler *hdl) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&irdma_handler_lock, flags); > + list_add(&hdl->list, &irdma_handlers); > + spin_unlock_irqrestore(&irdma_handler_lock, flags); > +} > + > +/** > + * irdma_del_handler - delete a handler from the list > + * @hdl: handler to be deleted from the handler list > + */ > +void irdma_del_handler(struct irdma_handler *hdl) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&irdma_handler_lock, flags); > + list_del(&hdl->list); > + spin_unlock_irqrestore(&irdma_handler_lock, flags); > +} > + > +/** > + * irdma_register_notifiers - register tcp ip notifiers > + */ > +void irdma_register_notifiers(void) > +{ > + register_inetaddr_notifier(&irdma_inetaddr_notifier); > + register_inet6addr_notifier(&irdma_inetaddr6_notifier); > + register_netevent_notifier(&irdma_net_notifier); > + register_netdevice_notifier(&irdma_netdevice_notifier); > +} > + > +void irdma_unregister_notifiers(void) > +{ > + unregister_netevent_notifier(&irdma_net_notifier); > + unregister_inetaddr_notifier(&irdma_inetaddr_notifier); > + unregister_inet6addr_notifier(&irdma_inetaddr6_notifier); > + unregister_netdevice_notifier(&irdma_netdevice_notifier); > +} > + > +/** > + * irdma_add_ipv6_addr - add ipv6 address to the hw arp table > + * @iwdev: irdma device > + */ > +static void irdma_add_ipv6_addr(struct irdma_device *iwdev) > +{ > + struct net_device *ip_dev; > + struct inet6_dev *idev; > + struct inet6_ifaddr *ifp, *tmp; > + u32 local_ipaddr6[4]; > + > + rcu_read_lock(); > + for_each_netdev_rcu (&init_net, ip_dev) { > + if (((rdma_vlan_dev_vlan_id(ip_dev) < 0xFFFF && > + rdma_vlan_dev_real_dev(ip_dev) == iwdev->netdev) || > + ip_dev == iwdev->netdev) && ip_dev->flags & IFF_UP) { > + idev = __in6_dev_get(ip_dev); > + if (!idev) { > + dev_err(rfdev_to_dev(&iwdev->rf->sc_dev), > + "ipv6 inet device not found\n"); > + break; > + } > + list_for_each_entry_safe (ifp, tmp, &idev->addr_list, > + if_list) { > + dev_dbg(rfdev_to_dev(&iwdev->rf->sc_dev), > + "INIT: IP=%pI6, vlan_id=%d, MAC=%pM\n", > + &ifp->addr, > + rdma_vlan_dev_vlan_id(ip_dev), > + ip_dev->dev_addr); > + > + irdma_copy_ip_ntohl(local_ipaddr6, > + ifp->addr.in6_u.u6_addr32); > + irdma_manage_arp_cache(iwdev->rf, > + ip_dev->dev_addr, > + local_ipaddr6, false, > + IRDMA_ARP_ADD); > + } > + } > + } > + rcu_read_unlock(); > +} > + > +/** > + * irdma_add_ipv4_addr - add ipv4 address to the hw arp table > + * @iwdev: irdma device > + */ > +static void irdma_add_ipv4_addr(struct irdma_device *iwdev) > +{ > + struct net_device *dev; > + struct in_device *idev; > + u32 ip_addr; > + > + rcu_read_lock(); > + for_each_netdev_rcu (&init_net, dev) { > + if (((rdma_vlan_dev_vlan_id(dev) < 0xFFFF && > + rdma_vlan_dev_real_dev(dev) == iwdev->netdev) || > + dev == iwdev->netdev) && dev->flags & IFF_UP) { > + const struct in_ifaddr *ifa; > + > + idev = __in_dev_get_rcu(dev); > + if (!idev) > + continue; > + in_dev_for_each_ifa_rcu(ifa, idev) { > + dev_dbg(rfdev_to_dev(&iwdev->rf->sc_dev), > + "CM: IP=%pI4, vlan_id=%d, MAC=%pM\n", > + &ifa->ifa_address, > + rdma_vlan_dev_vlan_id(dev), > + dev->dev_addr); > + > + ip_addr = ntohl(ifa->ifa_address); > + irdma_manage_arp_cache(iwdev->rf, dev->dev_addr, > + &ip_addr, true, > + IRDMA_ARP_ADD); > + } > + } > + } > + rcu_read_unlock(); > +} > + > +/** > + * irdma_add_ip - add ip addresses > + * @iwdev: irdma device > + * > + * Add ipv4/ipv6 addresses to the arp cache > + */ > +void irdma_add_ip(struct irdma_device *iwdev) > +{ > + irdma_add_ipv4_addr(iwdev); > + irdma_add_ipv6_addr(iwdev); > +} > + > +static int irdma_devlink_rsrc_limits_validate(struct devlink *dl, u32 id, > + union devlink_param_value val, > + struct netlink_ext_ack *extack) > +{ > + u8 value = val.vu8; > + > + if (value > 5) { > + NL_SET_ERR_MSG_MOD(extack, "resource limits selector range is (0-5)"); > + return -ERANGE; > + } > + > + return 0; > +} > + > +static int irdma_devlink_enable_roce_validate(struct devlink *dl, u32 id, > + union devlink_param_value val, > + struct netlink_ext_ack *extack) > +{ > + struct irdma_dl_priv *priv = devlink_priv(dl); > + const struct virtbus_dev_id *vid = priv->vdev->matched_element; > + u8 gen_ver = vid->driver_data; > + bool value = val.vbool; > + > + if (value && gen_ver == IRDMA_GEN_1) { > + NL_SET_ERR_MSG_MOD(extack, "RoCE not supported on device"); > + return -EOPNOTSUPP; > + } > + > + return 0; > +} > + > +static int irdma_devlink_upload_ctx_get(struct devlink *devlink, u32 id, > + struct devlink_param_gset_ctx *ctx) > +{ > + ctx->val.vbool = irdma_upload_context; > + return 0; > +} > + > +static int irdma_devlink_upload_ctx_set(struct devlink *devlink, u32 id, > + struct devlink_param_gset_ctx *ctx) > +{ > + irdma_upload_context = ctx->val.vbool; > + return 0; > +} > + > +enum irdma_dl_param_id { > + IRDMA_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, > + IRDMA_DEVLINK_PARAM_ID_LIMITS_SELECTOR, > + IRDMA_DEVLINK_PARAM_ID_UPLOAD_CONTEXT, > +}; > + > +static const struct devlink_param irdma_devlink_params[] = { > + /* Common */ > + DEVLINK_PARAM_DRIVER(IRDMA_DEVLINK_PARAM_ID_LIMITS_SELECTOR, > + "resource_limits_selector", DEVLINK_PARAM_TYPE_U8, > + BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), > + NULL, NULL, irdma_devlink_rsrc_limits_validate), > + DEVLINK_PARAM_DRIVER(IRDMA_DEVLINK_PARAM_ID_UPLOAD_CONTEXT, > + "upload_context", DEVLINK_PARAM_TYPE_BOOL, > + BIT(DEVLINK_PARAM_CMODE_RUNTIME), > + irdma_devlink_upload_ctx_get, > + irdma_devlink_upload_ctx_set, NULL), > + DEVLINK_PARAM_GENERIC(ENABLE_ROCE, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), > + NULL, NULL, irdma_devlink_enable_roce_validate) > +}; > + > +static int irdma_devlink_reload_down(struct devlink *devlink, bool netns_change, > + struct netlink_ext_ack *extack) > +{ > + struct irdma_dl_priv *priv = devlink_priv(devlink); > + const struct virtbus_dev_id *id = priv->vdev->matched_element; > + u8 gen_ver = id->driver_data; > + > + switch (gen_ver) { > + case IRDMA_GEN_2: > + irdma_remove(priv->vdev); > + break; > + case IRDMA_GEN_1: > + i40iw_remove(priv->vdev); > + break; > + default: > + return -ENODEV; > + } > + > + return 0; > +} > + > +static int irdma_devlink_reload_up(struct devlink *devlink, > + struct netlink_ext_ack *extack) > +{ > + struct irdma_dl_priv *priv = devlink_priv(devlink); > + union devlink_param_value saved_value; > + const struct virtbus_dev_id *id = priv->vdev->matched_element; Like irdma_probe(), struct iidc_virtbus_object *vo is accesible for the given priv. Please use struct iidc_virtbus_object for any sharing between two drivers. matched_element modification inside the virtbus match() function and accessing pointer to some driver data between two driver through this matched_element is not appropriate.