/** * 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 #include "knem_ep.h" #include "knem_md.h" #include #include 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; }