4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright 2022 Hewlett Packard Enterprise Development LP
26 * This file is part of Lustre, http://www.lustre.org/
29 * kfilnd domain and fabric implementation.
31 #include "kfilnd_dom.h"
32 #include "kfilnd_tn.h"
34 /* Global list of allocated KFI LND fabrics. */
35 static LIST_HEAD(fab_list);
36 static DEFINE_MUTEX(fab_list_lock);
39 * kfilnd_dom_free() - Free a KFI LND domain.
40 * @dom: KFI LND domain to be freed.
42 static void kfilnd_dom_free(struct kref *kref)
44 struct kfilnd_dom *dom;
49 dom = container_of(kref, struct kfilnd_dom, cnt);
51 mutex_lock(&dom->fab->dom_list_lock);
52 list_del(&dom->entry);
53 mutex_unlock(&dom->fab->dom_list_lock);
55 kfi_close(&dom->domain->fid);
56 LIBCFS_FREE(dom, sizeof(*dom));
60 * kfilnd_dom_alloc() - Allocate a new KFI LND domain.
61 * @dom_info: KFI info structure used to allocate the KFI LND domain.
62 * @fab: KFI LND fabric used by the domain.
64 * A KFI LND domain (and the underlying KFI domain) provides access to a
65 * specific NIC on a fabric. The same KFI LND domain can be used to allocate
66 * different KFI LND devices.
68 * Return: On success, valid pointer. Else, negative errno pointer.
70 static struct kfilnd_dom *kfilnd_dom_alloc(struct kfi_info *dom_info,
71 struct kfilnd_fab *fab)
74 struct kfilnd_dom *dom;
76 if (!dom_info || !fab) {
81 LIBCFS_ALLOC_GFP(dom, sizeof(*dom), GFP_KERNEL);
87 INIT_LIST_HEAD(&dom->dev_list);
88 spin_lock_init(&dom->lock);
92 rc = kfi_domain(fab->fabric, dom_info, &dom->domain, dom);
94 CERROR("Failed to create KFI domain: rc=%d\n", rc);
98 mutex_lock(&fab->dom_list_lock);
99 list_add_tail(&dom->entry, &fab->dom_list);
100 mutex_unlock(&fab->dom_list_lock);
105 LIBCFS_FREE(dom, sizeof(*dom));
111 * kfilnd_dom_reuse() - Attempt to reuse an already allocated domain.
112 * @node: Node string used to limit domains to.
113 * @service: Service string used to limit domains to.
114 * @hints: Hints used to allocate KFI info structures.
115 * @fab: Fabric used to limit domains to.
117 * Return: On success (matching domain is found), valid pointer is returned.
120 struct kfilnd_dom *kfilnd_dom_reuse(const char *node, const char *service,
121 struct kfi_info *hints,
122 struct kfilnd_fab *fab)
124 struct kfilnd_dom *dom;
125 struct kfi_info *info;
128 if (!node || !service || !hints || !fab)
131 /* Update the hints domain attribute with an already allocated domain to
132 * see if domains can be reused.
134 hints->fabric_attr->fabric = fab->fabric;
136 mutex_lock(&fab->dom_list_lock);
137 list_for_each_entry(dom, &fab->dom_list, entry) {
138 hints->domain_attr->domain = dom->domain;
140 rc = kfi_getinfo(0, node, service, KFI_SOURCE, hints, &info);
144 mutex_unlock(&fab->dom_list_lock);
151 mutex_unlock(&fab->dom_list_lock);
153 hints->domain_attr->domain = NULL;
159 * kfilnd_fab_free() - Free KFI LND fabric.
161 static void kfilnd_fab_free(struct kref *kref)
163 struct kfilnd_fab *fab;
168 fab = container_of(kref, struct kfilnd_fab, cnt);
170 mutex_lock(&fab_list_lock);
171 list_del(&fab->entry);
172 mutex_unlock(&fab_list_lock);
174 kfi_close(&fab->fabric->fid);
175 LIBCFS_FREE(fab, sizeof(*fab));
179 * kfilnd_fab_alloc() - Allocate a new KFI LND fabric.
180 * @attr: KFI fabric attributes used to allocate the underlying KFI fabric.
182 * A KFI LND fabric (and the underlying KFI fabric) providers access to NICs on
183 * the same fabric. The underlying KFI fabric should be shared between all NICs
184 * (KFI domains) on the same fabric.
186 * Return: On success, valid pointer. Else, negative errno pointer.
188 static struct kfilnd_fab *kfilnd_fab_alloc(struct kfi_fabric_attr *attr)
191 struct kfilnd_fab *fab;
198 LIBCFS_ALLOC_GFP(fab, sizeof(*fab), GFP_KERNEL);
204 INIT_LIST_HEAD(&fab->dom_list);
205 mutex_init(&fab->dom_list_lock);
206 kref_init(&fab->cnt);
208 rc = kfi_fabric(attr, &fab->fabric, fab);
210 CERROR("Failed to allocate KFI fabric: rc=%d\n", rc);
214 mutex_lock(&fab_list_lock);
215 list_add_tail(&fab->entry, &fab_list);
216 mutex_unlock(&fab_list_lock);
221 LIBCFS_FREE(fab, sizeof(*fab));
227 * kfilnd_fab_reuse() - Attempt to reuse an already allocated fabric.
228 * @node: Node string used to limit fabrics to.
229 * @service: Service string used to limit fabrics to.
230 * @hints: Hints used to allocate KFI info structures.
232 * Return: On success (matching fabric is found), valid pointer is returned.
235 struct kfilnd_fab *kfilnd_fab_reuse(const char *node, const char *service,
236 struct kfi_info *hints)
238 struct kfilnd_fab *fab;
239 struct kfi_info *info;
242 if (!node || !service || !hints)
245 /* Update the hints fabric attribute with an already allocated fabric to
246 * see if fabrics can be reused.
248 mutex_lock(&fab_list_lock);
249 list_for_each_entry(fab, &fab_list, entry) {
250 hints->fabric_attr->fabric = fab->fabric;
252 rc = kfi_getinfo(0, node, service, KFI_SOURCE, hints, &info);
256 mutex_unlock(&fab_list_lock);
263 mutex_unlock(&fab_list_lock);
265 hints->fabric_attr->fabric = NULL;
271 * kfi_domain_put() - Put a KFI LND domain reference.
273 void kfilnd_dom_put(struct kfilnd_dom *dom)
275 struct kfilnd_fab *fab;
282 kref_put(&dom->cnt, kfilnd_dom_free);
284 kref_put(&fab->cnt, kfilnd_fab_free);
288 * kfilnd_dom_get() - Get a KFI LND domain.
289 * @ni: LNet NI used to define the KFI LND domain address.
290 * @node: Node string which can be passed into kfi_getinfo().
291 * @dev_info: KFI info structure which should be used to allocate a KFI LND
292 * device using this domain.
294 * On success, a KFI info structure is returned to the user in addition to a KFI
295 * LND domain. Callers should free the KFI info structure once done using it.
297 * Return: On success, dev_info is set to a valid KFI info structure and a valid
298 * KFI LND domain is returned. Else, negative errno pointer is returned.
300 struct kfilnd_dom *kfilnd_dom_get(struct lnet_ni *ni, const char *node,
301 struct kfi_info **dev_info)
304 struct kfi_info *hints;
305 struct kfi_info *info;
306 struct kfi_info *hints_tmp;
307 struct kfi_info *info_tmp;
308 struct kfilnd_fab *fab;
309 struct kfilnd_dom *dom;
310 struct kfi_cxi_fabric_ops *fab_ops;
313 if (!ni || !dev_info) {
318 service = kasprintf(GFP_KERNEL, "%u", ni->ni_nid.nid_num);
324 hints = kfi_allocinfo();
327 goto err_free_service;
330 hints->caps = KFI_MSG | KFI_RMA | KFI_SEND | KFI_RECV | KFI_READ |
331 KFI_WRITE | KFI_REMOTE_READ | KFI_REMOTE_WRITE |
332 KFI_MULTI_RECV | KFI_REMOTE_COMM | KFI_NAMED_RX_CTX |
333 KFI_TAGGED | KFI_TAGGED_RMA | KFI_DIRECTED_RECV;
334 hints->fabric_attr->prov_version =
335 KFI_VERSION(ni->ni_lnd_tunables.lnd_tun_u.lnd_kfi.lnd_prov_major_version,
336 ni->ni_lnd_tunables.lnd_tun_u.lnd_kfi.lnd_prov_minor_version);
337 hints->domain_attr->mr_iov_limit = 256; /* 1 MiB LNet message */
338 hints->domain_attr->mr_key_size = sizeof(int);
339 hints->domain_attr->resource_mgmt = KFI_RM_DISABLED;
340 hints->ep_attr->max_msg_size = LNET_MAX_PAYLOAD;
341 hints->rx_attr->op_flags = KFI_COMPLETION | KFI_MULTI_RECV;
342 hints->rx_attr->iov_limit = 256; /* 1 MiB LNet message */
343 hints->tx_attr->op_flags = KFI_COMPLETION;
344 hints->tx_attr->iov_limit = 256; /* 1 MiB LNet message */
345 hints->tx_attr->rma_iov_limit = 256; /* 1 MiB LNet message */
346 hints->ep_attr->auth_key =
347 (void *)&ni->ni_lnd_tunables.lnd_tun_u.lnd_kfi.lnd_auth_key;
348 hints->ep_attr->auth_key_size =
349 sizeof(ni->ni_lnd_tunables.lnd_tun_u.lnd_kfi.lnd_auth_key);
351 /* Check if dynamic resource allocation is supported.
352 * Set dynamic resource alloc hints if it is.
354 * Need to check if op is supported since due to a bug can't
355 * simply set ctx_cnts greater than 1 (default value) if it isn't.
357 hints_tmp = kfi_dupinfo(hints);
359 rc = kfi_getinfo(0, node, service, KFI_SOURCE, hints_tmp,
362 fab = kfilnd_fab_alloc(info_tmp->fabric_attr);
364 rc = kfi_open_ops(&fab->fabric->fid,
365 KFI_CXI_FAB_OPS_1, 0, (void **)&fab_ops,
368 /* Set dynamic resource alloc hints */
369 hints->domain_attr->cq_cnt = ni->ni_ncpts * 2;
370 hints->domain_attr->tx_ctx_cnt = ni->ni_ncpts;
371 hints->domain_attr->rx_ctx_cnt = ni->ni_ncpts;
372 hints->rx_attr->size =
373 ni->ni_net->net_tunables.lct_max_tx_credits +
374 immediate_rx_buf_count;
376 kref_put(&fab->cnt, kfilnd_fab_free);
378 kfi_freeinfo(info_tmp);
380 kfi_freeinfo(hints_tmp);
383 /* Check to see if any KFI LND fabrics/domains can be reused. */
384 fab = kfilnd_fab_reuse(node, service, hints);
385 dom = kfilnd_dom_reuse(node, service, hints, fab);
388 hints->fabric_attr->fabric = fab->fabric;
390 hints->domain_attr->domain = dom->domain;
392 /* Allocate the official KFI info structure to be used for KFI LND
395 rc = kfi_getinfo(0, node, service, KFI_SOURCE, hints, &info);
397 /* Authorization key information is now stored in the returned kfi_info
398 * structure. Since kfi_freeinfo() will try to free the auth_key pointer
399 * and this memory is owned as part of the LNet NI, need to zero this
400 * information in the hints to prevent LNet NI corruption.
402 hints->ep_attr->auth_key = NULL;
403 hints->ep_attr->auth_key_size = 0;
411 goto err_free_service;
413 /* Allocate a new KFI LND fabric and domain if necessary. */
415 fab = kfilnd_fab_alloc(info->fabric_attr);
423 /* Enable dynamic resource allocation if operation supported */
424 rc = kfi_open_ops(&fab->fabric->fid, KFI_CXI_FAB_OPS_1, 0,
425 (void **)&fab_ops, NULL);
427 rc = fab_ops->enable_dynamic_rsrc_alloc(&fab->fabric->fid, true);
429 CDEBUG(D_NET, "Enabled dynamic resource allocation for KFI domain\n");
431 dom = kfilnd_dom_alloc(info, fab);
443 kref_put(&fab->cnt, kfilnd_fab_free);