#include "config.h"
#include "fi_verbs.h"
static int
fi_ibv_msg_ep_atomic_writevalid(struct fid_ep *ep, enum fi_datatype datatype,
enum fi_op op, size_t *count)
{
switch (op) {
case FI_ATOMIC_WRITE:
break;
default:
return -FI_ENOSYS;
}
switch (datatype) {
case FI_INT64:
case FI_UINT64:
#if __BITS_PER_LONG == 64
case FI_DOUBLE:
case FI_FLOAT:
#endif
break;
default:
return -FI_EINVAL;
}
if (count)
*count = 1;
return 0;
}
static int
fi_ibv_msg_ep_atomic_readwritevalid(struct fid_ep *ep, enum fi_datatype datatype,
enum fi_op op, size_t *count)
{
struct fi_ibv_msg_ep *_ep = container_of(ep, struct fi_ibv_msg_ep, ep_fid);
switch (op) {
case FI_ATOMIC_READ:
break;
case FI_SUM:
if (_ep->info->tx_attr->op_flags & FI_INJECT) {
VERBS_INFO(FI_LOG_EP_DATA,"FI_INJECT not "
"supported for fi_fetch_atomic with FI_SUM op\n");
return -FI_EINVAL;
}
break;
default:
return -FI_ENOSYS;
}
switch (datatype) {
case FI_INT64:
case FI_UINT64:
#if __BITS_PER_LONG == 64
case FI_DOUBLE:
case FI_FLOAT:
#endif
break;
default:
return -FI_EINVAL;
}
if (count)
*count = 1;
return 0;
}
static int
fi_ibv_msg_ep_atomic_compwritevalid(struct fid_ep *ep, enum fi_datatype datatype,
enum fi_op op, size_t *count)
{
struct fi_ibv_msg_ep *_ep = container_of(ep, struct fi_ibv_msg_ep, ep_fid);
if (op != FI_CSWAP)
return -FI_ENOSYS;
if (_ep->info->tx_attr->op_flags & FI_INJECT) {
VERBS_INFO(FI_LOG_EP_DATA, "FI_INJECT not supported "
"for fi_compare_atomic\n");
return -FI_EINVAL;
}
switch (datatype) {
case FI_INT64:
case FI_UINT64:
#if __BITS_PER_LONG == 64
case FI_DOUBLE:
case FI_FLOAT:
#endif
break;
default:
return -FI_EINVAL;
}
if (count)
*count = 1;
return 0;
}
static ssize_t
fi_ibv_msg_ep_atomic_write(struct fid_ep *ep_fid, const void *buf, size_t count,
void *desc, fi_addr_t dest_addr, uint64_t addr, uint64_t key,
enum fi_datatype datatype, enum fi_op op, void *context)
{
struct fi_ibv_msg_ep *ep;
struct ibv_send_wr wr;
size_t count_copy;
int ret;
if (count != 1)
return -FI_E2BIG;
count_copy = count;
ret = fi_ibv_msg_ep_atomic_writevalid(ep_fid, datatype, op, &count_copy);
if (ret)
return ret;
memset(&wr, 0, sizeof(wr));
switch(op) {
case FI_ATOMIC_WRITE:
wr.opcode = IBV_WR_RDMA_WRITE;
wr.wr.rdma.remote_addr = addr;
wr.wr.rdma.rkey = (uint32_t) (uintptr_t) key;
break;
default:
return -ENOSYS;
}
ep = container_of(ep_fid, struct fi_ibv_msg_ep, ep_fid);
wr.send_flags = VERBS_INJECT(ep, sizeof(uint64_t)) | VERBS_COMP(ep) |
IBV_SEND_FENCE;
return fi_ibv_send_buf(ep, &wr, buf, sizeof(uint64_t), desc, context);
}
static ssize_t
fi_ibv_msg_ep_atomic_writev(struct fid_ep *ep,
const struct fi_ioc *iov, void **desc, size_t count,
fi_addr_t dest_addr, uint64_t addr, uint64_t key,
enum fi_datatype datatype, enum fi_op op, void *context)
{
if (iov->count != 1)
return -FI_E2BIG;
return fi_ibv_msg_ep_atomic_write(ep, iov->addr, count, desc[0],
dest_addr, addr, key, datatype, op, context);
}
static ssize_t
fi_ibv_msg_ep_atomic_writemsg(struct fid_ep *ep_fid,
const struct fi_msg_atomic *msg, uint64_t flags)
{
struct fi_ibv_msg_ep *ep;
struct ibv_send_wr wr;
size_t count_copy;
int ret;
if (msg->iov_count != 1 || msg->msg_iov->count != 1)
return -FI_E2BIG;
count_copy = msg->iov_count;
ret = fi_ibv_msg_ep_atomic_writevalid(ep_fid, msg->datatype, msg->op,
&count_copy);
if (ret)
return ret;
memset(&wr, 0, sizeof(wr));
switch (msg->op) {
case FI_ATOMIC_WRITE:
if (flags & FI_REMOTE_CQ_DATA) {
wr.opcode = IBV_WR_RDMA_WRITE_WITH_IMM;
wr.imm_data = htonl((uint32_t)msg->data);
} else {
wr.opcode = IBV_WR_RDMA_WRITE;
}
wr.wr.rdma.remote_addr = msg->rma_iov->addr;
wr.wr.rdma.rkey = (uint32_t) (uintptr_t) msg->rma_iov->key;
break;
default:
return -ENOSYS;
}
ep = container_of(ep_fid, struct fi_ibv_msg_ep, ep_fid);
wr.send_flags = VERBS_INJECT_FLAGS(ep, sizeof(uint64_t), flags) |
VERBS_COMP_FLAGS(ep, flags) | IBV_SEND_FENCE;
return fi_ibv_send_buf(ep, &wr, msg->msg_iov->addr, sizeof(uint64_t),
msg->desc[0], msg->context);
}
static ssize_t
fi_ibv_msg_ep_atomic_readwrite(struct fid_ep *ep_fid, const void *buf, size_t count,
void *desc, void *result, void *result_desc,
fi_addr_t dest_addr, uint64_t addr, uint64_t key,
enum fi_datatype datatype,
enum fi_op op, void *context)
{
struct fi_ibv_msg_ep *ep;
struct ibv_send_wr wr;
size_t count_copy;
int ret;
if (count != 1)
return -FI_E2BIG;
count_copy = count;
ret = fi_ibv_msg_ep_atomic_readwritevalid(ep_fid, datatype, op,
&count_copy);
if (ret)
return ret;
ep = container_of(ep_fid, struct fi_ibv_msg_ep, ep_fid);
memset(&wr, 0, sizeof(wr));
switch (op) {
case FI_ATOMIC_READ:
wr.opcode = IBV_WR_RDMA_READ;
wr.wr.rdma.remote_addr = addr;
wr.wr.rdma.rkey = (uint32_t) (uintptr_t) key;
break;
case FI_SUM:
wr.opcode = IBV_WR_ATOMIC_FETCH_AND_ADD;
wr.wr.atomic.remote_addr = addr;
wr.wr.atomic.compare_add = (uintptr_t) buf;
wr.wr.atomic.swap = 0;
wr.wr.atomic.rkey = (uint32_t) (uintptr_t) key;
break;
default:
return -ENOSYS;
}
wr.send_flags = VERBS_COMP(ep) | IBV_SEND_FENCE;
return fi_ibv_send_buf(ep, &wr, result, sizeof(uint64_t), result_desc,
context);
}
static ssize_t
fi_ibv_msg_ep_atomic_readwritev(struct fid_ep *ep, const struct fi_ioc *iov,
void **desc, size_t count,
struct fi_ioc *resultv, void **result_desc,
size_t result_count, fi_addr_t dest_addr, uint64_t addr,
uint64_t key, enum fi_datatype datatype,
enum fi_op op, void *context)
{
if (iov->count != 1)
return -FI_E2BIG;
return fi_ibv_msg_ep_atomic_readwrite(ep, iov->addr, count,
desc[0], resultv->addr, result_desc[0],
dest_addr, addr, key, datatype, op, context);
}
static ssize_t
fi_ibv_msg_ep_atomic_readwritemsg(struct fid_ep *ep_fid,
const struct fi_msg_atomic *msg,
struct fi_ioc *resultv, void **result_desc,
size_t result_count, uint64_t flags)
{
struct fi_ibv_msg_ep *ep;
struct ibv_send_wr wr;
size_t count_copy;
int ret;
if (msg->iov_count != 1 || msg->msg_iov->count != 1)
return -FI_E2BIG;
count_copy = msg->iov_count;
ret = fi_ibv_msg_ep_atomic_readwritevalid(ep_fid, msg->datatype, msg->op,
&count_copy);
if (ret)
return ret;
ep = container_of(ep_fid, struct fi_ibv_msg_ep, ep_fid);
memset(&wr, 0, sizeof(wr));
switch (msg->op) {
case FI_ATOMIC_READ:
wr.opcode = IBV_WR_RDMA_READ;
wr.wr.rdma.remote_addr = msg->rma_iov->addr;
wr.wr.rdma.rkey = (uint32_t) (uintptr_t) msg->rma_iov->key;
break;
case FI_SUM:
wr.opcode = IBV_WR_ATOMIC_FETCH_AND_ADD;
wr.wr.atomic.remote_addr = msg->rma_iov->addr;
wr.wr.atomic.compare_add = (uintptr_t) msg->addr;
wr.wr.atomic.swap = 0;
wr.wr.atomic.rkey = (uint32_t) (uintptr_t) msg->rma_iov->key;
break;
default:
return -ENOSYS;
}
wr.send_flags = VERBS_COMP_FLAGS(ep, flags) | IBV_SEND_FENCE;
if (flags & FI_REMOTE_CQ_DATA)
wr.imm_data = htonl((uint32_t) msg->data);
return fi_ibv_send_buf(ep, &wr, resultv->addr, sizeof(uint64_t),
result_desc[0], msg->context);
}
static ssize_t
fi_ibv_msg_ep_atomic_compwrite(struct fid_ep *ep_fid, const void *buf, size_t count,
void *desc, const void *compare,
void *compare_desc, void *result,
void *result_desc,
fi_addr_t dest_addr, uint64_t addr, uint64_t key,
enum fi_datatype datatype,
enum fi_op op, void *context)
{
struct fi_ibv_msg_ep *ep;
struct ibv_send_wr wr;
size_t count_copy;
int ret;
if (count != 1)
return -FI_E2BIG;
count_copy = count;
ret = fi_ibv_msg_ep_atomic_compwritevalid(ep_fid, datatype, op, &count_copy);
if (ret)
return ret;
memset(&wr, 0, sizeof(wr));
wr.opcode = IBV_WR_ATOMIC_CMP_AND_SWP;
wr.wr.atomic.remote_addr = addr;
wr.wr.atomic.compare_add = (uintptr_t) compare;
wr.wr.atomic.swap = (uintptr_t) buf;
wr.wr.atomic.rkey = (uint32_t) (uintptr_t) key;
ep = container_of(ep_fid, struct fi_ibv_msg_ep, ep_fid);
wr.send_flags = VERBS_COMP(ep) | IBV_SEND_FENCE;
return fi_ibv_send_buf(ep, &wr, result, sizeof(uint64_t), result_desc, context);
}
static ssize_t
fi_ibv_msg_ep_atomic_compwritev(struct fid_ep *ep, const struct fi_ioc *iov,
void **desc, size_t count,
const struct fi_ioc *comparev,
void **compare_desc, size_t compare_count,
struct fi_ioc *resultv, void **result_desc,
size_t result_count,
fi_addr_t dest_addr, uint64_t addr, uint64_t key,
enum fi_datatype datatype,
enum fi_op op, void *context)
{
if (iov->count != 1)
return -FI_E2BIG;
return fi_ibv_msg_ep_atomic_compwrite(ep, iov->addr, count, desc[0],
comparev->addr, compare_desc[0], resultv->addr,
result_desc[0], dest_addr, addr, key,
datatype, op, context);
}
static ssize_t
fi_ibv_msg_ep_atomic_compwritemsg(struct fid_ep *ep_fid,
const struct fi_msg_atomic *msg,
const struct fi_ioc *comparev,
void **compare_desc, size_t compare_count,
struct fi_ioc *resultv,
void **result_desc, size_t result_count,
uint64_t flags)
{
struct fi_ibv_msg_ep *ep;
struct ibv_send_wr wr;
size_t count_copy;
int ret;
if (msg->iov_count != 1 || msg->msg_iov->count != 1)
return -FI_E2BIG;
count_copy = msg->iov_count;
ret = fi_ibv_msg_ep_atomic_compwritevalid(ep_fid, msg->datatype, msg->op,
&count_copy);
if (ret)
return ret;
memset(&wr, 0, sizeof(wr));
wr.opcode = IBV_WR_ATOMIC_CMP_AND_SWP;
wr.wr.atomic.remote_addr = msg->rma_iov->addr;
wr.wr.atomic.compare_add = (uintptr_t) comparev->addr;
wr.wr.atomic.swap = (uintptr_t) msg->addr;
wr.wr.atomic.rkey = (uint32_t) (uintptr_t) msg->rma_iov->key;
ep = container_of(ep_fid, struct fi_ibv_msg_ep, ep_fid);
wr.send_flags = VERBS_COMP_FLAGS(ep, flags) | IBV_SEND_FENCE;
if (flags & FI_REMOTE_CQ_DATA)
wr.imm_data = htonl((uint32_t) msg->data);
return fi_ibv_send_buf(ep, &wr, resultv->addr, sizeof(uint64_t),
result_desc[0], msg->context);
}
static struct fi_ops_atomic fi_ibv_msg_ep_atomic_ops = {
.size = sizeof(struct fi_ops_atomic),
.write = fi_ibv_msg_ep_atomic_write,
.writev = fi_ibv_msg_ep_atomic_writev,
.writemsg = fi_ibv_msg_ep_atomic_writemsg,
.inject = fi_no_atomic_inject,
.readwrite = fi_ibv_msg_ep_atomic_readwrite,
.readwritev = fi_ibv_msg_ep_atomic_readwritev,
.readwritemsg = fi_ibv_msg_ep_atomic_readwritemsg,
.compwrite = fi_ibv_msg_ep_atomic_compwrite,
.compwritev = fi_ibv_msg_ep_atomic_compwritev,
.compwritemsg = fi_ibv_msg_ep_atomic_compwritemsg,
.writevalid = fi_ibv_msg_ep_atomic_writevalid,
.readwritevalid = fi_ibv_msg_ep_atomic_readwritevalid,
.compwritevalid = fi_ibv_msg_ep_atomic_compwritevalid
};
struct fi_ops_atomic *fi_ibv_msg_ep_ops_atomic(struct fi_ibv_msg_ep *ep)
{
return &fi_ibv_msg_ep_atomic_ops;
}