Blame ptl_ips/ptl.c

Packit 961e70
/*
Packit 961e70
Packit 961e70
  This file is provided under a dual BSD/GPLv2 license.  When using or
Packit 961e70
  redistributing this file, you may do so under either license.
Packit 961e70
Packit 961e70
  GPL LICENSE SUMMARY
Packit 961e70
Packit 961e70
  Copyright(c) 2015 Intel Corporation.
Packit 961e70
Packit 961e70
  This program is free software; you can redistribute it and/or modify
Packit 961e70
  it under the terms of version 2 of the GNU General Public License as
Packit 961e70
  published by the Free Software Foundation.
Packit 961e70
Packit 961e70
  This program is distributed in the hope that it will be useful, but
Packit 961e70
  WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 961e70
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 961e70
  General Public License for more details.
Packit 961e70
Packit 961e70
  Contact Information:
Packit 961e70
  Intel Corporation, www.intel.com
Packit 961e70
Packit 961e70
  BSD LICENSE
Packit 961e70
Packit 961e70
  Copyright(c) 2015 Intel Corporation.
Packit 961e70
Packit 961e70
  Redistribution and use in source and binary forms, with or without
Packit 961e70
  modification, are permitted provided that the following conditions
Packit 961e70
  are met:
Packit 961e70
Packit 961e70
    * Redistributions of source code must retain the above copyright
Packit 961e70
      notice, this list of conditions and the following disclaimer.
Packit 961e70
    * Redistributions in binary form must reproduce the above copyright
Packit 961e70
      notice, this list of conditions and the following disclaimer in
Packit 961e70
      the documentation and/or other materials provided with the
Packit 961e70
      distribution.
Packit 961e70
    * Neither the name of Intel Corporation nor the names of its
Packit 961e70
      contributors may be used to endorse or promote products derived
Packit 961e70
      from this software without specific prior written permission.
Packit 961e70
Packit 961e70
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 961e70
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 961e70
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit 961e70
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit 961e70
  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit 961e70
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 961e70
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 961e70
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 961e70
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 961e70
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 961e70
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 961e70
Packit 961e70
*/
Packit 961e70
Packit 961e70
/* Copyright (c) 2003-2014 Intel Corporation. All rights reserved. */
Packit 961e70
Packit 961e70
/* This file implements the PSM PTL for ips */
Packit 961e70
#include "psm_user.h"
Packit 961e70
#include "psm2_hal.h"
Packit 961e70
#include "ptl_ips.h"
Packit 961e70
#include "psm_mq_internal.h"
Packit 961e70
Packit 961e70
int ips_ptl_recvq_isempty(const struct ptl *ptl);
Packit 961e70
Packit 961e70
static
Packit 961e70
int
Packit 961e70
ips_subcontext_ignore(struct ips_recvhdrq_event *rcv_ev,
Packit 961e70
		      uint32_t subcontext)
Packit 961e70
{
Packit 961e70
	return IPS_RECVHDRQ_CONTINUE;
Packit 961e70
}
Packit 961e70
Packit 961e70
static
Packit 961e70
int
Packit 961e70
ips_subcontext_process(struct ips_recvhdrq_event *rcv_ev,
Packit 961e70
		       uint32_t subcontext)
Packit 961e70
{
Packit 961e70
	struct ptl_shared *recvshc = ((struct ptl_ips *)(rcv_ev->proto->ptl))->recvshc;
Packit 961e70
	if_pt(subcontext != recvshc->subcontext &&
Packit 961e70
	      subcontext < recvshc->subcontext_cnt) {
Packit 961e70
		return psmi_hal_forward_packet_to_subcontext(&recvshc->writeq[subcontext],
Packit 961e70
							     rcv_ev, subcontext,
Packit 961e70
							     rcv_ev->recvq->context->psm_hw_ctxt);
Packit 961e70
	}
Packit 961e70
	else {
Packit 961e70
		_HFI_VDBG
Packit 961e70
			("Drop pkt for subcontext %d out of %d (I am %d) : errors 0x%x\n",
Packit 961e70
			 (int)subcontext, (int)recvshc->subcontext_cnt,
Packit 961e70
			 (int)recvshc->subcontext, psmi_hal_rhf_get_all_err_flags(rcv_ev->psm_hal_rhf));
Packit 961e70
                return IPS_RECVHDRQ_BREAK;
Packit 961e70
	}
Packit 961e70
}
Packit 961e70
Packit 961e70
static psm2_error_t shrecvq_init(ptl_t *ptl, const psmi_context_t *context);
Packit 961e70
static psm2_error_t shrecvq_fini(ptl_t *ptl);
Packit 961e70
Packit 961e70
static size_t ips_ptl_sizeof(void)
Packit 961e70
{
Packit 961e70
	return sizeof(struct ptl_ips);
Packit 961e70
}
Packit 961e70
Packit 961e70
static
Packit 961e70
int ips_ptl_epaddr_stats_num(void)
Packit 961e70
{
Packit 961e70
	return sizeof(struct ips_proto_epaddr_stats) / sizeof(uint64_t);
Packit 961e70
}
Packit 961e70
Packit 961e70
static
Packit 961e70
int ips_ptl_epaddr_stats_init(char **desc, uint16_t *flags)
Packit 961e70
{
Packit 961e70
	int num_stats =
Packit 961e70
	    sizeof(struct ips_proto_epaddr_stats) / sizeof(uint64_t);
Packit 961e70
	int i;
Packit 961e70
Packit 961e70
	/* All stats are uint64_t */
Packit 961e70
	for (i = 0; i < num_stats; i++)
Packit 961e70
		flags[i] = MPSPAWN_STATS_REDUCTION_ALL |
Packit 961e70
		    MPSPAWN_STATS_SKIP_IF_ZERO;
Packit 961e70
Packit 961e70
	desc[0] = "errchecks sent";
Packit 961e70
	desc[1] = "errchecks recv";
Packit 961e70
	desc[2] = "naks sent";
Packit 961e70
	desc[3] = "naks recv";
Packit 961e70
	desc[4] = "connect reqs sent";
Packit 961e70
	desc[5] = "disconnect reqs sent";
Packit 961e70
	desc[6] = "tid grants sent";
Packit 961e70
	desc[7] = "tid grants recv";
Packit 961e70
	desc[8] = "send rexmit";
Packit 961e70
	desc[9] = "congestion packets";
Packit 961e70
Packit 961e70
	return num_stats;
Packit 961e70
}
Packit 961e70
Packit 961e70
int ips_ptl_epaddr_stats_get(psm2_epaddr_t epaddr, uint64_t *stats_o)
Packit 961e70
{
Packit 961e70
	int i, num_stats =
Packit 961e70
	    sizeof(struct ips_proto_epaddr_stats) / sizeof(uint64_t);
Packit 961e70
	uint64_t *stats_i = (uint64_t *) &epaddr->proto->epaddr_stats;
Packit 961e70
Packit 961e70
	for (i = 0; i < num_stats; i++)
Packit 961e70
		stats_o[i] = stats_i[i];
Packit 961e70
Packit 961e70
	return num_stats;
Packit 961e70
}
Packit 961e70
Packit 961e70
static
Packit 961e70
psm2_error_t
Packit 961e70
psmi_context_check_status_callback(struct psmi_timer *t, uint64_t current)
Packit 961e70
{
Packit 961e70
	struct ptl_ips *ptl = (struct ptl_ips *)t->context;
Packit 961e70
	const uint64_t current_count = get_cycles();
Packit 961e70
	psm2_error_t err;
Packit 961e70
Packit 961e70
	err = psmi_context_check_status(ptl->context);
Packit 961e70
	if (err == PSM2_OK || err == PSM2_OK_NO_PROGRESS)
Packit 961e70
	{
Packit 961e70
		int rc = psmi_hal_spio_process_events((struct ptl *)ptl);
Packit 961e70
		err = rc >= 0 ? PSM2_OK : PSM2_INTERNAL_ERR;
Packit 961e70
	}
Packit 961e70
	psmi_timer_request_always(&ptl->timerq, &ptl->status_timer,
Packit 961e70
				  current_count + ptl->status_cyc_timeout);
Packit 961e70
Packit 961e70
	return err;
Packit 961e70
}
Packit 961e70
Packit 961e70
static
Packit 961e70
psm2_error_t ips_ptl_init(const psm2_ep_t ep, ptl_t *ptl_gen, ptl_ctl_t *ctl)
Packit 961e70
{
Packit 961e70
	struct ptl_ips *ptl = (struct ptl_ips *)ptl_gen;
Packit 961e70
	psm2_error_t err = PSM2_OK;
Packit 961e70
	uint32_t num_of_send_bufs = ep->hfi_num_sendbufs;
Packit 961e70
	uint32_t num_of_send_desc = ep->hfi_num_descriptors;
Packit 961e70
	uint32_t imm_size = ep->hfi_imm_size;
Packit 961e70
	const psmi_context_t *context = &ep->context;
Packit 961e70
	const int enable_shcontexts = (psmi_hal_get_subctxt_cnt(context->psm_hw_ctxt) > 0);
Packit 961e70
	const uint64_t current_count = get_cycles();
Packit 961e70
Packit 961e70
	/* Preconditions */
Packit 961e70
	psmi_assert_always(ep != NULL);
Packit 961e70
	psmi_assert_always(ep->epaddr != NULL);
Packit 961e70
	psmi_assert_always(ep->epid != 0);
Packit 961e70
	psmi_assert_always(ep->hfi_num_sendbufs > 0);
Packit 961e70
Packit 961e70
	memset(ptl, 0, sizeof(struct ptl_ips));
Packit 961e70
Packit 961e70
	ptl->ep = ep;		/* back pointer */
Packit 961e70
	ptl->epid = ep->epid;	/* cache epid */
Packit 961e70
	ptl->epaddr = ep->epaddr;	/* cache a copy */
Packit 961e70
	ptl->ctl = ctl;
Packit 961e70
	ptl->context = context;
Packit 961e70
Packit 961e70
	memset(ctl, 0, sizeof(*ctl));
Packit 961e70
	/* Fill in the control structure */
Packit 961e70
	ctl->ep = ep;
Packit 961e70
	ctl->ptl = ptl_gen;
Packit 961e70
	ctl->ep_poll = enable_shcontexts ? ips_ptl_shared_poll : ips_ptl_poll;
Packit 961e70
	ctl->ep_connect = ips_ptl_connect;
Packit 961e70
	ctl->ep_disconnect = ips_ptl_disconnect;
Packit 961e70
	ctl->mq_send = ips_proto_mq_send;
Packit 961e70
	ctl->mq_isend = ips_proto_mq_isend;
Packit 961e70
Packit 961e70
	ctl->am_get_parameters = ips_am_get_parameters;
Packit 961e70
Packit 961e70
	ctl->am_short_request = ips_am_short_request;
Packit 961e70
	ctl->am_short_reply = ips_am_short_reply;
Packit 961e70
Packit 961e70
	ctl->epaddr_stats_num = ips_ptl_epaddr_stats_num;
Packit 961e70
	ctl->epaddr_stats_init = ips_ptl_epaddr_stats_init;
Packit 961e70
	ctl->epaddr_stats_get = ips_ptl_epaddr_stats_get;
Packit 961e70
Packit 961e70
	ctl->msg_size_thresh_query = ips_proto_msg_size_thresh_query;
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * Runtime flags in 'ptl' are different from runtime flags in 'context'.
Packit 961e70
	 * In 'context', runtime flags reflect what the driver is capable of.
Packit 961e70
	 * In 'ptl', runtime flags reflect the features we can or want to use in
Packit 961e70
	 *           the driver's supported runtime flags.
Packit 961e70
	 */
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * This timer is to be used to check the context's status at every
Packit 961e70
	 * PSMI_CONTEXT_STATUS_CHECK_INTERVAL_MSECS.  This is useful to detect when
Packit 961e70
	 * the link transitions from the DOWN state to the UP state.  We can thus
Packit 961e70
	 * stop aggregating link failure messages once we detect that the link is
Packit 961e70
	 * up.
Packit 961e70
	 */
Packit 961e70
	psmi_timer_entry_init(&ptl->status_timer,
Packit 961e70
			      psmi_context_check_status_callback, ptl);
Packit 961e70
Packit 961e70
	/* cache the context's status timeout in cycles */
Packit 961e70
	ptl->status_cyc_timeout =
Packit 961e70
	    ms_2_cycles(PSMI_CONTEXT_STATUS_CHECK_INTERVAL_MSECS);
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * Retransmissions and pending operations are kept in a timer structure
Packit 961e70
	 * (queue).  The timerq is shared to various internal IPS interfaces so
Packit 961e70
	 * that they too may schedule events on the timer queue.  The timerq is
Packit 961e70
	 * drained in the progress function.
Packit 961e70
	 */
Packit 961e70
	if ((err = psmi_timer_init(&ptl->timerq)))
Packit 961e70
		goto fail;
Packit 961e70
Packit 961e70
	/* start the context's status timer */
Packit 961e70
	psmi_timer_request_always(&ptl->timerq, &ptl->status_timer,
Packit 961e70
				  current_count + ptl->status_cyc_timeout);
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * Epstate maps endpoint ids (epid integers) to ipsaddr (structs). Mappings
Packit 961e70
	 * are added/removed by the connect portion of the ips protocol and lookup
Packit 961e70
	 * is made by the receive queue processing component.
Packit 961e70
	 */
Packit 961e70
	if ((err = ips_epstate_init(&ptl->epstate, context)))
Packit 961e70
		goto fail;
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * Context sharing, setup subcontext ureg page.
Packit 961e70
	 */
Packit 961e70
	if (enable_shcontexts) {
Packit 961e70
		struct ptl_shared *recvshc;
Packit 961e70
Packit 961e70
		recvshc = (struct ptl_shared *)
Packit 961e70
		    psmi_calloc(ep, UNDEFINED, 1, sizeof(struct ptl_shared));
Packit 961e70
		if (recvshc == NULL) {
Packit 961e70
			err = PSM2_NO_MEMORY;
Packit 961e70
			goto fail;
Packit 961e70
		}
Packit 961e70
Packit 961e70
		ptl->recvshc = recvshc;
Packit 961e70
		recvshc->ptl = ptl_gen;
Packit 961e70
Packit 961e70
		/* Initialize recvshc fields */
Packit 961e70
		recvshc->context = psmi_hal_get_context(context->psm_hw_ctxt);
Packit 961e70
		recvshc->subcontext = psmi_hal_get_subctxt(context->psm_hw_ctxt);
Packit 961e70
		recvshc->subcontext_cnt = psmi_hal_get_subctxt_cnt(context->psm_hw_ctxt);
Packit 961e70
		psmi_assert_always(recvshc->subcontext_cnt <=
Packit 961e70
				   PSM_HAL_MAX_SHARED_CTXTS);
Packit 961e70
		psmi_assert_always(recvshc->subcontext <
Packit 961e70
				   recvshc->subcontext_cnt);
Packit 961e70
Packit 961e70
		/*
Packit 961e70
		 * Using ep->context to avoid const modifier since this function
Packit 961e70
		 * will modify the content in ep->context.
Packit 961e70
		 */
Packit 961e70
		if ((err = psmi_hal_subcontext_ureg_get(ptl_gen,
Packit 961e70
							recvshc->subcontext_ureg, context->psm_hw_ctxt)))
Packit 961e70
			goto fail;
Packit 961e70
Packit 961e70
		/* Note that the GEN1 HAL instance initializes struct ips_subcontext_ureg
Packit 961e70
		   during context open. */
Packit 961e70
Packit 961e70
		recvshc->context_lock = &recvshc->hwcontext_ctrl->context_lock;
Packit 961e70
		if (recvshc->subcontext == 0) {
Packit 961e70
			if (pthread_spin_init(recvshc->context_lock,
Packit 961e70
					      PTHREAD_PROCESS_SHARED) != 0) {
Packit 961e70
				err =
Packit 961e70
				    psmi_handle_error(ptl->ep,
Packit 961e70
						      PSM2_EP_DEVICE_FAILURE,
Packit 961e70
						      "Couldn't initialize process-shared spin lock");
Packit 961e70
				goto fail;
Packit 961e70
			}
Packit 961e70
		}
Packit 961e70
	}
Packit 961e70
	/*
Packit 961e70
	 * Hardware send pio used by eager and control messages.
Packit 961e70
	 */
Packit 961e70
	if ((err = psmi_hal_spio_init(context, ptl_gen, &ptl->spioc)))
Packit 961e70
		goto fail;
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * Actual ips protocol handling.
Packit 961e70
	 */
Packit 961e70
	if ((err =
Packit 961e70
	     ips_proto_init(context, ptl_gen, num_of_send_bufs, num_of_send_desc,
Packit 961e70
			    imm_size, &ptl->timerq, &ptl->epstate, ptl->spioc,
Packit 961e70
			    &ptl->proto)))
Packit 961e70
		goto fail;
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * Hardware receive hdr/egr queue, services incoming packets and issues
Packit 961e70
	 * callbacks for protocol handling in proto_recv.  It uses the epstate
Packit 961e70
	 * interface to determine if a packet is known or unknown.
Packit 961e70
	 */
Packit 961e70
	if (!enable_shcontexts) {
Packit 961e70
		struct ips_recvhdrq_callbacks recvq_callbacks;
Packit 961e70
		recvq_callbacks.callback_packet_unknown =
Packit 961e70
		    ips_proto_process_unknown;
Packit 961e70
		recvq_callbacks.callback_subcontext = ips_subcontext_ignore;
Packit 961e70
		recvq_callbacks.callback_error = ips_proto_process_packet_error;
Packit 961e70
		if ((err =
Packit 961e70
		     ips_recvhdrq_init(context, &ptl->epstate, &ptl->proto,
Packit 961e70
				       &recvq_callbacks,
Packit 961e70
				       0, &ptl->recvq,
Packit 961e70
				       &ptl->recvq_state,
Packit 961e70
				       PSM_HAL_CL_Q_RX_HDR_Q)))
Packit 961e70
			goto fail;
Packit 961e70
	}
Packit 961e70
	/*
Packit 961e70
	 * Software receive hdr/egr queue, used in shared contexts.
Packit 961e70
	 */
Packit 961e70
	else if ((err = shrecvq_init(ptl_gen, context)))
Packit 961e70
		goto fail;
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * Receive thread, always initialized but not necessary creates a
Packit 961e70
	 * pthread.
Packit 961e70
	 */
Packit 961e70
	if ((err = ips_ptl_rcvthread_init(ptl_gen, &ptl->recvq)))
Packit 961e70
		goto fail;
Packit 961e70
fail:
Packit 961e70
	return err;
Packit 961e70
}
Packit 961e70
Packit 961e70
static psm2_error_t ips_ptl_fini(ptl_t *ptl_gen, int force, uint64_t timeout_in)
Packit 961e70
{
Packit 961e70
	struct ptl_ips *ptl = (struct ptl_ips *)ptl_gen;
Packit 961e70
	psm2_error_t err = PSM2_OK;
Packit 961e70
	const int enable_shcontexts = (psmi_hal_get_subctxt_cnt(ptl->context->psm_hw_ctxt) > 0);
Packit 961e70
Packit 961e70
	if ((err = ips_proto_fini(&ptl->proto, force, timeout_in)))
Packit 961e70
		goto fail;
Packit 961e70
Packit 961e70
	/* We have to cancel the thread after terminating the protocol because
Packit 961e70
	 * connect/disconnect packets use interrupts and the kernel doesn't
Packit 961e70
	 * like to have no pollers waiting */
Packit 961e70
	if ((err = ips_ptl_rcvthread_fini(ptl_gen)))
Packit 961e70
		goto fail;
Packit 961e70
Packit 961e70
	if ((err = ips_epstate_fini(&ptl->epstate)))
Packit 961e70
		goto fail;
Packit 961e70
Packit 961e70
	if ((err = psmi_hal_spio_fini(&ptl->spioc, ptl->context->psm_hw_ctxt)))
Packit 961e70
		goto fail;
Packit 961e70
Packit 961e70
	if ((err = psmi_timer_fini(&ptl->timerq)))
Packit 961e70
		goto fail;
Packit 961e70
Packit 961e70
Packit 961e70
	if (enable_shcontexts && (err = shrecvq_fini(ptl_gen)))
Packit 961e70
		goto fail;
Packit 961e70
Packit 961e70
fail:
Packit 961e70
	return err;
Packit 961e70
}
Packit 961e70
Packit 961e70
static
Packit 961e70
psm2_error_t
Packit 961e70
ips_ptl_optctl(const void *core_obj, int optname,
Packit 961e70
	       void *optval, uint64_t *optlen, int get)
Packit 961e70
{
Packit 961e70
	psm2_error_t err = PSM2_OK;
Packit 961e70
Packit 961e70
	switch (optname) {
Packit 961e70
	case PSM2_IB_OPT_EP_SL:
Packit 961e70
		{
Packit 961e70
			/* Core object is psm2_epaddr */
Packit 961e70
			psm2_epaddr_t epaddr = (psm2_epaddr_t) core_obj;
Packit 961e70
			ips_epaddr_t *ipsaddr = (ips_epaddr_t *) epaddr;
Packit 961e70
Packit 961e70
			/* If endpoint does not use IB ignore for set, complain for get */
Packit 961e70
			if (epaddr->ptlctl->ep_connect != ips_ptl_connect) {
Packit 961e70
				if (get)
Packit 961e70
					err =
Packit 961e70
					    psmi_handle_error(PSMI_EP_LOGEVENT,
Packit 961e70
							      PSM2_PARAM_ERR,
Packit 961e70
							      "Invalid EP transport");
Packit 961e70
				goto exit_fn;
Packit 961e70
			}
Packit 961e70
Packit 961e70
			/* Sanity check option length */
Packit 961e70
			if (*optlen < sizeof(uint8_t)) {
Packit 961e70
				err =
Packit 961e70
				    psmi_handle_error(PSMI_EP_LOGEVENT,
Packit 961e70
						      PSM2_PARAM_ERR,
Packit 961e70
						      "Option value length error");
Packit 961e70
				*optlen = sizeof(unsigned);
Packit 961e70
				goto exit_fn;
Packit 961e70
			}
Packit 961e70
Packit 961e70
			if (get) {
Packit 961e70
				/* Get returns the SL for the PIO flow */
Packit 961e70
				*((uint8_t *) optval) =
Packit 961e70
				    (uint8_t) ipsaddr->
Packit 961e70
				    flows[EP_FLOW_GO_BACK_N_PIO].path->pr_sl;
Packit 961e70
			} else {
Packit 961e70
				uint16_t new_sl;
Packit 961e70
Packit 961e70
				/* Sanity check if SL is within range */
Packit 961e70
				new_sl = (uint16_t) *(uint8_t *) optval;
Packit 961e70
				if (new_sl > PSMI_SL_MAX) {
Packit 961e70
					err =
Packit 961e70
					    psmi_handle_error(PSMI_EP_LOGEVENT,
Packit 961e70
						      PSM2_PARAM_ERR,
Packit 961e70
						      "Invalid SL value %u. %d<= SL <=%d.",
Packit 961e70
						      new_sl, PSMI_SL_MIN, PSMI_SL_MAX);
Packit 961e70
					goto exit_fn;
Packit 961e70
				}
Packit 961e70
Packit 961e70
				/* Set new SL for all flows */
Packit 961e70
				ipsaddr->flows[EP_FLOW_GO_BACK_N_PIO].path->
Packit 961e70
				    pr_sl = new_sl;
Packit 961e70
				ipsaddr->flows[EP_FLOW_GO_BACK_N_DMA].path->
Packit 961e70
				    pr_sl = new_sl;
Packit 961e70
			}
Packit 961e70
		}
Packit 961e70
		break;
Packit 961e70
	case PSM2_IB_OPT_DF_SL:
Packit 961e70
		{
Packit 961e70
			/* Set default SL to be used by an endpoint for all communication */
Packit 961e70
			/* Core object is psm2_epaddr */
Packit 961e70
			psm2_ep_t ep = (psm2_ep_t) core_obj;
Packit 961e70
Packit 961e70
			/* Make sure ep is specified */
Packit 961e70
			if (!ep) {
Packit 961e70
				err =
Packit 961e70
				    psmi_handle_error(PSMI_EP_LOGEVENT,
Packit 961e70
						      PSM2_PARAM_ERR,
Packit 961e70
						      "Invalid PSM Endpoint");
Packit 961e70
				goto exit_fn;
Packit 961e70
			}
Packit 961e70
Packit 961e70
			/* Sanity check option length */
Packit 961e70
			if (*optlen < sizeof(uint8_t)) {
Packit 961e70
				err =
Packit 961e70
				    psmi_handle_error(PSMI_EP_LOGEVENT,
Packit 961e70
						      PSM2_PARAM_ERR,
Packit 961e70
						      "Option value length error");
Packit 961e70
				*optlen = sizeof(uint8_t);
Packit 961e70
				goto exit_fn;
Packit 961e70
			}
Packit 961e70
Packit 961e70
			if (get) {
Packit 961e70
				*((uint8_t *) optval) =
Packit 961e70
					((struct ptl_ips *)(ep->ptl_ips.ptl))->proto.epinfo.ep_sl;
Packit 961e70
			} else {
Packit 961e70
				uint16_t new_sl;
Packit 961e70
Packit 961e70
				/* Sanity check if SL is within range */
Packit 961e70
				new_sl = (uint16_t) *(uint8_t *) optval;
Packit 961e70
				if (new_sl > PSMI_SL_MAX) {
Packit 961e70
					err =
Packit 961e70
					    psmi_handle_error(PSMI_EP_LOGEVENT,
Packit 961e70
						      PSM2_PARAM_ERR,
Packit 961e70
						      "Invalid SL value %u. %d<= SL <=%d.",
Packit 961e70
						      new_sl, PSMI_SL_MIN, PSMI_SL_MAX);
Packit 961e70
					goto exit_fn;
Packit 961e70
				}
Packit 961e70
Packit 961e70
				((struct ptl_ips *)(ep->ptl_ips.ptl))->proto.epinfo.ep_sl =
Packit 961e70
				    (uint8_t) new_sl;
Packit 961e70
			}
Packit 961e70
		}
Packit 961e70
		break;
Packit 961e70
	default:
Packit 961e70
		err =
Packit 961e70
		    psmi_handle_error(NULL, PSM2_PARAM_ERR,
Packit 961e70
				      "Unknown PSM2_IB option %u.", optname);
Packit 961e70
	}
Packit 961e70
Packit 961e70
exit_fn:
Packit 961e70
	return err;
Packit 961e70
}
Packit 961e70
Packit 961e70
static
Packit 961e70
psm2_error_t
Packit 961e70
ips_ptl_setopt(const void *component_obj, int optname,
Packit 961e70
	       const void *optval, uint64_t optlen)
Packit 961e70
{
Packit 961e70
	return ips_ptl_optctl(component_obj, optname, (void *)optval, &optlen,
Packit 961e70
			      0);
Packit 961e70
}
Packit 961e70
Packit 961e70
static
Packit 961e70
psm2_error_t
Packit 961e70
ips_ptl_getopt(const void *component_obj, int optname,
Packit 961e70
	       void *optval, uint64_t *optlen)
Packit 961e70
{
Packit 961e70
	return ips_ptl_optctl(component_obj, optname, optval, optlen, 1);
Packit 961e70
}
Packit 961e70
Packit 961e70
static
Packit 961e70
uint32_t
Packit 961e70
ips_ptl_rcvthread_is_enabled(const ptl_t *ptl)
Packit 961e70
{
Packit 961e70
	return psmi_hal_has_sw_status(PSM_HAL_PSMI_RUNTIME_RX_THREAD_STARTED);
Packit 961e70
}
Packit 961e70
Packit 961e70
psm2_error_t ips_ptl_poll(ptl_t *ptl_gen, int _ignored)
Packit 961e70
{
Packit 961e70
	struct ptl_ips *ptl = (struct ptl_ips *)ptl_gen;
Packit 961e70
	const uint64_t current_count = get_cycles();
Packit 961e70
	const int do_lock = PSMI_LOCK_DISABLED &&
Packit 961e70
		psmi_hal_has_sw_status(PSM_HAL_PSMI_RUNTIME_RX_THREAD_STARTED);
Packit 961e70
	psm2_error_t err = PSM2_OK_NO_PROGRESS;
Packit 961e70
	psm2_error_t err2;
Packit 961e70
Packit 961e70
	if (!ips_recvhdrq_isempty(&ptl->recvq)) {
Packit 961e70
		if (do_lock && !ips_recvhdrq_trylock(&ptl->recvq))
Packit 961e70
			return err;
Packit 961e70
		if (ptl->recvq.proto->flags & IPS_PROTO_FLAG_CCA_PRESCAN) {
Packit 961e70
			ips_recvhdrq_scan_cca(&ptl->recvq);
Packit 961e70
		}
Packit 961e70
		err = ips_recvhdrq_progress(&ptl->recvq);
Packit 961e70
		if (do_lock)
Packit 961e70
			ips_recvhdrq_unlock(&ptl->recvq);
Packit 961e70
		if_pf(err > PSM2_OK_NO_PROGRESS)
Packit 961e70
		    return err;
Packit 961e70
		err2 =
Packit 961e70
		    psmi_timer_process_if_expired(&(ptl->timerq),
Packit 961e70
						  current_count);
Packit 961e70
		if (err2 != PSM2_OK_NO_PROGRESS)
Packit 961e70
			return err2;
Packit 961e70
		else
Packit 961e70
			return err;
Packit 961e70
	}
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * Process timer expirations after servicing receive queues (some packets
Packit 961e70
	 * may have been acked, some requests-to-send may have been queued).
Packit 961e70
	 *
Packit 961e70
	 * It's safe to look at the timer without holding the lock because it's not
Packit 961e70
	 * incorrect to be wrong some of the time.
Packit 961e70
	 */
Packit 961e70
	if (psmi_timer_is_expired(&(ptl->timerq), current_count)) {
Packit 961e70
		if (do_lock)
Packit 961e70
			ips_recvhdrq_lock(&ptl->recvq);
Packit 961e70
		err = psmi_timer_process_expired(&(ptl->timerq), current_count);
Packit 961e70
		if (do_lock)
Packit 961e70
			ips_recvhdrq_unlock(&ptl->recvq);
Packit 961e70
	}
Packit 961e70
Packit 961e70
	return err;
Packit 961e70
}
Packit 961e70
Packit 961e70
PSMI_INLINE(int ips_try_lock_shared_context(struct ptl_shared *recvshc))
Packit 961e70
{
Packit 961e70
	return pthread_spin_trylock(recvshc->context_lock);
Packit 961e70
}
Packit Service 7ed5cc
/* Unused
Packit 961e70
PSMI_INLINE(void ips_lock_shared_context(struct ptl_shared *recvshc))
Packit 961e70
{
Packit 961e70
	pthread_spin_lock(recvshc->context_lock);
Packit 961e70
}
Packit Service 7ed5cc
*/
Packit 961e70
PSMI_INLINE(void ips_unlock_shared_context(struct ptl_shared *recvshc))
Packit 961e70
{
Packit 961e70
	pthread_spin_unlock(recvshc->context_lock);
Packit 961e70
}
Packit 961e70
Packit 961e70
psm2_error_t ips_ptl_shared_poll(ptl_t *ptl_gen, int _ignored)
Packit 961e70
{
Packit 961e70
	struct ptl_ips *ptl = (struct ptl_ips *)ptl_gen;
Packit 961e70
	const uint64_t current_count = get_cycles();
Packit 961e70
	psm2_error_t err = PSM2_OK_NO_PROGRESS;
Packit 961e70
	psm2_error_t err2;
Packit 961e70
	struct ptl_shared *recvshc = ptl->recvshc;
Packit 961e70
	psmi_assert(recvshc != NULL);
Packit 961e70
Packit 961e70
	/* The following header queue checks are speculative (but safe)
Packit 961e70
	 * until this process has acquired the lock. The idea is to
Packit 961e70
	 * minimize lock contention due to processes spinning on the
Packit 961e70
	 * shared context. */
Packit 961e70
	if (ips_recvhdrq_isempty(&recvshc->recvq)) {
Packit 961e70
		if (!ips_recvhdrq_isempty(&ptl->recvq) &&
Packit 961e70
		    ips_try_lock_shared_context(recvshc) == 0) {
Packit 961e70
			/* check that subcontext is empty while under lock to avoid
Packit 961e70
			 * re-ordering of incoming packets (since packets from
Packit 961e70
			 * hardware context will be processed immediately). */
Packit 961e70
			if_pt(ips_recvhdrq_isempty(&recvshc->recvq)) {
Packit 961e70
				if (ptl->recvq.proto->flags & IPS_PROTO_FLAG_CCA_PRESCAN) {
Packit 961e70
					ips_recvhdrq_scan_cca(&ptl->recvq);
Packit 961e70
				}
Packit 961e70
				err = ips_recvhdrq_progress(&ptl->recvq);
Packit 961e70
			}
Packit 961e70
			ips_unlock_shared_context(recvshc);
Packit 961e70
		}
Packit 961e70
	}
Packit 961e70
Packit 961e70
	if_pf(err > PSM2_OK_NO_PROGRESS)
Packit 961e70
	    return err;
Packit 961e70
Packit 961e70
	if (!ips_recvhdrq_isempty(&recvshc->recvq)) {
Packit 961e70
		if (recvshc->recvq.proto->flags & IPS_PROTO_FLAG_CCA_PRESCAN) {
Packit 961e70
			ips_recvhdrq_scan_cca(&recvshc->recvq);
Packit 961e70
		}
Packit 961e70
		err2 = ips_recvhdrq_progress(&recvshc->recvq);
Packit 961e70
		if (err2 != PSM2_OK_NO_PROGRESS) {
Packit 961e70
			err = err2;
Packit 961e70
		}
Packit 961e70
	}
Packit 961e70
Packit 961e70
	if_pf(err > PSM2_OK_NO_PROGRESS)
Packit 961e70
	    return err;
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * Process timer expirations after servicing receive queues (some packets
Packit 961e70
	 * may have been acked, some requests-to-send may have been queued).
Packit 961e70
	 */
Packit 961e70
	err2 = psmi_timer_process_if_expired(&(ptl->timerq), current_count);
Packit 961e70
	if (err2 != PSM2_OK_NO_PROGRESS)
Packit 961e70
		err = err2;
Packit 961e70
Packit 961e70
	return err;
Packit 961e70
}
Packit 961e70
Packit 961e70
int ips_ptl_recvq_isempty(const ptl_t *ptl_gen)
Packit 961e70
{
Packit 961e70
	struct ptl_ips *ptl = (struct ptl_ips *)ptl_gen;
Packit 961e70
	struct ptl_shared *recvshc = ptl->recvshc;
Packit 961e70
Packit 961e70
	if (recvshc != NULL && !ips_recvhdrq_isempty(&recvshc->recvq))
Packit 961e70
		return 0;
Packit 961e70
	return ips_recvhdrq_isempty(&ptl->recvq);
Packit 961e70
}
Packit 961e70
Packit 961e70
/*
Packit 961e70
 * Legacy ips_get_stat -- do nothing.
Packit 961e70
 */
Packit 961e70
int ips_get_stat(psm2_epaddr_t epaddr, ips_sess_stat *stats)
Packit 961e70
{
Packit 961e70
	memset(stats, 0, sizeof(ips_sess_stat));
Packit 961e70
	return 0;
Packit 961e70
}
Packit 961e70
Packit 961e70
static psm2_error_t shrecvq_init(ptl_t *ptl_gen, const psmi_context_t *context)
Packit 961e70
{
Packit 961e70
	struct ptl_ips *ptl = (struct ptl_ips *)ptl_gen;
Packit 961e70
	struct ptl_shared *recvshc = ptl->recvshc;
Packit 961e70
	struct ips_recvhdrq_callbacks recvq_callbacks;
Packit 961e70
	psm2_error_t err = PSM2_OK;
Packit 961e70
	int i;
Packit 961e70
Packit 961e70
	/* Initialize (shared) hardware context recvq (ptl->recvq) */
Packit 961e70
	/* NOTE: uses recvq in ptl structure for shared h/w context */
Packit 961e70
	recvq_callbacks.callback_packet_unknown = ips_proto_process_unknown;
Packit 961e70
	recvq_callbacks.callback_subcontext = ips_subcontext_process;
Packit 961e70
	recvq_callbacks.callback_error = ips_proto_process_packet_error;
Packit 961e70
	if ((err = ips_recvhdrq_init(context, &ptl->epstate, &ptl->proto,
Packit 961e70
				     &recvq_callbacks,
Packit 961e70
				     recvshc->subcontext,
Packit 961e70
				     &ptl->recvq,
Packit 961e70
				     &recvshc->hwcontext_ctrl->recvq_state,
Packit 961e70
				     PSM_HAL_CL_Q_RX_HDR_Q))) {
Packit 961e70
		goto fail;
Packit 961e70
	}
Packit 961e70
Packit 961e70
	/* Initialize software subcontext (recvshc->recvq). Subcontexts do */
Packit 961e70
	/* not require the rcvhdr copy feature. */
Packit 961e70
	recvq_callbacks.callback_subcontext = ips_subcontext_ignore;
Packit 961e70
	if ((err = ips_recvhdrq_init(context, &ptl->epstate, &ptl->proto,
Packit 961e70
				     &recvq_callbacks,
Packit 961e70
				     recvshc->subcontext,
Packit 961e70
				     &recvshc->recvq, &recvshc->recvq_state,
Packit 961e70
				     PSM_HAL_GET_SC_CL_Q_RX_HDR_Q(recvshc->subcontext)))) {
Packit 961e70
		goto fail;
Packit 961e70
	}
Packit 961e70
Packit 961e70
	/* Initialize each recvshc->writeq for shared contexts */
Packit 961e70
	for (i = 0; i < recvshc->subcontext_cnt; i++) {
Packit 961e70
		if ((err = ips_writehdrq_init(context,
Packit 961e70
					      &recvshc->writeq[i],
Packit 961e70
					      &recvshc->subcontext_ureg[i]->
Packit 961e70
					      writeq_state,
Packit 961e70
					      i))) {
Packit 961e70
			goto fail;
Packit 961e70
		}
Packit 961e70
	}
Packit 961e70
Packit 961e70
	if (err == PSM2_OK)
Packit 961e70
		_HFI_DBG
Packit 961e70
		    ("Context sharing in use: lid %d, context %d, sub-context %d\n",
Packit 961e70
		     (int)psm2_epid_nid(ptl->epid), recvshc->context,
Packit 961e70
		     recvshc->subcontext);
Packit 961e70
fail:
Packit 961e70
	return err;
Packit 961e70
}
Packit 961e70
Packit 961e70
static psm2_error_t shrecvq_fini(ptl_t *ptl_gen)
Packit 961e70
{
Packit 961e70
	struct ptl_ips *ptl = (struct ptl_ips *)ptl_gen;
Packit 961e70
	psm2_error_t err = PSM2_OK;
Packit 961e70
	int i;
Packit 961e70
Packit 961e70
	/* disable my write header queue before deallocation */
Packit 961e70
	i = ptl->recvshc->subcontext;
Packit 961e70
	ptl->recvshc->subcontext_ureg[i]->writeq_state.enabled = 0;
Packit 961e70
	psmi_free(ptl->recvshc);
Packit 961e70
	return err;
Packit 961e70
}
Packit 961e70
Packit 961e70
psm2_error_t
Packit 961e70
ips_ptl_connect(ptl_t *ptl_gen, int numep, const psm2_epid_t *array_of_epid,
Packit 961e70
		const int *array_of_epid_mask, psm2_error_t *array_of_errors,
Packit 961e70
		psm2_epaddr_t *array_of_epaddr, uint64_t timeout_in)
Packit 961e70
{
Packit 961e70
	struct ptl_ips *ptl = (struct ptl_ips *)ptl_gen;
Packit 961e70
	psm2_error_t err;
Packit 961e70
	psm2_ep_t ep;
Packit 961e70
	psm2_epid_t *epid_array = NULL;
Packit 961e70
	psm2_error_t *error_array = NULL;
Packit 961e70
	psm2_epaddr_t *epaddr_array = NULL;
Packit 961e70
	ips_epaddr_t *ipsaddr_master, *ipsaddr;
Packit 961e70
	int *mask_array = NULL;
Packit 961e70
	int i;
Packit 961e70
Packit 961e70
	PSMI_LOCK_ASSERT(ptl->ep->mq->progress_lock);
Packit 961e70
	err = ips_proto_connect(&ptl->proto, numep, array_of_epid,
Packit 961e70
				array_of_epid_mask, array_of_errors,
Packit 961e70
				array_of_epaddr, timeout_in);
Packit 961e70
	if (err)
Packit 961e70
		return err;
Packit 961e70
Packit 961e70
	psmi_assert_always(ptl->ep->mctxt_master == ptl->ep);
Packit 961e70
	if (ptl->ep->mctxt_next == ptl->ep)
Packit 961e70
		return err;
Packit 961e70
Packit 961e70
	/* make the additional mutil-context connections. */
Packit 961e70
	epid_array = (psm2_epid_t *)
Packit 961e70
	    psmi_malloc(ptl->ep, UNDEFINED, sizeof(psm2_epid_t) * numep);
Packit 961e70
	mask_array = (int *)
Packit 961e70
	    psmi_malloc(ptl->ep, UNDEFINED, sizeof(int) * numep);
Packit 961e70
	error_array = (psm2_error_t *)
Packit 961e70
	    psmi_malloc(ptl->ep, UNDEFINED, sizeof(psm2_error_t) * numep);
Packit 961e70
	epaddr_array = (psm2_epaddr_t *)
Packit 961e70
	    psmi_malloc(ptl->ep, UNDEFINED, sizeof(psm2_epaddr_t) * numep);
Packit 961e70
	if (!epid_array || !mask_array || !error_array || !epaddr_array) {
Packit 961e70
		goto fail;
Packit 961e70
	}
Packit 961e70
Packit 961e70
	ep = ptl->ep->mctxt_next;
Packit 961e70
	while (ep != ep->mctxt_master) {
Packit 961e70
Packit 961e70
		/* Setup the mask array and epid array. */
Packit 961e70
		for (i = 0; i < numep; i++) {
Packit 961e70
			if (array_of_epid_mask[i]
Packit 961e70
			    && array_of_errors[i] == PSM2_OK) {
Packit 961e70
				ipsaddr_master =
Packit 961e70
				    (ips_epaddr_t *) array_of_epaddr[i];
Packit 961e70
				ipsaddr = ipsaddr_master->next;
Packit 961e70
				mask_array[i] = 0;
Packit 961e70
				while (ipsaddr != ipsaddr_master) {
Packit 961e70
					if (((psm2_epaddr_t) ipsaddr)->proto->
Packit 961e70
					    ep == ep) {
Packit 961e70
						mask_array[i] = 1;
Packit 961e70
						epid_array[i] =
Packit 961e70
						    ((psm2_epaddr_t) ipsaddr)->
Packit 961e70
						    epid;
Packit 961e70
						break;
Packit 961e70
					}
Packit 961e70
					ipsaddr = ipsaddr->next;
Packit 961e70
				}
Packit 961e70
			} else {
Packit 961e70
				mask_array[i] = 0;
Packit 961e70
			}
Packit 961e70
		}
Packit 961e70
Packit 961e70
		/* Make the real protocol connections. */
Packit 961e70
		err =
Packit 961e70
			ips_proto_connect(&((struct ptl_ips *)(ep->ptl_ips.ptl))->proto,
Packit 961e70
					  numep, epid_array, mask_array, error_array,
Packit 961e70
					  epaddr_array, timeout_in);
Packit 961e70
		if (err)
Packit 961e70
			goto fail;
Packit 961e70
Packit 961e70
		ep = ep->mctxt_next;
Packit 961e70
	}
Packit 961e70
Packit 961e70
fail:
Packit 961e70
	if (epid_array)
Packit 961e70
		psmi_free(epid_array);
Packit 961e70
	if (mask_array)
Packit 961e70
		psmi_free(mask_array);
Packit 961e70
	if (error_array)
Packit 961e70
		psmi_free(error_array);
Packit 961e70
	if (epaddr_array)
Packit 961e70
		psmi_free(epaddr_array);
Packit 961e70
Packit 961e70
	return err;
Packit 961e70
}
Packit 961e70
Packit 961e70
psm2_error_t
Packit 961e70
ips_ptl_disconnect(ptl_t *ptl_gen, int force, int numep,
Packit 961e70
		   psm2_epaddr_t array_of_epaddr[],
Packit 961e70
		   const int array_of_epaddr_mask[],
Packit 961e70
		   psm2_error_t array_of_errors[], uint64_t timeout_in)
Packit 961e70
{
Packit 961e70
	struct ptl_ips *ptl = (struct ptl_ips *)ptl_gen;
Packit 961e70
	int *array_of_epaddr_mask_internal, i;
Packit 961e70
	psm2_error_t err;
Packit 961e70
Packit 961e70
	/*
Packit 961e70
	 * Copy true values from array_of_epaddr_mask, provided that their
Packit 961e70
	 * respective epaddr is an ips one.
Packit 961e70
	 * Newly created mask will be used for the protocol disconnect call
Packit 961e70
	 * instead.
Packit 961e70
	 */
Packit 961e70
	PSMI_LOCK_ASSERT(ptl->ep->mq->progress_lock);
Packit 961e70
	array_of_epaddr_mask_internal = psmi_calloc(ptl->ep, UNDEFINED,
Packit 961e70
						    sizeof(int), numep);
Packit 961e70
	if (!array_of_epaddr_mask_internal)
Packit 961e70
		return PSM2_NO_MEMORY;
Packit 961e70
Packit 961e70
	for (i = 0; i < numep; ++i) {
Packit 961e70
		if (array_of_epaddr_mask[i] && array_of_epaddr[i]
Packit 961e70
		    && array_of_epaddr[i]->ptlctl->ptl == ptl_gen) {
Packit 961e70
			array_of_epaddr_mask_internal[i] = 1;
Packit 961e70
		}
Packit 961e70
	}
Packit 961e70
Packit 961e70
	err = ips_proto_disconnect(&ptl->proto, force, numep, array_of_epaddr,
Packit 961e70
				   array_of_epaddr_mask_internal,
Packit 961e70
				   array_of_errors, timeout_in);
Packit 961e70
Packit 961e70
	psmi_free(array_of_epaddr_mask_internal);
Packit 961e70
	return err;
Packit 961e70
}
Packit 961e70
Packit 961e70
/* Only symbol we expose out of here */
Packit 961e70
struct ptl_ctl_init
Packit 961e70
psmi_ptl_ips = {
Packit 961e70
	ips_ptl_sizeof, ips_ptl_init, ips_ptl_fini, ips_ptl_setopt,
Packit 961e70
	    ips_ptl_getopt
Packit 961e70
};
Packit 961e70
Packit 961e70
struct ptl_ctl_rcvthread
Packit 961e70
psmi_ptl_ips_rcvthread = {
Packit 961e70
	ips_ptl_rcvthread_is_enabled,
Packit 961e70
	ips_ptl_rcvthread_transfer_ownership,
Packit 961e70
};