[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <6f01d517-3196-1183-112e-8151b821bd72@mellanox.com>
Date: Fri, 14 Feb 2020 22:13:25 +0000
From: Parav Pandit <parav@...lanox.com>
To: Jeff Kirsher <jeffrey.t.kirsher@...el.com>,
"davem@...emloft.net" <davem@...emloft.net>,
"gregkh@...uxfoundation.org" <gregkh@...uxfoundation.org>
CC: Mustafa Ismail <mustafa.ismail@...el.com>,
"netdev@...r.kernel.org" <netdev@...r.kernel.org>,
"linux-rdma@...r.kernel.org" <linux-rdma@...r.kernel.org>,
"nhorman@...hat.com" <nhorman@...hat.com>,
"sassmann@...hat.com" <sassmann@...hat.com>,
"jgg@...pe.ca" <jgg@...pe.ca>,
Shiraz Saleem <shiraz.saleem@...el.com>
Subject: Re: [RFC PATCH v4 10/25] RDMA/irdma: Add driver framework definitions
On 2/12/2020 1:14 PM, Jeff Kirsher wrote:
> From: Mustafa Ismail <mustafa.ismail@...el.com>
>
> 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@...el.com>
> Signed-off-by: Shiraz Saleem <shiraz.saleem@...el.com>
> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@...el.com>
> ---
> 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@...ts.sourceforge.net>");
> +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.
Powered by blists - more mailing lists