/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2011-2017 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2011 UT-Battelle, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef MCA_BTL_UGNI_ENDPOINT_H #define MCA_BTL_UGNI_ENDPOINT_H #include "btl_ugni.h" enum mca_btl_ugni_endpoint_state_t { MCA_BTL_UGNI_EP_STATE_INIT = 0, MCA_BTL_UGNI_EP_STATE_CONNECTING, MCA_BTL_UGNI_EP_STATE_CONNECTED, }; typedef enum mca_btl_ugni_endpoint_state_t mca_btl_ugni_endpoint_state_t; struct mca_btl_ugni_smsg_mbox_t; struct mca_btl_ugni_endpoint_handle_t { opal_free_list_item_t super; mca_btl_ugni_device_t *device; gni_ep_handle_t gni_handle; }; typedef struct mca_btl_ugni_endpoint_handle_t mca_btl_ugni_endpoint_handle_t; OBJ_CLASS_DECLARATION(mca_btl_ugni_endpoint_handle_t); typedef struct mca_btl_base_endpoint_t { opal_list_item_t super; opal_proc_t *peer_proc; /** may need to lock recursively as the modex lookup could call opal_progress * and hence our progress function. if this changes modify this mutex to not * be recursive. also need to update the constructor function. */ opal_recursive_mutex_t lock; mca_btl_ugni_endpoint_state_t state; /** Remote NIC address */ uint32_t ep_rem_addr; /** Remote CDM identifier (base) */ uint32_t ep_rem_id; /** endpoint to use for SMSG messages */ mca_btl_ugni_endpoint_handle_t *smsg_ep_handle; /** temporary space to store the remote SMSG attributes */ mca_btl_ugni_endpoint_attr_t *remote_attr; /** SMSG mailbox assigned to this endpoint */ struct mca_btl_ugni_smsg_mbox_t *mailbox; /** Remote IRQ handle (for async completion) */ gni_mem_handle_t rmt_irq_mem_hndl; /** frags waiting for SMSG credits */ opal_list_t frag_wait_list; /** endpoint is currently wait-listed for SMSG progress */ bool wait_listed; /** protect against race on connection */ bool dg_posted; /** protect against re-entry to SMSG */ int32_t smsg_progressing; int index; } mca_btl_base_endpoint_t; typedef mca_btl_base_endpoint_t mca_btl_ugni_endpoint_t; OBJ_CLASS_DECLARATION(mca_btl_ugni_endpoint_t); int mca_btl_ugni_ep_connect_progress (mca_btl_ugni_endpoint_t *ep); int mca_btl_ugni_ep_disconnect (mca_btl_ugni_endpoint_t *ep, bool send_disconnect); int mca_btl_ugni_wildcard_ep_post (mca_btl_ugni_module_t *ugni_module); void mca_btl_ugni_release_ep (mca_btl_ugni_endpoint_t *ep); int mca_btl_ugni_init_ep (mca_btl_ugni_module_t *ugni_module, mca_btl_ugni_endpoint_t **ep, mca_btl_ugni_module_t *btl, opal_proc_t *peer_proc); static inline int mca_btl_ugni_check_endpoint_state (mca_btl_ugni_endpoint_t *ep) { int rc; if (OPAL_LIKELY(MCA_BTL_UGNI_EP_STATE_CONNECTED == ep->state)) { return OPAL_SUCCESS; } opal_mutex_lock (&ep->lock); switch (ep->state) { case MCA_BTL_UGNI_EP_STATE_INIT: rc = mca_btl_ugni_ep_connect_progress (ep); if (OPAL_SUCCESS != rc) { break; } case MCA_BTL_UGNI_EP_STATE_CONNECTING: rc = OPAL_ERR_RESOURCE_BUSY; break; default: rc = OPAL_SUCCESS; } opal_mutex_unlock (&ep->lock); return rc; } /** * Accessor function for endpoint btl * * @param[in] ep endpoint to query * * This helper function exists to make it easy to switch between using a single * and multiple ugni modules. Currently there is only one so we just use the * pointer in the component structure. This saves 4-8 bytes in the endpoint * structure. */ static inline mca_btl_ugni_module_t *mca_btl_ugni_ep_btl (mca_btl_ugni_endpoint_t *ep) { /* there is only one ugni module at this time. if that changes add a btl pointer back * to the endpoint structure. */ return mca_btl_ugni_component.modules; } /** * Allocate and bind a uGNI endpoint handle to the remote peer. * * @param[in] ep BTL endpoint * @param[in] cq completion queue * @param[out] ep_handle uGNI endpoint handle */ mca_btl_ugni_endpoint_handle_t *mca_btl_ugni_ep_handle_create (mca_btl_ugni_endpoint_t *ep, gni_cq_handle_t cq, mca_btl_ugni_device_t *device); /** * Unbind and free the uGNI endpoint handle. * * @param[in] ep_handle uGNI endpoint handle to unbind and release */ int mca_btl_ugni_ep_handle_destroy (mca_btl_ugni_endpoint_handle_t *ep_handle); /** * Free list initialization function for endpoint handles (DO NOT CALL outside free list) * * @param[in] item Free list item to initialize * @param[in] ctx Free list context * * @returns OPAL_SUCCESS on success * @returns OPAL error code on error */ int mca_btl_ugni_endpoint_handle_init_rdma (opal_free_list_item_t *item, void *ctx); /** * @brief get an endpoint handle from a device's free list * * @param[in] ep btl endpoint * @param[in] device btl device to use * * This function MUST be called with the device lock held. This was done over using * the atomic free list to avoid unnecessary atomics in the critical path. */ static inline mca_btl_ugni_endpoint_handle_t * mca_btl_ugni_ep_get_rdma (mca_btl_ugni_endpoint_t *ep, mca_btl_ugni_device_t *device) { mca_btl_ugni_endpoint_handle_t *ep_handle; gni_return_t grc; ep_handle = (mca_btl_ugni_endpoint_handle_t *) opal_free_list_get_st (&device->endpoints); if (OPAL_UNLIKELY(NULL == ep_handle)) { return NULL; } grc = GNI_EpBind (ep_handle->gni_handle, ep->ep_rem_addr, ep->ep_rem_id | device->dev_index); if (OPAL_UNLIKELY(GNI_RC_SUCCESS != grc)) { opal_free_list_return_st (&device->endpoints, &ep_handle->super); ep_handle = NULL; } return ep_handle; } /** * @brief return an endpoint handle to a device's free list * * @param[in] ep_handle endpoint handle to return * * This function MUST be called with the device lock held. This was done over using * the atomic free list to avoid unnecessary atomics in the critical path. If */ static inline void mca_btl_ugni_ep_return_rdma (mca_btl_ugni_endpoint_handle_t *ep_handle) { (void) GNI_EpUnbind (ep_handle->gni_handle); opal_free_list_return_st (&ep_handle->device->endpoints, &ep_handle->super); } #endif /* MCA_BTL_UGNI_ENDPOINT_H */