示例#1
0
static int map_range_append_(
		struct dlist_entry_t *ranges,
		struct map_t_ *maps,
		const size_t map_count,
		size_t *i)
{
	size_t idx = *i;

	if (idx >= map_count) {
		return 0;
	}

	uint32_t from_code_max = 0;
	uint32_t to_code_max = 0;
	struct map_range_t_ range = {
		.start_map_idx = idx,
		.end_map_idx = idx,
		.type = map_type_(&maps[idx])
	};

	dlist_init(&range.list);

	do {
		if (from_code_max < maps[idx].from) {
			from_code_max = maps[idx].from;
		}

		if (to_code_max < maps[idx].to) {
			to_code_max = maps[idx].to;
		}

		range.end_map_idx = idx++;
	} while (
		idx < map_count &&
		maps[range.end_map_idx].from + 1 == maps[idx].from &&
		map_type_(&maps[idx]) == range.type);

	range.end_map_idx = idx;

	struct map_range_t_ *r = malloc(sizeof(*r));

	if (r == NULL) {
		return -1;
	}

	*r = range;

	r->from_code_width = map_code_width_(from_code_max);
	r->to_code_width = map_code_width_(to_code_max);

	dlist_insert_before(ranges, &r->list);

	*i = idx;

	return 1;
}
示例#2
0
int psmx2_stx_ctx(struct fid_domain *domain, struct fi_tx_attr *attr,
		  struct fid_stx **stx, void *context)
{
	struct psmx2_fid_domain *domain_priv;
	struct psmx2_trx_ctxt *trx_ctxt;
	struct psmx2_fid_stx *stx_priv;
	int err = -FI_EINVAL;

	domain_priv = container_of(domain, struct psmx2_fid_domain,
				   util_domain.domain_fid.fid);
	if (!domain_priv)
		goto errout;

	stx_priv = (struct psmx2_fid_stx *) calloc(1, sizeof *stx_priv);
	if (!stx_priv) {
		err = -FI_ENOMEM;
		goto errout;
	}

	trx_ctxt = psmx2_trx_ctxt_alloc(domain_priv, NULL/*src_addr*/, 0);
	if (!trx_ctxt) {
		err = -FI_ENOMEM;
		goto errout_free_stx;
	}

	psmx2_domain_acquire(domain_priv);
	stx_priv->stx.fid.fclass = FI_CLASS_STX_CTX;
	stx_priv->stx.fid.context = context;
	stx_priv->stx.fid.ops = &psmx2_fi_ops_stx;
	stx_priv->stx.ops = &psmx2_stx_ops;
	stx_priv->domain = domain_priv;
	stx_priv->tx = trx_ctxt;
	ofi_atomic_initialize32(&stx_priv->ref, 0);

	psmx2_lock(&domain_priv->trx_ctxt_lock, 1);
	dlist_insert_before(&trx_ctxt->entry,
			    &domain_priv->trx_ctxt_list);
	psmx2_unlock(&domain_priv->trx_ctxt_lock, 1);

	*stx = &stx_priv->stx;
	return 0;

errout_free_stx:
	free(stx_priv);

errout:
	return err;
}
示例#3
0
int psmx2_sep_open(struct fid_domain *domain, struct fi_info *info,
		   struct fid_ep **sep, void *context)
{
	struct psmx2_fid_domain *domain_priv;
	struct psmx2_fid_ep *ep_priv;
	struct psmx2_fid_sep *sep_priv;
	struct psmx2_ep_name ep_name;
	struct psmx2_ep_name *src_addr;
	struct psmx2_trx_ctxt *trx_ctxt;
	size_t ctxt_cnt = 1;
	size_t ctxt_size;
	int err = -FI_EINVAL;
	int i;

	domain_priv = container_of(domain, struct psmx2_fid_domain,
				   util_domain.domain_fid.fid);
	if (!domain_priv)
		goto errout;

	if (info && info->ep_attr) {
		if (info->ep_attr->tx_ctx_cnt > psmx2_env.sep_trx_ctxt) {
			FI_WARN(&psmx2_prov, FI_LOG_EP_CTRL,
				"tx_ctx_cnt %"PRIu64" exceed limit %d.\n",
				info->ep_attr->tx_ctx_cnt,
				psmx2_env.sep_trx_ctxt);
			goto errout;
		}
		if (info->ep_attr->rx_ctx_cnt > psmx2_env.sep_trx_ctxt) {
			FI_WARN(&psmx2_prov, FI_LOG_EP_CTRL,
				"rx_ctx_cnt %"PRIu64" exceed limit %d.\n",
				info->ep_attr->rx_ctx_cnt,
				psmx2_env.sep_trx_ctxt);
			goto errout;
		}
		ctxt_cnt = info->ep_attr->tx_ctx_cnt;
		if (ctxt_cnt < info->ep_attr->rx_ctx_cnt)
			ctxt_cnt = info->ep_attr->rx_ctx_cnt;
		if (ctxt_cnt == 0) {
			FI_INFO(&psmx2_prov, FI_LOG_EP_CTRL,
				"tx_ctx_cnt and rx_ctx_cnt are 0, use 1.\n");
			ctxt_cnt = 1;
		}
	}

	ctxt_size = ctxt_cnt * sizeof(struct psmx2_sep_ctxt);
	sep_priv = (struct psmx2_fid_sep *) calloc(1, sizeof(*sep_priv) + ctxt_size);
	if (!sep_priv) {
		err = -FI_ENOMEM;
		goto errout;
	}

	sep_priv->ep.fid.fclass = FI_CLASS_SEP;
	sep_priv->ep.fid.context = context;
	sep_priv->ep.fid.ops = &psmx2_fi_ops_sep;
	sep_priv->ep.ops = &psmx2_sep_ops;
	sep_priv->ep.cm = &psmx2_cm_ops;
	sep_priv->domain = domain_priv;
	sep_priv->ctxt_cnt = ctxt_cnt;
	ofi_atomic_initialize32(&sep_priv->ref, 0);
 
	src_addr = NULL;
	if (info && info->src_addr) {
		if (info->addr_format == FI_ADDR_STR)
			src_addr = psmx2_string_to_ep_name(info->src_addr);
		else
			src_addr = info->src_addr;
	}

	for (i = 0; i < ctxt_cnt; i++) {
		trx_ctxt = psmx2_trx_ctxt_alloc(domain_priv, src_addr, i);
		if (!trx_ctxt) {
			err = -FI_ENOMEM;
			goto errout_free_ctxt;
		}

		sep_priv->ctxts[i].trx_ctxt = trx_ctxt;

		err = psmx2_ep_open_internal(domain_priv, info, &ep_priv, context,
					     trx_ctxt);
		if (err)
			goto errout_free_ctxt;

		/* override the ops so the fid can't be closed individually */
		ep_priv->ep.fid.ops = &psmx2_fi_ops_sep_ctxt;

		trx_ctxt->ep = ep_priv;
		sep_priv->ctxts[i].ep = ep_priv;
	}

	sep_priv->type = PSMX2_EP_SCALABLE;
	sep_priv->service = PSMX2_ANY_SERVICE;
	if (src_addr) {
		sep_priv->service = src_addr->service;
		if (info->addr_format == FI_ADDR_STR)
			free(src_addr);
	}

	if (sep_priv->service == PSMX2_ANY_SERVICE)
		sep_priv->service = ((getpid() & 0x7FFF) << 16) +
				   ((uintptr_t)sep_priv & 0xFFFF);

	sep_priv->id = ofi_atomic_inc32(&domain_priv->sep_cnt);

	psmx2_lock(&domain_priv->sep_lock, 1);
	dlist_insert_before(&sep_priv->entry, &domain_priv->sep_list);
	psmx2_unlock(&domain_priv->sep_lock, 1);

	psmx2_lock(&domain_priv->trx_ctxt_lock, 1);
	for (i = 0; i< ctxt_cnt; i++) {
		dlist_insert_before(&sep_priv->ctxts[i].trx_ctxt->entry,
				    &domain_priv->trx_ctxt_list);
	}
	psmx2_unlock(&domain_priv->trx_ctxt_lock, 1);

	ep_name.epid = sep_priv->ctxts[0].trx_ctxt->psm2_epid;
	ep_name.sep_id = sep_priv->id;
	ep_name.type = sep_priv->type;

	ofi_ns_add_local_name(&domain_priv->fabric->name_server,
			      &sep_priv->service, &ep_name);

	psmx2_domain_acquire(domain_priv);
	*sep = &sep_priv->ep;

	/* Make sure the AM handler is installed to answer SEP query */
	psmx2_am_init(sep_priv->ctxts[0].trx_ctxt);

	return 0;

errout_free_ctxt:
	while (i) {
		if (sep_priv->ctxts[i].ep)
			psmx2_ep_close_internal(sep_priv->ctxts[i].ep);

		if (sep_priv->ctxts[i].trx_ctxt)
			psmx2_trx_ctxt_free(sep_priv->ctxts[i].trx_ctxt);

		i--;
	}

	free(sep_priv);

errout:
	return err;
}
示例#4
0
int psmx2_ep_open(struct fid_domain *domain, struct fi_info *info,
		  struct fid_ep **ep, void *context)
{
	struct psmx2_fid_domain *domain_priv;
	struct psmx2_fid_ep *ep_priv;
	struct psmx2_ep_name ep_name;
	struct psmx2_ep_name *src_addr;
	struct psmx2_trx_ctxt *trx_ctxt = NULL;
	int err = -FI_EINVAL;
	int alloc_trx_ctxt = 1;

	domain_priv = container_of(domain, struct psmx2_fid_domain,
				   util_domain.domain_fid.fid);
	if (!domain_priv)
		goto errout;

	if (info && info->ep_attr && info->ep_attr->rx_ctx_cnt == FI_SHARED_CONTEXT)
		return  -FI_ENOSYS;

	if (info && info->ep_attr && info->ep_attr->tx_ctx_cnt == FI_SHARED_CONTEXT &&
	    !ofi_recv_allowed(info->caps) && !ofi_rma_target_allowed(info->caps)) {
		alloc_trx_ctxt = 0;
		FI_INFO(&psmx2_prov, FI_LOG_EP_CTRL, "Tx only endpoint with STX context.\n");
	}

	src_addr = NULL;
	if (info && info->src_addr) {
		if (info->addr_format == FI_ADDR_STR)
			src_addr = psmx2_string_to_ep_name(info->src_addr);
		else
			src_addr = info->src_addr;
	}

	if (alloc_trx_ctxt) {
		trx_ctxt = psmx2_trx_ctxt_alloc(domain_priv, src_addr, 0);
		if (!trx_ctxt)
			goto errout;
	}

	err = psmx2_ep_open_internal(domain_priv, info, &ep_priv, context,
				     trx_ctxt);
	if (err)
		goto errout_free_ctxt;

	ep_priv->type = PSMX2_EP_REGULAR;
	ep_priv->service = PSMX2_ANY_SERVICE;
	if (src_addr) {
		ep_priv->service = src_addr->service;
		if (info->addr_format == FI_ADDR_STR)
			free(src_addr);
	}

	if (ep_priv->service == PSMX2_ANY_SERVICE)
		ep_priv->service = ((getpid() & 0x7FFF) << 16) +
				   ((uintptr_t)ep_priv & 0xFFFF);

	if (alloc_trx_ctxt) {
		trx_ctxt->ep = ep_priv;

		psmx2_lock(&domain_priv->trx_ctxt_lock, 1);
		dlist_insert_before(&trx_ctxt->entry,
				    &domain_priv->trx_ctxt_list);
		psmx2_unlock(&domain_priv->trx_ctxt_lock, 1);

		ep_name.epid = trx_ctxt->psm2_epid;
		ep_name.type = ep_priv->type;

		ofi_ns_add_local_name(&domain_priv->fabric->name_server,
				      &ep_priv->service, &ep_name);
	}

	*ep = &ep_priv->ep;
	return 0;

errout_free_ctxt:
	psmx2_trx_ctxt_free(trx_ctxt);

errout:
	return err;
}
示例#5
0
static int map_range_merge_(
		const struct map_t_ *const maps,
		struct dlist_entry_t *clusters,
		struct dlist_entry_t *ranges)
{
	while (!dlist_is_empty(ranges)) {
		struct map_range_t_ *next_range = dlist_entry(
			ranges->next, struct map_range_t_, list);
		struct map_cluster_t_ *last_cluster = dlist_is_empty(clusters) ?
			NULL : dlist_entry(clusters->prev, struct map_cluster_t_, list);
		struct map_range_t_ *last_clustered = (last_cluster == NULL) ?
			NULL : dlist_entry(
				last_cluster->ranges.prev,
				struct map_range_t_, list);

		if ( dlist_is_empty(clusters) ||
			 map_range_is_large_equal_(next_range) ||
			!map_range_can_be_merged_(maps, last_cluster, next_range))
		{
			if ((last_cluster = malloc(sizeof(*last_cluster))) == NULL) {
				return -1;
			}

			last_cluster->illegal_code = ILLEGAL_NOT_SET;
			last_cluster->illegal_code_width = 0;
			dlist_init(&last_cluster->ranges);
			dlist_init(&last_cluster->list);
			dlist_insert_before(clusters, &last_cluster->list);
		}

		dlist_remove(&next_range->list);
		dlist_insert_before(&last_cluster->ranges, &next_range->list);

		if (last_clustered != NULL) {
			/* do not decrease code widths with merged range */

			if (next_range->to_code_width <
					last_clustered->to_code_width)
			{
				next_range->to_code_width =
					last_clustered->to_code_width;
			}

			if (next_range->from_code_width <
					last_clustered->from_code_width)
			{
				next_range->from_code_width =
					last_clustered->from_code_width;
			}
		}
	}

	/* find the maximum code width for a whole cluster */
	struct map_cluster_t_ *c;

	dlist_foreach_entry(c, struct map_cluster_t_, list, clusters) {
		int to_code_width = 0;
		struct map_range_t_ *r;

		dlist_foreach_entry(r, struct map_range_t_, list, &c->ranges) {
			if (to_code_width < r->to_code_width) {
				to_code_width = r->to_code_width;
			}
		}

		dlist_foreach_entry(r, struct map_range_t_, list, &c->ranges) {
			r->to_code_width = to_code_width;
		}

		c->illegal_code_width = to_code_width;
	}
示例#6
0
int psmx2_domain_open(struct fid_fabric *fabric, struct fi_info *info,
		      struct fid_domain **domain, void *context)
{
	struct psmx2_fid_fabric *fabric_priv;
	struct psmx2_fid_domain *domain_priv;
	struct psmx2_ep_name *src_addr = info->src_addr;
	int mr_mode = (info->domain_attr->mr_mode & FI_MR_BASIC) ? FI_MR_BASIC : 0;
	int err;

	FI_INFO(&psmx2_prov, FI_LOG_DOMAIN, "\n");

	fabric_priv = container_of(fabric, struct psmx2_fid_fabric,
				   util_fabric.fabric_fid);

	if (!info->domain_attr->name ||
	    strcmp(info->domain_attr->name, PSMX2_DOMAIN_NAME)) {
		err = -FI_EINVAL;
		goto err_out;
	}

	domain_priv = (struct psmx2_fid_domain *) calloc(1, sizeof *domain_priv);
	if (!domain_priv) {
		err = -FI_ENOMEM;
		goto err_out;
	}

	err = ofi_domain_init(fabric, info, &domain_priv->util_domain, context);
	if (err)
		goto err_out_free_domain;

	/* fclass & context are set in ofi_domain_init */
	domain_priv->util_domain.domain_fid.fid.ops = &psmx2_fi_ops;
	domain_priv->util_domain.domain_fid.ops = &psmx2_domain_ops;
	domain_priv->util_domain.domain_fid.mr = &psmx2_mr_ops;
	domain_priv->mr_mode = mr_mode;
	domain_priv->mode = info->mode;
	domain_priv->caps = PSMX2_CAPS | PSMX2_DOM_CAPS;
	domain_priv->fabric = fabric_priv;
	domain_priv->progress_thread_enabled =
		(info->domain_attr->data_progress == FI_PROGRESS_AUTO);
	domain_priv->addr_format = info->addr_format;

	if (info->addr_format == FI_ADDR_STR)
		src_addr = psmx2_string_to_ep_name(info->src_addr);

	err = psmx2_domain_init(domain_priv, src_addr);
	if (info->addr_format == FI_ADDR_STR)
		free(src_addr);
	if (err)
		goto err_out_close_domain;

	psmx2_fabric_acquire(fabric_priv);
	psmx2_lock(&fabric_priv->domain_lock, 1);
	dlist_insert_before(&domain_priv->entry, &fabric_priv->domain_list);
	psmx2_unlock(&fabric_priv->domain_lock, 1);

	*domain = &domain_priv->util_domain.domain_fid;
	return 0;

err_out_close_domain:
	ofi_domain_close(&domain_priv->util_domain);

err_out_free_domain:
	free(domain_priv);

err_out:
	return err;
}
示例#7
0
static int psmx2_domain_init(struct psmx2_fid_domain *domain,
			     struct psmx2_src_name *src_addr)
{
	int err;

	psmx2_am_global_init();
	psmx2_atomic_global_init();

	domain->base_trx_ctxt = psmx2_trx_ctxt_alloc(domain, src_addr, -1);
	if (!domain->base_trx_ctxt)
		return -FI_ENODEV;

	err = fastlock_init(&domain->mr_lock);
	if (err) {
		FI_WARN(&psmx2_prov, FI_LOG_CORE,
			"fastlock_init(mr_lock) returns %d\n", err);
		goto err_out_free_trx_ctxt;
	}

	domain->mr_map = rbtNew(&psmx2_key_compare);
	if (!domain->mr_map) {
		FI_WARN(&psmx2_prov, FI_LOG_CORE,
			"rbtNew failed\n");
		goto err_out_destroy_mr_lock;
	}

	domain->mr_reserved_key = 1;
	
	err = fastlock_init(&domain->vl_lock);
	if (err) {
		FI_WARN(&psmx2_prov, FI_LOG_CORE,
			"fastlock_init(vl_lock) returns %d\n", err);
		goto err_out_delete_mr_map;
	}
	memset(domain->vl_map, 0, sizeof(domain->vl_map));
	domain->vl_alloc = 0;

	ofi_atomic_initialize32(&domain->sep_cnt, 0);
	fastlock_init(&domain->sep_lock);
	dlist_init(&domain->sep_list);
	dlist_init(&domain->trx_ctxt_list);
	fastlock_init(&domain->trx_ctxt_lock);
	dlist_insert_before(&domain->base_trx_ctxt->entry, &domain->trx_ctxt_list);

	/* Set active domain before psmx2_domain_enable_ep() installs the
	 * AM handlers to ensure that psmx2_active_fabric->active_domain
	 * is always non-NULL inside the handlers. Notice that the vlaue
	 * active_domain becomes NULL again only when the domain is closed.
	 * At that time the AM handlers are gone with the PSM endpoint.
	 */
	domain->fabric->active_domain = domain;

	if (psmx2_domain_enable_ep(domain, NULL) < 0)
		goto err_out_reset_active_domain;

	if (domain->progress_thread_enabled)
		psmx2_domain_start_progress(domain);

	psmx2_am_init(domain->base_trx_ctxt);
	return 0;

err_out_reset_active_domain:
	domain->fabric->active_domain = NULL;
	fastlock_destroy(&domain->vl_lock);

err_out_delete_mr_map:
	rbtDelete(domain->mr_map);

err_out_destroy_mr_lock:
	fastlock_destroy(&domain->mr_lock);

err_out_free_trx_ctxt:
	psmx2_trx_ctxt_free(domain->base_trx_ctxt);
	return err;
}
示例#8
0
static int __gnix_vc_hndl_conn_req(struct gnix_cm_nic *cm_nic,
				   char *msg_buffer,
				   struct gnix_address src_cm_nic_addr)
{
	int ret = FI_SUCCESS;
	gni_return_t __attribute__((unused)) status;
	struct gnix_fid_ep *ep = NULL;
	gnix_ht_key_t *key_ptr;
	struct gnix_av_addr_entry entry;
	struct gnix_address src_addr, target_addr;
	struct gnix_vc *vc = NULL;
	struct gnix_vc *vc_try = NULL;
	struct gnix_work_req *work_req;
	int src_vc_id;
	gni_smsg_attr_t src_smsg_attr;
	uint64_t src_vc_ptr;
	struct wq_hndl_conn_req *data = NULL;

	ssize_t __attribute__((unused)) len;

	GNIX_TRACE(FI_LOG_EP_CTRL, "\n");

	/*
	 * unpack the message
	 */

	__gnix_vc_unpack_conn_req(msg_buffer,
				  &target_addr,
				  &src_addr,
				  &src_vc_id,
				  &src_vc_ptr,
				  &src_smsg_attr);


	GNIX_DEBUG(FI_LOG_EP_CTRL,
		"conn req rx: (From Aries addr 0x%x Id %d to Aries 0x%x Id %d src vc 0x%lx )\n",
		 src_addr.device_addr,
		 src_addr.cdm_id,
		 target_addr.device_addr,
		 target_addr.cdm_id,
		 src_vc_ptr);

	/*
	 * lookup the ep from the addr_to_ep_ht using the target_addr
	 * in the datagram
	 */

	key_ptr = (gnix_ht_key_t *)&target_addr;

	ep = (struct gnix_fid_ep *)_gnix_ht_lookup(cm_nic->addr_to_ep_ht,
						   *key_ptr);
	if (ep == NULL) {
		GNIX_WARN(FI_LOG_EP_DATA,
			  "_gnix_ht_lookup addr_to_ep failed\n");
		ret = -FI_ENOENT;
		goto err;
	}

	/*
	 * look to see if there is a VC already for the
	 * address of the connecting EP.
	 */

	key_ptr = (gnix_ht_key_t *)&src_addr;

	fastlock_acquire(&ep->vc_ht_lock);
	vc = (struct gnix_vc *)_gnix_ht_lookup(ep->vc_ht,
					       *key_ptr);

	/*
 	 * if there is no corresponding vc in the hash,
 	 * or there is an entry and its not in connecting state
 	 * go down the conn req ack route.
 	 */

	if ((vc == NULL)  ||
	    (vc->conn_state == GNIX_VC_CONN_NONE)) {
		if (vc == NULL) {
			entry.gnix_addr = src_addr;
			entry.cm_nic_cdm_id = src_cm_nic_addr.cdm_id;
			ret = _gnix_vc_alloc(ep,
					     &entry,
					     &vc_try);
			if (ret != FI_SUCCESS) {
				GNIX_WARN(FI_LOG_EP_CTRL,
					  "_gnix_vc_alloc returned %s\n",
					  fi_strerror(-ret));
				goto err;
			}

			vc_try->conn_state = GNIX_VC_CONNECTING;
			ret = _gnix_ht_insert(ep->vc_ht,
					      *key_ptr,
					      vc_try);
			if (likely(ret == FI_SUCCESS)) {
				vc = vc_try;
				vc->modes |= GNIX_VC_MODE_IN_HT;
			} else if (ret == -FI_ENOSPC) {
				_gnix_vc_destroy(vc_try);
			} else {
				GNIX_WARN(FI_LOG_EP_DATA,
				  "_gnix_ht_insert returned %s\n",
				   fi_strerror(-ret));
				goto err;
			}
		} else
			vc->conn_state = GNIX_VC_CONNECTING;

		/*
		 * prepare a work request to
		 * initiate an request response
		 */

		work_req = calloc(1, sizeof(*work_req));
		if (work_req == NULL) {
			ret = -FI_ENOMEM;
			goto err;
		}

		data = calloc(1, sizeof(struct wq_hndl_conn_req));
		if (data == NULL) {
			ret = -FI_ENOMEM;
			goto err;
		}
		memcpy(&data->src_smsg_attr,
		       &src_smsg_attr,
		       sizeof(src_smsg_attr));
		data->vc = vc;
		data->src_vc_id = src_vc_id;
		data->src_vc_ptr = src_vc_ptr;

		work_req->progress_fn = __gnix_vc_conn_ack_prog_fn;
		work_req->data = data;
		work_req->completer_fn = __gnix_vc_conn_ack_comp_fn;
		work_req->completer_data = data;

		/*
		 * add the work request to the tail of the
		 * cm_nic's work queue, progress the cm_nic.
		 */


		fastlock_acquire(&cm_nic->wq_lock);
		dlist_insert_before(&work_req->list, &cm_nic->cm_nic_wq);
		fastlock_release(&cm_nic->wq_lock);

		fastlock_release(&ep->vc_ht_lock);

		_gnix_vc_schedule(vc);
		ret = _gnix_cm_nic_progress(cm_nic);
		if (ret != FI_SUCCESS)
			GNIX_WARN(FI_LOG_EP_CTRL,
				"_gnix_cm_nic_progress returned %s\n",
				fi_strerror(-ret));

	} else {

		/*
		 * we can only be in connecting state if we
		 * reach here.  We have all the informatinon,
		 * and the other side will get the information
		 * at some point, so go ahead and build SMSG connection.
		 */
		if (vc->conn_state != GNIX_VC_CONNECTING) {
			GNIX_WARN(FI_LOG_EP_CTRL,
				 "vc %p not in connecting state nor in cm wq\n",
				  vc, vc->conn_state);
			ret = -FI_EINVAL;
			goto err;
		}

		ret = __gnix_vc_smsg_init(vc, src_vc_id,
					  &src_smsg_attr);
		if (ret != FI_SUCCESS) {
			GNIX_WARN(FI_LOG_EP_CTRL,
				  "_gnix_vc_smsg_init returned %s\n",
				  fi_strerror(-ret));
			goto err;
		}

		vc->conn_state = GNIX_VC_CONNECTED;
		GNIX_DEBUG(FI_LOG_EP_CTRL, "moving vc %p state to connected\n",
			vc);

		fastlock_release(&ep->vc_ht_lock);

		ret = _gnix_vc_schedule(vc);
		ret = _gnix_cm_nic_progress(cm_nic);
		if (ret != FI_SUCCESS)
			GNIX_WARN(FI_LOG_EP_CTRL,
				"_gnix_cm_nic_progress returned %s\n",
				fi_strerror(-ret));
	}
err:
	return ret;
}
示例#9
0
int _gnix_vc_connect(struct gnix_vc *vc)
{
	int ret = FI_SUCCESS;
	struct gnix_fid_ep *ep = NULL;
	struct gnix_cm_nic *cm_nic = NULL;
	struct gnix_work_req *work_req;

	GNIX_TRACE(FI_LOG_EP_CTRL, "\n");

	/*
	 * can happen that we are already connecting, or
	 * are connected
	 */

	if ((vc->conn_state == GNIX_VC_CONNECTING) ||
		(vc->conn_state == GNIX_VC_CONNECTED)) {
		return FI_SUCCESS;
	}

	ep = vc->ep;
	if (ep == NULL)
		return -FI_EINVAL;

	cm_nic = ep->cm_nic;
	if (cm_nic == NULL)
		return -FI_EINVAL;

	/*
	 * only endpoints of type FI_EP_RDM use this
	 * connection method
	 */
	if (ep->type != FI_EP_RDM)
		return -FI_EINVAL;

	/*
	 * have to do something special for
	 * connect to same cm_nic
	 */

	if (!memcmp(&vc->peer_cm_nic_addr,
		   &cm_nic->my_name.gnix_addr,
		   sizeof(struct gnix_address))) {
		return  __gnix_vc_connect_to_same_cm_nic(vc);
	}

	/*
	 * allocate a work request and try to
	 * run the progress function once.  If it
	 * doesn't succeed, put it on the cm_nic work queue.
	 */

	work_req = calloc(1, sizeof(*work_req));
	if (work_req == NULL)
		return -FI_ENOMEM;

	work_req->progress_fn = __gnix_vc_conn_req_prog_fn;
	work_req->data = vc;
	work_req->completer_fn = __gnix_vc_conn_req_comp_fn;
	work_req->completer_data = vc;

	/*
	 * add the work request to the tail of the
	 * cm_nic's work queue, progress the cm_nic.
	 */

	fastlock_acquire(&cm_nic->wq_lock);
	dlist_insert_before(&work_req->list, &cm_nic->cm_nic_wq);
	fastlock_release(&cm_nic->wq_lock);

	ret = _gnix_vc_schedule(vc);

	return ret;
}
示例#10
0
int _gnix_cm_nic_send(struct gnix_cm_nic *cm_nic,
		      char *sbuf, size_t len,
		      struct gnix_address target_addr)
{
	int ret = FI_SUCCESS;
	struct gnix_datagram *dgram = NULL;
	ssize_t  __attribute__((unused)) plen;
	uint8_t tag;
	struct gnix_work_req *work_req;

	GNIX_TRACE(FI_LOG_EP_CTRL, "\n");

	if ((cm_nic == NULL) || (sbuf == NULL))
		return -FI_EINVAL;

	if (len > GNI_DATAGRAM_MAXSIZE)
		return -FI_ENOSPC;

	ret = _gnix_dgram_alloc(cm_nic->dgram_hndl,
				GNIX_DGRAM_BND,
				&dgram);
	if (ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "_gnix_dgram_alloc returned %s\n",
			  fi_strerror(-ret));
		goto exit;
	}

	dgram->target_addr = target_addr;
	dgram->callback_fn = __process_datagram;
	dgram->cache = cm_nic;

	tag = GNIX_CM_NIC_BND_TAG;
	 __dgram_set_tag(dgram, tag);

	plen = _gnix_dgram_pack_buf(dgram, GNIX_DGRAM_IN_BUF,
				   sbuf, len);
	assert (plen == len);

	/* If connecting with the same CM NIC, skip datagram exchange.  The
	 * caller could be holding an endpoint lock, so schedule connection
	 * completion for later. */
	if (GNIX_ADDR_EQUAL(target_addr, cm_nic->my_name.gnix_addr)) {
		char tmp_buf[GNIX_CM_NIC_MAX_MSG_SIZE];

		/* Pack output buffer with input data. */
		_gnix_dgram_unpack_buf(dgram, GNIX_DGRAM_IN_BUF, tmp_buf,
				       GNIX_CM_NIC_MAX_MSG_SIZE);
		_gnix_dgram_pack_buf(dgram, GNIX_DGRAM_OUT_BUF, tmp_buf,
				       GNIX_CM_NIC_MAX_MSG_SIZE);

		work_req = calloc(1, sizeof(*work_req));
		if (work_req == NULL) {
			_gnix_dgram_free(dgram);
			return -FI_ENOMEM;
		}

		work_req->progress_fn = __gnix_cm_nic_intra_progress_fn;
		work_req->data = dgram;
		work_req->completer_fn = NULL;

		fastlock_acquire(&cm_nic->wq_lock);
		dlist_insert_before(&work_req->list, &cm_nic->cm_nic_wq);
		fastlock_release(&cm_nic->wq_lock);

		GNIX_INFO(FI_LOG_EP_CTRL, "Initiated intra-CM NIC connect\n");
	} else {
		ret = _gnix_dgram_bnd_post(dgram);
		if (ret == -FI_EBUSY) {
			ret = -FI_EAGAIN;
			_gnix_dgram_free(dgram);
		}
	}

exit:
	return ret;
}
示例#11
0
int _gnix_cm_nic_progress(void *arg)
{
	struct gnix_cm_nic *cm_nic = (struct gnix_cm_nic *)arg;
	int ret = FI_SUCCESS;
	int complete;
	struct gnix_work_req *p = NULL;

	/*
	 * if we're doing FI_PROGRESS_MANUAL,
	 * see what's going on inside kgni's datagram
	 * box...
	 */

	if (cm_nic->ctrl_progress == FI_PROGRESS_MANUAL) {
		++cm_nic->poll_cnt;
		if (((cm_nic->poll_cnt % 512) == 0)  ||
			!dlist_empty(&cm_nic->cm_nic_wq)) {
			ret = _gnix_dgram_poll(cm_nic->dgram_hndl,
						  GNIX_DGRAM_NOBLOCK);
			if (ret != FI_SUCCESS) {
				GNIX_WARN(FI_LOG_EP_CTRL,
					"_gnix_dgram_poll returned %s\n",
					  fi_strerror(-ret));
					goto err;
			}
		}
	}

	/*
	 * do a quick check if queue doesn't have anything yet,
	 * don't need this to be atomic
	 */

check_again:
	if (dlist_empty(&cm_nic->cm_nic_wq))
		return ret;

	/*
	 * okay, stuff to do, lock work queue,
	 * dequeue head, unlock, process work element,
	 * if it doesn't compete, put back at the tail
	 * of the queue.
	 */

	fastlock_acquire(&cm_nic->wq_lock);
	p = dlist_first_entry(&cm_nic->cm_nic_wq, struct gnix_work_req,
			      list);
	if (p == NULL) {
		fastlock_release(&cm_nic->wq_lock);
		return ret;
	}

	dlist_remove_init(&p->list);
	fastlock_release(&cm_nic->wq_lock);

	assert(p->progress_fn);

	ret = p->progress_fn(p->data, &complete);
	if (ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "dgram prog fn returned %s\n",
			  fi_strerror(-ret));
	}

	if (complete == 1) {
		if (p->completer_fn) {
			ret = p->completer_fn(p->completer_data);
			free(p);
			if (ret != FI_SUCCESS) {
				GNIX_WARN(FI_LOG_EP_CTRL,
					  "dgram completer fn returned %s\n",
					  fi_strerror(-ret));
				goto err;
			}
		} else {
			free(p);
		}
		goto check_again;
	} else {
		fastlock_acquire(&cm_nic->wq_lock);
		dlist_insert_before(&p->list, &cm_nic->cm_nic_wq);
		fastlock_release(&cm_nic->wq_lock);
	}

err:
	return ret;
}