/**
* Copyright (C) UT-Battelle, LLC. 2015. ALL RIGHTS RESERVED.
* Copyright (C) Mellanox Technologies Ltd. 2001-2019. ALL RIGHTS RESERVED.
* See file LICENSE for terms.
*/
#include <knem_io.h>
#include "knem_ep.h"
#include "knem_md.h"
#include <uct/sm/base/sm_iface.h>
#include <ucs/debug/log.h>
static UCS_CLASS_INIT_FUNC(uct_knem_ep_t, const uct_ep_params_t *params)
{
uct_knem_iface_t *iface = ucs_derived_of(params->iface, uct_knem_iface_t);
UCS_CLASS_CALL_SUPER_INIT(uct_base_ep_t, &iface->super.super);
return UCS_OK;
}
static UCS_CLASS_CLEANUP_FUNC(uct_knem_ep_t)
{
/* No op */
}
UCS_CLASS_DEFINE(uct_knem_ep_t, uct_base_ep_t)
UCS_CLASS_DEFINE_NEW_FUNC(uct_knem_ep_t, uct_ep_t, const uct_ep_params_t *);
UCS_CLASS_DEFINE_DELETE_FUNC(uct_knem_ep_t, uct_ep_t);
#define uct_knem_trace_data(_remote_addr, _rkey, _fmt, ...) \
ucs_trace_data(_fmt " to %"PRIx64"(%+ld)", ## __VA_ARGS__, (_remote_addr), \
(_rkey))
#define UCT_KNEM_ZERO_LENGTH_POST(len) \
if (0 == len) { \
ucs_trace_data("Zero length request: skip it"); \
return UCS_OK; \
}
static inline ucs_status_t uct_knem_rma(uct_ep_h tl_ep, const uct_iov_t *iov,
size_t iovcnt, uint64_t remote_addr,
uct_knem_key_t *key, int write)
{
uct_knem_iface_t *knem_iface = ucs_derived_of(tl_ep->iface, uct_knem_iface_t);
int knem_fd = knem_iface->knem_md->knem_fd;
size_t knem_iov_it = 0;
struct knem_cmd_inline_copy icopy;
struct knem_cmd_param_iovec knem_iov[UCT_SM_MAX_IOV];
int rc;
size_t iov_it;
for (iov_it = 0; iov_it < ucs_min(UCT_SM_MAX_IOV, iovcnt); ++iov_it) {
knem_iov[knem_iov_it].base = (uintptr_t)iov[iov_it].buffer;
knem_iov[knem_iov_it].len = uct_iov_get_length(iov + iov_it);
/* Skip zero length buffers */
if (knem_iov[knem_iov_it].len != 0) {
++knem_iov_it;
}
}
UCT_KNEM_ZERO_LENGTH_POST(knem_iov_it);
icopy.local_iovec_array = (uintptr_t)knem_iov;
icopy.local_iovec_nr = knem_iov_it;
icopy.remote_cookie = key->cookie;
ucs_assert(remote_addr >= key->address);
icopy.current_status = 0;
icopy.remote_offset = remote_addr - key->address;
/* if 0 then, READ from the remote region into my local segments
* if 1 then, WRITE to the remote region from my local segment */
icopy.write = write;
/* TBD: add check and support for KNEM_FLAG_DMA */
icopy.flags = 0;
ucs_assert(knem_fd > -1);
rc = ioctl(knem_fd, KNEM_CMD_INLINE_COPY, &icopy);
if (ucs_unlikely((rc < 0) || (icopy.current_status != KNEM_STATUS_SUCCESS))) {
ucs_error("KNEM inline copy failed, ioctl() return value - %d, "
"copy status - %d: %m", rc, icopy.current_status);
return UCS_ERR_IO_ERROR;
}
uct_knem_trace_data(remote_addr, (uintptr_t)key, "%s [length %zu]",
write?"PUT_ZCOPY":"GET_ZCOPY",
uct_iov_total_length(iov, iovcnt));
return UCS_OK;
}
ucs_status_t uct_knem_ep_put_zcopy(uct_ep_h tl_ep, const uct_iov_t *iov, size_t iovcnt,
uint64_t remote_addr, uct_rkey_t rkey,
uct_completion_t *comp)
{
uct_knem_key_t *key = (uct_knem_key_t *)rkey;
ucs_status_t status;
UCT_CHECK_IOV_SIZE(iovcnt, uct_sm_get_max_iov(), "uct_knem_ep_put_zcopy");
status = uct_knem_rma(tl_ep, iov, iovcnt, remote_addr, key, 1);
UCT_TL_EP_STAT_OP_IF_SUCCESS(status, ucs_derived_of(tl_ep, uct_base_ep_t),
PUT, ZCOPY, uct_iov_total_length(iov, iovcnt));
return status;
}
ucs_status_t uct_knem_ep_get_zcopy(uct_ep_h tl_ep, const uct_iov_t *iov, size_t iovcnt,
uint64_t remote_addr, uct_rkey_t rkey,
uct_completion_t *comp)
{
uct_knem_key_t *key = (uct_knem_key_t *)rkey;
ucs_status_t status;
UCT_CHECK_IOV_SIZE(iovcnt, uct_sm_get_max_iov(), "uct_knem_ep_get_zcopy");
status = uct_knem_rma(tl_ep, iov, iovcnt, remote_addr, key, 0);
UCT_TL_EP_STAT_OP_IF_SUCCESS(status, ucs_derived_of(tl_ep, uct_base_ep_t),
GET, ZCOPY, uct_iov_total_length(iov, iovcnt));
return status;
}