git: 9d48fd452ed2 - main - qlnx: Report the programmed RSS key and hash types

From: Kevin Bowling <kbowling_at_FreeBSD.org>
Date: Fri, 18 Sep 2026 23:14:41 UTC
The branch main has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=9d48fd452ed20746e468dd986fa6b54ca20350a6

commit 9d48fd452ed20746e468dd986fa6b54ca20350a6
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-09-18 10:11:36 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-09-18 23:13:43 +0000

    qlnx: Report the programmed RSS key and hash types
    
    Implement SIOCGIFRSSKEY and SIOCGIFRSSHASH for qlnxe and qlnxev using
    the cached vport RSS configuration.  This lets hn(4) synchronize its
    synthetic RSS configuration with the VF without assuming that every
    driver programs all of the common RSS hash selections.
    
    Serialize the queries with the device lock and reject them while the
    interface is not running.  Convert the firmware request's key words back
    into network byte order and translate the six representable IPv4/IPv6
    TCP/UDP hash selections.  Report no hashing when RSS is disabled, including
    the driver's single-queue configuration.
    
    For VFs, require a successful RSS extension response from every hardware
    function.  The overall vport-update reply can succeed while its RSS TLV
    is missing or rejected; recording that result prevents reporting an
    unconfirmed configuration.  Invalidate the confirmation before each RSS
    request.  Leave existing vport-update return semantics, queue setup, and
    the receive datapath unchanged.
    
    Reviewed by:    gallatin
    MFC after:      2 weeks
    Sponsored by:   BBOX.io
    Differential Revision:  https://reviews.freebsd.org/D59810
---
 sys/dev/qlnx/qlnxe/ecore_vf.c |  5 +++
 sys/dev/qlnx/qlnxe/ecore_vf.h |  3 ++
 sys/dev/qlnx/qlnxe/qlnx_os.c  | 84 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 92 insertions(+)

diff --git a/sys/dev/qlnx/qlnxe/ecore_vf.c b/sys/dev/qlnx/qlnxe/ecore_vf.c
index a7b006b982de..fcde9d4046b7 100644
--- a/sys/dev/qlnx/qlnxe/ecore_vf.c
+++ b/sys/dev/qlnx/qlnxe/ecore_vf.c
@@ -1242,6 +1242,9 @@ ecore_vf_handle_vp_update_tlvs_resp(struct ecore_hwfn *p_hwfn,
 		p_resp = (struct pfvf_def_resp_tlv *)
 			 ecore_iov_search_list_tlvs(p_hwfn, p_iov->pf2vf_reply,
 						    tlv);
+		if (tlv == CHANNEL_TLV_VPORT_UPDATE_RSS)
+			p_iov->rss_configured = p_resp &&
+			    p_resp->hdr.status == PFVF_STATUS_SUCCESS;
 		if (p_resp && p_resp->hdr.status)
 			DP_VERBOSE(p_hwfn, ECORE_MSG_IOV,
 				   "TLV[%d] type %s Configuration %s\n",
@@ -1270,6 +1273,8 @@ enum _ecore_status_t ecore_vf_pf_vport_update(struct ecore_hwfn *p_hwfn,
 
 	/* clear mailbox and prep header tlv */
 	ecore_vf_pf_prep(p_hwfn, CHANNEL_TLV_VPORT_UPDATE, sizeof(*req));
+	if (p_params->rss_params)
+		p_iov->rss_configured = false;
 
 	/* Prepare extended tlvs */
 	if (update_rx || update_tx) {
diff --git a/sys/dev/qlnx/qlnxe/ecore_vf.h b/sys/dev/qlnx/qlnxe/ecore_vf.h
index 5ae2fecfb0e7..c6481ec8be3b 100644
--- a/sys/dev/qlnx/qlnxe/ecore_vf.h
+++ b/sys/dev/qlnx/qlnxe/ecore_vf.h
@@ -82,6 +82,9 @@ struct ecore_vf_iov {
 	 * bar or via the doorbell bar.
 	 */
 	bool b_doorbell_bar;
+
+	/* FreeBSD RSS queries require the RSS TLV itself to be accepted. */
+	bool rss_configured;
 };
 
 /**
diff --git a/sys/dev/qlnx/qlnxe/qlnx_os.c b/sys/dev/qlnx/qlnxe/qlnx_os.c
index 853bd4cb7108..6b896729bf67 100644
--- a/sys/dev/qlnx/qlnxe/qlnx_os.c
+++ b/sys/dev/qlnx/qlnxe/qlnx_os.c
@@ -58,6 +58,7 @@
 #include "ecore_dbg_fw_funcs.h"
 #include "ecore_iov_api.h"
 #include "ecore_vf_api.h"
+#include "ecore_vf.h"
 
 #include "qlnx_ioctl.h"
 #include "qlnx_def.h"
@@ -2527,6 +2528,77 @@ _qlnx_set_promisc_allmulti(qlnx_host_t *ha, bool promisc, bool allmulti)
 	return (rc);
 }
 
+static int
+qlnx_rss_query_status(qlnx_host_t *ha)
+{
+	int i;
+
+	sx_assert(&ha->hw_lock, SA_XLOCKED);
+	if (ha->state != QLNX_STATE_OPEN ||
+	    (if_getdrvflags(ha->ifp) & IFF_DRV_RUNNING) == 0)
+		return (ENXIO);
+	if (IS_VF(&ha->cdev) && ha->rss_params.rss_enable) {
+		for (i = 0; i < ha->cdev.num_hwfns; i++) {
+			struct ecore_vf_iov *iov = ha->cdev.hwfns[i].vf_iov_info;
+
+			if (iov == NULL || !iov->rss_configured)
+				return (ENXIO);
+		}
+	}
+	return (0);
+}
+
+static int
+qlnx_get_rss_key(qlnx_host_t *ha, struct ifrsskey *ifrk)
+{
+	const struct ecore_rss_params *rss = &ha->rss_params;
+	int error, i;
+
+	error = qlnx_rss_query_status(ha);
+	if (error != 0)
+		return (error);
+	ifrk->ifrk_func = rss->rss_enable ? RSS_FUNC_TOEPLITZ : RSS_FUNC_NONE;
+	ifrk->ifrk_keylen = rss->rss_enable ? sizeof(rss->rss_key) : 0;
+	_Static_assert(sizeof(ifrk->ifrk_key) >= sizeof(rss->rss_key),
+	    "RSS query buffer too small");
+	bzero(ifrk->ifrk_key, sizeof(ifrk->ifrk_key));
+	/* Undo the word conversion used when preparing the firmware request. */
+	if (rss->rss_enable) {
+		for (i = 0; i < ECORE_RSS_KEY_SIZE; i++)
+			be32enc(ifrk->ifrk_key + i * sizeof(uint32_t),
+			    rss->rss_key[i]);
+	}
+	return (0);
+}
+
+static int
+qlnx_get_rss_hash(qlnx_host_t *ha, struct ifrsshash *ifrh)
+{
+	const struct ecore_rss_params *rss = &ha->rss_params;
+	uint8_t caps;
+	int error;
+
+	error = qlnx_rss_query_status(ha);
+	if (error != 0)
+		return (error);
+	ifrh->ifrh_func = rss->rss_enable ? RSS_FUNC_TOEPLITZ : RSS_FUNC_NONE;
+	ifrh->ifrh_types = 0;
+	caps = rss->rss_enable ? rss->rss_caps : 0;
+	if (caps & ECORE_RSS_IPV4)
+		ifrh->ifrh_types |= RSS_TYPE_IPV4;
+	if (caps & ECORE_RSS_IPV4_TCP)
+		ifrh->ifrh_types |= RSS_TYPE_TCP_IPV4;
+	if (caps & ECORE_RSS_IPV4_UDP)
+		ifrh->ifrh_types |= RSS_TYPE_UDP_IPV4;
+	if (caps & ECORE_RSS_IPV6)
+		ifrh->ifrh_types |= RSS_TYPE_IPV6;
+	if (caps & ECORE_RSS_IPV6_TCP)
+		ifrh->ifrh_types |= RSS_TYPE_TCP_IPV6;
+	if (caps & ECORE_RSS_IPV6_UDP)
+		ifrh->ifrh_types |= RSS_TYPE_UDP_IPV6;
+	return (0);
+}
+
 static int
 qlnx_ioctl(if_t ifp, u_long cmd, caddr_t data)
 {
@@ -2538,6 +2610,18 @@ qlnx_ioctl(if_t ifp, u_long cmd, caddr_t data)
 	ha = (qlnx_host_t *)if_getsoftc(ifp);
 
 	switch (cmd) {
+	case SIOCGIFRSSKEY:
+		QLNX_LOCK(ha);
+		ret = qlnx_get_rss_key(ha, (struct ifrsskey *)data);
+		QLNX_UNLOCK(ha);
+		break;
+
+	case SIOCGIFRSSHASH:
+		QLNX_LOCK(ha);
+		ret = qlnx_get_rss_hash(ha, (struct ifrsshash *)data);
+		QLNX_UNLOCK(ha);
+		break;
+
 	case SIOCSIFMTU:
 		QL_DPRINT4(ha, "SIOCSIFMTU (0x%lx)\n", cmd);