Re: [RFC PATCH v4 10/25] RDMA/irdma: Add driver framework definitions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux