xref: /freebsd/sys/dev/ice/ice_rdma.c (revision f2635e844dd138ac9dfba676f27d41750049af26)
18a13362dSEric Joyner /* SPDX-License-Identifier: BSD-3-Clause */
2015f8cc5SEric Joyner /*  Copyright (c) 2024, Intel Corporation
38a13362dSEric Joyner  *  All rights reserved.
48a13362dSEric Joyner  *
58a13362dSEric Joyner  *  Redistribution and use in source and binary forms, with or without
68a13362dSEric Joyner  *  modification, are permitted provided that the following conditions are met:
78a13362dSEric Joyner  *
88a13362dSEric Joyner  *   1. Redistributions of source code must retain the above copyright notice,
98a13362dSEric Joyner  *      this list of conditions and the following disclaimer.
108a13362dSEric Joyner  *
118a13362dSEric Joyner  *   2. Redistributions in binary form must reproduce the above copyright
128a13362dSEric Joyner  *      notice, this list of conditions and the following disclaimer in the
138a13362dSEric Joyner  *      documentation and/or other materials provided with the distribution.
148a13362dSEric Joyner  *
158a13362dSEric Joyner  *   3. Neither the name of the Intel Corporation nor the names of its
168a13362dSEric Joyner  *      contributors may be used to endorse or promote products derived from
178a13362dSEric Joyner  *      this software without specific prior written permission.
188a13362dSEric Joyner  *
198a13362dSEric Joyner  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
208a13362dSEric Joyner  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
218a13362dSEric Joyner  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
228a13362dSEric Joyner  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
238a13362dSEric Joyner  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
248a13362dSEric Joyner  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
258a13362dSEric Joyner  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
268a13362dSEric Joyner  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
278a13362dSEric Joyner  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
288a13362dSEric Joyner  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
298a13362dSEric Joyner  *  POSSIBILITY OF SUCH DAMAGE.
308a13362dSEric Joyner  */
318a13362dSEric Joyner 
328a13362dSEric Joyner /**
338a13362dSEric Joyner  * @file ice_rdma.c
348a13362dSEric Joyner  * @brief RDMA client driver interface
358a13362dSEric Joyner  *
368a13362dSEric Joyner  * Functions to interface with the RDMA client driver, for enabling RMDA
378a13362dSEric Joyner  * functionality for the ice driver.
388a13362dSEric Joyner  *
398a13362dSEric Joyner  * The RDMA client interface is based on a simple kobject interface which is
408a13362dSEric Joyner  * defined by the rmda_if.m and irdma_di_if.m interfaces.
418a13362dSEric Joyner  *
428a13362dSEric Joyner  * The ice device driver provides the rmda_di_if.m interface methods, while
438a13362dSEric Joyner  * the client RDMA driver provides the irdma_if.m interface methods as an
448a13362dSEric Joyner  * extension ontop of the irdma_di_if kobject.
458a13362dSEric Joyner  *
468a13362dSEric Joyner  * The initial connection between drivers is done via the RDMA client driver
478a13362dSEric Joyner  * calling ice_rdma_register.
488a13362dSEric Joyner  */
498a13362dSEric Joyner 
508a13362dSEric Joyner #include "ice_iflib.h"
518a13362dSEric Joyner #include "ice_rdma_internal.h"
528a13362dSEric Joyner 
538a13362dSEric Joyner #include "irdma_if.h"
548a13362dSEric Joyner #include "irdma_di_if.h"
558a13362dSEric Joyner 
568a13362dSEric Joyner /**
578a13362dSEric Joyner  * @var ice_rdma
588a13362dSEric Joyner  * @brief global RDMA driver state
598a13362dSEric Joyner  *
608a13362dSEric Joyner  * Contains global state the driver uses to connect to a client RDMA interface
618a13362dSEric Joyner  * driver.
628a13362dSEric Joyner  */
638a13362dSEric Joyner static struct ice_rdma_state ice_rdma;
648a13362dSEric Joyner 
658a13362dSEric Joyner /*
668a13362dSEric Joyner  * Helper function prototypes
678a13362dSEric Joyner  */
688a13362dSEric Joyner static int ice_rdma_pf_attach_locked(struct ice_softc *sc);
698a13362dSEric Joyner static void ice_rdma_pf_detach_locked(struct ice_softc *sc);
708a13362dSEric Joyner static int ice_rdma_check_version(struct ice_rdma_info *info);
718a13362dSEric Joyner static void ice_rdma_cp_qos_info(struct ice_hw *hw,
728a13362dSEric Joyner 				 struct ice_dcbx_cfg *dcbx_cfg,
738a13362dSEric Joyner 				 struct ice_qos_params *qos_info);
748a13362dSEric Joyner 
758a13362dSEric Joyner /*
768a13362dSEric Joyner  * RDMA Device Interface prototypes
778a13362dSEric Joyner  */
788a13362dSEric Joyner static int ice_rdma_pf_reset(struct ice_rdma_peer *peer);
798a13362dSEric Joyner static int ice_rdma_pf_msix_init(struct ice_rdma_peer *peer,
808a13362dSEric Joyner 				 struct ice_rdma_msix_mapping *msix_info);
818a13362dSEric Joyner static int ice_rdma_qset_register_request(struct ice_rdma_peer *peer,
828a13362dSEric Joyner 			     struct ice_rdma_qset_update *res);
838a13362dSEric Joyner static int ice_rdma_update_vsi_filter(struct ice_rdma_peer *peer_dev,
848a13362dSEric Joyner 				      bool enable);
858a13362dSEric Joyner static void ice_rdma_request_handler(struct ice_rdma_peer *peer,
868a13362dSEric Joyner 				     struct ice_rdma_request *req);
878a13362dSEric Joyner 
888a13362dSEric Joyner 
898a13362dSEric Joyner /**
908a13362dSEric Joyner  * @var ice_rdma_di_methods
918a13362dSEric Joyner  * @brief RDMA driver interface methods
928a13362dSEric Joyner  *
938a13362dSEric Joyner  * Kobject methods implementing the driver-side interface for the RDMA peer
948a13362dSEric Joyner  * clients. This method table contains the operations which the client can
958a13362dSEric Joyner  * request from the driver.
968a13362dSEric Joyner  *
978a13362dSEric Joyner  * The client driver will then extend this kobject class with methods that the
988a13362dSEric Joyner  * driver can request from the client.
998a13362dSEric Joyner  */
1008a13362dSEric Joyner static kobj_method_t ice_rdma_di_methods[] = {
1018a13362dSEric Joyner 	KOBJMETHOD(irdma_di_reset, ice_rdma_pf_reset),
1028a13362dSEric Joyner 	KOBJMETHOD(irdma_di_msix_init, ice_rdma_pf_msix_init),
1038a13362dSEric Joyner 	KOBJMETHOD(irdma_di_qset_register_request, ice_rdma_qset_register_request),
1048a13362dSEric Joyner 	KOBJMETHOD(irdma_di_vsi_filter_update, ice_rdma_update_vsi_filter),
1058a13362dSEric Joyner 	KOBJMETHOD(irdma_di_req_handler, ice_rdma_request_handler),
1068a13362dSEric Joyner 	KOBJMETHOD_END
1078a13362dSEric Joyner };
1088a13362dSEric Joyner 
1098a13362dSEric Joyner /* Define ice_rdma_di class which will be extended by the iRDMA driver */
1108a13362dSEric Joyner DEFINE_CLASS_0(ice_rdma_di, ice_rdma_di_class, ice_rdma_di_methods, sizeof(struct ice_rdma_peer));
1118a13362dSEric Joyner 
1128a13362dSEric Joyner /**
1138a13362dSEric Joyner  * ice_rdma_pf_reset - RDMA client interface requested a reset
1148a13362dSEric Joyner  * @peer: the RDMA peer client structure
1158a13362dSEric Joyner  *
1168a13362dSEric Joyner  * Implements IRDMA_DI_RESET, called by the RDMA client driver to request
1178a13362dSEric Joyner  * a reset of an ice driver device.
1189c30461dSEric Joyner  * @return 0 on success
1198a13362dSEric Joyner  */
1208a13362dSEric Joyner static int
1218a13362dSEric Joyner ice_rdma_pf_reset(struct ice_rdma_peer *peer)
1228a13362dSEric Joyner {
1238a13362dSEric Joyner 	struct ice_softc *sc = ice_rdma_peer_to_sc(peer);
1248a13362dSEric Joyner 
12501fbb869SBartosz Sobczak 	/* Tell the base driver that RDMA is requesting a PFR */
12601fbb869SBartosz Sobczak 	ice_set_state(&sc->state, ICE_STATE_RESET_PFR_REQ);
12701fbb869SBartosz Sobczak 
12801fbb869SBartosz Sobczak 	/* XXX: Base driver will notify RDMA when it's done */
1298a13362dSEric Joyner 
1308a13362dSEric Joyner 	return (0);
1318a13362dSEric Joyner }
1328a13362dSEric Joyner 
1338a13362dSEric Joyner /**
1348a13362dSEric Joyner  * ice_rdma_pf_msix_init - RDMA client interface request MSI-X initialization
1358a13362dSEric Joyner  * @peer: the RDMA peer client structure
1368a13362dSEric Joyner  * @msix_info: requested MSI-X mapping
1378a13362dSEric Joyner  *
1388a13362dSEric Joyner  * Implements IRDMA_DI_MSIX_INIT, called by the RDMA client driver to
1398a13362dSEric Joyner  * initialize the MSI-X resources required for RDMA functionality.
1409c30461dSEric Joyner  * @returns ENOSYS
1418a13362dSEric Joyner  */
1428a13362dSEric Joyner static int
1438a13362dSEric Joyner ice_rdma_pf_msix_init(struct ice_rdma_peer *peer,
1448a13362dSEric Joyner 		      struct ice_rdma_msix_mapping __unused *msix_info)
1458a13362dSEric Joyner {
1468a13362dSEric Joyner 	struct ice_softc *sc = ice_rdma_peer_to_sc(peer);
1478a13362dSEric Joyner 
1488a13362dSEric Joyner 	MPASS(msix_info != NULL);
1498a13362dSEric Joyner 
1508a13362dSEric Joyner 	device_printf(sc->dev, "%s: iRDMA MSI-X initialization request is not yet implemented\n", __func__);
1518a13362dSEric Joyner 
1528a13362dSEric Joyner 	/* TODO: implement MSI-X initialization for RDMA */
1538a13362dSEric Joyner 	return (ENOSYS);
1548a13362dSEric Joyner }
1558a13362dSEric Joyner 
1568a13362dSEric Joyner /**
1578a13362dSEric Joyner  * ice_rdma_register_request - RDMA client interface request qset
1588a13362dSEric Joyner  *                             registration or unregistration
1598a13362dSEric Joyner  * @peer: the RDMA peer client structure
1608a13362dSEric Joyner  * @res: resources to be registered or unregistered
1619c30461dSEric Joyner  * @returns 0 on success, EINVAL on argument issues, ENOMEM on memory
1629c30461dSEric Joyner  * allocation failure, EXDEV on vsi device mismatch
1638a13362dSEric Joyner  */
1648a13362dSEric Joyner static int
1658a13362dSEric Joyner ice_rdma_qset_register_request(struct ice_rdma_peer *peer, struct ice_rdma_qset_update *res)
1668a13362dSEric Joyner {
1678a13362dSEric Joyner 	struct ice_softc *sc = ice_rdma_peer_to_sc(peer);
1688a13362dSEric Joyner 	struct ice_vsi *vsi = NULL;
1698a13362dSEric Joyner 	struct ice_dcbx_cfg *dcbx_cfg;
1708a13362dSEric Joyner 	struct ice_hw *hw = &sc->hw;
171*f2635e84SEric Joyner 	int status;
1728a13362dSEric Joyner 	int count, i, ret = 0;
1738a13362dSEric Joyner 	uint32_t *qset_teid;
1748a13362dSEric Joyner 	uint16_t *qs_handle;
1758a13362dSEric Joyner 	uint16_t max_rdmaqs[ICE_MAX_TRAFFIC_CLASS];
1768a13362dSEric Joyner 	uint16_t vsi_id;
1778a13362dSEric Joyner 	uint8_t ena_tc = 0;
1788a13362dSEric Joyner 
1798a13362dSEric Joyner 	if (!res)
1808a13362dSEric Joyner 		return -EINVAL;
1818a13362dSEric Joyner 
1828a13362dSEric Joyner 	if (res->cnt_req > ICE_MAX_TXQ_PER_TXQG)
1838a13362dSEric Joyner 		return -EINVAL;
1848a13362dSEric Joyner 
1858a13362dSEric Joyner 	switch(res->res_type) {
1868a13362dSEric Joyner 	case ICE_RDMA_QSET_ALLOC:
1878a13362dSEric Joyner 		count = res->cnt_req;
1888a13362dSEric Joyner 		vsi_id = peer->pf_vsi_num;
1898a13362dSEric Joyner 		break;
1908a13362dSEric Joyner 	case ICE_RDMA_QSET_FREE:
1918a13362dSEric Joyner 		count = res->res_allocated;
1928a13362dSEric Joyner 		vsi_id = res->qsets.vsi_id;
1938a13362dSEric Joyner 		break;
1948a13362dSEric Joyner 	default:
1958a13362dSEric Joyner 		return -EINVAL;
1968a13362dSEric Joyner 	}
1978a13362dSEric Joyner 	qset_teid = (uint32_t *)ice_calloc(hw, count, sizeof(*qset_teid));
1988a13362dSEric Joyner 	if (!qset_teid)
1998a13362dSEric Joyner 		return -ENOMEM;
2008a13362dSEric Joyner 
2018a13362dSEric Joyner 	qs_handle = (uint16_t *)ice_calloc(hw, count, sizeof(*qs_handle));
2028a13362dSEric Joyner 	if (!qs_handle) {
2038a13362dSEric Joyner 		ice_free(hw, qset_teid);
2048a13362dSEric Joyner 		return -ENOMEM;
2058a13362dSEric Joyner 	}
2068a13362dSEric Joyner 
2078a13362dSEric Joyner 	ice_for_each_traffic_class(i)
2088a13362dSEric Joyner 		max_rdmaqs[i] = 0;
2098a13362dSEric Joyner 	for (i = 0; i < sc->num_available_vsi; i++) {
2108a13362dSEric Joyner 		if (sc->all_vsi[i] &&
2118a13362dSEric Joyner 		    ice_get_hw_vsi_num(hw, sc->all_vsi[i]->idx) == vsi_id) {
2128a13362dSEric Joyner 			vsi = sc->all_vsi[i];
2138a13362dSEric Joyner 			break;
2148a13362dSEric Joyner 		}
2158a13362dSEric Joyner 	}
2168a13362dSEric Joyner 
2178a13362dSEric Joyner 	if (!vsi) {
2188a13362dSEric Joyner 		ice_debug(hw, ICE_DBG_RDMA, "RDMA QSet invalid VSI\n");
2198a13362dSEric Joyner 		ret = -EINVAL;
2208a13362dSEric Joyner 		goto out;
2218a13362dSEric Joyner 	}
2228a13362dSEric Joyner 	if (sc != vsi->sc) {
2238a13362dSEric Joyner 		ice_debug(hw, ICE_DBG_RDMA, "VSI is tied to unexpected device\n");
2248a13362dSEric Joyner 		ret = -EXDEV;
2258a13362dSEric Joyner 		goto out;
2268a13362dSEric Joyner 	}
2278a13362dSEric Joyner 
2288a13362dSEric Joyner 	for (i = 0; i < count; i++) {
2298a13362dSEric Joyner 		struct ice_rdma_qset_params *qset;
2308a13362dSEric Joyner 
2318a13362dSEric Joyner 		qset = &res->qsets;
2328a13362dSEric Joyner 		if (qset->vsi_id != peer->pf_vsi_num) {
2338a13362dSEric Joyner 			ice_debug(hw, ICE_DBG_RDMA, "RDMA QSet invalid VSI requested %d %d\n",
2348a13362dSEric Joyner 				  qset->vsi_id, peer->pf_vsi_num);
2358a13362dSEric Joyner 			ret = -EINVAL;
2368a13362dSEric Joyner 			goto out;
2378a13362dSEric Joyner 		}
2388a13362dSEric Joyner 		max_rdmaqs[qset->tc]++;
2398a13362dSEric Joyner 		qs_handle[i] = qset->qs_handle;
2408a13362dSEric Joyner 		qset_teid[i] = qset->teid;
2418a13362dSEric Joyner 	}
2428a13362dSEric Joyner 
2438a13362dSEric Joyner 	switch(res->res_type) {
2448a13362dSEric Joyner 	case ICE_RDMA_QSET_ALLOC:
2458a13362dSEric Joyner 		dcbx_cfg = &hw->port_info->qos_cfg.local_dcbx_cfg;
2468923de59SPiotr Kubaj 		ena_tc = ice_dcb_get_tc_map(dcbx_cfg);
2478a13362dSEric Joyner 
2488a13362dSEric Joyner 		ice_debug(hw, ICE_DBG_RDMA, "%s:%d ena_tc=%x\n", __func__, __LINE__, ena_tc);
2498a13362dSEric Joyner 		status = ice_cfg_vsi_rdma(hw->port_info, vsi->idx, ena_tc,
2508a13362dSEric Joyner 					  max_rdmaqs);
2518a13362dSEric Joyner 		if (status) {
2528a13362dSEric Joyner 			ice_debug(hw, ICE_DBG_RDMA, "Failed VSI RDMA qset config\n");
2538a13362dSEric Joyner 			ret = -EINVAL;
2548a13362dSEric Joyner 			goto out;
2558a13362dSEric Joyner 		}
2568a13362dSEric Joyner 
2578a13362dSEric Joyner 		for (i = 0; i < count; i++) {
2588a13362dSEric Joyner 			struct ice_rdma_qset_params *qset;
2598a13362dSEric Joyner 
2608a13362dSEric Joyner 			qset = &res->qsets;
2618a13362dSEric Joyner 			status = ice_ena_vsi_rdma_qset(hw->port_info, vsi->idx,
2628a13362dSEric Joyner 						       qset->tc, &qs_handle[i], 1,
2638a13362dSEric Joyner 						       &qset_teid[i]);
2648a13362dSEric Joyner 			if (status) {
2658a13362dSEric Joyner 				ice_debug(hw, ICE_DBG_RDMA, "Failed VSI RDMA qset enable\n");
2668a13362dSEric Joyner 				ret = -EINVAL;
2678a13362dSEric Joyner 				goto out;
2688a13362dSEric Joyner 			}
2698a13362dSEric Joyner 			qset->teid = qset_teid[i];
2708a13362dSEric Joyner 		}
2718a13362dSEric Joyner 		break;
2728a13362dSEric Joyner 	case ICE_RDMA_QSET_FREE:
2738a13362dSEric Joyner 		status = ice_dis_vsi_rdma_qset(hw->port_info, count, qset_teid, qs_handle);
2748a13362dSEric Joyner 		if (status)
2758a13362dSEric Joyner 			ret = -EINVAL;
2768a13362dSEric Joyner 		break;
2778a13362dSEric Joyner 	default:
2788a13362dSEric Joyner 		ret = -EINVAL;
2798a13362dSEric Joyner 		break;
2808a13362dSEric Joyner 	}
2818a13362dSEric Joyner 
2828a13362dSEric Joyner out:
2838a13362dSEric Joyner 	ice_free(hw, qs_handle);
2848a13362dSEric Joyner 	ice_free(hw, qset_teid);
2858a13362dSEric Joyner 
2868a13362dSEric Joyner 	return ret;
2878a13362dSEric Joyner }
2888a13362dSEric Joyner 
2898a13362dSEric Joyner /**
2908a13362dSEric Joyner  *  ice_rdma_update_vsi_filter - configure vsi information
2918a13362dSEric Joyner  *                               when opening or closing rdma driver
2928a13362dSEric Joyner  *  @peer: the RDMA peer client structure
2938a13362dSEric Joyner  *  @enable: enable or disable the rdma filter
2949c30461dSEric Joyner  *  @return 0 on success, EINVAL on wrong vsi
2958a13362dSEric Joyner  */
2968a13362dSEric Joyner static int
2978a13362dSEric Joyner ice_rdma_update_vsi_filter(struct ice_rdma_peer *peer,
2988a13362dSEric Joyner 			   bool enable)
2998a13362dSEric Joyner {
3008a13362dSEric Joyner 	struct ice_softc *sc = ice_rdma_peer_to_sc(peer);
3018a13362dSEric Joyner 	struct ice_vsi *vsi;
3028a13362dSEric Joyner 	int ret;
3038a13362dSEric Joyner 
3048a13362dSEric Joyner 	vsi = &sc->pf_vsi;
3058a13362dSEric Joyner 	if (!vsi)
3068a13362dSEric Joyner 		return -EINVAL;
3078a13362dSEric Joyner 
3088a13362dSEric Joyner 	ret = ice_cfg_iwarp_fltr(&sc->hw, vsi->idx, enable);
3098a13362dSEric Joyner 	if (ret) {
3108a13362dSEric Joyner 		device_printf(sc->dev, "Failed to  %sable iWARP filtering\n",
3118a13362dSEric Joyner 				enable ? "en" : "dis");
3128a13362dSEric Joyner 	} else {
3138a13362dSEric Joyner 		if (enable)
3148a13362dSEric Joyner 			vsi->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
3158a13362dSEric Joyner 		else
3168a13362dSEric Joyner 			vsi->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
3178a13362dSEric Joyner 	}
3188a13362dSEric Joyner 
3198a13362dSEric Joyner 	return ret;
3208a13362dSEric Joyner }
3218a13362dSEric Joyner 
3228a13362dSEric Joyner /**
3238a13362dSEric Joyner  * ice_rdma_request_handler - handle requests incoming from RDMA driver
3248a13362dSEric Joyner  * @peer: the RDMA peer client structure
3258a13362dSEric Joyner  * @req: structure containing request
3268a13362dSEric Joyner  */
3278a13362dSEric Joyner static void
3288a13362dSEric Joyner ice_rdma_request_handler(struct ice_rdma_peer *peer,
3298a13362dSEric Joyner 			 struct ice_rdma_request *req)
3308a13362dSEric Joyner {
3318a13362dSEric Joyner 	if (!req || !peer) {
3328a13362dSEric Joyner 		log(LOG_WARNING, "%s: peer or req are not valid\n", __func__);
3338a13362dSEric Joyner 		return;
3348a13362dSEric Joyner 	}
3358a13362dSEric Joyner 
3368a13362dSEric Joyner 	switch(req->type) {
3378a13362dSEric Joyner 	case ICE_RDMA_EVENT_RESET:
33801fbb869SBartosz Sobczak 		ice_rdma_pf_reset(peer);
3398a13362dSEric Joyner 		break;
3408a13362dSEric Joyner 	case ICE_RDMA_EVENT_QSET_REGISTER:
3418a13362dSEric Joyner 		ice_rdma_qset_register_request(peer, &req->res);
3428a13362dSEric Joyner 		break;
3438a13362dSEric Joyner 	case ICE_RDMA_EVENT_VSI_FILTER_UPDATE:
3448a13362dSEric Joyner 		ice_rdma_update_vsi_filter(peer, req->enable_filter);
3458a13362dSEric Joyner 		break;
3468a13362dSEric Joyner 	default:
3478a13362dSEric Joyner 		log(LOG_WARNING, "%s: Event %d not supported\n", __func__, req->type);
3488a13362dSEric Joyner 		break;
3498a13362dSEric Joyner 	}
3508a13362dSEric Joyner }
3518a13362dSEric Joyner 
3528a13362dSEric Joyner /**
3538a13362dSEric Joyner  * ice_rdma_cp_qos_info - gather current QOS/DCB settings in LAN to pass
3548a13362dSEric Joyner  *                        to RDMA driver
3558a13362dSEric Joyner  * @hw: ice hw structure
3568a13362dSEric Joyner  * @dcbx_cfg: current DCB settings in ice driver
3578a13362dSEric Joyner  * @qos_info: destination of the DCB settings
3588a13362dSEric Joyner  */
3598a13362dSEric Joyner static void
3608a13362dSEric Joyner ice_rdma_cp_qos_info(struct ice_hw *hw, struct ice_dcbx_cfg *dcbx_cfg,
3618a13362dSEric Joyner 		     struct ice_qos_params *qos_info)
3628a13362dSEric Joyner {
3638a13362dSEric Joyner 	u32 up2tc;
3648a13362dSEric Joyner 	u8 j;
3658a13362dSEric Joyner 	u8 num_tc = 0;
3668a13362dSEric Joyner 	u8 val_tc = 0;  /* number of TC for validation */
3678a13362dSEric Joyner 	u8 cnt_tc = 0;
3688a13362dSEric Joyner 
3698a13362dSEric Joyner 	/* setup qos_info fields with defaults */
3708a13362dSEric Joyner 	qos_info->num_apps = 0;
3718a13362dSEric Joyner 	qos_info->num_tc = 1;
3728a13362dSEric Joyner 
3738a13362dSEric Joyner 	for (j = 0; j < ICE_TC_MAX_USER_PRIORITY; j++)
3748a13362dSEric Joyner 		qos_info->up2tc[j] = 0;
3758a13362dSEric Joyner 
3768a13362dSEric Joyner 	qos_info->tc_info[0].rel_bw = 100;
3778a13362dSEric Joyner 	for (j = 1; j < IEEE_8021QAZ_MAX_TCS; j++)
3788a13362dSEric Joyner 		qos_info->tc_info[j].rel_bw = 0;
3798a13362dSEric Joyner 
3808a13362dSEric Joyner 	/* gather current values */
3818a13362dSEric Joyner 	up2tc = rd32(hw, PRTDCB_TUP2TC);
3828a13362dSEric Joyner 	qos_info->num_apps = dcbx_cfg->numapps;
3838a13362dSEric Joyner 
3848a13362dSEric Joyner 	for (j = 0; j < ICE_MAX_TRAFFIC_CLASS; j++) {
3858a13362dSEric Joyner 		num_tc |= BIT(dcbx_cfg->etscfg.prio_table[j]);
3868a13362dSEric Joyner 	}
3878a13362dSEric Joyner 	for (j = 0; j < ICE_MAX_TRAFFIC_CLASS; j++) {
3888a13362dSEric Joyner 		if (num_tc & BIT(j)) {
3898a13362dSEric Joyner 			cnt_tc++;
3908a13362dSEric Joyner 			val_tc |= BIT(j);
3918a13362dSEric Joyner 		} else {
3928a13362dSEric Joyner 			break;
3938a13362dSEric Joyner 		}
3948a13362dSEric Joyner 	}
3958a13362dSEric Joyner 	qos_info->num_tc = (val_tc == num_tc && num_tc != 0) ? cnt_tc : 1;
3968a13362dSEric Joyner 	for (j = 0; j < ICE_TC_MAX_USER_PRIORITY; j++)
3978a13362dSEric Joyner 		qos_info->up2tc[j] = (up2tc >> (j * 3)) & 0x7;
3988a13362dSEric Joyner 
3998a13362dSEric Joyner 	for (j = 0; j < IEEE_8021QAZ_MAX_TCS; j++)
4008a13362dSEric Joyner 		qos_info->tc_info[j].rel_bw = dcbx_cfg->etscfg.tcbwtable[j];
4018a13362dSEric Joyner 	for (j = 0; j < qos_info->num_apps; j++) {
4028a13362dSEric Joyner 		qos_info->apps[j].priority = dcbx_cfg->app[j].priority;
4038a13362dSEric Joyner 		qos_info->apps[j].prot_id = dcbx_cfg->app[j].prot_id;
4048a13362dSEric Joyner 		qos_info->apps[j].selector = dcbx_cfg->app[j].selector;
4058a13362dSEric Joyner 	}
4068923de59SPiotr Kubaj 
4078923de59SPiotr Kubaj 	/* Gather DSCP-to-TC mapping and QoS/PFC mode */
4088923de59SPiotr Kubaj 	memcpy(qos_info->dscp_map, dcbx_cfg->dscp_map, sizeof(qos_info->dscp_map));
4098923de59SPiotr Kubaj 	qos_info->pfc_mode = dcbx_cfg->pfc_mode;
4108a13362dSEric Joyner }
4118a13362dSEric Joyner 
4128a13362dSEric Joyner /**
4138a13362dSEric Joyner  * ice_rdma_check_version - Check that the provided RDMA version is compatible
4148a13362dSEric Joyner  * @info: the RDMA client information structure
4158a13362dSEric Joyner  *
4168a13362dSEric Joyner  * Verify that the client RDMA driver provided a version that is compatible
4178a13362dSEric Joyner  * with the driver interface.
4189c30461dSEric Joyner  * @return 0 on success, ENOTSUP when LAN-RDMA interface version doesn't match,
4199c30461dSEric Joyner  * EINVAL on kobject interface fail.
4208a13362dSEric Joyner  */
4218a13362dSEric Joyner static int
4228a13362dSEric Joyner ice_rdma_check_version(struct ice_rdma_info *info)
4238a13362dSEric Joyner {
4248a13362dSEric Joyner 	/* Make sure the MAJOR version matches */
4258a13362dSEric Joyner 	if (info->major_version != ICE_RDMA_MAJOR_VERSION) {
4268a13362dSEric Joyner 		log(LOG_WARNING, "%s: the iRDMA driver requested version %d.%d.%d, but this driver only supports major version %d.x.x\n",
4278a13362dSEric Joyner 		    __func__,
4288a13362dSEric Joyner 		    info->major_version, info->minor_version, info->patch_version,
4298a13362dSEric Joyner 		    ICE_RDMA_MAJOR_VERSION);
4308a13362dSEric Joyner 		return (ENOTSUP);
4318a13362dSEric Joyner 	}
4328a13362dSEric Joyner 
4338a13362dSEric Joyner 	/*
4348a13362dSEric Joyner 	 * Make sure that the MINOR version is compatible.
4358a13362dSEric Joyner 	 *
4368a13362dSEric Joyner 	 * This means that the RDMA client driver version MUST not be greater
4378a13362dSEric Joyner 	 * than the version provided by the driver, as it would indicate that
4388a13362dSEric Joyner 	 * the RDMA client expects features which are not supported by the
4398a13362dSEric Joyner 	 * main driver.
4408a13362dSEric Joyner 	 */
4418a13362dSEric Joyner 	if (info->minor_version > ICE_RDMA_MINOR_VERSION) {
4428a13362dSEric Joyner 		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",
4438a13362dSEric Joyner 		__func__,
4448a13362dSEric Joyner 		info->major_version, info->minor_version, info->patch_version,
4458a13362dSEric Joyner 		ICE_RDMA_MAJOR_VERSION, ICE_RDMA_MINOR_VERSION);
4468a13362dSEric Joyner 		return (ENOTSUP);
4478a13362dSEric Joyner 	}
4488a13362dSEric Joyner 
4498a13362dSEric Joyner 	/*
4508a13362dSEric Joyner 	 * Make sure that the PATCH version is compatible.
4518a13362dSEric Joyner 	 *
4528a13362dSEric Joyner 	 * This means that the RDMA client version MUST not be greater than
4538a13362dSEric Joyner 	 * the version provided by the driver, as it may indicate that the
4548a13362dSEric Joyner 	 * RDMA client expects certain backwards compatible bug fixes which
4558a13362dSEric Joyner 	 * are not implemented by this version of the main driver.
4568a13362dSEric Joyner 	 */
4578a13362dSEric Joyner 	if ((info->minor_version == ICE_RDMA_MINOR_VERSION) &&
4588a13362dSEric Joyner 	    (info->patch_version > ICE_RDMA_PATCH_VERSION)) {
4598a13362dSEric Joyner 		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",
4608a13362dSEric Joyner 		__func__,
4618a13362dSEric Joyner 		info->major_version, info->minor_version, info->patch_version,
4628a13362dSEric Joyner 		ICE_RDMA_MAJOR_VERSION, ICE_RDMA_MINOR_VERSION, ICE_RDMA_PATCH_VERSION);
4638a13362dSEric Joyner 		return (ENOTSUP);
4648a13362dSEric Joyner 	}
4658a13362dSEric Joyner 
4668a13362dSEric Joyner 	/* Make sure that the kobject class is initialized */
4678a13362dSEric Joyner 	if (info->rdma_class == NULL) {
4688a13362dSEric Joyner 		log(LOG_WARNING, "%s: the iRDMA driver did not specify a kobject interface\n",
4698a13362dSEric Joyner 		    __func__);
4708a13362dSEric Joyner 		return (EINVAL);
4718a13362dSEric Joyner 	}
4728a13362dSEric Joyner 
4738a13362dSEric Joyner 	return (0);
4748a13362dSEric Joyner }
4758a13362dSEric Joyner 
4768a13362dSEric Joyner /**
4778a13362dSEric Joyner  * ice_rdma_register - Register an RDMA client driver
4788a13362dSEric Joyner  * @info: the RDMA client information structure
4798a13362dSEric Joyner  *
4808a13362dSEric Joyner  * Called by the RDMA client driver on load. Used to initialize the RDMA
4818a13362dSEric Joyner  * client driver interface and enable interop between the ice driver and the
4828a13362dSEric Joyner  * RDMA client driver.
4838a13362dSEric Joyner  *
4848a13362dSEric Joyner  * The RDMA client driver must provide the version number it expects, along
4858a13362dSEric Joyner  * with a pointer to a kobject class that extends the irdma_di_if class, and
4868a13362dSEric Joyner  * implements the irdma_if class interface.
4879c30461dSEric Joyner  * @return 0 on success, ECONNREFUSED when RDMA is turned off, EBUSY when irdma
4889c30461dSEric Joyner  * already registered, ENOTSUP when LAN-RDMA interface version doesn't match,
4899c30461dSEric Joyner  * EINVAL on kobject interface fail.
4908a13362dSEric Joyner  */
4918a13362dSEric Joyner int
4928a13362dSEric Joyner ice_rdma_register(struct ice_rdma_info *info)
4938a13362dSEric Joyner {
4948a13362dSEric Joyner 	struct ice_rdma_entry *entry;
4958923de59SPiotr Kubaj 	struct ice_softc *sc;
4968a13362dSEric Joyner 	int err = 0;
4978a13362dSEric Joyner 
4988a13362dSEric Joyner 	sx_xlock(&ice_rdma.mtx);
4998a13362dSEric Joyner 
5008a13362dSEric Joyner 	if (!ice_enable_irdma) {
5018a13362dSEric Joyner 		log(LOG_INFO, "%s: The iRDMA driver interface has been disabled\n", __func__);
5028a13362dSEric Joyner 		err = (ECONNREFUSED);
5038a13362dSEric Joyner 		goto return_unlock;
5048a13362dSEric Joyner 	}
5058a13362dSEric Joyner 
5068a13362dSEric Joyner 	if (ice_rdma.registered) {
5078a13362dSEric Joyner 		log(LOG_WARNING, "%s: iRDMA driver already registered\n", __func__);
5088a13362dSEric Joyner 		err = (EBUSY);
5098a13362dSEric Joyner 		goto return_unlock;
5108a13362dSEric Joyner 	}
5118a13362dSEric Joyner 
5128a13362dSEric Joyner 	/* Make sure the iRDMA version is compatible */
5138a13362dSEric Joyner 	err = ice_rdma_check_version(info);
5148a13362dSEric Joyner 	if (err)
5158a13362dSEric Joyner 		goto return_unlock;
5168a13362dSEric Joyner 
5178a13362dSEric Joyner 	log(LOG_INFO, "%s: iRDMA driver registered using version %d.%d.%d\n",
5188a13362dSEric Joyner 	    __func__, info->major_version, info->minor_version, info->patch_version);
5198a13362dSEric Joyner 
5208a13362dSEric Joyner 	ice_rdma.peer_class = info->rdma_class;
5218a13362dSEric Joyner 
5228a13362dSEric Joyner 	/*
5238a13362dSEric Joyner 	 * Initialize the kobject interface and notify the RDMA client of each
5248a13362dSEric Joyner 	 * existing PF interface.
5258a13362dSEric Joyner 	 */
5268a13362dSEric Joyner 	LIST_FOREACH(entry, &ice_rdma.peers, node) {
5278a13362dSEric Joyner 		kobj_init((kobj_t)&entry->peer, ice_rdma.peer_class);
5288923de59SPiotr Kubaj 		/* Gather DCB/QOS info into peer */
5298923de59SPiotr Kubaj 		sc = __containerof(entry, struct ice_softc, rdma_entry);
5308923de59SPiotr Kubaj 		memset(&entry->peer.initial_qos_info, 0, sizeof(entry->peer.initial_qos_info));
5318923de59SPiotr Kubaj 		ice_rdma_cp_qos_info(&sc->hw, &sc->hw.port_info->qos_cfg.local_dcbx_cfg,
5328923de59SPiotr Kubaj 				     &entry->peer.initial_qos_info);
5338923de59SPiotr Kubaj 
5348a13362dSEric Joyner 		IRDMA_PROBE(&entry->peer);
5358a13362dSEric Joyner 		if (entry->initiated)
5368a13362dSEric Joyner 			IRDMA_OPEN(&entry->peer);
5378a13362dSEric Joyner 	}
5388a13362dSEric Joyner 	ice_rdma.registered = true;
5398a13362dSEric Joyner 
5408a13362dSEric Joyner return_unlock:
5418a13362dSEric Joyner 	sx_xunlock(&ice_rdma.mtx);
5428a13362dSEric Joyner 
5438a13362dSEric Joyner 	return (err);
5448a13362dSEric Joyner }
5458a13362dSEric Joyner 
5468a13362dSEric Joyner /**
5478a13362dSEric Joyner  * ice_rdma_unregister - Unregister an RDMA client driver
5488a13362dSEric Joyner  *
5498a13362dSEric Joyner  * Called by the RDMA client driver on unload. Used to de-initialize the RDMA
5508a13362dSEric Joyner  * client driver interface and shut down communication between the ice driver
5518a13362dSEric Joyner  * and the RDMA client driver.
5529c30461dSEric Joyner  * @return 0 on success, ENOENT when irdma driver wasn't registered
5538a13362dSEric Joyner  */
5548a13362dSEric Joyner int
5558a13362dSEric Joyner ice_rdma_unregister(void)
5568a13362dSEric Joyner {
5578a13362dSEric Joyner 	struct ice_rdma_entry *entry;
5588a13362dSEric Joyner 
5598a13362dSEric Joyner 	sx_xlock(&ice_rdma.mtx);
5608a13362dSEric Joyner 
5618a13362dSEric Joyner 	if (!ice_rdma.registered) {
5628a13362dSEric Joyner 		log(LOG_WARNING, "%s: iRDMA driver was not previously registered\n",
5638a13362dSEric Joyner 		       __func__);
5648a13362dSEric Joyner 		sx_xunlock(&ice_rdma.mtx);
5658a13362dSEric Joyner 		return (ENOENT);
5668a13362dSEric Joyner 	}
5678a13362dSEric Joyner 
5688a13362dSEric Joyner 	log(LOG_INFO, "%s: iRDMA driver unregistered\n", __func__);
5698a13362dSEric Joyner 	ice_rdma.registered = false;
5708a13362dSEric Joyner 	ice_rdma.peer_class = NULL;
5718a13362dSEric Joyner 
5728a13362dSEric Joyner 	/*
5738a13362dSEric Joyner 	 * Release the kobject interface for each of the existing PF
5748a13362dSEric Joyner 	 * interfaces. Note that we do not notify the client about removing
5758a13362dSEric Joyner 	 * each PF, as it is assumed that the client will have already cleaned
5768a13362dSEric Joyner 	 * up any associated resources when it is unregistered.
5778a13362dSEric Joyner 	 */
5788a13362dSEric Joyner 	LIST_FOREACH(entry, &ice_rdma.peers, node)
5798a13362dSEric Joyner 		kobj_delete((kobj_t)&entry->peer, NULL);
5808a13362dSEric Joyner 
5818a13362dSEric Joyner 	sx_xunlock(&ice_rdma.mtx);
5828a13362dSEric Joyner 
5838a13362dSEric Joyner 	return (0);
5848a13362dSEric Joyner }
5858a13362dSEric Joyner 
5868a13362dSEric Joyner /**
5878a13362dSEric Joyner  * ice_rdma_init - RDMA driver init routine
5888a13362dSEric Joyner  *
5898a13362dSEric Joyner  * Called during ice driver module initialization to setup the RDMA client
5908a13362dSEric Joyner  * interface mutex and RDMA peer structure list.
5918a13362dSEric Joyner  */
5928a13362dSEric Joyner void
5938a13362dSEric Joyner ice_rdma_init(void)
5948a13362dSEric Joyner {
5958a13362dSEric Joyner 	LIST_INIT(&ice_rdma.peers);
5968a13362dSEric Joyner 	sx_init_flags(&ice_rdma.mtx, "ice rdma interface", SX_DUPOK);
5978a13362dSEric Joyner 
5988a13362dSEric Joyner 	ice_rdma.registered = false;
5998a13362dSEric Joyner 	ice_rdma.peer_class = NULL;
6008a13362dSEric Joyner }
6018a13362dSEric Joyner 
6028a13362dSEric Joyner /**
6038a13362dSEric Joyner  * ice_rdma_exit - RDMA driver exit routine
6048a13362dSEric Joyner  *
6058a13362dSEric Joyner  * Called during ice driver module exit to shutdown the RDMA client interface
6068a13362dSEric Joyner  * mutex.
6078a13362dSEric Joyner  */
6088a13362dSEric Joyner void
6098a13362dSEric Joyner ice_rdma_exit(void)
6108a13362dSEric Joyner {
6118a13362dSEric Joyner 	MPASS(LIST_EMPTY(&ice_rdma.peers));
6128a13362dSEric Joyner 	sx_destroy(&ice_rdma.mtx);
6138a13362dSEric Joyner }
6148a13362dSEric Joyner 
6158a13362dSEric Joyner /**
6168a13362dSEric Joyner  * ice_rdma_pf_attach_locked - Prepare a PF for RDMA connections
6178a13362dSEric Joyner  * @sc: the ice driver softc
6188a13362dSEric Joyner  *
6198a13362dSEric Joyner  * Initialize a peer entry for this PF and add it to the RDMA interface list.
6208a13362dSEric Joyner  * Notify the client RDMA driver of a new PF device.
6218a13362dSEric Joyner  *
6228a13362dSEric Joyner  * @pre must be called while holding the ice_rdma mutex.
6239c30461dSEric Joyner  * @return 0 on success and when RDMA feature is not available, EEXIST when
6249c30461dSEric Joyner  * irdma is already attached
6258a13362dSEric Joyner  */
6268a13362dSEric Joyner static int
6278a13362dSEric Joyner ice_rdma_pf_attach_locked(struct ice_softc *sc)
6288a13362dSEric Joyner {
6298a13362dSEric Joyner 	struct ice_rdma_entry *entry;
6308a13362dSEric Joyner 
6318a13362dSEric Joyner 	/* Do not attach the PF unless RDMA is supported */
6328a13362dSEric Joyner 	if (!ice_is_bit_set(sc->feat_cap, ICE_FEATURE_RDMA))
6338a13362dSEric Joyner 		return (0);
6348a13362dSEric Joyner 
6358a13362dSEric Joyner 	entry = &sc->rdma_entry;
6368a13362dSEric Joyner 	if (entry->attached) {
6378a13362dSEric Joyner 		device_printf(sc->dev, "iRDMA peer entry already exists\n");
6388a13362dSEric Joyner 		return (EEXIST);
6398a13362dSEric Joyner 	}
6408a13362dSEric Joyner 
6418a13362dSEric Joyner 	entry->attached = true;
6428a13362dSEric Joyner 	entry->peer.dev = sc->dev;
6438a13362dSEric Joyner 	entry->peer.ifp = sc->ifp;
6448a13362dSEric Joyner 	entry->peer.pf_id = sc->hw.pf_id;
6458a13362dSEric Joyner 	entry->peer.pci_mem = sc->bar0.res;
6468a13362dSEric Joyner 	entry->peer.pf_vsi_num = ice_get_hw_vsi_num(&sc->hw, sc->pf_vsi.idx);
6478a13362dSEric Joyner 	if (sc->rdma_imap && sc->rdma_imap[0] != ICE_INVALID_RES_IDX &&
6488a13362dSEric Joyner 	    sc->irdma_vectors > 0) {
6498a13362dSEric Joyner 		entry->peer.msix.base = sc->rdma_imap[0];
6508a13362dSEric Joyner 		entry->peer.msix.count = sc->irdma_vectors;
6518a13362dSEric Joyner 	}
6528a13362dSEric Joyner 
6538a13362dSEric Joyner 	/* Gather DCB/QOS info into peer */
6548a13362dSEric Joyner 	memset(&entry->peer.initial_qos_info, 0, sizeof(entry->peer.initial_qos_info));
6558a13362dSEric Joyner 	ice_rdma_cp_qos_info(&sc->hw, &sc->hw.port_info->qos_cfg.local_dcbx_cfg,
6568a13362dSEric Joyner 			     &entry->peer.initial_qos_info);
6578a13362dSEric Joyner 
6588a13362dSEric Joyner 	/*
6598a13362dSEric Joyner 	 * If the RDMA client driver has already registered, initialize the
6608a13362dSEric Joyner 	 * kobject and notify the client of a new PF
6618a13362dSEric Joyner 	 */
6628a13362dSEric Joyner 	if (ice_rdma.registered) {
6638a13362dSEric Joyner 		kobj_init((kobj_t)&entry->peer, ice_rdma.peer_class);
6648a13362dSEric Joyner 		IRDMA_PROBE(&entry->peer);
6658a13362dSEric Joyner 	}
6668a13362dSEric Joyner 
6678a13362dSEric Joyner 	LIST_INSERT_HEAD(&ice_rdma.peers, entry, node);
6688a13362dSEric Joyner 
6698a13362dSEric Joyner 	ice_set_bit(ICE_FEATURE_RDMA, sc->feat_en);
6708a13362dSEric Joyner 
6718a13362dSEric Joyner 	return (0);
6728a13362dSEric Joyner }
6738a13362dSEric Joyner 
6748a13362dSEric Joyner /**
6758a13362dSEric Joyner  * ice_rdma_pf_attach - Notify the RDMA client of a new PF
6768a13362dSEric Joyner  * @sc: the ice driver softc
6778a13362dSEric Joyner  *
6788a13362dSEric Joyner  * Called during PF attach to notify the RDMA client of a new PF.
6799c30461dSEric Joyner  * @return 0 or EEXIST if irdma was already attached
6808a13362dSEric Joyner  */
6818a13362dSEric Joyner int
6828a13362dSEric Joyner ice_rdma_pf_attach(struct ice_softc *sc)
6838a13362dSEric Joyner {
6848a13362dSEric Joyner 	int err;
6858a13362dSEric Joyner 
6868a13362dSEric Joyner 	sx_xlock(&ice_rdma.mtx);
6878a13362dSEric Joyner 	err = ice_rdma_pf_attach_locked(sc);
6888a13362dSEric Joyner 	sx_xunlock(&ice_rdma.mtx);
6898a13362dSEric Joyner 
6908a13362dSEric Joyner 	return (err);
6918a13362dSEric Joyner }
6928a13362dSEric Joyner 
6938a13362dSEric Joyner /**
6948a13362dSEric Joyner  * ice_rdma_pf_detach_locked - Notify the RDMA client on PF detach
6958a13362dSEric Joyner  * @sc: the ice driver softc
6968a13362dSEric Joyner  *
6978a13362dSEric Joyner  * Notify the RDMA peer client driver of removal of a PF, and release any
6988a13362dSEric Joyner  * RDMA-specific resources associated with that PF. Remove the PF from the
6998a13362dSEric Joyner  * list of available RDMA entries.
7008a13362dSEric Joyner  *
7018a13362dSEric Joyner  * @pre must be called while holding the ice_rdma mutex.
7028a13362dSEric Joyner  */
7038a13362dSEric Joyner static void
7048a13362dSEric Joyner ice_rdma_pf_detach_locked(struct ice_softc *sc)
7058a13362dSEric Joyner {
7068a13362dSEric Joyner 	struct ice_rdma_entry *entry;
7078a13362dSEric Joyner 
7088a13362dSEric Joyner 	/* No need to detach the PF if RDMA is not enabled */
7098a13362dSEric Joyner 	if (!ice_is_bit_set(sc->feat_en, ICE_FEATURE_RDMA))
7108a13362dSEric Joyner 		return;
7118a13362dSEric Joyner 
7128a13362dSEric Joyner 	entry = &sc->rdma_entry;
7138a13362dSEric Joyner 	if (!entry->attached) {
7148a13362dSEric Joyner 		device_printf(sc->dev, "iRDMA peer entry was not attached\n");
7158a13362dSEric Joyner 		return;
7168a13362dSEric Joyner 	}
7178a13362dSEric Joyner 
7188a13362dSEric Joyner 	/*
7198a13362dSEric Joyner 	 * If the RDMA client driver is registered, notify the client that
7208a13362dSEric Joyner 	 * a PF has been removed, and release the kobject reference.
7218a13362dSEric Joyner 	 */
7228a13362dSEric Joyner 	if (ice_rdma.registered) {
7238a13362dSEric Joyner 		IRDMA_REMOVE(&entry->peer);
7248a13362dSEric Joyner 		kobj_delete((kobj_t)&entry->peer, NULL);
7258a13362dSEric Joyner 	}
7268a13362dSEric Joyner 
7278a13362dSEric Joyner 	LIST_REMOVE(entry, node);
7288a13362dSEric Joyner 	entry->attached = false;
7298a13362dSEric Joyner 
7308a13362dSEric Joyner 	ice_clear_bit(ICE_FEATURE_RDMA, sc->feat_en);
7318a13362dSEric Joyner }
7328a13362dSEric Joyner 
7338a13362dSEric Joyner /**
7348a13362dSEric Joyner  * ice_rdma_pf_detach - Notify the RDMA client of a PF detaching
7358a13362dSEric Joyner  * @sc: the ice driver softc
7368a13362dSEric Joyner  *
7378a13362dSEric Joyner  * Take the ice_rdma mutex and then notify the RDMA client that a PF has been
7388a13362dSEric Joyner  * removed.
7398a13362dSEric Joyner  */
7408a13362dSEric Joyner void
7418a13362dSEric Joyner ice_rdma_pf_detach(struct ice_softc *sc)
7428a13362dSEric Joyner {
7438a13362dSEric Joyner 	sx_xlock(&ice_rdma.mtx);
7448a13362dSEric Joyner 	ice_rdma_pf_detach_locked(sc);
7458a13362dSEric Joyner 	sx_xunlock(&ice_rdma.mtx);
7468a13362dSEric Joyner }
7478a13362dSEric Joyner 
7488a13362dSEric Joyner /**
7498a13362dSEric Joyner  * ice_rdma_pf_init - Notify the RDMA client that a PF has initialized
7508a13362dSEric Joyner  * @sc: the ice driver softc
7518a13362dSEric Joyner  *
7528a13362dSEric Joyner  * Called by the ice driver when a PF has been initialized. Notifies the RDMA
7538a13362dSEric Joyner  * client that a PF is up and ready to operate.
7549c30461dSEric Joyner  * @return 0 on success, propagates IRDMA_OPEN return value
7558a13362dSEric Joyner  */
7568a13362dSEric Joyner int
7578a13362dSEric Joyner ice_rdma_pf_init(struct ice_softc *sc)
7588a13362dSEric Joyner {
7598a13362dSEric Joyner 	struct ice_rdma_peer *peer = &sc->rdma_entry.peer;
7608a13362dSEric Joyner 
7618a13362dSEric Joyner 	sx_xlock(&ice_rdma.mtx);
7628a13362dSEric Joyner 
7638a13362dSEric Joyner 	/* Update the MTU */
764402810d3SJustin Hibbits 	peer->mtu = if_getmtu(sc->ifp);
7658a13362dSEric Joyner 	sc->rdma_entry.initiated = true;
7668a13362dSEric Joyner 
7678a13362dSEric Joyner 	if (sc->rdma_entry.attached && ice_rdma.registered) {
7688a13362dSEric Joyner 		sx_xunlock(&ice_rdma.mtx);
7698a13362dSEric Joyner 		return IRDMA_OPEN(peer);
7708a13362dSEric Joyner 	}
7718a13362dSEric Joyner 
7728a13362dSEric Joyner 	sx_xunlock(&ice_rdma.mtx);
7738a13362dSEric Joyner 
7748a13362dSEric Joyner 	return (0);
7758a13362dSEric Joyner }
7768a13362dSEric Joyner 
7778a13362dSEric Joyner /**
7788a13362dSEric Joyner  * ice_rdma_pf_stop - Notify the RDMA client of a stopped PF device
7798a13362dSEric Joyner  * @sc: the ice driver softc
7808a13362dSEric Joyner  *
7818a13362dSEric Joyner  * Called by the ice driver when a PF is stopped. Notifies the RDMA client
7828a13362dSEric Joyner  * driver that the PF has stopped and is not ready to operate.
7839c30461dSEric Joyner  * @return 0 on success
7848a13362dSEric Joyner  */
7858a13362dSEric Joyner int
7868a13362dSEric Joyner ice_rdma_pf_stop(struct ice_softc *sc)
7878a13362dSEric Joyner {
7888a13362dSEric Joyner 	sx_xlock(&ice_rdma.mtx);
7898a13362dSEric Joyner 
7908a13362dSEric Joyner 	sc->rdma_entry.initiated = false;
7918a13362dSEric Joyner 	if (sc->rdma_entry.attached && ice_rdma.registered) {
7928a13362dSEric Joyner 		sx_xunlock(&ice_rdma.mtx);
7938a13362dSEric Joyner 		return IRDMA_CLOSE(&sc->rdma_entry.peer);
7948a13362dSEric Joyner 	}
7958a13362dSEric Joyner 
7968a13362dSEric Joyner 	sx_xunlock(&ice_rdma.mtx);
7978a13362dSEric Joyner 
7988a13362dSEric Joyner 	return (0);
7998a13362dSEric Joyner }
8008a13362dSEric Joyner 
8018a13362dSEric Joyner /**
8028a13362dSEric Joyner  * ice_rdma_link_change - Notify RDMA client of a change in link status
8038a13362dSEric Joyner  * @sc: the ice driver softc
8048a13362dSEric Joyner  * @linkstate: the link status
8058a13362dSEric Joyner  * @baudrate: the link rate in bits per second
8068a13362dSEric Joyner  *
8078a13362dSEric Joyner  * Notify the RDMA client of a link status change, by sending it the new link
8088a13362dSEric Joyner  * state and baudrate.
8098a13362dSEric Joyner  *
8108a13362dSEric Joyner  * The link state is represented the same was as in the ifnet structure. It
8118a13362dSEric Joyner  * should be LINK_STATE_UNKNOWN, LINK_STATE_DOWN, or LINK_STATE_UP.
8128a13362dSEric Joyner  */
8138a13362dSEric Joyner void
8148a13362dSEric Joyner ice_rdma_link_change(struct ice_softc *sc, int linkstate, uint64_t baudrate)
8158a13362dSEric Joyner {
8168a13362dSEric Joyner 	struct ice_rdma_peer *peer = &sc->rdma_entry.peer;
8178a13362dSEric Joyner 	struct ice_rdma_event event;
8188a13362dSEric Joyner 
8198a13362dSEric Joyner 	memset(&event, 0, sizeof(struct ice_rdma_event));
8208a13362dSEric Joyner 	event.type = ICE_RDMA_EVENT_LINK_CHANGE;
8218a13362dSEric Joyner 	event.linkstate = linkstate;
8228a13362dSEric Joyner 	event.baudrate = baudrate;
8238a13362dSEric Joyner 
8248a13362dSEric Joyner 	sx_xlock(&ice_rdma.mtx);
8258a13362dSEric Joyner 
8268a13362dSEric Joyner 	if (sc->rdma_entry.attached && ice_rdma.registered)
8278a13362dSEric Joyner 		IRDMA_EVENT_HANDLER(peer, &event);
8288a13362dSEric Joyner 
8298a13362dSEric Joyner 	sx_xunlock(&ice_rdma.mtx);
8308a13362dSEric Joyner }
8318a13362dSEric Joyner 
8328a13362dSEric Joyner /**
8338a13362dSEric Joyner  *  ice_rdma_notify_dcb_qos_change - notify RDMA driver to pause traffic
8348a13362dSEric Joyner  *  @sc: the ice driver softc
8358a13362dSEric Joyner  *
8368a13362dSEric Joyner  *  Notify the RDMA driver that QOS/DCB settings are about to change.
8378a13362dSEric Joyner  *  Once the function return, all the QPs should be suspended.
8388a13362dSEric Joyner  */
8398a13362dSEric Joyner void
8408a13362dSEric Joyner ice_rdma_notify_dcb_qos_change(struct ice_softc *sc)
8418a13362dSEric Joyner {
8428a13362dSEric Joyner 	struct ice_rdma_peer *peer = &sc->rdma_entry.peer;
8438a13362dSEric Joyner 	struct ice_rdma_event event;
8448a13362dSEric Joyner 
8458a13362dSEric Joyner 	memset(&event, 0, sizeof(struct ice_rdma_event));
8468a13362dSEric Joyner 	event.type = ICE_RDMA_EVENT_TC_CHANGE;
8478a13362dSEric Joyner 	/* pre-event */
8488a13362dSEric Joyner 	event.prep = true;
8498a13362dSEric Joyner 
8508a13362dSEric Joyner 	sx_xlock(&ice_rdma.mtx);
8518a13362dSEric Joyner 	if (sc->rdma_entry.attached && ice_rdma.registered)
8528a13362dSEric Joyner 		IRDMA_EVENT_HANDLER(peer, &event);
8538a13362dSEric Joyner 	sx_xunlock(&ice_rdma.mtx);
8548a13362dSEric Joyner }
8558a13362dSEric Joyner 
8568a13362dSEric Joyner /**
8578a13362dSEric Joyner  *  ice_rdma_dcb_qos_update - pass the changed dcb settings to RDMA driver
8588a13362dSEric Joyner  *  @sc: the ice driver softc
8598a13362dSEric Joyner  *  @pi: the port info structure
8608a13362dSEric Joyner  *
8618a13362dSEric Joyner  *  Pass the changed DCB settings to RDMA traffic. This function should be
8628a13362dSEric Joyner  *  called only after ice_rdma_notify_dcb_qos_change has been called and
8638a13362dSEric Joyner  *  returned before. After the function returns, all the RDMA traffic
8648a13362dSEric Joyner  *  should be resumed.
8658a13362dSEric Joyner  */
8668a13362dSEric Joyner void
8678a13362dSEric Joyner ice_rdma_dcb_qos_update(struct ice_softc *sc, struct ice_port_info *pi)
8688a13362dSEric Joyner {
8698a13362dSEric Joyner 	struct ice_rdma_peer *peer = &sc->rdma_entry.peer;
8708a13362dSEric Joyner 	struct ice_rdma_event event;
8718a13362dSEric Joyner 
8728a13362dSEric Joyner 	memset(&event, 0, sizeof(struct ice_rdma_event));
8738a13362dSEric Joyner 	event.type = ICE_RDMA_EVENT_TC_CHANGE;
8748a13362dSEric Joyner 	/* post-event */
8758a13362dSEric Joyner 	event.prep = false;
8768a13362dSEric Joyner 
8778a13362dSEric Joyner 	/* gather current configuration */
8788a13362dSEric Joyner 	ice_rdma_cp_qos_info(&sc->hw, &pi->qos_cfg.local_dcbx_cfg, &event.port_qos);
8798a13362dSEric Joyner 	sx_xlock(&ice_rdma.mtx);
8808a13362dSEric Joyner 	if (sc->rdma_entry.attached && ice_rdma.registered)
8818a13362dSEric Joyner 		IRDMA_EVENT_HANDLER(peer, &event);
8828a13362dSEric Joyner 	sx_xunlock(&ice_rdma.mtx);
8838a13362dSEric Joyner }
88401fbb869SBartosz Sobczak 
88501fbb869SBartosz Sobczak /**
88601fbb869SBartosz Sobczak  *  ice_rdma_notify_pe_intr - notify irdma on incoming interrupts regarding PE
88701fbb869SBartosz Sobczak  *  @sc: the ice driver softc
88801fbb869SBartosz Sobczak  *  @oicr: interrupt cause
88901fbb869SBartosz Sobczak  *
89001fbb869SBartosz Sobczak  *  Pass the information about received interrupt to RDMA driver if it was
89101fbb869SBartosz Sobczak  *  relating to PE. Specifically PE_CRITERR and HMC_ERR.
89201fbb869SBartosz Sobczak  *  The irdma driver shall decide what should be done upon these interrupts.
89301fbb869SBartosz Sobczak  */
89401fbb869SBartosz Sobczak void
89501fbb869SBartosz Sobczak ice_rdma_notify_pe_intr(struct ice_softc *sc, uint32_t oicr)
89601fbb869SBartosz Sobczak {
89701fbb869SBartosz Sobczak 	struct ice_rdma_peer *peer = &sc->rdma_entry.peer;
89801fbb869SBartosz Sobczak 	struct ice_rdma_event event;
89901fbb869SBartosz Sobczak 
90001fbb869SBartosz Sobczak 	memset(&event, 0, sizeof(struct ice_rdma_event));
90101fbb869SBartosz Sobczak 	event.type = ICE_RDMA_EVENT_CRIT_ERR;
90201fbb869SBartosz Sobczak 	event.oicr_reg = oicr;
90301fbb869SBartosz Sobczak 
90401fbb869SBartosz Sobczak 	sx_xlock(&ice_rdma.mtx);
90501fbb869SBartosz Sobczak 	if (sc->rdma_entry.attached && ice_rdma.registered)
90601fbb869SBartosz Sobczak 		IRDMA_EVENT_HANDLER(peer, &event);
90701fbb869SBartosz Sobczak 	sx_xunlock(&ice_rdma.mtx);
90801fbb869SBartosz Sobczak }
90901fbb869SBartosz Sobczak 
91001fbb869SBartosz Sobczak /**
91101fbb869SBartosz Sobczak  *  ice_rdma_notify_reset - notify irdma on incoming pf-reset
91201fbb869SBartosz Sobczak  *  @sc: the ice driver softc
91301fbb869SBartosz Sobczak  *
91401fbb869SBartosz Sobczak  *  Inform irdma driver of an incoming PF reset.
91501fbb869SBartosz Sobczak  *  The irdma driver shall set its state to reset, and avoid using CQP
91601fbb869SBartosz Sobczak  *  anymore. Next step should be to call ice_rdma_pf_stop in order to
91701fbb869SBartosz Sobczak  *  remove resources.
91801fbb869SBartosz Sobczak  */
91901fbb869SBartosz Sobczak void
92001fbb869SBartosz Sobczak ice_rdma_notify_reset(struct ice_softc *sc)
92101fbb869SBartosz Sobczak {
92201fbb869SBartosz Sobczak 	struct ice_rdma_peer *peer = &sc->rdma_entry.peer;
92301fbb869SBartosz Sobczak 	struct ice_rdma_event event;
92401fbb869SBartosz Sobczak 
92501fbb869SBartosz Sobczak 	memset(&event, 0, sizeof(struct ice_rdma_event));
92601fbb869SBartosz Sobczak 	event.type = ICE_RDMA_EVENT_RESET;
92701fbb869SBartosz Sobczak 
92801fbb869SBartosz Sobczak 	sx_xlock(&ice_rdma.mtx);
92901fbb869SBartosz Sobczak 	if (sc->rdma_entry.attached && ice_rdma.registered)
93001fbb869SBartosz Sobczak 	        IRDMA_EVENT_HANDLER(peer, &event);
93101fbb869SBartosz Sobczak 	sx_xunlock(&ice_rdma.mtx);
93201fbb869SBartosz Sobczak }
933