RE: [PATCH rdma-next 11/13] RDMA/efa: Add EFA verbs implementation

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

 




> -----Original Message-----
> From: linux-rdma-owner@xxxxxxxxxxxxxxx <linux-rdma-
> owner@xxxxxxxxxxxxxxx> On Behalf Of Gal Pressman
> Sent: Tuesday, December 4, 2018 6:04 AM
> To: Doug Ledford <dledford@xxxxxxxxxx>; Jason Gunthorpe <jgg@xxxxxxxx>
> Cc: Alexander Matushevsky <matua@xxxxxxxxxx>; Yossi Leybovich
> <sleybo@xxxxxxxxxx>; linux-rdma@xxxxxxxxxxxxxxx; Tom Tucker
> <tom@xxxxxxxxxxxxxxxxxxxxx>; Gal Pressman <galpress@xxxxxxxxxx>
> Subject: [PATCH rdma-next 11/13] RDMA/efa: Add EFA verbs implementation
> 
> Add a file that implements the EFA verbs.
> 
> Signed-off-by: Gal Pressman <galpress@xxxxxxxxxx>
> ---
>  drivers/infiniband/hw/efa/efa_verbs.c | 1827
> +++++++++++++++++++++++++++++++++
>  1 file changed, 1827 insertions(+)
>  create mode 100644 drivers/infiniband/hw/efa/efa_verbs.c
> 
> diff --git a/drivers/infiniband/hw/efa/efa_verbs.c
> b/drivers/infiniband/hw/efa/efa_verbs.c
> new file mode 100644
> index 000000000000..ec887648060e
> --- /dev/null
> +++ b/drivers/infiniband/hw/efa/efa_verbs.c
> @@ -0,0 +1,1827 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
> +/*
> + * Copyright 2018 Amazon.com, Inc. or its affiliates.
> + */
> +

[..]

> +static int efa_get_ah_by_id(struct efa_dev *dev, u8 *id,
> +			    u16 *ah_res, bool ref_update)
> +{
> +	struct efa_ah_id *ah_id;
> +
> +	list_for_each_entry(ah_id, &dev->efa_ah_list, list) {
> +		if (efa_ah_id_equal(ah_id->id, id)) {
> +			*ah_res =  ah_id->address_handle;
> +			if (ref_update)
> +				ah_id->ref_count++;
> +			return 0;
> +		}
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int efa_add_ah_id(struct efa_dev *dev, u8 *id,
> +			 u16 address_handle)
> +{
> +	struct efa_ah_id *ah_id;
> +
> +	ah_id = kzalloc(sizeof(*ah_id), GFP_KERNEL);
> +	if (!ah_id)
> +		return -ENOMEM;
> +
> +	memcpy(ah_id->id, id, sizeof(ah_id->id));
> +	ah_id->address_handle = address_handle;
> +	ah_id->ref_count = 1;
> +	list_add_tail(&ah_id->list, &dev->efa_ah_list);
> +
> +	return 0;
> +}
> +
> +static void efa_remove_ah_id(struct efa_dev *dev, u8 *id, u32
> +*ref_count) {
> +	struct efa_ah_id *ah_id, *tmp;
> +
> +	list_for_each_entry_safe(ah_id, tmp, &dev->efa_ah_list, list) {
> +		if (efa_ah_id_equal(ah_id->id, id)) {
> +			*ref_count = --ah_id->ref_count;
> +			if (ah_id->ref_count == 0) {
> +				list_del(&ah_id->list);
> +				kfree(ah_id);
> +				return;
> +			}
> +		}
> +	}
> +}
> +
> +static void ah_destroy_on_device(struct efa_dev *dev, u16 device_ah) {
> +	struct efa_com_destroy_ah_params params;
> +	int err;
> +
> +	params.ah = device_ah;
> +	err = efa_com_destroy_ah(dev->edev, &params);
> +	if (err)
> +		pr_err("efa_com_destroy_ah failed (%d)\n", err); }
> +
> +static int efa_create_ah_id(struct efa_dev *dev, u8 *id,
> +			    u16 *efa_address_handle)
> +{
> +	struct efa_com_create_ah_params params = {};
> +	struct efa_com_create_ah_result result = {};
> +	int err;
> +
> +	mutex_lock(&dev->ah_list_lock);
> +	err = efa_get_ah_by_id(dev, id, efa_address_handle, true);
> +	if (err) {
> +		memcpy(params.dest_addr, id, sizeof(params.dest_addr));
> +		err = efa_com_create_ah(dev->edev, &params, &result);
> +		if (err) {
> +			pr_err("efa_com_create_ah failed %d\n", err);
> +			goto err_unlock;
> +		}
> +
> +		pr_debug("create address handle %u for address %pI6\n",
> +			 result.ah, params.dest_addr);
> +
> +		err = efa_add_ah_id(dev, id, result.ah);
> +		if (err) {
> +			pr_err("efa_add_ah_id failed %d\n", err);
> +			goto err_destroy_ah;
> +		}
> +
> +		*efa_address_handle = result.ah;
> +	}
> +	mutex_unlock(&dev->ah_list_lock);
> +
> +	return 0;
> +
> +err_destroy_ah:
> +	ah_destroy_on_device(dev, result.ah);
> +err_unlock:
> +	mutex_unlock(&dev->ah_list_lock);
> +	return err;
> +}
> +
> +static void efa_destroy_ah_id(struct efa_dev *dev, u8 *id) {
> +	u16 device_ah;
> +	u32 ref_count;
> +	int err;
> +
> +	mutex_lock(&dev->ah_list_lock);

Create and destroy ah for kernel consumers cannot sleep.
Though I understand that currently you don't have kernel consumers.
This should be changed to spin lock along with other allocation to GFP_ATOMIC.

> +	err = efa_get_ah_by_id(dev, id, &device_ah, false);
> +	if (err) {
> +		WARN_ON(1);
> +		goto out_unlock;
> +	}
> +
> +	efa_remove_ah_id(dev, id, &ref_count);
> +	if (!ref_count)
> +		ah_destroy_on_device(dev, device_ah);
> +
> +out_unlock:
> +	mutex_unlock(&dev->ah_list_lock);
> +}
> +
> +struct ib_ah *efa_create_ah(struct ib_pd *ibpd,
> +			    struct rdma_ah_attr *ah_attr,
> +			    struct ib_udata *udata)
> +{
> +	struct efa_dev *dev = to_edev(ibpd->device);
> +	struct efa_ibv_create_ah_resp resp = {};
> +	u16 efa_address_handle;
> +	struct efa_ah *ah;
> +	int err;
> +
> +	pr_debug("--->\n");
> +
> +	if (udata && udata->inlen &&
> +	    !ib_is_udata_cleared(udata, 0, udata->inlen)) {
> +		pr_err_ratelimited("Incompatiable ABI params\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	ah = kzalloc(sizeof(*ah), GFP_KERNEL);
> +	if (!ah) {
> +		dev->stats.sw_stats.create_ah_alloc_err++;
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	err = efa_create_ah_id(dev, ah_attr->grh.dgid.raw,
> &efa_address_handle);
> +	if (err)
> +		goto err_free;
> +
> +	resp.efa_address_handle = efa_address_handle;
> +
> +	if (udata && udata->outlen) {
> +		err = ib_copy_to_udata(udata, &resp,
> +				       min(sizeof(resp), udata->outlen));
> +		if (err) {
> +			pr_err_ratelimited("failed to copy udata for
> create_ah response\n");
> +			goto err_destroy_ah;
> +		}
> +	}
> +
> +	memcpy(ah->id, ah_attr->grh.dgid.raw, sizeof(ah->id));
> +	return &ah->ibah;
> +
> +err_destroy_ah:
> +	efa_destroy_ah_id(dev, ah_attr->grh.dgid.raw);
> +err_free:
> +	kfree(ah);
> +	return ERR_PTR(err);
> +}
> +




[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