int _gnix_ep_alloc()

in prov/gni/src/gnix_ep.c [2467:2726]


int _gnix_ep_alloc(struct fid_domain *domain, struct fi_info *info,
			   struct gnix_ep_attr *attr,
			   struct fid_ep **ep, void *context)
{
	int ret = FI_SUCCESS;
	int err_ret;
	struct gnix_fid_domain *domain_priv;
	struct gnix_fid_ep *ep_priv;
	gnix_ht_key_t *key_ptr;
	struct gnix_auth_key *auth_key;
	uint32_t cdm_id;
	bool free_list_inited = false;
	struct gnix_nic_attr nic_attr = {0};

	GNIX_TRACE(FI_LOG_EP_CTRL, "\n");

	if ((domain == NULL) || (info == NULL) || (ep == NULL) ||
	    (info->ep_attr == NULL))
		return -FI_EINVAL;

	domain_priv = container_of(domain, struct gnix_fid_domain, domain_fid);

	if (info->ep_attr->auth_key_size) {
		auth_key = GNIX_GET_AUTH_KEY(info->ep_attr->auth_key,
				info->ep_attr->auth_key_size,
				domain_priv->using_vmdh);
		if (!auth_key)
			return -FI_EINVAL;
	} else {
		auth_key = domain_priv->auth_key;
		assert(auth_key);
	}

	ep_priv = calloc(1, sizeof(*ep_priv));
	if (!ep_priv)
		return -FI_ENOMEM;

	ep_priv->auth_key = auth_key;

	ep_priv->requires_lock = (domain_priv->thread_model !=
				FI_THREAD_COMPLETION);

	ep_priv->ep_fid.fid.fclass = FI_CLASS_EP;
	ep_priv->ep_fid.fid.context = context;

	ep_priv->ep_fid.fid.ops = &gnix_ep_fi_ops;
	ep_priv->ep_fid.ops = &gnix_ep_ops;
	ep_priv->domain = domain_priv;
	ep_priv->type = info->ep_attr->type;
	ep_priv->info = fi_dupinfo(info);

	_gnix_ref_init(&ep_priv->ref_cnt, 1, __ep_destruct);

	ep_priv->caps = info->caps & GNIX_EP_CAPS_FULL;

	if (info->tx_attr)
		ep_priv->op_flags = info->tx_attr->op_flags;
	if (info->rx_attr)
		ep_priv->op_flags |= info->rx_attr->op_flags;
	ep_priv->op_flags &= GNIX_EP_OP_FLAGS;

	ep_priv->min_multi_recv = GNIX_OPT_MIN_MULTI_RECV_DEFAULT;

	if (attr && attr->msg_ops)
		ep_priv->ep_fid.msg = attr->msg_ops;
	else
		ep_priv->ep_fid.msg = &gnix_ep_msg_ops;

	if (attr && attr->rma_ops)
		ep_priv->ep_fid.rma = attr->rma_ops;
	else
		ep_priv->ep_fid.rma = &gnix_ep_rma_ops;

	if (attr && attr->tagged_ops)
		ep_priv->ep_fid.tagged = attr->tagged_ops;
	else
		ep_priv->ep_fid.tagged = &gnix_ep_tagged_ops;

	if (attr && attr->atomic_ops)
		ep_priv->ep_fid.atomic = attr->atomic_ops;
	else
		ep_priv->ep_fid.atomic = &gnix_ep_atomic_ops;

	if (attr && attr->cm_ops)
		ep_priv->ep_fid.cm = attr->cm_ops;
	else
		ep_priv->ep_fid.cm = &gnix_ep_ops_cm;

	gnix_ep_caps(ep_priv, ep_priv->caps);

	ret = __init_tag_storages(ep_priv, GNIX_TAG_LIST, 1);
	if (ret) {
		goto err;
	}

	ret = __fr_freelist_init(ep_priv);
	if (ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			 "Error allocating gnix_fab_req freelist (%s)",
			 fi_strerror(-ret));
		goto err;
	} else
		free_list_inited = true;

	/*
	 * try out XPMEM
	 */

	ret = _gnix_xpmem_handle_create(domain_priv,
					&ep_priv->xpmem_hndl);
	if (ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_CTRL, "xpmem_handl_create returned %s\n",
			  fi_strerror(-ret));
	}

	if (attr && attr->cm_nic) {
		ep_priv->cm_nic = attr->cm_nic;
		_gnix_ref_get(ep_priv->cm_nic);
	} else {

		/*
		 * if a cm_nic has not yet been allocated for this
		 * domain, do it now.  Reuse the embedded gnix_nic
		 * in the cm_nic as the nic for this endpoint
		 * to reduce demand on Aries hw resources.
		 */

		fastlock_acquire(&domain_priv->cm_nic_lock);
		if (domain_priv->cm_nic == NULL) {
			ret = _gnix_cm_nic_alloc(domain_priv, info,
						 cdm_id,
						 ep_priv->auth_key,
						 &domain_priv->cm_nic);
			if (ret != FI_SUCCESS) {
				GNIX_WARN(FI_LOG_EP_CTRL,
					"_gnix_cm_nic_alloc returned %s\n",
					fi_strerror(-ret));
				fastlock_release(
					 &domain_priv->cm_nic_lock);
				goto err;
			}
			ep_priv->cm_nic = domain_priv->cm_nic;
			ep_priv->nic = ep_priv->cm_nic->nic;
			_gnix_ref_get(ep_priv->nic);
		} else {
			ep_priv->cm_nic = domain_priv->cm_nic;
			_gnix_ref_get(ep_priv->cm_nic);
		}

		fastlock_release(&domain_priv->cm_nic_lock);

	}

	ep_priv->src_addr.gnix_addr.device_addr =
		ep_priv->cm_nic->my_name.gnix_addr.device_addr;
	ep_priv->src_addr.cm_nic_cdm_id =
		ep_priv->cm_nic->my_name.gnix_addr.cdm_id;

	if (attr && attr->use_cdm_id) {
		cdm_id = attr->cdm_id;
	} else {
		ret = _gnix_cm_nic_create_cdm_id(domain_priv, &cdm_id);
		if (ret != FI_SUCCESS) {
			GNIX_WARN(FI_LOG_EP_CTRL,
				    "gnix_cm_nic_create_cdm_id returned %s\n",
				     fi_strerror(-ret));
			goto err;
		}
	}
	ep_priv->src_addr.gnix_addr.cdm_id = cdm_id;

	key_ptr = (gnix_ht_key_t *)&ep_priv->src_addr.gnix_addr;
	ret = _gnix_ht_insert(ep_priv->cm_nic->addr_to_ep_ht,
			      *key_ptr,
			      ep_priv);
	if ((ret != FI_SUCCESS) && (ret != -FI_ENOSPC)) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "__gnix_ht_insert returned %d\n",
			  ret);
		goto err;
	}

	fastlock_init(&ep_priv->vc_lock);

	ep_priv->progress_fn = NULL;
	ep_priv->rx_progress_fn = NULL;
	ep_priv->tx_enabled = false;
	ep_priv->rx_enabled = false;

	if (attr && attr->nic) {
		ep_priv->nic = attr->nic;
	} else {
		assert(ep_priv->nic == NULL);
		nic_attr.auth_key = ep_priv->auth_key;

		ret = gnix_nic_alloc(domain_priv, &nic_attr,
			&ep_priv->nic);
		if (ret != FI_SUCCESS) {
			GNIX_WARN(FI_LOG_EP_CTRL,
				    "gnix_nic_alloc call returned %d\n", ret);
			goto err;
		}
		if (!(attr && attr->cm_nic)) {
			ep_priv->cm_nic = domain_priv->cm_nic;
		}
		_gnix_ref_get(ep_priv->nic);
	}

	/*
	 * if smsg callbacks not present hook them up now
	 */

	if (ep_priv->nic->smsg_callbacks == NULL)
		ep_priv->nic->smsg_callbacks = gnix_ep_smsg_callbacks;

	_gnix_ref_get(ep_priv->domain);
	*ep = &ep_priv->ep_fid;
	return ret;

err:
	if (ep_priv->xpmem_hndl) {
		err_ret = _gnix_xpmem_handle_destroy(ep_priv->xpmem_hndl);
		if (err_ret != FI_SUCCESS) {
			GNIX_WARN(FI_LOG_EP_CTRL,
					"_gnix_xpmem_handle_destroy returned %s\n",
					fi_strerror(-err_ret));
		}
	}

	err_ret = __destruct_tag_storages(ep_priv);
	if (err_ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_CTRL,
				"__destruct_tag_stroages returned %s\n",
				fi_strerror(-err_ret));
	}

	if (free_list_inited == true)
		__fr_freelist_destroy(ep_priv);

	if (ep_priv->cm_nic != NULL) {
		err_ret = _gnix_cm_nic_free(ep_priv->cm_nic);
		if (err_ret != FI_SUCCESS) {
			GNIX_WARN(FI_LOG_EP_CTRL,
					"_gnix_cm_nic_free returned %s\n",
					fi_strerror(-err_ret));
		}
	}

	if (ep_priv->nic != NULL) {
		err_ret = _gnix_nic_free(ep_priv->nic);
		if (err_ret != FI_SUCCESS) {
			GNIX_WARN(FI_LOG_EP_CTRL,
					"_gnix_nic_free returned %s\n",
					fi_strerror(-err_ret));
		}
	}

	free(ep_priv);
	return ret;
}