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