/**
* Copyright (c) UT-Battelle, LLC. 2014-2017. ALL RIGHTS RESERVED.
* Copyright (C) Mellanox Technologies Ltd. 2001-2019. ALL RIGHTS RESERVED.
* See file LICENSE for terms.
*/
#include "ugni_device.h"
#include "ugni_iface.h"
#include "ugni_md.h"
/* Forward declarations */
UCS_CONFIG_DEFINE_ARRAY(ugni_alloc_methods, sizeof(uct_alloc_method_t),
UCS_CONFIG_TYPE_ENUM(uct_alloc_method_names));
pthread_mutex_t uct_ugni_global_lock = PTHREAD_MUTEX_INITIALIZER;
/* For Cray devices we have only one MD */
static ucs_status_t
uct_ugni_query_md_resources(uct_component_h component,
uct_md_resource_desc_t **resources_p,
unsigned *num_resources_p)
{
if (getenv("PMI_GNI_PTAG") == NULL) {
return uct_md_query_empty_md_resource(resources_p, num_resources_p);
}
return uct_md_query_single_md_resource(component, resources_p,
num_resources_p);
}
static ucs_status_t uct_ugni_md_query(uct_md_h md, uct_md_attr_t *md_attr)
{
md_attr->rkey_packed_size = 3 * sizeof(uint64_t);
md_attr->cap.flags = UCT_MD_FLAG_REG |
UCT_MD_FLAG_NEED_MEMH |
UCT_MD_FLAG_NEED_RKEY;
md_attr->cap.reg_mem_types = UCS_MEMORY_TYPES_CPU_ACCESSIBLE;
md_attr->cap.access_mem_type = UCS_MEMORY_TYPE_HOST;
md_attr->cap.detect_mem_types = 0;
md_attr->cap.max_alloc = 0;
md_attr->cap.max_reg = ULONG_MAX;
md_attr->reg_cost.overhead = 1000.0e-9;
md_attr->reg_cost.growth = 0.007e-9;
memset(&md_attr->local_cpus, 0xff, sizeof(md_attr->local_cpus));
return UCS_OK;
}
static ucs_status_t uct_ugni_mem_reg(uct_md_h md, void *address, size_t length,
unsigned flags, uct_mem_h *memh_p)
{
ucs_status_t status;
gni_return_t ugni_rc;
uct_ugni_md_t *ugni_md = ucs_derived_of(md, uct_ugni_md_t);
gni_mem_handle_t * mem_hndl = NULL;
if (0 == length) {
ucs_error("Unexpected length %zu", length);
return UCS_ERR_INVALID_PARAM;
}
mem_hndl = ucs_malloc(sizeof(gni_mem_handle_t), "gni_mem_handle_t");
if (NULL == mem_hndl) {
ucs_error("Failed to allocate memory for gni_mem_handle_t");
status = UCS_ERR_NO_MEMORY;
goto mem_err;
}
uct_ugni_cdm_lock(&ugni_md->cdm);
ugni_rc = GNI_MemRegister(ugni_md->cdm.nic_handle, (uint64_t)address,
length, NULL,
GNI_MEM_READWRITE | GNI_MEM_RELAXED_PI_ORDERING,
-1, mem_hndl);
uct_ugni_cdm_unlock(&ugni_md->cdm);
if (GNI_RC_SUCCESS != ugni_rc) {
ucs_error("GNI_MemRegister failed (addr %p, size %zu), Error status: %s %d",
address, length, gni_err_str[ugni_rc], ugni_rc);
status = UCS_ERR_IO_ERROR;
goto mem_err;
}
ucs_debug("Memory registration address %p, len %lu, keys [%"PRIx64" %"PRIx64"]",
address, length, mem_hndl->qword1, mem_hndl->qword2);
*memh_p = mem_hndl;
return UCS_OK;
mem_err:
free(mem_hndl);
return status;
}
static ucs_status_t uct_ugni_mem_dereg(uct_md_h md, uct_mem_h memh)
{
uct_ugni_md_t *ugni_md = ucs_derived_of(md, uct_ugni_md_t);
gni_mem_handle_t *mem_hndl = (gni_mem_handle_t *) memh;
gni_return_t ugni_rc;
ucs_status_t status = UCS_OK;
uct_ugni_cdm_lock(&ugni_md->cdm);
ugni_rc = GNI_MemDeregister(ugni_md->cdm.nic_handle, mem_hndl);
uct_ugni_cdm_unlock(&ugni_md->cdm);
if (GNI_RC_SUCCESS != ugni_rc) {
ucs_error("GNI_MemDeregister failed, Error status: %s %d",
gni_err_str[ugni_rc], ugni_rc);
status = UCS_ERR_IO_ERROR;
}
ucs_free(mem_hndl);
return status;
}
static ucs_status_t uct_ugni_rkey_pack(uct_md_h md, uct_mem_h memh,
void *rkey_buffer)
{
gni_mem_handle_t *mem_hndl = (gni_mem_handle_t *) memh;
uint64_t *ptr = rkey_buffer;
ptr[0] = UCT_UGNI_RKEY_MAGIC;
ptr[1] = mem_hndl->qword1;
ptr[2] = mem_hndl->qword2;
ucs_debug("Packed [ %"PRIx64" %"PRIx64" %"PRIx64"]", ptr[0], ptr[1], ptr[2]);
return UCS_OK;
}
static ucs_status_t uct_ugni_rkey_release(uct_component_t *component,
uct_rkey_t rkey, void *handle)
{
ucs_assert(NULL == handle);
ucs_free((void *)rkey);
return UCS_OK;
}
static ucs_status_t uct_ugni_rkey_unpack(uct_component_t *component,
const void *rkey_buffer,
uct_rkey_t *rkey_p, void **handle_p)
{
const uint64_t *ptr = rkey_buffer;
gni_mem_handle_t *mem_hndl = NULL;
uint64_t magic = 0;
ucs_debug("Unpacking [ %"PRIx64" %"PRIx64" %"PRIx64"]", ptr[0], ptr[1], ptr[2]);
magic = ptr[0];
if (magic != UCT_UGNI_RKEY_MAGIC) {
ucs_error("Failed to identify key. Expected %llx but received %"PRIx64"",
UCT_UGNI_RKEY_MAGIC, magic);
return UCS_ERR_UNSUPPORTED;
}
mem_hndl = ucs_malloc(sizeof(gni_mem_handle_t), "gni_mem_handle_t");
if (NULL == mem_hndl) {
ucs_error("Failed to allocate memory for gni_mem_handle_t");
return UCS_ERR_NO_MEMORY;
}
mem_hndl->qword1 = ptr[1];
mem_hndl->qword2 = ptr[2];
*rkey_p = (uintptr_t)mem_hndl;
*handle_p = NULL;
return UCS_OK;
}
static void uct_ugni_md_close(uct_md_h md)
{
uct_ugni_md_t *ugni_md = ucs_derived_of(md, uct_ugni_md_t);
pthread_mutex_lock(&uct_ugni_global_lock);
ugni_md->ref_count--;
if (!ugni_md->ref_count) {
ucs_debug("Tearing down MD CDM");
uct_ugni_destroy_cdm(&ugni_md->cdm);
}
pthread_mutex_unlock(&uct_ugni_global_lock);
}
static ucs_status_t
uct_ugni_md_open(uct_component_h component,const char *md_name,
const uct_md_config_t *md_config, uct_md_h *md_p)
{
ucs_status_t status = UCS_OK;
pthread_mutex_lock(&uct_ugni_global_lock);
static uct_md_ops_t md_ops = {
.close = uct_ugni_md_close,
.query = uct_ugni_md_query,
.mem_alloc = (void*)ucs_empty_function,
.mem_free = (void*)ucs_empty_function,
.mem_reg = uct_ugni_mem_reg,
.mem_dereg = uct_ugni_mem_dereg,
.mkey_pack = uct_ugni_rkey_pack,
.detect_memory_type = ucs_empty_function_return_unsupported,
};
static uct_ugni_md_t md = {
.super.ops = &md_ops,
.super.component = &uct_ugni_component,
.ref_count = 0
};
*md_p = &md.super;
if (!md.ref_count) {
status = init_device_list();
if (UCS_OK != status) {
ucs_error("Failed to init device list, Error status: %d", status);
goto error;
}
status = uct_ugni_create_md_cdm(&md.cdm);
if (UCS_OK != status) {
ucs_error("Failed to UGNI NIC, Error status: %d", status);
goto error;
}
}
md.ref_count++;
error:
pthread_mutex_unlock(&uct_ugni_global_lock);
return status;
}
uct_component_t uct_ugni_component = {
.query_md_resources = uct_ugni_query_md_resources,
.md_open = uct_ugni_md_open,
.cm_open = ucs_empty_function_return_unsupported,
.rkey_unpack = uct_ugni_rkey_unpack,
.rkey_ptr = ucs_empty_function_return_unsupported,
.rkey_release = uct_ugni_rkey_release,
.name = UCT_UGNI_MD_NAME,
.md_config = {
.name = "UGNI memory domain",
.prefix = "UGNI_",
.table = uct_md_config_table,
.size = sizeof(uct_md_config_t),
},
.cm_config = UCS_CONFIG_EMPTY_GLOBAL_LIST_ENTRY,
.tl_list = UCT_COMPONENT_TL_LIST_INITIALIZER(&uct_ugni_component),
.flags = 0
};
UCT_COMPONENT_REGISTER(&uct_ugni_component);