xref: /freebsd/sys/dev/ice/ice_rdma.c (revision f2635e844dd138ac9dfba676f27d41750049af26)
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*  Copyright (c) 2024, Intel Corporation
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above copyright notice,
9  *      this list of conditions and the following disclaimer.
10  *
11  *   2. Redistributions in binary form must reproduce the above copyright
12  *      notice, this list of conditions and the following disclaimer in the
13  *      documentation and/or other materials provided with the distribution.
14  *
15  *   3. Neither the name of the Intel Corporation nor the names of its
16  *      contributors may be used to endorse or promote products derived from
17  *      this software without specific prior written permission.
18  *
19  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  *  POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /**
33  * @file ice_rdma.c
34  * @brief RDMA client driver interface
35  *
36  * Functions to interface with the RDMA client driver, for enabling RMDA
37  * functionality for the ice driver.
38  *
39  * The RDMA client interface is based on a simple kobject interface which is
40  * defined by the rmda_if.m and irdma_di_if.m interfaces.
41  *
42  * The ice device driver provides the rmda_di_if.m interface methods, while
43  * the client RDMA driver provides the irdma_if.m interface methods as an
44  * extension ontop of the irdma_di_if kobject.
45  *
46  * The initial connection between drivers is done via the RDMA client driver
47  * calling ice_rdma_register.
48  */
49 
50 #include "ice_iflib.h"
51 #include "ice_rdma_internal.h"
52 
53 #include "irdma_if.h"
54 #include "irdma_di_if.h"
55 
56 /**
57  * @var ice_rdma
58  * @brief global RDMA driver state
59  *
60  * Contains global state the driver uses to connect to a client RDMA interface
61  * driver.
62  */
63 static struct ice_rdma_state ice_rdma;
64 
65 /*
66  * Helper function prototypes
67  */
68 static int ice_rdma_pf_attach_locked(struct ice_softc *sc);
69 static void ice_rdma_pf_detach_locked(struct ice_softc *sc);
70 static int ice_rdma_check_version(struct ice_rdma_info *info);
71 static void ice_rdma_cp_qos_info(struct ice_hw *hw,
72 				 struct ice_dcbx_cfg *dcbx_cfg,
73 				 struct ice_qos_params *qos_info);
74 
75 /*
76  * RDMA Device Interface prototypes
77  */
78 static int ice_rdma_pf_reset(struct ice_rdma_peer *peer);
79 static int ice_rdma_pf_msix_init(struct ice_rdma_peer *peer,
80 				 struct ice_rdma_msix_mapping *msix_info);
81 static int ice_rdma_qset_register_request(struct ice_rdma_peer *peer,
82 			     struct ice_rdma_qset_update *res);
83 static int ice_rdma_update_vsi_filter(struct ice_rdma_peer *peer_dev,
84 				      bool enable);
85 static void ice_rdma_request_handler(struct ice_rdma_peer *peer,
86 				     struct ice_rdma_request *req);
87 
88 
89 /**
90  * @var ice_rdma_di_methods
91  * @brief RDMA driver interface methods
92  *
93  * Kobject methods implementing the driver-side interface for the RDMA peer
94  * clients. This method table contains the operations which the client can
95  * request from the driver.
96  *
97  * The client driver will then extend this kobject class with methods that the
98  * driver can request from the client.
99  */
100 static kobj_method_t ice_rdma_di_methods[] = {
101 	KOBJMETHOD(irdma_di_reset, ice_rdma_pf_reset),
102 	KOBJMETHOD(irdma_di_msix_init, ice_rdma_pf_msix_init),
103 	KOBJMETHOD(irdma_di_qset_register_request, ice_rdma_qset_register_request),
104 	KOBJMETHOD(irdma_di_vsi_filter_update, ice_rdma_update_vsi_filter),
105 	KOBJMETHOD(irdma_di_req_handler, ice_rdma_request_handler),
106 	KOBJMETHOD_END
107 };
108 
109 /* Define ice_rdma_di class which will be extended by the iRDMA driver */
110 DEFINE_CLASS_0(ice_rdma_di, ice_rdma_di_class, ice_rdma_di_methods, sizeof(struct ice_rdma_peer));
111 
112 /**
113  * ice_rdma_pf_reset - RDMA client interface requested a reset
114  * @peer: the RDMA peer client structure
115  *
116  * Implements IRDMA_DI_RESET, called by the RDMA client driver to request
117  * a reset of an ice driver device.
118  * @return 0 on success
119  */
120 static int
121 ice_rdma_pf_reset(struct ice_rdma_peer *peer)
122 {
123 	struct ice_softc *sc = ice_rdma_peer_to_sc(peer);
124 
125 	/* Tell the base driver that RDMA is requesting a PFR */
126 	ice_set_state(&sc->state, ICE_STATE_RESET_PFR_REQ);
127 
128 	/* XXX: Base driver will notify RDMA when it's done */
129 
130 	return (0);
131 }
132 
133 /**
134  * ice_rdma_pf_msix_init - RDMA client interface request MSI-X initialization
135  * @peer: the RDMA peer client structure
136  * @msix_info: requested MSI-X mapping
137  *
138  * Implements IRDMA_DI_MSIX_INIT, called by the RDMA client driver to
139  * initialize the MSI-X resources required for RDMA functionality.
140  * @returns ENOSYS
141  */
142 static int
143 ice_rdma_pf_msix_init(struct ice_rdma_peer *peer,
144 		      struct ice_rdma_msix_mapping __unused *msix_info)
145 {
146 	struct ice_softc *sc = ice_rdma_peer_to_sc(peer);
147 
148 	MPASS(msix_info != NULL);
149 
150 	device_printf(sc->dev, "%s: iRDMA MSI-X initialization request is not yet implemented\n", __func__);
151 
152 	/* TODO: implement MSI-X initialization for RDMA */
153 	return (ENOSYS);
154 }
155 
156 /**
157  * ice_rdma_register_request - RDMA client interface request qset
158  *                             registration or unregistration
159  * @peer: the RDMA peer client structure
160  * @res: resources to be registered or unregistered
161  * @returns 0 on success, EINVAL on argument issues, ENOMEM on memory
162  * allocation failure, EXDEV on vsi device mismatch
163  */
164 static int
165 ice_rdma_qset_register_request(struct ice_rdma_peer *peer, struct ice_rdma_qset_update *res)
166 {
167 	struct ice_softc *sc = ice_rdma_peer_to_sc(peer);
168 	struct ice_vsi *vsi = NULL;
169 	struct ice_dcbx_cfg *dcbx_cfg;
170 	struct ice_hw *hw = &sc->hw;
171 	int status;
172 	int count, i, ret = 0;
173 	uint32_t *qset_teid;
174 	uint16_t *qs_handle;
175 	uint16_t max_rdmaqs[ICE_MAX_TRAFFIC_CLASS];
176 	uint16_t vsi_id;
177 	uint8_t ena_tc = 0;
178 
179 	if (!res)
180 		return -EINVAL;
181 
182 	if (res->cnt_req > ICE_MAX_TXQ_PER_TXQG)
183 		return -EINVAL;
184 
185 	switch(res->res_type) {
186 	case ICE_RDMA_QSET_ALLOC:
187 		count = res->cnt_req;
188 		vsi_id = peer->pf_vsi_num;
189 		break;
190 	case ICE_RDMA_QSET_FREE:
191 		count = res->res_allocated;
192 		vsi_id = res->qsets.vsi_id;
193 		break;
194 	default:
195 		return -EINVAL;
196 	}
197 	qset_teid = (uint32_t *)ice_calloc(hw, count, sizeof(*qset_teid));
198 	if (!qset_teid)
199 		return -ENOMEM;
200 
201 	qs_handle = (uint16_t *)ice_calloc(hw, count, sizeof(*qs_handle));
202 	if (!qs_handle) {
203 		ice_free(hw, qset_teid);
204 		return -ENOMEM;
205 	}
206 
207 	ice_for_each_traffic_class(i)
208 		max_rdmaqs[i] = 0;
209 	for (i = 0; i < sc->num_available_vsi; i++) {
210 		if (sc->all_vsi[i] &&
211 		    ice_get_hw_vsi_num(hw, sc->all_vsi[i]->idx) == vsi_id) {
212 			vsi = sc->all_vsi[i];
213 			break;
214 		}
215 	}
216 
217 	if (!vsi) {
218 		ice_debug(hw, ICE_DBG_RDMA, "RDMA QSet invalid VSI\n");
219 		ret = -EINVAL;
220 		goto out;
221 	}
222 	if (sc != vsi->sc) {
223 		ice_debug(hw, ICE_DBG_RDMA, "VSI is tied to unexpected device\n");
224 		ret = -EXDEV;
225 		goto out;
226 	}
227 
228 	for (i = 0; i < count; i++) {
229 		struct ice_rdma_qset_params *qset;
230 
231 		qset = &res->qsets;
232 		if (qset->vsi_id != peer->pf_vsi_num) {
233 			ice_debug(hw, ICE_DBG_RDMA, "RDMA QSet invalid VSI requested %d %d\n",
234 				  qset->vsi_id, peer->pf_vsi_num);
235 			ret = -EINVAL;
236 			goto out;
237 		}
238 		max_rdmaqs[qset->tc]++;
239 		qs_handle[i] = qset->qs_handle;
240 		qset_teid[i] = qset->teid;
241 	}
242 
243 	switch(res->res_type) {
244 	case ICE_RDMA_QSET_ALLOC:
245 		dcbx_cfg = &hw->port_info->qos_cfg.local_dcbx_cfg;
246 		ena_tc = ice_dcb_get_tc_map(dcbx_cfg);
247 
248 		ice_debug(hw, ICE_DBG_RDMA, "%s:%d ena_tc=%x\n", __func__, __LINE__, ena_tc);
249 		status = ice_cfg_vsi_rdma(hw->port_info, vsi->idx, ena_tc,
250 					  max_rdmaqs);
251 		if (status) {
252 			ice_debug(hw, ICE_DBG_RDMA, "Failed VSI RDMA qset config\n");
253 			ret = -EINVAL;
254 			goto out;
255 		}
256 
257 		for (i = 0; i < count; i++) {
258 			struct ice_rdma_qset_params *qset;
259 
260 			qset = &res->qsets;
261 			status = ice_ena_vsi_rdma_qset(hw->port_info, vsi->idx,
262 						       qset->tc, &qs_handle[i], 1,
263 						       &qset_teid[i]);
264 			if (status) {
265 				ice_debug(hw, ICE_DBG_RDMA, "Failed VSI RDMA qset enable\n");
266 				ret = -EINVAL;
267 				goto out;
268 			}
269 			qset->teid = qset_teid[i];
270 		}
271 		break;
272 	case ICE_RDMA_QSET_FREE:
273 		status = ice_dis_vsi_rdma_qset(hw->port_info, count, qset_teid, qs_handle);
274 		if (status)
275 			ret = -EINVAL;
276 		break;
277 	default:
278 		ret = -EINVAL;
279 		break;
280 	}
281 
282 out:
283 	ice_free(hw, qs_handle);
284 	ice_free(hw, qset_teid);
285 
286 	return ret;
287 }
288 
289 /**
290  *  ice_rdma_update_vsi_filter - configure vsi information
291  *                               when opening or closing rdma driver
292  *  @peer: the RDMA peer client structure
293  *  @enable: enable or disable the rdma filter
294  *  @return 0 on success, EINVAL on wrong vsi
295  */
296 static int
297 ice_rdma_update_vsi_filter(struct ice_rdma_peer *peer,
298 			   bool enable)
299 {
300 	struct ice_softc *sc = ice_rdma_peer_to_sc(peer);
301 	struct ice_vsi *vsi;
302 	int ret;
303 
304 	vsi = &sc->pf_vsi;
305 	if (!vsi)
306 		return -EINVAL;
307 
308 	ret = ice_cfg_iwarp_fltr(&sc->hw, vsi->idx, enable);
309 	if (ret) {
310 		device_printf(sc->dev, "Failed to  %sable iWARP filtering\n",
311 				enable ? "en" : "dis");
312 	} else {
313 		if (enable)
314 			vsi->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
315 		else
316 			vsi->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
317 	}
318 
319 	return ret;
320 }
321 
322 /**
323  * ice_rdma_request_handler - handle requests incoming from RDMA driver
324  * @peer: the RDMA peer client structure
325  * @req: structure containing request
326  */
327 static void
328 ice_rdma_request_handler(struct ice_rdma_peer *peer,
329 			 struct ice_rdma_request *req)
330 {
331 	if (!req || !peer) {
332 		log(LOG_WARNING, "%s: peer or req are not valid\n", __func__);
333 		return;
334 	}
335 
336 	switch(req->type) {
337 	case ICE_RDMA_EVENT_RESET:
338 		ice_rdma_pf_reset(peer);
339 		break;
340 	case ICE_RDMA_EVENT_QSET_REGISTER:
341 		ice_rdma_qset_register_request(peer, &req->res);
342 		break;
343 	case ICE_RDMA_EVENT_VSI_FILTER_UPDATE:
344 		ice_rdma_update_vsi_filter(peer, req->enable_filter);
345 		break;
346 	default:
347 		log(LOG_WARNING, "%s: Event %d not supported\n", __func__, req->type);
348 		break;
349 	}
350 }
351 
352 /**
353  * ice_rdma_cp_qos_info - gather current QOS/DCB settings in LAN to pass
354  *                        to RDMA driver
355  * @hw: ice hw structure
356  * @dcbx_cfg: current DCB settings in ice driver
357  * @qos_info: destination of the DCB settings
358  */
359 static void
360 ice_rdma_cp_qos_info(struct ice_hw *hw, struct ice_dcbx_cfg *dcbx_cfg,
361 		     struct ice_qos_params *qos_info)
362 {
363 	u32 up2tc;
364 	u8 j;
365 	u8 num_tc = 0;
366 	u8 val_tc = 0;  /* number of TC for validation */
367 	u8 cnt_tc = 0;
368 
369 	/* setup qos_info fields with defaults */
370 	qos_info->num_apps = 0;
371 	qos_info->num_tc = 1;
372 
373 	for (j = 0; j < ICE_TC_MAX_USER_PRIORITY; j++)
374 		qos_info->up2tc[j] = 0;
375 
376 	qos_info->tc_info[0].rel_bw = 100;
377 	for (j = 1; j < IEEE_8021QAZ_MAX_TCS; j++)
378 		qos_info->tc_info[j].rel_bw = 0;
379 
380 	/* gather current values */
381 	up2tc = rd32(hw, PRTDCB_TUP2TC);
382 	qos_info->num_apps = dcbx_cfg->numapps;
383 
384 	for (j = 0; j < ICE_MAX_TRAFFIC_CLASS; j++) {
385 		num_tc |= BIT(dcbx_cfg->etscfg.prio_table[j]);
386 	}
387 	for (j = 0; j < ICE_MAX_TRAFFIC_CLASS; j++) {
388 		if (num_tc & BIT(j)) {
389 			cnt_tc++;
390 			val_tc |= BIT(j);
391 		} else {
392 			break;
393 		}
394 	}
395 	qos_info->num_tc = (val_tc == num_tc && num_tc != 0) ? cnt_tc : 1;
396 	for (j = 0; j < ICE_TC_MAX_USER_PRIORITY; j++)
397 		qos_info->up2tc[j] = (up2tc >> (j * 3)) & 0x7;
398 
399 	for (j = 0; j < IEEE_8021QAZ_MAX_TCS; j++)
400 		qos_info->tc_info[j].rel_bw = dcbx_cfg->etscfg.tcbwtable[j];
401 	for (j = 0; j < qos_info->num_apps; j++) {
402 		qos_info->apps[j].priority = dcbx_cfg->app[j].priority;
403 		qos_info->apps[j].prot_id = dcbx_cfg->app[j].prot_id;
404 		qos_info->apps[j].selector = dcbx_cfg->app[j].selector;
405 	}
406 
407 	/* Gather DSCP-to-TC mapping and QoS/PFC mode */
408 	memcpy(qos_info->dscp_map, dcbx_cfg->dscp_map, sizeof(qos_info->dscp_map));
409 	qos_info->pfc_mode = dcbx_cfg->pfc_mode;
410 }
411 
412 /**
413  * ice_rdma_check_version - Check that the provided RDMA version is compatible
414  * @info: the RDMA client information structure
415  *
416  * Verify that the client RDMA driver provided a version that is compatible
417  * with the driver interface.
418  * @return 0 on success, ENOTSUP when LAN-RDMA interface version doesn't match,
419  * EINVAL on kobject interface fail.
420  */
421 static int
422 ice_rdma_check_version(struct ice_rdma_info *info)
423 {
424 	/* Make sure the MAJOR version matches */
425 	if (info->major_version != ICE_RDMA_MAJOR_VERSION) {
426 		log(LOG_WARNING, "%s: the iRDMA driver requested version %d.%d.%d, but this driver only supports major version %d.x.x\n",
427 		    __func__,
428 		    info->major_version, info->minor_version, info->patch_version,
429 		    ICE_RDMA_MAJOR_VERSION);
430 		return (ENOTSUP);
431 	}
432 
433 	/*
434 	 * Make sure that the MINOR version is compatible.
435 	 *
436 	 * This means that the RDMA client driver version MUST not be greater
437 	 * than the version provided by the driver, as it would indicate that
438 	 * the RDMA client expects features which are not supported by the
439 	 * main driver.
440 	 */
441 	if (info->minor_version > ICE_RDMA_MINOR_VERSION) {
442 		log(LOG_WARNING, "%s: the iRDMA driver requested version %d.%d.%d, but this driver only supports up to minor version %d.%d.x\n",
443 		__func__,
444 		info->major_version, info->minor_version, info->patch_version,
445 		ICE_RDMA_MAJOR_VERSION, ICE_RDMA_MINOR_VERSION);
446 		return (ENOTSUP);
447 	}
448 
449 	/*
450 	 * Make sure that the PATCH version is compatible.
451 	 *
452 	 * This means that the RDMA client version MUST not be greater than
453 	 * the version provided by the driver, as it may indicate that the
454 	 * RDMA client expects certain backwards compatible bug fixes which
455 	 * are not implemented by this version of the main driver.
456 	 */
457 	if ((info->minor_version == ICE_RDMA_MINOR_VERSION) &&
458 	    (info->patch_version > ICE_RDMA_PATCH_VERSION)) {
459 		log(LOG_WARNING, "%s: the iRDMA driver requested version %d.%d.%d, but this driver only supports up to patch version %d.%d.%d\n",
460 		__func__,
461 		info->major_version, info->minor_version, info->patch_version,
462 		ICE_RDMA_MAJOR_VERSION, ICE_RDMA_MINOR_VERSION, ICE_RDMA_PATCH_VERSION);
463 		return (ENOTSUP);
464 	}
465 
466 	/* Make sure that the kobject class is initialized */
467 	if (info->rdma_class == NULL) {
468 		log(LOG_WARNING, "%s: the iRDMA driver did not specify a kobject interface\n",
469 		    __func__);
470 		return (EINVAL);
471 	}
472 
473 	return (0);
474 }
475 
476 /**
477  * ice_rdma_register - Register an RDMA client driver
478  * @info: the RDMA client information structure
479  *
480  * Called by the RDMA client driver on load. Used to initialize the RDMA
481  * client driver interface and enable interop between the ice driver and the
482  * RDMA client driver.
483  *
484  * The RDMA client driver must provide the version number it expects, along
485  * with a pointer to a kobject class that extends the irdma_di_if class, and
486  * implements the irdma_if class interface.
487  * @return 0 on success, ECONNREFUSED when RDMA is turned off, EBUSY when irdma
488  * already registered, ENOTSUP when LAN-RDMA interface version doesn't match,
489  * EINVAL on kobject interface fail.
490  */
491 int
492 ice_rdma_register(struct ice_rdma_info *info)
493 {
494 	struct ice_rdma_entry *entry;
495 	struct ice_softc *sc;
496 	int err = 0;
497 
498 	sx_xlock(&ice_rdma.mtx);
499 
500 	if (!ice_enable_irdma) {
501 		log(LOG_INFO, "%s: The iRDMA driver interface has been disabled\n", __func__);
502 		err = (ECONNREFUSED);
503 		goto return_unlock;
504 	}
505 
506 	if (ice_rdma.registered) {
507 		log(LOG_WARNING, "%s: iRDMA driver already registered\n", __func__);
508 		err = (EBUSY);
509 		goto return_unlock;
510 	}
511 
512 	/* Make sure the iRDMA version is compatible */
513 	err = ice_rdma_check_version(info);
514 	if (err)
515 		goto return_unlock;
516 
517 	log(LOG_INFO, "%s: iRDMA driver registered using version %d.%d.%d\n",
518 	    __func__, info->major_version, info->minor_version, info->patch_version);
519 
520 	ice_rdma.peer_class = info->rdma_class;
521 
522 	/*
523 	 * Initialize the kobject interface and notify the RDMA client of each
524 	 * existing PF interface.
525 	 */
526 	LIST_FOREACH(entry, &ice_rdma.peers, node) {
527 		kobj_init((kobj_t)&entry->peer, ice_rdma.peer_class);
528 		/* Gather DCB/QOS info into peer */
529 		sc = __containerof(entry, struct ice_softc, rdma_entry);
530 		memset(&entry->peer.initial_qos_info, 0, sizeof(entry->peer.initial_qos_info));
531 		ice_rdma_cp_qos_info(&sc->hw, &sc->hw.port_info->qos_cfg.local_dcbx_cfg,
532 				     &entry->peer.initial_qos_info);
533 
534 		IRDMA_PROBE(&entry->peer);
535 		if (entry->initiated)
536 			IRDMA_OPEN(&entry->peer);
537 	}
538 	ice_rdma.registered = true;
539 
540 return_unlock:
541 	sx_xunlock(&ice_rdma.mtx);
542 
543 	return (err);
544 }
545 
546 /**
547  * ice_rdma_unregister - Unregister an RDMA client driver
548  *
549  * Called by the RDMA client driver on unload. Used to de-initialize the RDMA
550  * client driver interface and shut down communication between the ice driver
551  * and the RDMA client driver.
552  * @return 0 on success, ENOENT when irdma driver wasn't registered
553  */
554 int
555 ice_rdma_unregister(void)
556 {
557 	struct ice_rdma_entry *entry;
558 
559 	sx_xlock(&ice_rdma.mtx);
560 
561 	if (!ice_rdma.registered) {
562 		log(LOG_WARNING, "%s: iRDMA driver was not previously registered\n",
563 		       __func__);
564 		sx_xunlock(&ice_rdma.mtx);
565 		return (ENOENT);
566 	}
567 
568 	log(LOG_INFO, "%s: iRDMA driver unregistered\n", __func__);
569 	ice_rdma.registered = false;
570 	ice_rdma.peer_class = NULL;
571 
572 	/*
573 	 * Release the kobject interface for each of the existing PF
574 	 * interfaces. Note that we do not notify the client about removing
575 	 * each PF, as it is assumed that the client will have already cleaned
576 	 * up any associated resources when it is unregistered.
577 	 */
578 	LIST_FOREACH(entry, &ice_rdma.peers, node)
579 		kobj_delete((kobj_t)&entry->peer, NULL);
580 
581 	sx_xunlock(&ice_rdma.mtx);
582 
583 	return (0);
584 }
585 
586 /**
587  * ice_rdma_init - RDMA driver init routine
588  *
589  * Called during ice driver module initialization to setup the RDMA client
590  * interface mutex and RDMA peer structure list.
591  */
592 void
593 ice_rdma_init(void)
594 {
595 	LIST_INIT(&ice_rdma.peers);
596 	sx_init_flags(&ice_rdma.mtx, "ice rdma interface", SX_DUPOK);
597 
598 	ice_rdma.registered = false;
599 	ice_rdma.peer_class = NULL;
600 }
601 
602 /**
603  * ice_rdma_exit - RDMA driver exit routine
604  *
605  * Called during ice driver module exit to shutdown the RDMA client interface
606  * mutex.
607  */
608 void
609 ice_rdma_exit(void)
610 {
611 	MPASS(LIST_EMPTY(&ice_rdma.peers));
612 	sx_destroy(&ice_rdma.mtx);
613 }
614 
615 /**
616  * ice_rdma_pf_attach_locked - Prepare a PF for RDMA connections
617  * @sc: the ice driver softc
618  *
619  * Initialize a peer entry for this PF and add it to the RDMA interface list.
620  * Notify the client RDMA driver of a new PF device.
621  *
622  * @pre must be called while holding the ice_rdma mutex.
623  * @return 0 on success and when RDMA feature is not available, EEXIST when
624  * irdma is already attached
625  */
626 static int
627 ice_rdma_pf_attach_locked(struct ice_softc *sc)
628 {
629 	struct ice_rdma_entry *entry;
630 
631 	/* Do not attach the PF unless RDMA is supported */
632 	if (!ice_is_bit_set(sc->feat_cap, ICE_FEATURE_RDMA))
633 		return (0);
634 
635 	entry = &sc->rdma_entry;
636 	if (entry->attached) {
637 		device_printf(sc->dev, "iRDMA peer entry already exists\n");
638 		return (EEXIST);
639 	}
640 
641 	entry->attached = true;
642 	entry->peer.dev = sc->dev;
643 	entry->peer.ifp = sc->ifp;
644 	entry->peer.pf_id = sc->hw.pf_id;
645 	entry->peer.pci_mem = sc->bar0.res;
646 	entry->peer.pf_vsi_num = ice_get_hw_vsi_num(&sc->hw, sc->pf_vsi.idx);
647 	if (sc->rdma_imap && sc->rdma_imap[0] != ICE_INVALID_RES_IDX &&
648 	    sc->irdma_vectors > 0) {
649 		entry->peer.msix.base = sc->rdma_imap[0];
650 		entry->peer.msix.count = sc->irdma_vectors;
651 	}
652 
653 	/* Gather DCB/QOS info into peer */
654 	memset(&entry->peer.initial_qos_info, 0, sizeof(entry->peer.initial_qos_info));
655 	ice_rdma_cp_qos_info(&sc->hw, &sc->hw.port_info->qos_cfg.local_dcbx_cfg,
656 			     &entry->peer.initial_qos_info);
657 
658 	/*
659 	 * If the RDMA client driver has already registered, initialize the
660 	 * kobject and notify the client of a new PF
661 	 */
662 	if (ice_rdma.registered) {
663 		kobj_init((kobj_t)&entry->peer, ice_rdma.peer_class);
664 		IRDMA_PROBE(&entry->peer);
665 	}
666 
667 	LIST_INSERT_HEAD(&ice_rdma.peers, entry, node);
668 
669 	ice_set_bit(ICE_FEATURE_RDMA, sc->feat_en);
670 
671 	return (0);
672 }
673 
674 /**
675  * ice_rdma_pf_attach - Notify the RDMA client of a new PF
676  * @sc: the ice driver softc
677  *
678  * Called during PF attach to notify the RDMA client of a new PF.
679  * @return 0 or EEXIST if irdma was already attached
680  */
681 int
682 ice_rdma_pf_attach(struct ice_softc *sc)
683 {
684 	int err;
685 
686 	sx_xlock(&ice_rdma.mtx);
687 	err = ice_rdma_pf_attach_locked(sc);
688 	sx_xunlock(&ice_rdma.mtx);
689 
690 	return (err);
691 }
692 
693 /**
694  * ice_rdma_pf_detach_locked - Notify the RDMA client on PF detach
695  * @sc: the ice driver softc
696  *
697  * Notify the RDMA peer client driver of removal of a PF, and release any
698  * RDMA-specific resources associated with that PF. Remove the PF from the
699  * list of available RDMA entries.
700  *
701  * @pre must be called while holding the ice_rdma mutex.
702  */
703 static void
704 ice_rdma_pf_detach_locked(struct ice_softc *sc)
705 {
706 	struct ice_rdma_entry *entry;
707 
708 	/* No need to detach the PF if RDMA is not enabled */
709 	if (!ice_is_bit_set(sc->feat_en, ICE_FEATURE_RDMA))
710 		return;
711 
712 	entry = &sc->rdma_entry;
713 	if (!entry->attached) {
714 		device_printf(sc->dev, "iRDMA peer entry was not attached\n");
715 		return;
716 	}
717 
718 	/*
719 	 * If the RDMA client driver is registered, notify the client that
720 	 * a PF has been removed, and release the kobject reference.
721 	 */
722 	if (ice_rdma.registered) {
723 		IRDMA_REMOVE(&entry->peer);
724 		kobj_delete((kobj_t)&entry->peer, NULL);
725 	}
726 
727 	LIST_REMOVE(entry, node);
728 	entry->attached = false;
729 
730 	ice_clear_bit(ICE_FEATURE_RDMA, sc->feat_en);
731 }
732 
733 /**
734  * ice_rdma_pf_detach - Notify the RDMA client of a PF detaching
735  * @sc: the ice driver softc
736  *
737  * Take the ice_rdma mutex and then notify the RDMA client that a PF has been
738  * removed.
739  */
740 void
741 ice_rdma_pf_detach(struct ice_softc *sc)
742 {
743 	sx_xlock(&ice_rdma.mtx);
744 	ice_rdma_pf_detach_locked(sc);
745 	sx_xunlock(&ice_rdma.mtx);
746 }
747 
748 /**
749  * ice_rdma_pf_init - Notify the RDMA client that a PF has initialized
750  * @sc: the ice driver softc
751  *
752  * Called by the ice driver when a PF has been initialized. Notifies the RDMA
753  * client that a PF is up and ready to operate.
754  * @return 0 on success, propagates IRDMA_OPEN return value
755  */
756 int
757 ice_rdma_pf_init(struct ice_softc *sc)
758 {
759 	struct ice_rdma_peer *peer = &sc->rdma_entry.peer;
760 
761 	sx_xlock(&ice_rdma.mtx);
762 
763 	/* Update the MTU */
764 	peer->mtu = if_getmtu(sc->ifp);
765 	sc->rdma_entry.initiated = true;
766 
767 	if (sc->rdma_entry.attached && ice_rdma.registered) {
768 		sx_xunlock(&ice_rdma.mtx);
769 		return IRDMA_OPEN(peer);
770 	}
771 
772 	sx_xunlock(&ice_rdma.mtx);
773 
774 	return (0);
775 }
776 
777 /**
778  * ice_rdma_pf_stop - Notify the RDMA client of a stopped PF device
779  * @sc: the ice driver softc
780  *
781  * Called by the ice driver when a PF is stopped. Notifies the RDMA client
782  * driver that the PF has stopped and is not ready to operate.
783  * @return 0 on success
784  */
785 int
786 ice_rdma_pf_stop(struct ice_softc *sc)
787 {
788 	sx_xlock(&ice_rdma.mtx);
789 
790 	sc->rdma_entry.initiated = false;
791 	if (sc->rdma_entry.attached && ice_rdma.registered) {
792 		sx_xunlock(&ice_rdma.mtx);
793 		return IRDMA_CLOSE(&sc->rdma_entry.peer);
794 	}
795 
796 	sx_xunlock(&ice_rdma.mtx);
797 
798 	return (0);
799 }
800 
801 /**
802  * ice_rdma_link_change - Notify RDMA client of a change in link status
803  * @sc: the ice driver softc
804  * @linkstate: the link status
805  * @baudrate: the link rate in bits per second
806  *
807  * Notify the RDMA client of a link status change, by sending it the new link
808  * state and baudrate.
809  *
810  * The link state is represented the same was as in the ifnet structure. It
811  * should be LINK_STATE_UNKNOWN, LINK_STATE_DOWN, or LINK_STATE_UP.
812  */
813 void
814 ice_rdma_link_change(struct ice_softc *sc, int linkstate, uint64_t baudrate)
815 {
816 	struct ice_rdma_peer *peer = &sc->rdma_entry.peer;
817 	struct ice_rdma_event event;
818 
819 	memset(&event, 0, sizeof(struct ice_rdma_event));
820 	event.type = ICE_RDMA_EVENT_LINK_CHANGE;
821 	event.linkstate = linkstate;
822 	event.baudrate = baudrate;
823 
824 	sx_xlock(&ice_rdma.mtx);
825 
826 	if (sc->rdma_entry.attached && ice_rdma.registered)
827 		IRDMA_EVENT_HANDLER(peer, &event);
828 
829 	sx_xunlock(&ice_rdma.mtx);
830 }
831 
832 /**
833  *  ice_rdma_notify_dcb_qos_change - notify RDMA driver to pause traffic
834  *  @sc: the ice driver softc
835  *
836  *  Notify the RDMA driver that QOS/DCB settings are about to change.
837  *  Once the function return, all the QPs should be suspended.
838  */
839 void
840 ice_rdma_notify_dcb_qos_change(struct ice_softc *sc)
841 {
842 	struct ice_rdma_peer *peer = &sc->rdma_entry.peer;
843 	struct ice_rdma_event event;
844 
845 	memset(&event, 0, sizeof(struct ice_rdma_event));
846 	event.type = ICE_RDMA_EVENT_TC_CHANGE;
847 	/* pre-event */
848 	event.prep = true;
849 
850 	sx_xlock(&ice_rdma.mtx);
851 	if (sc->rdma_entry.attached && ice_rdma.registered)
852 		IRDMA_EVENT_HANDLER(peer, &event);
853 	sx_xunlock(&ice_rdma.mtx);
854 }
855 
856 /**
857  *  ice_rdma_dcb_qos_update - pass the changed dcb settings to RDMA driver
858  *  @sc: the ice driver softc
859  *  @pi: the port info structure
860  *
861  *  Pass the changed DCB settings to RDMA traffic. This function should be
862  *  called only after ice_rdma_notify_dcb_qos_change has been called and
863  *  returned before. After the function returns, all the RDMA traffic
864  *  should be resumed.
865  */
866 void
867 ice_rdma_dcb_qos_update(struct ice_softc *sc, struct ice_port_info *pi)
868 {
869 	struct ice_rdma_peer *peer = &sc->rdma_entry.peer;
870 	struct ice_rdma_event event;
871 
872 	memset(&event, 0, sizeof(struct ice_rdma_event));
873 	event.type = ICE_RDMA_EVENT_TC_CHANGE;
874 	/* post-event */
875 	event.prep = false;
876 
877 	/* gather current configuration */
878 	ice_rdma_cp_qos_info(&sc->hw, &pi->qos_cfg.local_dcbx_cfg, &event.port_qos);
879 	sx_xlock(&ice_rdma.mtx);
880 	if (sc->rdma_entry.attached && ice_rdma.registered)
881 		IRDMA_EVENT_HANDLER(peer, &event);
882 	sx_xunlock(&ice_rdma.mtx);
883 }
884 
885 /**
886  *  ice_rdma_notify_pe_intr - notify irdma on incoming interrupts regarding PE
887  *  @sc: the ice driver softc
888  *  @oicr: interrupt cause
889  *
890  *  Pass the information about received interrupt to RDMA driver if it was
891  *  relating to PE. Specifically PE_CRITERR and HMC_ERR.
892  *  The irdma driver shall decide what should be done upon these interrupts.
893  */
894 void
895 ice_rdma_notify_pe_intr(struct ice_softc *sc, uint32_t oicr)
896 {
897 	struct ice_rdma_peer *peer = &sc->rdma_entry.peer;
898 	struct ice_rdma_event event;
899 
900 	memset(&event, 0, sizeof(struct ice_rdma_event));
901 	event.type = ICE_RDMA_EVENT_CRIT_ERR;
902 	event.oicr_reg = oicr;
903 
904 	sx_xlock(&ice_rdma.mtx);
905 	if (sc->rdma_entry.attached && ice_rdma.registered)
906 		IRDMA_EVENT_HANDLER(peer, &event);
907 	sx_xunlock(&ice_rdma.mtx);
908 }
909 
910 /**
911  *  ice_rdma_notify_reset - notify irdma on incoming pf-reset
912  *  @sc: the ice driver softc
913  *
914  *  Inform irdma driver of an incoming PF reset.
915  *  The irdma driver shall set its state to reset, and avoid using CQP
916  *  anymore. Next step should be to call ice_rdma_pf_stop in order to
917  *  remove resources.
918  */
919 void
920 ice_rdma_notify_reset(struct ice_softc *sc)
921 {
922 	struct ice_rdma_peer *peer = &sc->rdma_entry.peer;
923 	struct ice_rdma_event event;
924 
925 	memset(&event, 0, sizeof(struct ice_rdma_event));
926 	event.type = ICE_RDMA_EVENT_RESET;
927 
928 	sx_xlock(&ice_rdma.mtx);
929 	if (sc->rdma_entry.attached && ice_rdma.registered)
930 	        IRDMA_EVENT_HANDLER(peer, &event);
931 	sx_xunlock(&ice_rdma.mtx);
932 }
933