/* * Copyright (c) 2018-2019 Intel Corporation, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "mrail.h" static int mrail_domain_close(fid_t fid) { struct mrail_domain *mrail_domain = container_of(fid, struct mrail_domain, util_domain.domain_fid.fid); int ret, retv = 0; if (mrail_domain->domains) { ret = mrail_close_fids((struct fid **)mrail_domain->domains, mrail_domain->num_domains); if (ret) retv = ret; free(mrail_domain->domains); } ret = ofi_domain_close(&mrail_domain->util_domain); if (ret) retv = ret; free(mrail_domain); return retv; } static int mrail_domain_map_raw(struct mrail_domain *mrail_domain, struct fi_mr_map_raw *map) { struct mrail_addr_key *mr_map; /* Copy the raw key and use a pointer as the new key. */ mr_map = calloc(1, map->key_size); if (!mr_map) { return -FI_ENOMEM; } memcpy(mr_map, map->raw_key, map->key_size); *(map->key) = (uint64_t)mr_map; return 0; } static int mrail_domain_unmap_key(struct mrail_addr_key **mr_map) { assert(mr_map); free(*mr_map); return 0; } static int mrail_domain_control(struct fid *fid, int command, void *arg) { struct mrail_domain *mrail_domain = container_of(fid, struct mrail_domain, util_domain.domain_fid.fid); switch(command) { case FI_MAP_RAW_MR: return mrail_domain_map_raw(mrail_domain, arg); case FI_UNMAP_KEY: return mrail_domain_unmap_key(arg); } return -FI_EINVAL; } static struct fi_ops mrail_domain_fi_ops = { .size = sizeof(struct fi_ops), .close = mrail_domain_close, .bind = fi_no_bind, .control = mrail_domain_control, .ops_open = fi_no_ops_open, }; static int mrail_mr_close(fid_t fid) { uint32_t i; struct mrail_mr *mrail_mr = container_of(fid, struct mrail_mr, mr_fid.fid); for (i = 0; i < mrail_mr->num_mrs; ++i) { fi_close(&mrail_mr->rails[i].mr->fid); } return 0; } static int mrail_mr_raw_attr(struct mrail_mr *mrail_mr, struct fi_mr_raw_attr *attr) { uint32_t num_rails; uint32_t i; struct mrail_addr_key *rail; size_t required_key_size; num_rails = mrail_mr->num_mrs; required_key_size = num_rails * sizeof(struct mrail_addr_key); if (*(attr->key_size) < required_key_size) { *(attr->key_size) = required_key_size; return -FI_ETOOSMALL; } /* The raw key is the concatenation of one "struct mrail_addr_key" per * rail. */ for (i = 0, rail = (struct mrail_addr_key*)attr->raw_key; i < num_rails; ++i, ++rail) { rail->base_addr = mrail_mr->rails[i].base_addr; rail->key = fi_mr_key(mrail_mr->rails[i].mr); } *(attr->key_size) = required_key_size; *(attr->base_addr) = 0; return 0; } static int mrail_mr_control(struct fid *fid, int command, void *arg) { struct mrail_mr *mrail_mr = container_of(fid, struct mrail_mr, mr_fid.fid); switch(command) { case FI_GET_RAW_MR: return mrail_mr_raw_attr(mrail_mr, arg); } return -FI_EINVAL; } static struct fi_ops mrail_mr_ops = { .size = sizeof(struct fi_ops), .close = mrail_mr_close, .bind = fi_no_bind, .control = mrail_mr_control, .ops_open = fi_no_ops_open, }; static int mrail_mr_reg(struct fid *domain_fid, const void *buf, size_t len, uint64_t access, uint64_t offset, uint64_t requested_key, uint64_t flags, struct fid_mr **mr, void *context) { struct mrail_domain *mrail_domain = container_of(domain_fid, struct mrail_domain, util_domain.domain_fid.fid); size_t num_rails = mrail_domain->num_domains; struct mrail_mr *mrail_mr; struct fi_info *fi; uint32_t rail; int ret = 0; mrail_mr = calloc(1, sizeof(*mrail_mr) + num_rails * sizeof(*mrail_mr->rails)); if (!mrail_mr) return -FI_ENOMEM; for (rail = 0, fi = mrail_domain->info->next; rail < mrail_domain->num_domains; ++rail, fi = fi->next) { ret = fi_mr_reg(mrail_domain->domains[rail], buf, len, access, offset, requested_key, flags, &mrail_mr->rails[rail].mr, context); if (ret) { FI_WARN(&mrail_prov, FI_LOG_DOMAIN, "Unable to register memory, rail %" PRIu32 "\n", rail); goto err1; } mrail_mr->rails[rail].base_addr = (fi->domain_attr->mr_mode & FI_MR_VIRT_ADDR) ? (uint64_t)buf : 0; } mrail_mr->mr_fid.fid.fclass = FI_CLASS_MR; mrail_mr->mr_fid.fid.context = context; mrail_mr->mr_fid.fid.ops = &mrail_mr_ops; mrail_mr->mr_fid.mem_desc = mrail_mr; mrail_mr->mr_fid.key = FI_KEY_NOTAVAIL; mrail_mr->num_mrs = mrail_domain->num_domains; *mr = &mrail_mr->mr_fid; return 0; err1: for (; rail != 0; --rail) fi_close(&mrail_mr->rails[rail].mr->fid); free(mrail_mr); return ret; } static int mrail_mr_regv(struct fid *domain_fid, const struct iovec *iov, size_t count, uint64_t access, uint64_t offset, uint64_t requested_key, uint64_t flags, struct fid_mr **mr, void *context) { struct mrail_domain *mrail_domain = container_of(domain_fid, struct mrail_domain, util_domain.domain_fid.fid); size_t num_rails = mrail_domain->num_domains; struct mrail_mr *mrail_mr; struct fi_info *fi; uint32_t rail; int ret = 0; mrail_mr = calloc(1, sizeof(*mrail_mr) + num_rails * sizeof(*mrail_mr->rails)); if (!mrail_mr) return -FI_ENOMEM; for (rail = 0, fi = mrail_domain->info->next; rail < mrail_domain->num_domains; ++rail, fi = fi->next) { ret = fi_mr_regv(mrail_domain->domains[rail], iov, count, access, offset, requested_key, flags, &mrail_mr->rails[rail].mr, context); if (ret) { FI_WARN(&mrail_prov, FI_LOG_DOMAIN, "Unable to register memory, rail %" PRIu32 "\n", rail); goto err1; } mrail_mr->rails[rail].base_addr = (fi->domain_attr->mr_mode & FI_MR_VIRT_ADDR) ? (uint64_t)iov[0].iov_base : 0; } mrail_mr->mr_fid.fid.fclass = FI_CLASS_MR; mrail_mr->mr_fid.fid.context = context; mrail_mr->mr_fid.fid.ops = &mrail_mr_ops; mrail_mr->mr_fid.mem_desc = mrail_mr; mrail_mr->mr_fid.key = FI_KEY_NOTAVAIL; mrail_mr->num_mrs = mrail_domain->num_domains; *mr = &mrail_mr->mr_fid; return 0; err1: for (; rail != 0; --rail) fi_close(&mrail_mr->rails[rail].mr->fid); free(mrail_mr); return ret; } static int mrail_mr_regattr(struct fid *domain_fid, const struct fi_mr_attr *attr, uint64_t flags, struct fid_mr **mr) { struct mrail_domain *mrail_domain = container_of(domain_fid, struct mrail_domain, util_domain.domain_fid.fid); size_t num_rails = mrail_domain->num_domains; struct mrail_mr *mrail_mr; struct fi_info *fi; uint32_t rail; int ret = 0; mrail_mr = calloc(1, sizeof(*mrail_mr) + num_rails * sizeof(*mrail_mr->rails)); if (!mrail_mr) return -FI_ENOMEM; for (rail = 0, fi = mrail_domain->info->next; rail < mrail_domain->num_domains; ++rail, fi = fi->next) { ret = fi_mr_regattr(mrail_domain->domains[rail], attr, flags, &mrail_mr->rails[rail].mr); if (ret) { FI_WARN(&mrail_prov, FI_LOG_DOMAIN, "Unable to register memory, rail %" PRIu32 "\n", rail); goto err1; } mrail_mr->rails[rail].base_addr = (fi->domain_attr->mr_mode & FI_MR_VIRT_ADDR) ? (uint64_t)attr->mr_iov[0].iov_base : 0; } mrail_mr->mr_fid.fid.fclass = FI_CLASS_MR; mrail_mr->mr_fid.fid.context = attr->context; mrail_mr->mr_fid.fid.ops = &mrail_mr_ops; mrail_mr->mr_fid.mem_desc = mrail_mr; mrail_mr->mr_fid.key = FI_KEY_NOTAVAIL; mrail_mr->num_mrs = mrail_domain->num_domains; *mr = &mrail_mr->mr_fid; return 0; err1: for (; rail != 0; --rail) fi_close(&mrail_mr->rails[rail].mr->fid); free(mrail_mr); return ret; } static struct fi_ops_mr mrail_domain_mr_ops = { .size = sizeof(struct fi_ops_mr), .reg = mrail_mr_reg, .regv = mrail_mr_regv, .regattr = mrail_mr_regattr, }; int mrail_cntr_open(struct fid_domain *domain, struct fi_cntr_attr *attr, struct fid_cntr **cntr_fid, void *context) { int ret; struct util_cntr *cntr; cntr = calloc(1, sizeof(*cntr)); if (!cntr) return -FI_ENOMEM; ret = ofi_cntr_init(&mrail_prov, domain, attr, cntr, &ofi_cntr_progress, context); if (ret) goto error; *cntr_fid = &cntr->cntr_fid; return FI_SUCCESS; error: free(cntr); return ret; } static struct fi_ops_domain mrail_domain_ops = { .size = sizeof(struct fi_ops_domain), .av_open = mrail_av_open, .cq_open = mrail_cq_open, .endpoint = mrail_ep_open, .scalable_ep = fi_no_scalable_ep, .cntr_open = mrail_cntr_open, .poll_open = fi_no_poll_open, .stx_ctx = fi_no_stx_context, .srx_ctx = fi_no_srx_context, .query_atomic = fi_no_query_atomic, .query_collective = fi_no_query_collective, }; int mrail_domain_open(struct fid_fabric *fabric, struct fi_info *info, struct fid_domain **domain, void *context) { struct mrail_fabric *mrail_fabric = container_of(fabric, struct mrail_fabric, util_fabric.fabric_fid); struct mrail_domain *mrail_domain; struct fi_info *fi; size_t i; int ret; assert(!strcmp(mrail_fabric->info->fabric_attr->name, info->fabric_attr->name)); mrail_domain = calloc(1, sizeof(*mrail_domain)); if (!mrail_domain) return -FI_ENOMEM; ret = ofi_domain_init(fabric, info, &mrail_domain->util_domain, context); if (ret) { free(mrail_domain); return ret; } mrail_domain->info = mrail_fabric->info; mrail_domain->num_domains = mrail_fabric->num_fabrics; mrail_domain->domains = calloc(mrail_domain->num_domains, sizeof(*mrail_domain->domains)); if (!mrail_domain->domains) { ret = -FI_ENOMEM; goto err; } for (i = 0, fi = mrail_domain->info->next; fi; fi = fi->next, i++) { ret = fi_domain(mrail_fabric->fabrics[i], fi, &mrail_domain->domains[i], context); if (ret) goto err; mrail_domain->addrlen += fi->src_addrlen; } *domain = &mrail_domain->util_domain.domain_fid; (*domain)->fid.ops = &mrail_domain_fi_ops; (*domain)->mr = &mrail_domain_mr_ops; (*domain)->ops = &mrail_domain_ops; return 0; err: mrail_domain_close(&mrail_domain->util_domain.domain_fid.fid); return ret; }