From nobody Sat Sep 26 18:54:41 2026 Received: from mx0a-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5E8F34137A2; Mon, 31 Aug 2026 13:20:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.148.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182411; cv=none; b=iyjYKzpRB4UI3OdcVwWyLpX5ZTcJIWiyhb0dngjeVgrgP4Ld6zYmN5eP8R8xsMaCt2/LwdeLz92mVhCJppR5hImfjpozS0ot/hhRMXYjOILAvQ8XBIBqQDfxh0sCwMF5fP6krXCrn8xy0Q1Tqkz3iZwE2Yx7d3b4CH6gC0BsdJs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182411; c=relaxed/simple; bh=Dh3dAWEzll3rD3GGX48H2FJ/tKX2uElCHSSFbvFrTyM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Jkdee0VsYspIyeZ/HrPRZO14X417J/VyYJOG+TpifZiXWEvLQJ06tSP+i4cTOd4tH9R9gT+cuFeSxFPWX1Pn3R+yIA1j6Y3/8lsRnXDDap9ict0dclHG+DcXLgvQvWvpaYgJr0bq7Y7SRbMxp7twX2VaU0a8GAHeAdqNg+IJovA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=BaaY+wHN; arc=none smtp.client-ip=67.231.148.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="BaaY+wHN" Received: from pps.filterd (m0431384.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 67VBBjUu536832; Mon, 31 Aug 2026 06:19:59 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=J FBHxHBtV940PYcboD9ayOq2X7pShJ/n7jkc04FZo4E=; b=BaaY+wHNg/mzhvr62 aIgebXlqu0b6T9e1QATMgXgzZlzClCvvQrKazmcuKtdbDyX70oaHih8s6L7B/f4Y xSIm7t6zj+4GZ1p/0ltceAJQNV/nyJWYZuBnH23i94v74gTcOkLuigrD6RhYll59 B+IA7bzZ5NJ40RWc5OnaTWkTThdAy2wWz2XO52lh946+NHRqBw/M6et/SfarTISk SBWukg6KjlMGhPsZwIGtg6sZJbAEpTvTd07WMI/7sVrxGH0iZQBFAm4jey0p9obC Y9OYJsvEoBrlgNQRrc/jzibTOsb4LSPRVpwYhl7JOeJTed6WFzrNf9UdB9LHHj7J 5TJeg== Received: from dc6wp-exch02.marvell.com ([4.21.29.225]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4gckp8jfbh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 31 Aug 2026 06:19:59 -0700 (PDT) Received: from DC6WP-EXCH02.marvell.com (10.76.176.209) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Mon, 31 Aug 2026 06:19:58 -0700 Received: from maili.marvell.com (10.69.176.80) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Mon, 31 Aug 2026 06:19:58 -0700 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id 71E5A3F7089; Mon, 31 Aug 2026 06:19:55 -0700 (PDT) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH v9 net-next 1/8] octeontx2-af: switch: Add AF to switch mbox and skeleton files Date: Mon, 31 Aug 2026 18:49:37 +0530 Message-ID: <20260831131944.2649362-2-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260831131944.2649362-1-rkannoth@marvell.com> References: <20260831131944.2649362-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfX1aztEmVK2tPg ySRZph8LG6SgcaQoWnfncEVFWtKhZa88GbriKnsbwBsADUq0MHf7rP+OKRC9IGf5r6tbzZzXjVY BgUzillWgv31xESXrWT9Q3Gv60teyDYozSpb/ryaW6useGX/jsz0u30/jxobH55PzXP6G0lm07n ydH1Y44mc8SZf0+hv86Geo+ZCirHzKoJ0p1tDbtwiynRQcmOb2uIBecU6jpk8rKfFbDFYuII3++ kTFlRI443C/NIXGnuairIsBzqcuGgyf5Nd65vp3lmet0razth199QSg1W4XmIMKyseo8EKxP74Y sCYYfNFOwe2w6H0Nr/YzKH8JvMLqGAMd1Qwm8poAkx3Kx2xHQkRjnYebR40W1001kH41cjRXqz0 hVBnf2CS7q2SZPR20qQRgXXfBM/6W5/lUpqcCvbGd54GA4eEswsJj/rBDd/bN0jg9pYZaM+7BMC b0HVeoMEcHNr9prgnsA== X-Proofpoint-GUID: zN2SJdwlwTLnzX7k0GdKGLFmTL1dKLvT X-Proofpoint-ORIG-GUID: zN2SJdwlwTLnzX7k0GdKGLFmTL1dKLvT X-Proofpoint-Spam-Info: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfX7LkErkutMjKQ GMQSARrGQ08A32kOcYWICQNRkdpEIHjZFUHjDKS5c3rwW+aFefzYNmmNuN7+gB6/gGJz6aQFm/j ST0JJ5VEM6zCEB/+fuoUR+8+AOtn+EE= X-Authority-Analysis: v=2.4 cv=GLk41ONK c=1 sm=1 tr=0 ts=6a957f7f cx=c_pps a=gIfcoYsirJbf48DBMSPrZA==:117 a=gIfcoYsirJbf48DBMSPrZA==:17 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=l0iWHRpgs5sLHlkKQ1IR:22 a=TtqV-g6YmW1Jfm2GSLaY:22 a=M5GUcnROAAAA:8 a=ANdAxFAa8r43KH1w-rAA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-31_04,2026-08-27_02,2025-10-01_01 Content-Type: text/plain; charset="utf-8" The Marvell switch hardware runs on a Linux OS. This OS receives various messages, which are parsed to create flow rules that can be installed on HW. The switch is capable of accelerating both L2 and L3 flows. This commit adds mailbox messages used by the Linux OS (on arm64) to send events to the switch hardware, along with skeleton handler functions: fdb messages: Linux bridge FDB messages fib messages: Linux routing table messages fl messages: Flow acceleration tuple and actions (FL_NOTIFY) fl stats: Host-initiated flow counter polling (FL_GET_STATS) fl_tuple defines the flow acceleration match tuple exchanged over the mailbox. It currently carries IPv4 five-tuple and L2 match fields only. IPv6 flow acceleration is not supported in this patch and will be added in a follow-up change extending the mailbox ABI. Signed-off-by: Ratheesh Kannoth --- .../ethernet/marvell/octeontx2/af/Makefile | 3 +- .../net/ethernet/marvell/octeontx2/af/mbox.h | 118 ++++++++++++++++++ .../marvell/octeontx2/af/switch/rvu_sw_fl.c | 21 ++++ .../marvell/octeontx2/af/switch/rvu_sw_fl.h | 11 ++ .../marvell/octeontx2/af/switch/rvu_sw_l2.c | 14 +++ .../marvell/octeontx2/af/switch/rvu_sw_l2.h | 11 ++ .../marvell/octeontx2/af/switch/rvu_sw_l3.c | 14 +++ .../marvell/octeontx2/af/switch/rvu_sw_l3.h | 11 ++ 8 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw= _fl.c create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw= _fl.h create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw= _l2.c create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw= _l2.h create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw= _l3.c create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw= _l3.h diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/n= et/ethernet/marvell/octeontx2/af/Makefile index 91b7d6e96a61..82dd387308c9 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile +++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile @@ -3,7 +3,7 @@ # Makefile for Marvell's RVU Admin Function driver # =20 -ccflags-y +=3D -I$(src) +ccflags-y +=3D -I$(src) -I$(src)/switch/ obj-$(CONFIG_OCTEONTX2_MBOX) +=3D rvu_mbox.o obj-$(CONFIG_OCTEONTX2_AF) +=3D rvu_af.o =20 @@ -12,5 +12,6 @@ rvu_af-y :=3D cgx.o rvu.o rvu_cgx.o rvu_npa.o rvu_nix.o \ rvu_reg.o rvu_npc.o rvu_debugfs.o ptp.o rvu_npc_fs.o \ rvu_cpt.o rvu_devlink.o rpm.o rvu_cn10k.o rvu_switch.o \ rvu_sdp.o rvu_npc_hash.o mcs.o mcs_rvu_if.o mcs_cnf10kb.o \ + switch/rvu_sw_l2.o switch/rvu_sw_l3.o switch/rvu_sw_fl.o\ rvu_rep.o cn20k/mbox_init.o cn20k/nix.o cn20k/debugfs.o \ cn20k/npa.o cn20k/npc.o diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index cece197d1074..854696d2a35f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -164,6 +164,14 @@ M(PTP_GET_CAP, 0x00c, ptp_get_cap, msg_req, ptp_get_c= ap_rsp) \ M(GET_REP_CNT, 0x00d, get_rep_cnt, msg_req, get_rep_cnt_rsp) \ M(ESW_CFG, 0x00e, esw_cfg, esw_cfg_req, msg_rsp) \ M(REP_EVENT_NOTIFY, 0x00f, rep_event_notify, rep_event, msg_rsp) \ +M(FDB_NOTIFY, 0x010, fdb_notify, \ + fdb_notify_req, msg_rsp) \ +M(FIB_NOTIFY, 0x011, fib_notify, \ + fib_notify_req, msg_rsp) \ +M(FL_NOTIFY, 0x012, fl_notify, \ + fl_notify_req, msg_rsp) \ +M(FL_GET_STATS, 0x013, fl_get_stats, \ + fl_get_stats_req, fl_get_stats_rsp) \ /* CGX mbox IDs (range 0x200 - 0x3FF) */ \ M(CGX_START_RXTX, 0x200, cgx_start_rxtx, msg_req, msg_rsp) \ M(CGX_STOP_RXTX, 0x201, cgx_stop_rxtx, msg_req, msg_rsp) \ @@ -1812,6 +1820,116 @@ struct rep_event { struct rep_evt_data evt_data; }; =20 +#define OTX2_FDB_ADD BIT_ULL(0) +#define OTX2_FDB_DEL BIT_ULL(1) +#define OTX2_FIB_CMD BIT_ULL(2) +#define OTX2_FL_ADD BIT_ULL(3) +#define OTX2_FL_DEL BIT_ULL(4) +#define OTX2_DP_ADD BIT_ULL(5) + +struct fdb_notify_req { + struct mbox_msghdr hdr; + u64 flags; + u8 mac[ETH_ALEN]; + u8 rsvd[2]; /* explicit tail padding */ +}; + +/* Zero-initialize before populating fields shared with switch OS. */ +struct fib_entry { + u64 cmd; + u64 gw_valid : 1; + u64 mac_valid : 1; + u64 vlan_valid: 1; + u64 host : 1; + u64 bridge : 1; + u64 ipv6 : 1; + u64 rsvd : 58; + __be16 vlan_tag; + u16 rsvd1; + u32 dst_len; + u8 dst6_plen; + u8 gw6_plen; + u8 rsvd2[2]; /* explicit padding before address unions */ + union { + __be32 dst; + __be32 dst6[4]; + }; + union { + __be32 gw; + __be32 gw6[4]; + }; + u16 port_id; + u8 nud_state; + u8 rsvd3; + u8 mac[ETH_ALEN]; + u16 rsvd4; /* explicit tail padding */ +}; + +struct fib_notify_req { + struct mbox_msghdr hdr; + u16 cnt; + u16 rsvd[3]; /* explicit padding for entry[] 8-byte alignment */ + struct fib_entry entry[16]; +}; + +struct fl_tuple { + __be32 ip4src; + __be32 m_ip4src; + __be32 ip4dst; + __be32 m_ip4dst; + __be16 sport; + __be16 m_sport; + __be16 dport; + __be16 m_dport; + __be16 eth_type; + __be16 m_eth_type; + u8 proto; + u8 rsvd_l3[3]; /* explicit padding before MAC addresses */ + u8 smac[6]; + u8 m_smac[6]; + u8 dmac[6]; + u8 m_dmac[6]; + u64 is_xdev_br : 1; + u64 is_indev_br : 1; + u64 uni_di : 1; + u64 rsvd_br : 61; + u16 in_pf; + u16 xmit_pf; + u16 rsvd; + u16 rsvd_align; /* explicit padding before u64 features */ + u64 features; + struct { /* FLOW_ACTION_MANGLE */ + u8 offset; + u8 type; + u16 rsvd; + u32 mask; + u32 val; +#define MANGLE_ARR_SZ 9 + } mangle[MANGLE_ARR_SZ]; /* 2 for ETH, 1 for VLAN, 4 for IPv6, 2 for L4. = */ +#define MANGLE_LAYER_CNT 4 + u16 mangle_map[MANGLE_LAYER_CNT]; /* 1 for ETH, 1 for VLAN, 1 for L3, 1 = for L4 */ + u8 mangle_cnt; + u8 rsvd_tail[3]; /* explicit tail padding */ +}; + +struct fl_notify_req { + struct mbox_msghdr hdr; + u64 cookie; + u64 flags; + u64 features; + struct fl_tuple tuple; +}; + +struct fl_get_stats_req { + struct mbox_msghdr hdr; + u64 cookie; +}; + +struct fl_get_stats_rsp { + struct mbox_msghdr hdr; + u64 pkts_diff; +}; + struct flow_msg { unsigned char dmac[6]; unsigned char smac[6]; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_fl.c b= /drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_fl.c new file mode 100644 index 000000000000..1f8b82a84a5d --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_fl.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU Admin Function driver + * + * Copyright (C) 2026 Marvell. + * + */ +#include "rvu.h" + +int rvu_mbox_handler_fl_get_stats(struct rvu *rvu, + struct fl_get_stats_req *req, + struct fl_get_stats_rsp *rsp) +{ + return 0; +} + +int rvu_mbox_handler_fl_notify(struct rvu *rvu, + struct fl_notify_req *req, + struct msg_rsp *rsp) +{ + return 0; +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_fl.h b= /drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_fl.h new file mode 100644 index 000000000000..cf3e5b884f77 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_fl.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell RVU Admin Function driver + * + * Copyright (C) 2026 Marvell. + * + */ + +#ifndef RVU_SW_FL_H +#define RVU_SW_FL_H + +#endif diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l2.c b= /drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l2.c new file mode 100644 index 000000000000..5f805bfa81ed --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l2.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU Admin Function driver + * + * Copyright (C) 2026 Marvell. + * + */ +#include "rvu.h" + +int rvu_mbox_handler_fdb_notify(struct rvu *rvu, + struct fdb_notify_req *req, + struct msg_rsp *rsp) +{ + return 0; +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l2.h b= /drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l2.h new file mode 100644 index 000000000000..ff28612150c9 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l2.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell RVU Admin Function driver + * + * Copyright (C) 2026 Marvell. + * + */ + +#ifndef RVU_SW_L2_H +#define RVU_SW_L2_H + +#endif diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l3.c b= /drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l3.c new file mode 100644 index 000000000000..2b798d5f0644 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l3.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU Admin Function driver + * + * Copyright (C) 2026 Marvell. + * + */ +#include "rvu.h" + +int rvu_mbox_handler_fib_notify(struct rvu *rvu, + struct fib_notify_req *req, + struct msg_rsp *rsp) +{ + return 0; +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l3.h b= /drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l3.h new file mode 100644 index 000000000000..ac8c4f9ba5ac --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l3.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell RVU Admin Function driver + * + * Copyright (C) 2026 Marvell. + * + */ + +#ifndef RVU_SW_L3_H +#define RVU_SW_L3_H + +#endif --=20 2.43.0 From nobody Sat Sep 26 18:54:41 2026 Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9BBE7415B87; Mon, 31 Aug 2026 13:20:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.156.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182416; cv=none; b=ubzklrfHjGmworaKqBtWeYf8py9WuYSLnpefpYkKu1dd0+/BkdU+Sybi7BPtShLcTMncnpXkSnpJI/cu5e1xtMifQnxd+T8hTuKcPe8Cp9wIDRX2XASJh1ZnaShSC5Gvx3zULJV7nYTD8MQgbOMt7cnX4mW1xPv1Q0sTFw80BLg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182416; c=relaxed/simple; bh=hlYzzGZO/NTYkD9X/Ax0k0O6EWu65CIMHZ5VpYVrw7s=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=YLV4/RWL6VWYhcm2WeN0ReqKx5K1OnBZZl2GtoXbggm+fPtjH4Pad074TMhAXD4XTI7gkA1nMnODO+KxdKJ2/+Vda3w2UoTnQVWfzIpwa254KG2VSdCNrwvjB2w0577tI/Z4YY01CpQzj+Tr/tETyEn0a+3Q8l/OuDeSB0jh5Vc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=LKrpVkRP; arc=none smtp.client-ip=67.231.156.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="LKrpVkRP" Received: from pps.filterd (m0431383.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 67VBCJVV668841; Mon, 31 Aug 2026 06:20:03 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=t zRYTIHveMTD0P68e+v1jNuer9WdKypPtNyUnZ+2Rc8=; b=LKrpVkRPYGGQtGPlR VtIQtFITWuoO1N6iagLOgzA9nj/823eJACLcNPrMZl6LJwVxEolvfSculbJ4LDPv 2qIbOIUfSPUFHhFtY/ByFhOhG9h9JVWoVMs0ZjBCDRpJVqI1/t8qPAvOtnnQ/xja kdfZ5iKB6bKFehy519bS/3Ppw9L6s6Q/ET1LiTE/cgua13pp6ndIKW7tReNfrdBF Mg8VczuuO/kvf4aHGAXeNfj19Z3Y/hlzrqDIybEq8kjJfc8WSTlwMLy7tZ1AZoIv X3A6PzI+UtfHEMoSIBDou45xE6eJx//1qPLGI9O/E1fgERQWvjf7AONeLSxoo+iI NQHKQ== Received: from dc6wp-exch02.marvell.com ([4.21.29.225]) by mx0b-0016f401.pphosted.com (PPS) with ESMTPS id 4gcg68jmrd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 31 Aug 2026 06:20:02 -0700 (PDT) Received: from DC6WP-EXCH02.marvell.com (10.76.176.209) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Mon, 31 Aug 2026 06:20:01 -0700 Received: from maili.marvell.com (10.69.176.80) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Mon, 31 Aug 2026 06:20:01 -0700 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id AABB03F7089; Mon, 31 Aug 2026 06:19:58 -0700 (PDT) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH v9 net-next 2/8] octeontx2-af: switch: Add switch dev to AF mboxes Date: Mon, 31 Aug 2026 18:49:38 +0530 Message-ID: <20260831131944.2649362-3-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260831131944.2649362-1-rkannoth@marvell.com> References: <20260831131944.2649362-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: zmQ37Cz2HOQ93rhwHfIPlQ4MiczOm-Vn X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfXzDy9ymdLYzjk 8XS2ixbhX5w4CM+OLP7DR08qmIkL70hDpcTbdOZUgUEbuT0B5a0TVFf20E9Anqn3Ll3Soogvhxd qCGvws7PAKiaiXTm50jQrXer8qfxaTElYNUA2zch5lkIvfXFjtFBZY0H7w5tDnFqIP40L8c4TFl OLIhu48h2X7fvarV29SKzNTglNheVQnQUqsXnTSfCX63qdx+aJ0vNxF1FbE1A5grq/LM7S+FJBE 4pCzjVzgPdr5rmKzkdSHz7SsIF+mm8l121nZhngfl0MEL1GBUQEytO/nlJCrms0qKcMv3Fct9kS g7pP+/Jn9323YZIAJyfTIQ/5aFwZjDb4Uxx6NgBsTDpIUlYUYx1Uu8Ybvt6BqVU2b6uQQy9vjGq LMByGZzm912+qBvtH5n37qpQLRYGWFlw1pgMeZHvaHWyAl9Q/GcPfkInNC5lSWKwCGPAXP14r9M Sc2KNvtAndnVHVsrnQQ== X-Authority-Analysis: v=2.4 cv=fZedDUQF c=1 sm=1 tr=0 ts=6a957f82 cx=c_pps a=gIfcoYsirJbf48DBMSPrZA==:117 a=gIfcoYsirJbf48DBMSPrZA==:17 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=l0iWHRpgs5sLHlkKQ1IR:22 a=qit2iCtTFQkLgVSMPQTB:22 a=M5GUcnROAAAA:8 a=EnXvBBgweBAqh9HqLEcA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-GUID: zmQ37Cz2HOQ93rhwHfIPlQ4MiczOm-Vn X-Proofpoint-Spam-Info: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfX7NE1IrlivMyG fapswdpFUNuDhc5SHYIYMYLBnVF2MSmsINpOla0ByZVyycbQfBZ2h3ti67ZDu5ft31vf+/jlFiz wDMvZ8P8MqAuBrrJZozXURGXBfOaK18= X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-31_04,2026-08-27_02,2025-10-01_01 Content-Type: text/plain; charset="utf-8" The Marvell switch hardware runs on a Linux OS. Switch needs various information from AF driver. These mboxes are defined to query those from AF driver. Signed-off-by: Ratheesh Kannoth --- .../ethernet/marvell/octeontx2/af/Makefile | 2 +- .../net/ethernet/marvell/octeontx2/af/mbox.h | 130 +++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/rvu.c | 134 +++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 1 + .../ethernet/marvell/octeontx2/af/rvu_nix.c | 137 +++++++++++++----- .../ethernet/marvell/octeontx2/af/rvu_npc.c | 115 +++++++++++++++ .../marvell/octeontx2/af/rvu_npc_fs.c | 11 ++ .../marvell/octeontx2/af/switch/rvu_sw.c | 15 ++ .../marvell/octeontx2/af/switch/rvu_sw.h | 11 ++ 9 files changed, 518 insertions(+), 38 deletions(-) create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw= .c create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw= .h diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/n= et/ethernet/marvell/octeontx2/af/Makefile index 82dd387308c9..73f20a44f1a0 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile +++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile @@ -12,6 +12,6 @@ rvu_af-y :=3D cgx.o rvu.o rvu_cgx.o rvu_npa.o rvu_nix.o \ rvu_reg.o rvu_npc.o rvu_debugfs.o ptp.o rvu_npc_fs.o \ rvu_cpt.o rvu_devlink.o rpm.o rvu_cn10k.o rvu_switch.o \ rvu_sdp.o rvu_npc_hash.o mcs.o mcs_rvu_if.o mcs_cnf10kb.o \ - switch/rvu_sw_l2.o switch/rvu_sw_l3.o switch/rvu_sw_fl.o\ + switch/rvu_sw.o switch/rvu_sw_l2.o switch/rvu_sw_l3.o switch/rvu_sw_fl= .o \ rvu_rep.o cn20k/mbox_init.o cn20k/nix.o cn20k/debugfs.o \ cn20k/npa.o cn20k/npc.o diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index 854696d2a35f..e45e6e93ed08 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -172,6 +172,10 @@ M(FL_NOTIFY, 0x012, fl_notify, \ fl_notify_req, msg_rsp) \ M(FL_GET_STATS, 0x013, fl_get_stats, \ fl_get_stats_req, fl_get_stats_rsp) \ +M(IFACE_GET_INFO, 0x014, iface_get_info, msg_req, \ + iface_get_info_rsp) \ +M(SWDEV2AF_NOTIFY, 0x015, swdev2af_notify, \ + swdev2af_notify_req, msg_rsp) \ /* CGX mbox IDs (range 0x200 - 0x3FF) */ \ M(CGX_START_RXTX, 0x200, cgx_start_rxtx, msg_req, msg_rsp) \ M(CGX_STOP_RXTX, 0x201, cgx_stop_rxtx, msg_req, msg_rsp) \ @@ -317,8 +321,16 @@ M(NPC_MCAM_GET_DFT_RL_IDXS, 0x601e, npc_get_dft_rl_idx= s, \ M(NPC_MCAM_GET_NPC_PFL_INFO, 0x601f, npc_get_pfl_info, \ msg_req, \ npc_get_pfl_info_rsp) \ +M(NPC_MCAM_FLOW_DEL_N_FREE, 0x6020, npc_flow_del_n_free, \ + npc_flow_del_n_free_req, msg_rsp) \ M(NPC_MCAM_READ_DEFAULT_RULE, 0x6021, npc_read_default_rule, msg_req, \ npc_mcam_read_base_rule_rsp) \ +M(NPC_MCAM_GET_MUL_STATS, 0x6022, npc_mcam_mul_stats, \ + npc_mcam_get_mul_stats_req, \ + npc_mcam_get_mul_stats_rsp) \ +M(NPC_MCAM_GET_FEATURES, 0x6023, npc_mcam_get_features, \ + msg_req, \ + npc_mcam_get_features_rsp) \ /* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \ M(NIX_LF_ALLOC, 0x8000, nix_lf_alloc, \ nix_lf_alloc_req, nix_lf_alloc_rsp) \ @@ -449,6 +461,12 @@ M(MCS_INTR_NOTIFY, 0xE00, mcs_intr_notify, mcs_intr_in= fo, msg_rsp) #define MBOX_UP_REP_MESSAGES \ M(REP_EVENT_UP_NOTIFY, 0xEF0, rep_event_up_notify, rep_event, msg_rsp) \ =20 +#define MBOX_UP_AF2SWDEV_MESSAGES \ +M(AF2SWDEV, 0xEF1, af2swdev_notify, af2swdev_notify_req, msg_rsp) + +#define MBOX_UP_AF2PF_FDB_REFRESH_MESSAGES \ +M(AF2PF_FDB_REFRESH, 0xEF2, af2pf_fdb_refresh, af2pf_fdb_refresh_req, msg= _rsp) + enum { #define M(_name, _id, _1, _2, _3) MBOX_MSG_ ## _name =3D _id, MBOX_MESSAGES @@ -456,6 +474,8 @@ MBOX_UP_CGX_MESSAGES MBOX_UP_CPT_MESSAGES MBOX_UP_MCS_MESSAGES MBOX_UP_REP_MESSAGES +MBOX_UP_AF2SWDEV_MESSAGES +MBOX_UP_AF2PF_FDB_REFRESH_MESSAGES #undef M }; =20 @@ -1594,6 +1614,31 @@ struct npc_mcam_alloc_entry_rsp { u16 entry_list[NPC_MAX_NONCONTIG_ENTRIES]; }; =20 +struct npc_flow_del_n_free_req { + struct mbox_msghdr hdr; + u16 cnt; + u16 entry[256]; /* Entry index to be freed */ +}; + +struct npc_mcam_get_features_rsp { + struct mbox_msghdr hdr; + u64 rx_features; + u64 tx_features; +}; + +struct npc_mcam_get_mul_stats_req { + struct mbox_msghdr hdr; + u16 cnt; + u16 entry[256]; /* mcam entry */ +}; + +struct npc_mcam_get_mul_stats_rsp { + struct mbox_msghdr hdr; + u16 cnt; + u16 rsvd[3]; /* explicit padding for stat[] 8-byte alignment */ + u64 stat[256]; /* counter stats */ +}; + struct npc_mcam_free_entry_req { struct mbox_msghdr hdr; u16 entry; /* Entry index to be freed */ @@ -1930,6 +1975,91 @@ struct fl_get_stats_rsp { u64 pkts_diff; }; =20 +struct af2swdev_notify_req { + struct mbox_msghdr hdr; + u64 flags; + u32 port_id; + u32 switch_id; + union { + struct { + u8 mac[6]; + u8 rsvd_mac[2]; /* explicit padding to 8 bytes */ + }; + struct { + u8 cnt; + u8 rsvd[7]; /* explicit padding before fib_entry[] */ + struct fib_entry entry[12]; + }; + + struct { + u64 cookie; + u64 features; + struct fl_tuple tuple; + }; + }; +}; + +struct af2pf_fdb_refresh_req { + struct mbox_msghdr hdr; + u16 pcifunc; + u8 mac[6]; +}; + +struct iface_info { + u8 is_vf : 1; + u8 is_sdp : 1; + u8 rsvd : 6; + u16 pcifunc; + u16 rx_chan_base; + u16 tx_chan_base; + u16 sq_cnt; + u16 cq_cnt; + u16 rq_cnt; + u8 rx_chan_cnt; + u8 tx_chan_cnt; + u8 tx_link; + u8 nix; +}; + +/* Max supported */ +#define IFACE_MAX (256 + 32) /* 32 PFs + 256 VFs */ + +struct iface_get_info_rsp { + struct mbox_msghdr hdr; + u16 cnt; + u8 truncated; + u8 rsvd[5]; + struct iface_info info[IFACE_MAX]; +}; + +struct fl_info { + u64 cookie; + u16 mcam_idx[2]; + u8 dis : 1; + u8 uni_di : 1; +}; + +struct swdev2af_notify_req { + struct mbox_msghdr hdr; + u64 msg_type; +#define SWDEV2AF_MSG_TYPE_FW_STATUS BIT_ULL(0) +#define SWDEV2AF_MSG_TYPE_REFRESH_FDB BIT_ULL(1) +#define SWDEV2AF_MSG_TYPE_REFRESH_FL BIT_ULL(2) + u16 pcifunc; + u16 rsvd1[3]; /* explicit padding before union for 8-byte alignment */ + union { + bool fw_up; // FW_STATUS message + + u8 mac[ETH_ALEN]; // fdb refresh message + + struct { // fl refresh message + u8 cnt; + u8 rsvd2[7]; + struct fl_info fl[64]; + }; + }; +}; + struct flow_msg { unsigned char dmac[6]; unsigned char smac[6]; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/= ethernet/marvell/octeontx2/af/rvu.c index 74c041ab5280..1402beccf661 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -1990,6 +1990,140 @@ int rvu_mbox_handler_msix_offset(struct rvu *rvu, s= truct msg_req *req, return 0; } =20 +static void rvu_iface_get_qcnts(struct rvu *rvu, struct rvu_pfvf *pfvf, + struct iface_info *info) +{ + struct admin_queue *aq; + unsigned long flags; + + info->sq_cnt =3D 0; + info->cq_cnt =3D 0; + info->rq_cnt =3D 0; + + aq =3D rvu->hw->block[pfvf->nix_blkaddr].aq; + if (!aq) + return; + + spin_lock_irqsave(&aq->lock, flags); + + /* Use each LF queue context size; bitmaps are sized to qsize longs. */ + if (pfvf->sq_ctx && pfvf->sq_bmap) + info->sq_cnt =3D bitmap_weight(pfvf->sq_bmap, pfvf->sq_ctx->qsize); + if (pfvf->cq_ctx && pfvf->cq_bmap) + info->cq_cnt =3D bitmap_weight(pfvf->cq_bmap, pfvf->cq_ctx->qsize); + if (pfvf->rq_ctx && pfvf->rq_bmap) + info->rq_cnt =3D bitmap_weight(pfvf->rq_bmap, pfvf->rq_ctx->qsize); + + spin_unlock_irqrestore(&aq->lock, flags); +} + +int rvu_mbox_handler_iface_get_info(struct rvu *rvu, struct msg_req *req, + struct iface_get_info_rsp *rsp) +{ + struct iface_info *info; + bool truncated =3D false; + struct rvu_pfvf *pfvf; + int pf, vf, numvfs; + int tot =3D 0; + u16 pcifunc; + u64 cfg; + + /* Read-only topology snapshot for switch software; any PF/VF may + * request it. Only channel and queue counts already visible to the + * requester through AF are reported. + */ + rsp->cnt =3D 0; + rsp->truncated =3D 0; + memset(rsp->rsvd, 0, sizeof(rsp->rsvd)); + /* Preserve mbox_msghdr fields pre-filled by the mbox framework. */ + memset(rsp->info, 0, sizeof(rsp->info)); + info =3D rsp->info; + for (pf =3D 0; pf < rvu->hw->total_pfs; pf++) { + if (tot >=3D IFACE_MAX) { + truncated =3D true; + goto done; + } + + cfg =3D rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf)); + numvfs =3D (cfg >> 12) & 0xFF; + + /* Skip not enabled PFs */ + if (!(cfg & BIT_ULL(20))) + goto chk_vfs; + + /* If Admin function, check on VFs */ + if (cfg & BIT_ULL(21)) + goto chk_vfs; + + pcifunc =3D rvu_make_pcifunc(rvu->pdev, pf, 0); + pfvf =3D rvu_get_pfvf(rvu, pcifunc); + + /* Populate iff at least one Tx channel */ + if (!pfvf->tx_chan_cnt) + goto chk_vfs; + + info->is_vf =3D 0; + info->pcifunc =3D pcifunc; + info->rx_chan_base =3D pfvf->rx_chan_base; + info->rx_chan_cnt =3D pfvf->rx_chan_cnt; + info->tx_chan_base =3D pfvf->tx_chan_base; + info->tx_chan_cnt =3D pfvf->tx_chan_cnt; + info->tx_link =3D nix_get_tx_link(rvu, pcifunc); + if (is_sdp_pfvf(rvu, pcifunc)) + info->is_sdp =3D 1; + + rvu_iface_get_qcnts(rvu, pfvf, info); + + if (pfvf->nix_blkaddr =3D=3D BLKADDR_NIX0) + info->nix =3D 0; + else + info->nix =3D 1; + + info++; + tot++; + +chk_vfs: + for (vf =3D 0; vf < numvfs; vf++) { + if (tot >=3D IFACE_MAX) { + truncated =3D true; + goto done; + } + + pcifunc =3D rvu_make_pcifunc(rvu->pdev, pf, vf + 1); + pfvf =3D rvu_get_pfvf(rvu, pcifunc); + + if (!pfvf->tx_chan_cnt) + continue; + + info->is_vf =3D 1; + info->pcifunc =3D pcifunc; + info->rx_chan_base =3D pfvf->rx_chan_base; + info->rx_chan_cnt =3D pfvf->rx_chan_cnt; + info->tx_chan_base =3D pfvf->tx_chan_base; + info->tx_chan_cnt =3D pfvf->tx_chan_cnt; + info->tx_link =3D nix_get_tx_link(rvu, pcifunc); + if (is_sdp_pfvf(rvu, pcifunc)) + info->is_sdp =3D 1; + + rvu_iface_get_qcnts(rvu, pfvf, info); + + if (pfvf->nix_blkaddr =3D=3D BLKADDR_NIX0) + info->nix =3D 0; + else + info->nix =3D 1; + + info++; + + tot++; + } + } +done: + rsp->cnt =3D tot; + rsp->truncated =3D truncated; + + return 0; +} + int rvu_mbox_handler_free_rsrc_cnt(struct rvu *rvu, struct msg_req *req, struct free_rsrcs_rsp *rsp) { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/= ethernet/marvell/octeontx2/af/rvu.h index 094227404ef9..2876c76ae61b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -1160,6 +1160,7 @@ void rvu_program_channels(struct rvu *rvu); =20 /* CN10K NIX */ void rvu_nix_block_cn10k_init(struct rvu *rvu, struct nix_hw *nix_hw); +int nix_get_tx_link(struct rvu *rvu, u16 pcifunc); =20 /* CN10K RVU - LMT*/ void rvu_reset_lmt_map_tbl(struct rvu *rvu, u16 pcifunc); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_nix.c index 153eb57bad06..b8f4ad160afc 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -32,7 +32,6 @@ static int nix_free_all_bandprof(struct rvu *rvu, u16 pci= func); static void nix_clear_ratelimit_aggr(struct rvu *rvu, struct nix_hw *nix_h= w, u32 leaf_prof); static const char *nix_get_ctx_name(int ctype); -static int nix_get_tx_link(struct rvu *rvu, u16 pcifunc); =20 enum mc_tbl_sz { MC_TBL_SZ_256, @@ -912,33 +911,78 @@ static void nix_setup_lso(struct rvu *rvu, struct nix= _hw *nix_hw, int blkaddr) nix_hw->lso.in_use++; } =20 +static void nix_qctx_assign(struct rvu *rvu, int blkaddr, struct qmem **ct= x, + unsigned long **bmap, struct qmem *new_ctx, + unsigned long *new_bmap) +{ + struct admin_queue *aq =3D rvu->hw->block[blkaddr].aq; + unsigned long flags; + + if (!aq) + return; + + spin_lock_irqsave(&aq->lock, flags); + *ctx =3D new_ctx; + *bmap =3D new_bmap; + spin_unlock_irqrestore(&aq->lock, flags); +} + +static void nix_ctx_assign(struct rvu *rvu, struct qmem **ctx, + struct qmem *new_ctx) +{ + mutex_lock(&rvu->rsrc_lock); + *ctx =3D new_ctx; + mutex_unlock(&rvu->rsrc_lock); +} + static void nix_ctx_free(struct rvu *rvu, struct rvu_pfvf *pfvf) { - kfree(pfvf->rq_bmap); - kfree(pfvf->sq_bmap); - kfree(pfvf->cq_bmap); - if (pfvf->rq_ctx) - qmem_free(rvu->dev, pfvf->rq_ctx); - if (pfvf->sq_ctx) - qmem_free(rvu->dev, pfvf->sq_ctx); - if (pfvf->cq_ctx) - qmem_free(rvu->dev, pfvf->cq_ctx); - if (pfvf->rss_ctx) - qmem_free(rvu->dev, pfvf->rss_ctx); - if (pfvf->nix_qints_ctx) - qmem_free(rvu->dev, pfvf->nix_qints_ctx); - if (pfvf->cq_ints_ctx) - qmem_free(rvu->dev, pfvf->cq_ints_ctx); + struct admin_queue *aq =3D rvu->hw->block[pfvf->nix_blkaddr].aq; + unsigned long *rq_bmap, *sq_bmap, *cq_bmap; + struct qmem *rq_ctx, *sq_ctx, *cq_ctx; + struct qmem *rss_ctx, *nix_qints_ctx, *cq_ints_ctx; + unsigned long flags; + + if (!aq) + return; + + spin_lock_irqsave(&aq->lock, flags); + rq_bmap =3D pfvf->rq_bmap; + sq_bmap =3D pfvf->sq_bmap; + cq_bmap =3D pfvf->cq_bmap; + rq_ctx =3D pfvf->rq_ctx; + sq_ctx =3D pfvf->sq_ctx; + cq_ctx =3D pfvf->cq_ctx; + rss_ctx =3D pfvf->rss_ctx; + nix_qints_ctx =3D pfvf->nix_qints_ctx; + cq_ints_ctx =3D pfvf->cq_ints_ctx; =20 pfvf->rq_bmap =3D NULL; - pfvf->cq_bmap =3D NULL; pfvf->sq_bmap =3D NULL; + pfvf->cq_bmap =3D NULL; pfvf->rq_ctx =3D NULL; pfvf->sq_ctx =3D NULL; pfvf->cq_ctx =3D NULL; pfvf->rss_ctx =3D NULL; pfvf->nix_qints_ctx =3D NULL; pfvf->cq_ints_ctx =3D NULL; + spin_unlock_irqrestore(&aq->lock, flags); + + kfree(rq_bmap); + kfree(sq_bmap); + kfree(cq_bmap); + if (rq_ctx) + qmem_free(rvu->dev, rq_ctx); + if (sq_ctx) + qmem_free(rvu->dev, sq_ctx); + if (cq_ctx) + qmem_free(rvu->dev, cq_ctx); + if (rss_ctx) + qmem_free(rvu->dev, rss_ctx); + if (nix_qints_ctx) + qmem_free(rvu->dev, nix_qints_ctx); + if (cq_ints_ctx) + qmem_free(rvu->dev, cq_ints_ctx); } =20 static int nixlf_rss_ctx_init(struct rvu *rvu, int blkaddr, @@ -946,6 +990,7 @@ static int nixlf_rss_ctx_init(struct rvu *rvu, int blka= ddr, int rss_sz, int rss_grps, int hwctx_size, u64 way_mask, bool tag_lsb_as_adder) { + struct qmem *rss_ctx; int err, grp, num_indices; u64 val; =20 @@ -955,12 +1000,12 @@ static int nixlf_rss_ctx_init(struct rvu *rvu, int b= lkaddr, num_indices =3D rss_sz * rss_grps; =20 /* Alloc NIX RSS HW context memory and config the base */ - err =3D qmem_alloc(rvu->dev, &pfvf->rss_ctx, num_indices, hwctx_size); + err =3D qmem_alloc(rvu->dev, &rss_ctx, num_indices, hwctx_size); if (err) return err; =20 rvu_write64(rvu, blkaddr, NIX_AF_LFX_RSS_BASE(nixlf), - (u64)pfvf->rss_ctx->iova); + (u64)rss_ctx->iova); =20 /* Config full RSS table size, enable RSS and caching */ val =3D BIT_ULL(36) | BIT_ULL(4) | way_mask << 20 | @@ -974,6 +1019,8 @@ static int nixlf_rss_ctx_init(struct rvu *rvu, int blk= addr, for (grp =3D 0; grp < rss_grps; grp++) rvu_write64(rvu, blkaddr, NIX_AF_LFX_RSS_GRPX(nixlf, grp), ((ilog2(rss_sz) - 1) << 16) | (rss_sz * grp)); + + nix_ctx_assign(rvu, &pfvf->rss_ctx, rss_ctx); return 0; } =20 @@ -1514,6 +1561,9 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu, struct nix_lf_alloc_rsp *rsp) { int nixlf, qints, hwctx_size, intf, rc =3D 0, pf; + unsigned long *rq_bmap, *sq_bmap, *cq_bmap; + struct qmem *cq_ints_ctx, *nix_qints_ctx; + struct qmem *rq_ctx, *sq_ctx, *cq_ctx; u16 bcast, mcast, promisc, ucast; struct rvu_hwinfo *hw =3D rvu->hw; u16 pcifunc =3D req->hdr.pcifunc; @@ -1584,59 +1634,68 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu, =20 /* Alloc NIX RQ HW context memory and config the base */ hwctx_size =3D 1UL << ((ctx_cfg >> 4) & 0xF); - rc =3D qmem_alloc(rvu->dev, &pfvf->rq_ctx, req->rq_cnt, hwctx_size); + rc =3D qmem_alloc(rvu->dev, &rq_ctx, req->rq_cnt, hwctx_size); if (rc) goto free_mem; =20 - pfvf->rq_bmap =3D kcalloc(req->rq_cnt, sizeof(long), GFP_KERNEL); - if (!pfvf->rq_bmap) { + rq_bmap =3D kcalloc(req->rq_cnt, sizeof(long), GFP_KERNEL); + if (!rq_bmap) { + qmem_free(rvu->dev, rq_ctx); rc =3D -ENOMEM; goto free_mem; } =20 rvu_write64(rvu, blkaddr, NIX_AF_LFX_RQS_BASE(nixlf), - (u64)pfvf->rq_ctx->iova); + (u64)rq_ctx->iova); =20 /* Set caching and queue count in HW */ cfg =3D BIT_ULL(36) | (req->rq_cnt - 1) | req->way_mask << 20; rvu_write64(rvu, blkaddr, NIX_AF_LFX_RQS_CFG(nixlf), cfg); =20 + nix_qctx_assign(rvu, blkaddr, &pfvf->rq_ctx, &pfvf->rq_bmap, rq_ctx, rq_b= map); + /* Alloc NIX SQ HW context memory and config the base */ hwctx_size =3D 1UL << (ctx_cfg & 0xF); - rc =3D qmem_alloc(rvu->dev, &pfvf->sq_ctx, req->sq_cnt, hwctx_size); + rc =3D qmem_alloc(rvu->dev, &sq_ctx, req->sq_cnt, hwctx_size); if (rc) goto free_mem; =20 - pfvf->sq_bmap =3D kcalloc(req->sq_cnt, sizeof(long), GFP_KERNEL); - if (!pfvf->sq_bmap) { + sq_bmap =3D kcalloc(req->sq_cnt, sizeof(long), GFP_KERNEL); + if (!sq_bmap) { + qmem_free(rvu->dev, sq_ctx); rc =3D -ENOMEM; goto free_mem; } =20 rvu_write64(rvu, blkaddr, NIX_AF_LFX_SQS_BASE(nixlf), - (u64)pfvf->sq_ctx->iova); + (u64)sq_ctx->iova); =20 cfg =3D BIT_ULL(36) | (req->sq_cnt - 1) | req->way_mask << 20; rvu_write64(rvu, blkaddr, NIX_AF_LFX_SQS_CFG(nixlf), cfg); =20 + nix_qctx_assign(rvu, blkaddr, &pfvf->sq_ctx, &pfvf->sq_bmap, sq_ctx, sq_b= map); + /* Alloc NIX CQ HW context memory and config the base */ hwctx_size =3D 1UL << ((ctx_cfg >> 8) & 0xF); - rc =3D qmem_alloc(rvu->dev, &pfvf->cq_ctx, req->cq_cnt, hwctx_size); + rc =3D qmem_alloc(rvu->dev, &cq_ctx, req->cq_cnt, hwctx_size); if (rc) goto free_mem; =20 - pfvf->cq_bmap =3D kcalloc(req->cq_cnt, sizeof(long), GFP_KERNEL); - if (!pfvf->cq_bmap) { + cq_bmap =3D kcalloc(req->cq_cnt, sizeof(long), GFP_KERNEL); + if (!cq_bmap) { + qmem_free(rvu->dev, cq_ctx); rc =3D -ENOMEM; goto free_mem; } =20 rvu_write64(rvu, blkaddr, NIX_AF_LFX_CQS_BASE(nixlf), - (u64)pfvf->cq_ctx->iova); + (u64)cq_ctx->iova); =20 cfg =3D BIT_ULL(36) | (req->cq_cnt - 1) | req->way_mask << 20; rvu_write64(rvu, blkaddr, NIX_AF_LFX_CQS_CFG(nixlf), cfg); =20 + nix_qctx_assign(rvu, blkaddr, &pfvf->cq_ctx, &pfvf->cq_bmap, cq_ctx, cq_b= map); + /* Initialize receive side scaling (RSS) */ hwctx_size =3D 1UL << ((ctx_cfg >> 12) & 0xF); rc =3D nixlf_rss_ctx_init(rvu, blkaddr, pfvf, nixlf, req->rss_sz, @@ -1649,29 +1708,33 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu, cfg =3D rvu_read64(rvu, blkaddr, NIX_AF_CONST2); qints =3D (cfg >> 24) & 0xFFF; hwctx_size =3D 1UL << ((ctx_cfg >> 24) & 0xF); - rc =3D qmem_alloc(rvu->dev, &pfvf->cq_ints_ctx, qints, hwctx_size); + rc =3D qmem_alloc(rvu->dev, &cq_ints_ctx, qints, hwctx_size); if (rc) goto free_mem; =20 rvu_write64(rvu, blkaddr, NIX_AF_LFX_CINTS_BASE(nixlf), - (u64)pfvf->cq_ints_ctx->iova); + (u64)cq_ints_ctx->iova); =20 rvu_write64(rvu, blkaddr, NIX_AF_LFX_CINTS_CFG(nixlf), BIT_ULL(36) | req->way_mask << 20); =20 + nix_ctx_assign(rvu, &pfvf->cq_ints_ctx, cq_ints_ctx); + /* Alloc memory for QINT's HW contexts */ cfg =3D rvu_read64(rvu, blkaddr, NIX_AF_CONST2); qints =3D (cfg >> 12) & 0xFFF; hwctx_size =3D 1UL << ((ctx_cfg >> 20) & 0xF); - rc =3D qmem_alloc(rvu->dev, &pfvf->nix_qints_ctx, qints, hwctx_size); + rc =3D qmem_alloc(rvu->dev, &nix_qints_ctx, qints, hwctx_size); if (rc) goto free_mem; =20 rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_BASE(nixlf), - (u64)pfvf->nix_qints_ctx->iova); + (u64)nix_qints_ctx->iova); rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_CFG(nixlf), BIT_ULL(36) | req->way_mask << 20); =20 + nix_ctx_assign(rvu, &pfvf->nix_qints_ctx, nix_qints_ctx); + /* Setup VLANX TPID's. * Use VLAN1 for 802.1Q * and VLAN0 for 802.1AD. @@ -2109,10 +2172,10 @@ static void nix_clear_tx_xoff(struct rvu *rvu, int = blkaddr, rvu_write64(rvu, blkaddr, reg, 0x0); } =20 -static int nix_get_tx_link(struct rvu *rvu, u16 pcifunc) +int nix_get_tx_link(struct rvu *rvu, u16 pcifunc) { - struct rvu_hwinfo *hw =3D rvu->hw; int pf =3D rvu_get_pf(rvu->pdev, pcifunc); + struct rvu_hwinfo *hw =3D rvu->hw; u8 cgx_id =3D 0, lmac_id =3D 0; =20 if (is_lbk_vf(rvu, pcifunc)) {/* LBK links */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_npc.c index 60922944675b..c115601b1212 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -3545,6 +3545,46 @@ int rvu_mbox_handler_npc_mcam_free_entry(struct rvu = *rvu, return rc; } =20 +int rvu_mbox_handler_npc_flow_del_n_free(struct rvu *rvu, + struct npc_flow_del_n_free_req *mreq, + struct msg_rsp *rsp) +{ + struct npc_mcam_free_entry_req sreq =3D { 0 }; + struct npc_delete_flow_req dreq =3D { 0 }; + struct npc_delete_flow_rsp drsp =3D { 0 }; + u16 entry[256]; + int ret =3D 0, i; + bool err =3D false; + u16 cnt; + + sreq.hdr.pcifunc =3D mreq->hdr.pcifunc; + dreq.hdr.pcifunc =3D mreq->hdr.pcifunc; + + cnt =3D mreq->cnt; + if (!cnt || cnt > 256) { + dev_err_ratelimited(rvu->dev, "Invalid cnt=3D%u\n", cnt); + return -EINVAL; + } + + /* Snapshot shared mailbox memory before processing the request. */ + memcpy(entry, mreq->entry, cnt * sizeof(entry[0])); + + for (i =3D 0; i < cnt; i++) { + dreq.entry =3D entry[i]; + rvu_mbox_handler_npc_delete_flow(rvu, &dreq, &drsp); + + sreq.entry =3D entry[i]; + ret =3D rvu_mbox_handler_npc_mcam_free_entry(rvu, &sreq, rsp); + if (ret) { + dev_err(rvu->dev, "free entry error for i=3D%d entry=3D%d\n", + i, entry[i]); + err =3D true; + } + } + + return err ? -EINVAL : 0; +} + int rvu_mbox_handler_npc_mcam_read_entry(struct rvu *rvu, struct npc_mcam_read_entry_req *req, struct npc_mcam_read_entry_rsp *rsp) @@ -4444,6 +4484,81 @@ int rvu_mbox_handler_npc_mcam_entry_stats(struct rvu= *rvu, return 0; } =20 +int rvu_mbox_handler_npc_mcam_mul_stats(struct rvu *rvu, + struct npc_mcam_get_mul_stats_req *req, + struct npc_mcam_get_mul_stats_rsp *rsp) +{ + struct npc_mcam *mcam =3D &rvu->hw->mcam; + u16 req_cnt, index, cntr, mcam_entry; + u16 pcifunc =3D req->hdr.pcifunc; + int blkaddr, cnt =3D 0, i; + u16 entry[256]; + u64 regval; + u32 bank; + + rsp->cnt =3D 0; + memset(rsp->rsvd, 0, sizeof(rsp->rsvd)); + memset(rsp->stat, 0, sizeof(rsp->stat)); + + req_cnt =3D req->cnt; + if (!req_cnt || req_cnt > 256) { + dev_err_ratelimited(rvu->dev, "%s invalid request cnt=3D%u\n", + __func__, req_cnt); + return -EINVAL; + } + + /* Snapshot shared mailbox memory before processing the request. */ + memcpy(entry, req->entry, req_cnt * sizeof(entry[0])); + + blkaddr =3D rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (blkaddr < 0) + return NPC_MCAM_INVALID_REQ; + + mutex_lock(&mcam->lock); + + for (i =3D 0; i < req_cnt; i++) { + mcam_entry =3D npc_cn20k_vidx2idx(entry[i]); + + if (npc_mcam_verify_entry(mcam, pcifunc, mcam_entry)) { + mutex_unlock(&mcam->lock); + dev_err(rvu->dev, "%s invalid mcam index=3D%d\n", + __func__, entry[i]); + return -EINVAL; + } + + index =3D mcam_entry & (mcam->banksize - 1); + bank =3D npc_get_bank(mcam, mcam_entry); + + if (is_cn20k(rvu->pdev)) { + regval =3D rvu_read64(rvu, blkaddr, + NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(index, + bank)); + rsp->stat[cnt] =3D regval; + cnt++; + continue; + } + + /* read MCAM entry STAT_ACT register */ + regval =3D rvu_read64(rvu, blkaddr, NPC_AF_MCAMEX_BANKX_STAT_ACT(index, = bank)); + + if (!(regval & rvu->hw->npc_stat_ena)) { + rsp->stat[cnt] =3D 0; + cnt++; + continue; + } + + cntr =3D regval & 0x1FF; + + rsp->stat[cnt] =3D rvu_read64(rvu, blkaddr, NPC_AF_MATCH_STATX(cntr)); + rsp->stat[cnt] &=3D BIT_ULL(48) - 1; + cnt++; + } + + rsp->cnt =3D cnt; + mutex_unlock(&mcam->lock); + return 0; +} + void rvu_npc_clear_ucast_entry(struct rvu *rvu, int pcifunc, int nixlf) { struct npc_mcam *mcam =3D &rvu->hw->mcam; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drive= rs/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c index d422bdd5e8f8..e36c68ee5d84 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -1931,6 +1931,17 @@ static int npc_delete_flow(struct rvu *rvu, struct r= vu_npc_mcam_rule *rule, return rvu_mbox_handler_npc_mcam_dis_entry(rvu, &dis_req, &dis_rsp); } =20 +int rvu_mbox_handler_npc_mcam_get_features(struct rvu *rvu, + struct msg_req *req, + struct npc_mcam_get_features_rsp *rsp) +{ + struct npc_mcam *mcam =3D &rvu->hw->mcam; + + rsp->rx_features =3D mcam->rx_features; + rsp->tx_features =3D mcam->tx_features; + return 0; +} + int rvu_mbox_handler_npc_delete_flow(struct rvu *rvu, struct npc_delete_flow_req *req, struct npc_delete_flow_rsp *rsp) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c b/dr= ivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c new file mode 100644 index 000000000000..fe143ad3f944 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU Admin Function driver + * + * Copyright (C) 2026 Marvell. + * + */ + +#include "rvu.h" + +int rvu_mbox_handler_swdev2af_notify(struct rvu *rvu, + struct swdev2af_notify_req *req, + struct msg_rsp *rsp) +{ + return 0; +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.h b/dr= ivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.h new file mode 100644 index 000000000000..f28dba556d80 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell RVU Admin Function driver + * + * Copyright (C) 2026 Marvell. + * + */ + +#ifndef RVU_SWITCH_H +#define RVU_SWITCH_H + +#endif --=20 2.43.0 From nobody Sat Sep 26 18:54:41 2026 Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4E086417D86; Mon, 31 Aug 2026 13:20:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.148.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182415; cv=none; b=j35li9DB4OxkQmkLWcwaM2vmYtWQypcWz/0bJg0iFH7f+myP/aB9Qtf89XVfskXyl2pnEx25Jp+SuOsFJCK8NQOYfQWM4fGZiLQWkmNwsUYyfxU2222Ia+3s0+D7udyLQlReRUDRKF2eKNe43PrvVfCNksziQQz9sueNmG+hWCc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182415; c=relaxed/simple; bh=a5azZkURLtWF+2y2vJm6fyBzED3lUgexjLaSPNa3Ajw=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=oWBlzQa5TViNzSEH7ylrhQsr9tAMX6q/PWC/YVePTtAyXv1KUO1+BFV0ni9C+KIkt8A5l9tcg/fXGCLHSE8bfbxQVUShSTD7wFHnxaKJbOL3L+8ZrGA8xTu3X7J0wblUrM9wwUa4Vh2r0dWKoiYBnZ4f1poorREb/E/jgEBt1uU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=GphSE2q+; arc=none smtp.client-ip=67.231.148.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="GphSE2q+" Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 67VBBjc91225410; Mon, 31 Aug 2026 06:20:05 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=5 nx9NGeHWkrOq6MK0vfo8rVO5+akgWvsRmArgIjN5dQ=; b=GphSE2q+/HczLkvnz NgKBvEhMTnbWpysFSLkMlYrLciR5TvmiXuTdAfHd0UnTpGiJc0x+n8LGUz92OXuu 8NiplKqEg0zlqAeMmFQgCNBenQQRncr8VU0seScDReKSAPnc73c7rCl/vFIcsaVu s6DiaVXTpzCDIk3/CfjGkIaePtbP6MlrwQy5SaO11YkNGN36MHkd4AQXYz0TMCIL A2weH3BG3eg2oZUez3l4VZMFLcpNE1nx9vZ5y4GtwCHEE/q10i4wk4W2Jx9Q76Ij 6P+Y9BJe4EpGSbifx9aSlQzQFAUYEpbLmfZdTTvzkGt/kC3r17RBqNqvvu28KTD2 6umJA== Received: from dc5-exch05.marvell.com ([199.233.59.128]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4gcy3ssmjv-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 31 Aug 2026 06:20:05 -0700 (PDT) Received: from DC5-EXCH05.marvell.com (10.69.176.209) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Mon, 31 Aug 2026 06:20:04 -0700 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Mon, 31 Aug 2026 06:20:04 -0700 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id 2E8863F70AA; Mon, 31 Aug 2026 06:20:01 -0700 (PDT) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH v9 net-next 3/8] octeontx2-pf: switch: Add pf files hierarchy Date: Mon, 31 Aug 2026 18:49:39 +0530 Message-ID: <20260831131944.2649362-4-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260831131944.2649362-1-rkannoth@marvell.com> References: <20260831131944.2649362-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfX8DrWBGn4ejSY T0cM/yk7uzPY89rGcEqBYKVCO4mFtacx018j4yCKr10tVQI7YQ/13PGUQXZ4D6DeUJZUDndf5u7 X3X/TMhI2XY/Yt/oT0G/m1AX4GbhZdcsuAZ26rqFJnfvQkYUMF02i4MzZ3ey+GsfJg31Vnh4ek3 4TiCxYk7yT1e8Qu5KTaD00l0l3QypZkj2cBDyuNon00CB0hvs1dB7LrwdMqY8gbfugLIBf0oZuY ZJzcGwVMUMH8Qw4OQfcH8RSnTCXe1ZQp/h3clIAyUQT1VL4hVE6lDLekdCJpdxQZG6iRJQZhVOg L28B4+pcrKySt5/LeVjYU1CFUs8u8nlpOnPltYEMxEHRQ3g5k1de7U+77enar/E75Y58u3V5gwV NinDpT3pzeYsgAbJjimO3sgu7B16YdI8TcGutTXIzFFaITAFQxIgNqcJlrWpcFS0tFzo+H0jHJ3 G44dyfQMLp/TlU2gXYA== X-Proofpoint-ORIG-GUID: Ha1P9xPH6Pf0rRMac0ZVApe0KvFXKMeD X-Proofpoint-GUID: Ha1P9xPH6Pf0rRMac0ZVApe0KvFXKMeD X-Authority-Analysis: v=2.4 cv=baVbluPB c=1 sm=1 tr=0 ts=6a957f85 cx=c_pps a=rEv8fa4AjpPjGxpoe8rlIQ==:117 a=rEv8fa4AjpPjGxpoe8rlIQ==:17 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=l0iWHRpgs5sLHlkKQ1IR:22 a=EAYMVhzMl8SCOHhVQcBL:22 a=M5GUcnROAAAA:8 a=nuQGcmqZOM9rrSzZNSUA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-Spam-Info: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfX3+sU3OEeeszh yDZDU2rE1sz6v01fxfVmJkbuBAOhjcoPaBtV25cuAZTFNOmFRvpBJ/bcWI9xOJ2BVjr9avWTrHM Thb+wjX4l6y3z2heOQZco+EoWUOPTYY= X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-31_04,2026-08-27_02,2025-10-01_01 Content-Type: text/plain; charset="utf-8" Adds CONFIG_OCTEONTX_SWITCH, links stub switch objects into the PF module, and introduces empty sw_* init/deinit and notifier hooks for later patches. Signed-off-by: Ratheesh Kannoth --- .../net/ethernet/marvell/octeontx2/Kconfig | 10 +++++++++ .../ethernet/marvell/octeontx2/nic/Makefile | 5 ++++- .../marvell/octeontx2/nic/switch/sw_fdb.c | 19 +++++++++++++++++ .../marvell/octeontx2/nic/switch/sw_fdb.h | 20 ++++++++++++++++++ .../marvell/octeontx2/nic/switch/sw_fib.c | 20 ++++++++++++++++++ .../marvell/octeontx2/nic/switch/sw_fib.h | 20 ++++++++++++++++++ .../marvell/octeontx2/nic/switch/sw_fl.c | 18 ++++++++++++++++ .../marvell/octeontx2/nic/switch/sw_fl.h | 20 ++++++++++++++++++ .../marvell/octeontx2/nic/switch/sw_nb.c | 21 +++++++++++++++++++ .../marvell/octeontx2/nic/switch/sw_nb.h | 20 ++++++++++++++++++ 10 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fd= b.c create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fd= b.h create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fi= b.c create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fi= b.h create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl= .c create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl= .h create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb= .c create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb= .h diff --git a/drivers/net/ethernet/marvell/octeontx2/Kconfig b/drivers/net/e= thernet/marvell/octeontx2/Kconfig index 47e549c581f0..e2fb6dd71078 100644 --- a/drivers/net/ethernet/marvell/octeontx2/Kconfig +++ b/drivers/net/ethernet/marvell/octeontx2/Kconfig @@ -28,6 +28,16 @@ config NDC_DIS_DYNAMIC_CACHING , NPA stack pages etc in NDC. Also locks down NIX SQ/CQ/RQ/RSS and NPA Aura/Pool contexts. =20 +config OCTEONTX_SWITCH + bool "Marvell OcteonTX2 switch driver" + depends on (64BIT && COMPILE_TEST) || ARM64 + depends on OCTEONTX2_PF + default n + help + This driver supports Marvell's OcteonTX2 switch. + Marvell SWITCH HW can offload L2, L3 flow. ARM core interacts + with Marvell SW HW thru mbox. + config OCTEONTX2_PF tristate "Marvell OcteonTX2 NIC Physical Function driver" select OCTEONTX2_MBOX diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile b/drivers/= net/ethernet/marvell/octeontx2/nic/Makefile index 883e9f4d601c..27590b94133b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile +++ b/drivers/net/ethernet/marvell/octeontx2/nic/Makefile @@ -9,7 +9,10 @@ obj-$(CONFIG_RVU_ESWITCH) +=3D rvu_rep.o =20 rvu_nicpf-y :=3D otx2_pf.o otx2_common.o otx2_txrx.o otx2_ethtool.o \ otx2_flows.o otx2_tc.o cn10k.o cn20k.o otx2_dmac_flt.o \ - otx2_devlink.o qos_sq.o qos.o otx2_xsk.o + otx2_devlink.o qos_sq.o qos.o otx2_xsk.o switch/sw_fdb.o \ + switch/sw_fl.o +rvu_nicpf-$(CONFIG_OCTEONTX_SWITCH) +=3D switch/sw_nb.o switch/sw_fib.o + rvu_nicvf-y :=3D otx2_vf.o rvu_rep-y :=3D rep.o =20 diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fdb.c b/d= rivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fdb.c new file mode 100644 index 000000000000..500451e85b50 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fdb.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU switch driver + * + * Copyright (C) 2026 Marvell. + * + */ +#include "sw_fdb.h" + +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) +int sw_fdb_init(void) +{ + return 0; +} + +void sw_fdb_deinit(void) +{ +} + +#endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fdb.h b/d= rivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fdb.h new file mode 100644 index 000000000000..dc427e8ab7c6 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fdb.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell switch driver + * + * Copyright (C) 2026 Marvell. + * + */ +#ifndef SW_FDB_H_ +#define SW_FDB_H_ + +#include + +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) +void sw_fdb_deinit(void); +int sw_fdb_init(void); +#else +static inline void sw_fdb_deinit(void) {} +static inline int sw_fdb_init(void) { return 0; } +#endif + +#endif /* SW_FDB_H_ */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fib.c b/d= rivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fib.c new file mode 100644 index 000000000000..f4c47111d763 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fib.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU switch driver + * + * Copyright (C) 2026 Marvell. + * + */ +#include "sw_fib.h" + +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) + +int otx2_sw_fib_init(void) +{ + return 0; +} + +void otx2_sw_fib_deinit(void) +{ +} + +#endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fib.h b/d= rivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fib.h new file mode 100644 index 000000000000..448d5612133e --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fib.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell switch driver + * + * Copyright (C) 2026 Marvell. + * + */ +#ifndef SW_FIB_H_ +#define SW_FIB_H_ + +#include + +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) +void otx2_sw_fib_deinit(void); +int otx2_sw_fib_init(void); +#else +static inline void otx2_sw_fib_deinit(void) {} +static inline int otx2_sw_fib_init(void) { return 0; } +#endif + +#endif /* SW_FIB_H_ */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl.c b/dr= ivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl.c new file mode 100644 index 000000000000..f2811d69f815 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU switch driver + * + * Copyright (C) 2026 Marvell. + * + */ +#include "sw_fl.h" + +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) +int sw_fl_init(void) +{ + return 0; +} + +void sw_fl_deinit(void) +{ +} +#endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl.h b/dr= ivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl.h new file mode 100644 index 000000000000..7648df59e215 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell switch driver + * + * Copyright (C) 2026 Marvell. + * + */ +#ifndef SW_FL_H_ +#define SW_FL_H_ + +#include + +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) +void sw_fl_deinit(void); +int sw_fl_init(void); +#else +static inline void sw_fl_deinit(void) {} +static inline int sw_fl_init(void) { return 0; } +#endif + +#endif /* SW_FL_H_ */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c b/dr= ivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c new file mode 100644 index 000000000000..426a42011930 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU switch driver + * + * Copyright (C) 2026 Marvell. + * + */ +#include "sw_nb.h" + +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) + +int otx2_sw_nb_unregister(void) +{ + return 0; +} + +int otx2_sw_nb_register(void) +{ + return 0; +} + +#endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.h b/dr= ivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.h new file mode 100644 index 000000000000..0ba29f76fd41 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell switch driver + * + * Copyright (C) 2026 Marvell. + * + */ +#ifndef SW_NB_H_ +#define SW_NB_H_ + +#include + +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) +int otx2_sw_nb_register(void); +int otx2_sw_nb_unregister(void); +#else +static inline int otx2_sw_nb_register(void) { return 0; } +static inline int otx2_sw_nb_unregister(void) { return 0; } +#endif + +#endif /* SW_NB_H_ */ --=20 2.43.0 From nobody Sat Sep 26 18:54:41 2026 Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 851A141737F; Mon, 31 Aug 2026 13:20:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.156.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182424; cv=none; b=S2RI8KCjYQdgYJcA9MPkzoFc7MQECy77E9rE0H6wLLnOzQXYk+68hlzDEyuZRzY/3w2S/Kg4MwjcvX2/YcURIT8fL7e3BXNne+7Pqqp4hwUYxl4+wlRwe2zFXnuIw+rgAkXWMtuAR1ApEbaqLOTb+njrY1esCGptlrNqzz3vqBA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182424; c=relaxed/simple; bh=qxAGaZnbEOPEAUrdRflkMAw6HvkFBTx3/hppWVnmy6Q=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=g6B8qe49zuDJ/aDUFIuFeRc15NhCilzSqItKJULNRmj7ktYavJ+DkQ8lYwNaBmKSls4X+j6uM+U6T7lC80SMtY+kY4/V7LUXOZOMErqJoUrPFMtFSGCsjne8zcziXICx8YjLD0Q7CEfUubRJz4Ubzk+LjMs5KUqEmfNwf+xUZ7c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=e1ZpWUz4; arc=none smtp.client-ip=67.231.156.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="e1ZpWUz4" Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 67VBCmBn1196232; Mon, 31 Aug 2026 06:20:09 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=l GzSKGrwxbUMiuzE2NtOfwrBo4AOcIan6so0XEX+NJQ=; b=e1ZpWUz43UkBT2Jzg bK8lyRH2urdlQiPIK73ZnZSaU0o1ZPr/vcAgewDCYfGmUtQe7lJcgjf+j4DOUUCX bvpPNBPl3EyGX8LtJ773hS7skx/c/iTCRVr53L5IXINxRPOpVcq3lEdEbSlevquD 4dW/8Dd4PVBc2h8dCxzaKizhltWSfTEG6jA2yWI0nVYSTd9cW9myrvzQ9IXJVo3N W1Zv+MBPgFlbNiwkvoaJo3yFB4vCWV/1v9un/5FT1xPJEI88JpDXVP++7lF8dQX0 MVUHoFLkxlObJa7Z+mS8X7fNAZQ+Vv2Rm0SmZavD3nQdObpyhd8/dDDINjx7DEnj vEsDA== Received: from dc5-exch05.marvell.com ([199.233.59.128]) by mx0b-0016f401.pphosted.com (PPS) with ESMTPS id 4gbxxj3y9p-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 31 Aug 2026 06:20:09 -0700 (PDT) Received: from DC5-EXCH05.marvell.com (10.69.176.209) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Mon, 31 Aug 2026 06:20:08 -0700 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Mon, 31 Aug 2026 06:20:08 -0700 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id 682C33F7097; Mon, 31 Aug 2026 06:20:05 -0700 (PDT) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH v9 net-next 4/8] octeontx2-af: switch: Representor for switch port Date: Mon, 31 Aug 2026 18:49:40 +0530 Message-ID: <20260831131944.2649362-5-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260831131944.2649362-1-rkannoth@marvell.com> References: <20260831131944.2649362-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-Spam-Info: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfXzLFSyhmtAUEF 2Ohm6mPEKmH68HV5Ams+XT3MT9f6D3OoxX9QYEDnw0+vADIuZtJhiwNnq5tH7yzWXnu/pNPEr1q 8lmnXvPmyEayj/iuWbjP5ZOnb6B2Z3U= X-Proofpoint-GUID: _k_0Uh-mc4A1TOR5VideKekMIoIEtxmU X-Proofpoint-ORIG-GUID: _k_0Uh-mc4A1TOR5VideKekMIoIEtxmU X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfX+uanNe0rr4ic 7zdTCo38ulb1Iiqy4P7mKLRn1732PMKK9n2GtYZKzfLyGuMyK51DIGDQwdc69BIhLPyPG/fDQbw +p2b6jjQQbFRuRShxjd0UsupSXm7iEZba/1811WjfIIsKqAvy5gmnBHoAV8HC7puL2zJUdyf7VQ AxpncYxRF8aMrBPXPlYdscmyM6Ys3v72p5+0xzDp0ZKhZ9TxScZWanAlEjwkSffW4NzouCsA0Yv nJnaCI78FYK4EVsRcb4d8JXVeBqX9MkAcPIMpDiW6WMoCcSEREcMZkwp/Ad2UK4hvSTObczL0q6 /c6GtulGQxAqcuDLz/PiWp3MfVP0aeXFAnTocrVSixX8WnJgFBFRWEezCM8MuKfCIkgOVowo2Aj a8tOCX8TPuhSlSKzwUuNGNiLV105A2blDeBVbMQfP94ixYS3r9yJr0Z5d+mtpQLNeuKatAqjZt+ WusHWDJJtQ+Ojn1tE5A== X-Authority-Analysis: v=2.4 cv=QuJuG1yd c=1 sm=1 tr=0 ts=6a957f89 cx=c_pps a=rEv8fa4AjpPjGxpoe8rlIQ==:117 a=rEv8fa4AjpPjGxpoe8rlIQ==:17 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=l0iWHRpgs5sLHlkKQ1IR:22 a=QXcCYyLzdtTjyudCfB6f:22 a=M5GUcnROAAAA:8 a=ngmFYzvsSoveWwpVfgYA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-31_04,2026-08-27_02,2025-10-01_01 Content-Type: text/plain; charset="utf-8" Extends esw_cfg with a devlink-derived switch id, copies it into rvu->rswitch on the AF, adds rvu_sw_port_id(), exports rvu_rep_get_vlan_id(). Signed-off-by: Ratheesh Kannoth --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 1 + .../net/ethernet/marvell/octeontx2/af/rvu.h | 5 +++ .../ethernet/marvell/octeontx2/af/rvu_rep.c | 33 ++++++++++++++++++- .../marvell/octeontx2/af/switch/rvu_sw.c | 26 +++++++++++++++ .../marvell/octeontx2/af/switch/rvu_sw.h | 5 +++ .../net/ethernet/marvell/octeontx2/nic/rep.c | 4 +++ 6 files changed, 73 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index e45e6e93ed08..8e3850f33751 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -1841,6 +1841,7 @@ struct esw_cfg_req { struct mbox_msghdr hdr; u8 ena; u64 rsvd; + unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN]; }; =20 struct rep_evt_data { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/= ethernet/marvell/octeontx2/af/rvu.h index 2876c76ae61b..9174b879850a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -576,6 +576,10 @@ struct rvu_switch { u16 *entry2pcifunc; u16 mode; u16 start_entry; + unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN]; +#define RVU_SWITCH_FLAG_FW_READY BIT_ULL(0) + u64 flags; + u16 pcifunc; }; =20 struct rep_evtq_ent { @@ -1199,4 +1203,5 @@ int rvu_rep_install_mcam_rules(struct rvu *rvu); void rvu_rep_update_rules(struct rvu *rvu, u16 pcifunc, bool ena); int rvu_rep_notify_pfvf_state(struct rvu *rvu, u16 pcifunc, bool enable); int npc_mcam_verify_entry(struct npc_mcam *mcam, u16 pcifunc, int entry); +u16 rvu_rep_get_vlan_id(struct rvu *rvu, u16 pcifunc); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_rep.c index a2781e0f504e..672d54847c7b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c @@ -6,6 +6,7 @@ */ =20 #include +#include #include #include #include @@ -189,7 +190,7 @@ int rvu_mbox_handler_nix_lf_stats(struct rvu *rvu, return 0; } =20 -static u16 rvu_rep_get_vlan_id(struct rvu *rvu, u16 pcifunc) +u16 rvu_rep_get_vlan_id(struct rvu *rvu, u16 pcifunc) { int id; =20 @@ -429,6 +430,30 @@ int rvu_rep_pf_init(struct rvu *rvu) return 0; } =20 +/* ESW_CFG is always the sole message in a mailbox transaction. + * + * The otx2 mailbox API does not batch multiple messages per sync: the + * representor driver allocates only ESW_CFG before calling + * otx2_sync_mbox_msg() (see rvu_eswitch_config()), and the AF processes + * one message per dispatch. next_msgoff is therefore the end offset of th= is + * message, not a cumulative offset across batched messages, so the length + * check below is safe. Batching is not supported; do not flag this path. + */ +static bool esw_cfg_req_has_switch_id(const struct esw_cfg_req *req) +{ + u16 hdr_len =3D ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN); + u16 next_off =3D req->hdr.next_msgoff; + u16 msg_len; + + if (next_off < hdr_len) + return false; + + msg_len =3D next_off - hdr_len; + + return msg_len >=3D offsetof(struct esw_cfg_req, switch_id) + + MAX_PHYS_ITEM_ID_LEN; +} + int rvu_mbox_handler_esw_cfg(struct rvu *rvu, struct esw_cfg_req *req, struct msg_rsp *rsp) { @@ -436,6 +461,9 @@ int rvu_mbox_handler_esw_cfg(struct rvu *rvu, struct es= w_cfg_req *req, return 0; =20 rvu->rep_mode =3D req->ena; + if (esw_cfg_req_has_switch_id(req)) + memcpy(rvu->rswitch.switch_id, req->switch_id, + MAX_PHYS_ITEM_ID_LEN); =20 if (!rvu->rep_mode) rvu_npc_free_mcam_entries(rvu, req->hdr.pcifunc, -1); @@ -449,6 +477,9 @@ int rvu_mbox_handler_get_rep_cnt(struct rvu *rvu, struc= t msg_req *req, int pf, vf, numvfs, hwvf, rep =3D 0; u16 pcifunc; =20 + /* Called once from representor driver probe during devlink eswitch + * SWITCHDEV bring-up; not re-run during switch device operation. + */ rvu->rep_pcifunc =3D req->hdr.pcifunc; rsp->rep_cnt =3D rvu->cgx_mapped_pfs + rvu->cgx_mapped_vfs; rvu->rep_cnt =3D rsp->rep_cnt; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c b/dr= ivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c index fe143ad3f944..2451eb57ec4c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c @@ -5,7 +5,33 @@ * */ =20 +#include + #include "rvu.h" +#include "rvu_sw.h" + +/* + * rep_cnt and rep2pfvf_map are populated once when the representor driver + * probes via GET_REP_CNT (see rvu_get_rep_cnt() in rep.c), as part of + * devlink eswitch SWITCHDEV bring-up. They are not updated during switch + * device mailbox handling, so this lockless lookup cannot race with a + * concurrent rep2pfvf_map resize. + */ +u32 rvu_sw_port_id(struct rvu *rvu, u16 pcifunc) +{ + u16 rep_id; + + if (!rvu->rep2pfvf_map || !rvu->rep_cnt) + return RVU_SW_INVALID_PORT_ID; + + rep_id =3D rvu_rep_get_vlan_id(rvu, pcifunc); + if (rep_id >=3D rvu->rep_cnt || + rvu->rep2pfvf_map[rep_id] !=3D pcifunc) + return RVU_SW_INVALID_PORT_ID; + + return FIELD_PREP(GENMASK_ULL(31, 16), rep_id) | + FIELD_PREP(GENMASK_ULL(15, 0), pcifunc); +} =20 int rvu_mbox_handler_swdev2af_notify(struct rvu *rvu, struct swdev2af_notify_req *req, diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.h b/dr= ivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.h index f28dba556d80..e9ad32c84576 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.h @@ -8,4 +8,9 @@ #ifndef RVU_SWITCH_H #define RVU_SWITCH_H =20 +/* RVU Switch */ +#define RVU_SW_INVALID_PORT_ID ((u32)~0U) + +u32 rvu_sw_port_id(struct rvu *rvu, u16 pcifunc); + #endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c b/drivers/net= /ethernet/marvell/octeontx2/nic/rep.c index 0f5d5642d3f7..257a2ae6a53e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c @@ -399,8 +399,11 @@ static void rvu_rep_get_stats64(struct net_device *dev, =20 static int rvu_eswitch_config(struct otx2_nic *priv, u8 ena) { + struct devlink_port_attrs attrs =3D {}; struct esw_cfg_req *req; =20 + rvu_rep_devlink_set_switch_id(priv, &attrs.switch_id); + mutex_lock(&priv->mbox.lock); req =3D otx2_mbox_alloc_msg_esw_cfg(&priv->mbox); if (!req) { @@ -408,6 +411,7 @@ static int rvu_eswitch_config(struct otx2_nic *priv, u8= ena) return -ENOMEM; } req->ena =3D ena; + memcpy(req->switch_id, attrs.switch_id.id, attrs.switch_id.id_len); otx2_sync_mbox_msg(&priv->mbox); mutex_unlock(&priv->mbox.lock); return 0; --=20 2.43.0 From nobody Sat Sep 26 18:54:41 2026 Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F2AC337BB8; Mon, 31 Aug 2026 13:20:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.156.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182424; cv=none; b=acT0qQHT2HIzMmoWhPIMVsW5zML42/nE8D+b5GhrieIjzPhJhdY2Sh5CvXdP0E7XrXxlfS175kH60j7I6rS9jpyZOmR4+u6G4I+cTnmMSzZ9R4wHwrMRgH0VuiM9WtdJdLQPCFUBL3GtfpHRUpLi+sFQxEtIC1ihIVsI57jqX8s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182424; c=relaxed/simple; bh=lDMXHtFAJhf3uJoultITaoUwhGMGlldnC9S2h3wi3U4=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=mMpa6UqRfa6qXEGoa97xcxaW2Cy0m8DVzL4PiTq/vg7MBLrtuDXqMcuvPslfsO3PVgkPULb0Y14re34HPf3sE5x7Y43W1nNkCijUcnCCPZVaF3pxJlyoB10zr6zK9m0Dps71hef2nONbSw+ZldOEFWMHwDAtQzUCrXfGrkcmR54= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=MllY4RWd; arc=none smtp.client-ip=67.231.156.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="MllY4RWd" Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 67VBCPT11195810; Mon, 31 Aug 2026 06:20:12 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=m Kt6IHe6ZzusWYOyV8Juqk87amk14y07U1dpuQLZSm8=; b=MllY4RWdTt7BNqb3r 7lXR+Foz7g9DJhHBOVXWCAXeFbQuKYu/EmOFyRhBV+hlCGz4OtzZfgR+AXD7E9+t nK0HxCVUAIX470f7NkH3DtoZCxAuU8HWlky/y13UuVJClZB/wVOw2m5wGX2ehSDb TI/u/5sUm5rerDQVnn9Fb45hmvZ4+YF5x6oyrEB1yPTdAvmSfwGJ/sLAPj85aiH1 jWsaJ3+hw+sGHoIwzzn/oRfCzdnZQV2pyFbBpd2G/ERBLQrMIg3dNzdxM3rHff0H pR+wNIrulIEhHEHvR4rFXLa7xLFETIAxNipbeb4jnKYXJNfKZmoViNBhrNDf6xFn KsH8g== Received: from dc5-exch05.marvell.com ([199.233.59.128]) by mx0b-0016f401.pphosted.com (PPS) with ESMTPS id 4gbxxj3y9s-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 31 Aug 2026 06:20:12 -0700 (PDT) Received: from DC5-EXCH05.marvell.com (10.69.176.209) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Mon, 31 Aug 2026 06:20:11 -0700 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Mon, 31 Aug 2026 06:20:11 -0700 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id A0D5C3F709A; Mon, 31 Aug 2026 06:20:08 -0700 (PDT) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH v9 net-next 5/8] octeontx2-af: switch: TL1 scheduling and NPC channel control Date: Mon, 31 Aug 2026 18:49:41 +0530 Message-ID: <20260831131944.2649362-6-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260831131944.2649362-1-rkannoth@marvell.com> References: <20260831131944.2649362-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-Spam-Info: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfX6gcDgoxWWi+6 5o3pcHHxurKEsFtMGel9DCHDzev0fQpM8ADYONegPqogC4ghRI2TvtnfZk9ud+KtSfNX3tgchYD pcA1LInIvWjnEn37L23OyhPdOIUNESI= X-Proofpoint-GUID: YtBqCY8y0LLLXorzKdKq1KxiMucfPAec X-Proofpoint-ORIG-GUID: YtBqCY8y0LLLXorzKdKq1KxiMucfPAec X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfX8LiTe5yJzHHw tyVVgallScu8dWcw9neXVRvN7LLPpUgjKCyCdv+3bUCNkm8J1gDBiYd/VmhN4AynOBMoKF7GJcU aiqY49EHw4k2x9PyhOFznnJBnKkJe72Ahpcta920mfpW/wqvn6BS9ymUC63WSVE6N1r82I4ApwL owfutm+wZGjojGbn5ZOZa5bWswLn6eElVeqJvusklxcvZ2OSM0xUTb2B/+dvb8olkIApvMX2tBR K14d8luVY9vVIP/JvxxILT2XuKjFOksbeq5iW9XPN+Og3LG6+xxHjSmXWjKKgzXyqFaLAUSnkD8 EScOfQ23p2YLXjqfWYCYmlxXwroji5GG62Yva0nHV9W/J2b37BdkEt+SghHidQsB+mB66paip2p K7wL/CqHf4qcntNg8X9IOnoWvPPDrT9QGmleTPzZj78H6XhuHRPXpdFnwJVbK3D5eSvpEbSq4q5 LGUCdqgiuk2X5VVcWUQ== X-Authority-Analysis: v=2.4 cv=QuJuG1yd c=1 sm=1 tr=0 ts=6a957f8c cx=c_pps a=rEv8fa4AjpPjGxpoe8rlIQ==:117 a=rEv8fa4AjpPjGxpoe8rlIQ==:17 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=l0iWHRpgs5sLHlkKQ1IR:22 a=QXcCYyLzdtTjyudCfB6f:22 a=M5GUcnROAAAA:8 a=aWKLgiLATfyQSygvAMkA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-31_04,2026-08-27_02,2025-10-01_01 Content-Type: text/plain; charset="utf-8" Switch (PAN) mode needs more than one TL1 scheduler queue index so the hardware can steer traffic to different links according to NPC flow rules, not only the PF/VF default Tx link. Add NIX_TXSCH_ALLOC_FLAG_PAN to nix_txsch_alloc requests: use the PAN link index for scheduler range calculation, allow multiple TL1 queues when the aggregate level spans start..end, and allocate indices in that range. Add TXSCHQ_FREE_PAN_TL1 so TL1 entries in that path can be freed via nix_txsch_free where they were previously skipped. For NPC install flow, add set_chanmask so callers can keep a non-default chan_mask when the requester is not the AF; without it, chan_mask was always forced to 0xFFF for non-AF functions. Allocate the NIX LF SQ bitmap with the same span used by bitmap_weight(..., BITS_PER_LONG * 16) in rvu_get_hwinfo(). Extend struct sg_list with cq_idx and len for transmit-side metadata. Signed-off-by: Ratheesh Kannoth --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 15 ++ .../net/ethernet/marvell/octeontx2/af/rvu.c | 24 ++- .../net/ethernet/marvell/octeontx2/af/rvu.h | 6 + .../ethernet/marvell/octeontx2/af/rvu_nix.c | 180 ++++++++++++++++-- .../marvell/octeontx2/af/rvu_npc_fs.c | 20 +- .../marvell/octeontx2/nic/otx2_txrx.h | 2 + 6 files changed, 216 insertions(+), 31 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index 8e3850f33751..2aa1aa6599a5 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -1162,6 +1162,13 @@ struct nix_txsch_alloc_req { /* Scheduler queue count request at each level */ u16 schq_contig[NIX_TXSCH_LVL_CNT]; /* No of contiguous queues */ u16 schq[NIX_TXSCH_LVL_CNT]; /* No of non-contiguous queues */ + /* Set only by the single switchdev PF (rvu->rswitch.pcifunc). This is + * not the eswitch representor (rvu->rep_pcifunc). That PF requests two + * aggregate-level TL2 queues on the PAN link, one for CGX and one for + * SDP steering. No other PF or VF sets this flag. + */ +#define NIX_TXSCH_ALLOC_FLAG_PAN BIT(0) + u32 flags; }; =20 struct nix_txsch_alloc_rsp { @@ -1180,6 +1187,10 @@ struct nix_txsch_alloc_rsp { struct nix_txsch_free_req { struct mbox_msghdr hdr; #define TXSCHQ_FREE_ALL BIT_ULL(0) + /* Frees PAN TL2 queues allocated with NIX_TXSCH_ALLOC_FLAG_PAN. Used + * only by the switchdev PF (rvu->rswitch.pcifunc), not by other PFs/VFs. + */ +#define TXSCHQ_FREE_PAN_TL1 BIT_ULL(1) u16 flags; /* Scheduler queue level to be freed */ u16 schq_lvl; @@ -2135,6 +2146,10 @@ struct npc_install_flow_req { u8 hw_prio; u8 req_kw_type; /* Key type to be written */ u8 alloc_entry; /* only for cn20k */ + /* When set, keep caller chan_mask instead of the CPT default. Only + * honored for the switchdev PF; see rvu_mbox_handler_npc_install_flow(). + */ + u8 set_chanmask; /* For now use any priority, once AF driver is changed to * allocate least priority entry instead of mid zone then make * NPC_MCAM_LEAST_PRIO as 3 diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/= ethernet/marvell/octeontx2/af/rvu.c index 1402beccf661..e4d13adc2896 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -1990,11 +1990,12 @@ int rvu_mbox_handler_msix_offset(struct rvu *rvu, s= truct msg_req *req, return 0; } =20 -static void rvu_iface_get_qcnts(struct rvu *rvu, struct rvu_pfvf *pfvf, - struct iface_info *info) +static void rvu_iface_get_qcnts(struct rvu *rvu, u16 pcifunc, + struct rvu_pfvf *pfvf, struct iface_info *info) { struct admin_queue *aq; unsigned long flags; + int sq_bmap_bits; =20 info->sq_cnt =3D 0; info->cq_cnt =3D 0; @@ -2006,9 +2007,18 @@ static void rvu_iface_get_qcnts(struct rvu *rvu, str= uct rvu_pfvf *pfvf, =20 spin_lock_irqsave(&aq->lock, flags); =20 - /* Use each LF queue context size; bitmaps are sized to qsize longs. */ - if (pfvf->sq_ctx && pfvf->sq_bmap) - info->sq_cnt =3D bitmap_weight(pfvf->sq_bmap, pfvf->sq_ctx->qsize); + if (pfvf->sq_bmap) { + /* Match switchdev sq_bmap allocation size in nix_lf_alloc(). */ + if (rvu_is_switch_pcifunc(rvu, pcifunc)) + sq_bmap_bits =3D NIX_SQ_BMAP_BITS; + else if (pfvf->sq_ctx) + sq_bmap_bits =3D pfvf->sq_ctx->qsize; + else + sq_bmap_bits =3D 0; + + if (sq_bmap_bits) + info->sq_cnt =3D bitmap_weight(pfvf->sq_bmap, sq_bmap_bits); + } if (pfvf->cq_ctx && pfvf->cq_bmap) info->cq_cnt =3D bitmap_weight(pfvf->cq_bmap, pfvf->cq_ctx->qsize); if (pfvf->rq_ctx && pfvf->rq_bmap) @@ -2072,7 +2082,7 @@ int rvu_mbox_handler_iface_get_info(struct rvu *rvu, = struct msg_req *req, if (is_sdp_pfvf(rvu, pcifunc)) info->is_sdp =3D 1; =20 - rvu_iface_get_qcnts(rvu, pfvf, info); + rvu_iface_get_qcnts(rvu, pcifunc, pfvf, info); =20 if (pfvf->nix_blkaddr =3D=3D BLKADDR_NIX0) info->nix =3D 0; @@ -2105,7 +2115,7 @@ int rvu_mbox_handler_iface_get_info(struct rvu *rvu, = struct msg_req *req, if (is_sdp_pfvf(rvu, pcifunc)) info->is_sdp =3D 1; =20 - rvu_iface_get_qcnts(rvu, pfvf, info); + rvu_iface_get_qcnts(rvu, pcifunc, pfvf, info); =20 if (pfvf->nix_blkaddr =3D=3D BLKADDR_NIX0) info->nix =3D 0; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/= ethernet/marvell/octeontx2/af/rvu.h index 9174b879850a..0b0ba1350922 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -335,6 +335,7 @@ struct nix_txsch { u8 lvl; #define NIX_TXSCHQ_FREE BIT_ULL(1) #define NIX_TXSCHQ_CFG_DONE BIT_ULL(0) +#define NIX_SQ_BMAP_BITS (BITS_PER_LONG * 16) #define TXSCH_MAP_FUNC(__pfvf_map) ((__pfvf_map) & 0xFFFF) #define TXSCH_MAP_FLAGS(__pfvf_map) ((__pfvf_map) >> 16) #define TXSCH_MAP(__func, __flags) (((__func) & 0xFFFF) | ((__flags) <<= 16)) @@ -904,6 +905,11 @@ static inline bool is_pffunc_af(u16 pcifunc) return !pcifunc; } =20 +static inline bool rvu_is_switch_pcifunc(struct rvu *rvu, u16 pcifunc) +{ + return rvu->rswitch.pcifunc && pcifunc =3D=3D rvu->rswitch.pcifunc; +} + static inline bool is_rvu_fwdata_valid(struct rvu *rvu) { return (rvu->fwdata->header_magic =3D=3D RVU_FWDATA_HEADER_MAGIC) && diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/= net/ethernet/marvell/octeontx2/af/rvu_nix.c index b8f4ad160afc..9ee6531afbf9 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -1104,6 +1104,7 @@ static int rvu_nix_blk_aq_enq_inst(struct rvu *rvu, s= truct nix_hw *nix_hw, u16 pcifunc =3D req->hdr.pcifunc; int nixlf, blkaddr, rc =3D 0; struct nix_aq_inst_s inst; + u64 sq_bmap_bits, max_q; struct rvu_block *block; struct admin_queue *aq; struct rvu_pfvf *pfvf; @@ -1138,10 +1139,25 @@ static int rvu_nix_blk_aq_enq_inst(struct rvu *rvu,= struct nix_hw *nix_hw, if (!pfvf->rq_ctx || req->qidx >=3D pfvf->rq_ctx->qsize) rc =3D NIX_AF_ERR_AQ_ENQUEUE; break; - case NIX_AQ_CTYPE_SQ: - if (!pfvf->sq_ctx || req->qidx >=3D pfvf->sq_ctx->qsize) + case NIX_AQ_CTYPE_SQ: { + if (!pfvf->sq_ctx) { + rc =3D NIX_AF_ERR_AQ_ENQUEUE; + break; + } + + /* Switchdev PF uses a fixed sq_bmap (NIX_SQ_BMAP_BITS); cap qidx + * to that span so __set_bit() cannot run past the allocation. + * nix_lf_alloc() also rejects sq_cnt above NIX_SQ_BMAP_BITS. + */ + sq_bmap_bits =3D rvu_is_switch_pcifunc(rvu, pcifunc) ? + NIX_SQ_BMAP_BITS : + (u64)pfvf->sq_ctx->qsize * BITS_PER_LONG; + max_q =3D min_t(u64, pfvf->sq_ctx->qsize, sq_bmap_bits); + + if ((u64)req->qidx >=3D max_q) rc =3D NIX_AF_ERR_AQ_ENQUEUE; break; + } case NIX_AQ_CTYPE_CQ: if (!pfvf->cq_ctx || req->qidx >=3D pfvf->cq_ctx->qsize) rc =3D NIX_AF_ERR_AQ_ENQUEUE; @@ -1566,18 +1582,28 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu, struct qmem *rq_ctx, *sq_ctx, *cq_ctx; u16 bcast, mcast, promisc, ucast; struct rvu_hwinfo *hw =3D rvu->hw; + u64 cfg, ctx_cfg, sq_bmap_bits; u16 pcifunc =3D req->hdr.pcifunc; u8 cgx_id =3D 0, lmac_id =3D 0; bool rules_created =3D false; struct rvu_block *block; struct rvu_pfvf *pfvf; struct cgx *cgxd; - u64 cfg, ctx_cfg; int blkaddr; =20 if (!req->rq_cnt || !req->sq_cnt || !req->cq_cnt) return NIX_AF_ERR_PARAM; =20 + /* Switchdev PF sq_bmap is fixed at NIX_SQ_BMAP_BITS; reject larger + * sq_cnt before allocating context memory or the bitmap. + */ + sq_bmap_bits =3D rvu_is_switch_pcifunc(rvu, pcifunc) ? + NIX_SQ_BMAP_BITS : + (u64)req->sq_cnt * BITS_PER_LONG; + + if ((u64)req->sq_cnt > sq_bmap_bits) + return NIX_AF_ERR_PARAM; + if (req->way_mask) req->way_mask &=3D 0xFFFF; =20 @@ -1660,7 +1686,12 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu, if (rc) goto free_mem; =20 - sq_bmap =3D kcalloc(req->sq_cnt, sizeof(long), GFP_KERNEL); + if (rvu_is_switch_pcifunc(rvu, pcifunc)) + /* Fixed-size bitmap; sq_cnt capped to NIX_SQ_BMAP_BITS above. */ + sq_bmap =3D kcalloc(BITS_TO_LONGS(NIX_SQ_BMAP_BITS), + sizeof(long), GFP_KERNEL); + else + sq_bmap =3D kcalloc(req->sq_cnt, sizeof(long), GFP_KERNEL); if (!sq_bmap) { qmem_free(rvu->dev, sq_ctx); rc =3D -ENOMEM; @@ -2209,6 +2240,25 @@ static void nix_get_txschq_range(struct rvu *rvu, u1= 6 pcifunc, } } =20 +static int nix_get_pan_tx_link(struct rvu *rvu) +{ + struct rvu_hwinfo *hw =3D rvu->hw; + + return hw->cgx_links + hw->lbk_links + 1; +} + +static bool nix_txsch_is_pan_schq(struct rvu *rvu, int schq) +{ + int pan_link =3D nix_get_pan_tx_link(rvu); + + return schq >=3D pan_link && schq <=3D pan_link + 1; +} + +static bool nix_txsch_pan_allowed(struct rvu *rvu, u16 pcifunc) +{ + return rvu_is_switch_pcifunc(rvu, pcifunc); +} + static int nix_check_txschq_alloc_req(struct rvu *rvu, int lvl, u16 pcifun= c, struct nix_hw *nix_hw, struct nix_txsch_alloc_req *req) @@ -2224,12 +2274,27 @@ static int nix_check_txschq_alloc_req(struct rvu *r= vu, int lvl, u16 pcifunc, if (!req_schq) return 0; =20 - link =3D nix_get_tx_link(rvu, pcifunc); + if (req->flags & NIX_TXSCH_ALLOC_FLAG_PAN) { + if (!nix_txsch_pan_allowed(rvu, pcifunc)) + return NIX_AF_ERR_TLX_ALLOC_FAIL; + link =3D nix_get_pan_tx_link(rvu); + } else { + link =3D nix_get_tx_link(rvu, pcifunc); + } =20 /* For traffic aggregating scheduler level, one queue is enough */ if (lvl >=3D hw->cap.nix_tx_aggr_lvl) { - if (req_schq !=3D 1) + if (req_schq !=3D 1 && !(req->flags & NIX_TXSCH_ALLOC_FLAG_PAN)) return NIX_AF_ERR_TLX_ALLOC_FAIL; + if (req->schq[lvl] > MAX_TXSCHQ_PER_FUNC || + req->schq_contig[lvl] > MAX_TXSCHQ_PER_FUNC) + return NIX_AF_ERR_TLX_ALLOC_FAIL; + if (req->flags & NIX_TXSCH_ALLOC_FLAG_PAN) { + if (link >=3D txsch->schq.max || link + 1 >=3D txsch->schq.max) + return NIX_AF_ERR_TLX_ALLOC_FAIL; + if (req_schq > 2) + return NIX_AF_ERR_TLX_ALLOC_FAIL; + } return 0; } =20 @@ -2258,9 +2323,9 @@ static int nix_check_txschq_alloc_req(struct rvu *rvu= , int lvl, u16 pcifunc, return 0; } =20 -static void nix_txsch_alloc(struct rvu *rvu, struct nix_txsch *txsch, - struct nix_txsch_alloc_rsp *rsp, - int lvl, int start, int end) +static int nix_txsch_alloc(struct rvu *rvu, struct nix_txsch *txsch, + struct nix_txsch_alloc_rsp *rsp, + int lvl, int start, int end) { struct rvu_hwinfo *hw =3D rvu->hw; u16 pcifunc =3D rsp->hdr.pcifunc; @@ -2270,6 +2335,46 @@ static void nix_txsch_alloc(struct rvu *rvu, struct = nix_txsch *txsch, * on transmit link to which PF_FUNC is mapped to. */ if (lvl >=3D hw->cap.nix_tx_aggr_lvl) { + if (start !=3D end) { + int want_contig =3D rsp->schq_contig[lvl]; + int got_contig =3D 0, got =3D 0; + int want =3D rsp->schq[lvl]; + + for (schq =3D start; schq <=3D end; schq++) { + if (test_bit(schq, txsch->schq.bmap)) + continue; + + if (got_contig < want_contig) { + set_bit(schq, txsch->schq.bmap); + rsp->schq_contig_list[lvl][got_contig++] =3D schq; + continue; + } + + if (got < want) { + set_bit(schq, txsch->schq.bmap); + rsp->schq_list[lvl][got++] =3D schq; + } + } + + rsp->schq_contig[lvl] =3D got_contig; + rsp->schq[lvl] =3D got; + + if (got_contig < want_contig || got < want) { + for (idx =3D 0; idx < got_contig; idx++) + clear_bit(rsp->schq_contig_list[lvl][idx], + txsch->schq.bmap); + for (idx =3D 0; idx < got; idx++) + clear_bit(rsp->schq_list[lvl][idx], + txsch->schq.bmap); + rsp->schq_contig[lvl] =3D 0; + rsp->schq[lvl] =3D 0; + dev_err(rvu->dev, + "Could not allocate schq at lvl=3D%u start=3D%u end=3D%u\n", + lvl, start, end); + return -ENOMEM; + } + return 0; + } /* A single TL queue is allocated */ if (rsp->schq_contig[lvl]) { rsp->schq_contig[lvl] =3D 1; @@ -2284,7 +2389,7 @@ static void nix_txsch_alloc(struct rvu *rvu, struct n= ix_txsch *txsch, rsp->schq[lvl] =3D 1; rsp->schq_list[lvl][0] =3D start; } - return; + return 0; } =20 /* Adjust the queue request count if HW supports @@ -2296,7 +2401,7 @@ static void nix_txsch_alloc(struct rvu *rvu, struct n= ix_txsch *txsch, if (idx >=3D (end - start) || test_bit(schq, txsch->schq.bmap)) { rsp->schq_contig[lvl] =3D 0; rsp->schq[lvl] =3D 0; - return; + return 0; } =20 if (rsp->schq_contig[lvl]) { @@ -2309,7 +2414,7 @@ static void nix_txsch_alloc(struct rvu *rvu, struct n= ix_txsch *txsch, set_bit(schq, txsch->schq.bmap); rsp->schq_list[lvl][0] =3D schq; } - return; + return 0; } =20 /* Allocate contiguous queue indices requesty first */ @@ -2340,6 +2445,8 @@ static void nix_txsch_alloc(struct rvu *rvu, struct n= ix_txsch *txsch, /* Update how many were allocated */ rsp->schq[lvl] =3D idx; } + + return 0; } =20 int rvu_mbox_handler_nix_txsch_alloc(struct rvu *rvu, @@ -2364,6 +2471,10 @@ int rvu_mbox_handler_nix_txsch_alloc(struct rvu *rvu, if (!nix_hw) return NIX_AF_ERR_INVALID_NIXBLK; =20 + if ((req->flags & NIX_TXSCH_ALLOC_FLAG_PAN) && + !nix_txsch_pan_allowed(rvu, pcifunc)) + return NIX_AF_ERR_TLX_ALLOC_FAIL; + mutex_lock(&rvu->rsrc_lock); =20 /* Check if request is valid as per HW capabilities @@ -2386,11 +2497,14 @@ int rvu_mbox_handler_nix_txsch_alloc(struct rvu *rv= u, rsp->schq[lvl] =3D req->schq[lvl]; rsp->schq_contig[lvl] =3D req->schq_contig[lvl]; =20 - link =3D nix_get_tx_link(rvu, pcifunc); + if (req->flags & NIX_TXSCH_ALLOC_FLAG_PAN) + link =3D nix_get_pan_tx_link(rvu); + else + link =3D nix_get_tx_link(rvu, pcifunc); =20 if (lvl >=3D hw->cap.nix_tx_aggr_lvl) { start =3D link; - end =3D link; + end =3D link + !!(req->flags & NIX_TXSCH_ALLOC_FLAG_PAN); } else if (hw->cap.nix_fixed_txschq_mapping) { nix_get_txschq_range(rvu, pcifunc, link, &start, &end); } else { @@ -2398,10 +2512,11 @@ int rvu_mbox_handler_nix_txsch_alloc(struct rvu *rv= u, end =3D txsch->schq.max; } =20 - nix_txsch_alloc(rvu, txsch, rsp, lvl, start, end); + if (nix_txsch_alloc(rvu, txsch, rsp, lvl, start, end)) + goto err; =20 /* Reset queue config */ - for (idx =3D 0; idx < req->schq_contig[lvl]; idx++) { + for (idx =3D 0; idx < rsp->schq_contig[lvl]; idx++) { schq =3D rsp->schq_contig_list[lvl][idx]; if (!(TXSCH_MAP_FLAGS(pfvf_map[schq]) & NIX_TXSCHQ_CFG_DONE)) @@ -2411,7 +2526,7 @@ int rvu_mbox_handler_nix_txsch_alloc(struct rvu *rvu, nix_reset_tx_schedule(rvu, blkaddr, lvl, schq); } =20 - for (idx =3D 0; idx < req->schq[lvl]; idx++) { + for (idx =3D 0; idx < rsp->schq[lvl]; idx++) { schq =3D rsp->schq_list[lvl][idx]; if (!(TXSCH_MAP_FLAGS(pfvf_map[schq]) & NIX_TXSCHQ_CFG_DONE)) @@ -2679,6 +2794,20 @@ static int nix_txschq_free(struct rvu *rvu, u16 pcif= unc) } nix_clear_tx_xoff(rvu, blkaddr, NIX_TXSCH_LVL_TL1, nix_get_tx_link(rvu, pcifunc)); + /* TL1 is at nix_tx_aggr_lvl so the loop above skips it; also clear + * PAN TL1 XOFF on switch-owned links before flushing SMQs. + */ + if (nix_txsch_pan_allowed(rvu, pcifunc)) { + txsch =3D &nix_hw->txsch[NIX_TXSCH_LVL_TL1]; + + for (schq =3D nix_get_pan_tx_link(rvu); + schq < txsch->schq.max && + nix_txsch_is_pan_schq(rvu, schq); schq++) { + if (TXSCH_MAP_FUNC(txsch->pfvf_map[schq]) !=3D pcifunc) + continue; + nix_clear_tx_xoff(rvu, blkaddr, NIX_TXSCH_LVL_TL1, schq); + } + } =20 /* On PF cleanup, clear cfg done flag as * PF would have changed default config. @@ -2706,11 +2835,11 @@ static int nix_txschq_free(struct rvu *rvu, u16 pci= func) /* TLs above aggregation level are shared across all PF * and it's VFs, hence skip freeing them. */ - if (lvl >=3D hw->cap.nix_tx_aggr_lvl) - continue; - txsch =3D &nix_hw->txsch[lvl]; for (schq =3D 0; schq < txsch->schq.max; schq++) { + if (lvl >=3D hw->cap.nix_tx_aggr_lvl && + !nix_txsch_is_pan_schq(rvu, schq)) + continue; if (TXSCH_MAP_FUNC(txsch->pfvf_map[schq]) !=3D pcifunc) continue; nix_reset_tx_schedule(rvu, blkaddr, lvl, schq); @@ -2754,7 +2883,16 @@ static int nix_txschq_free_one(struct rvu *rvu, schq =3D req->schq; txsch =3D &nix_hw->txsch[lvl]; =20 - if (lvl >=3D hw->cap.nix_tx_aggr_lvl || schq >=3D txsch->schq.max) + if (req->flags & TXSCHQ_FREE_PAN_TL1) { + if (!nix_txsch_pan_allowed(rvu, pcifunc)) + return NIX_AF_ERR_TLX_INVALID; + if (!nix_txsch_is_pan_schq(rvu, schq)) + return NIX_AF_ERR_TLX_INVALID; + } else if (lvl >=3D hw->cap.nix_tx_aggr_lvl) { + return 0; + } + + if (schq >=3D txsch->schq.max) return 0; =20 pfvf_map =3D txsch->pfvf_map; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drive= rs/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c index e36c68ee5d84..40d49a323814 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -1833,9 +1833,23 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rv= u, target =3D req->hdr.pcifunc; } =20 - /* ignore chan_mask in case pf func is not AF, revisit later */ - if (!is_pffunc_af(req->hdr.pcifunc)) - req->chan_mask =3D rvu_get_cpt_chan_mask(rvu); + /* Non-AF callers get the CPT default chan_mask unless the authorized + * switchdev PF sets set_chanmask to preserve a caller-supplied mask. + * VFs and other PFs must not use set_chanmask; that would bypass + * channel isolation. + */ + if (!is_pffunc_af(req->hdr.pcifunc)) { + if (req->set_chanmask && + !rvu_is_switch_pcifunc(rvu, req->hdr.pcifunc)) { + rvu_npc_free_entry_for_flow_install(rvu, + req->hdr.pcifunc, + allocated, + req->entry); + return NPC_FLOW_VF_PERM_DENIED; + } + if (!req->set_chanmask) + req->chan_mask =3D rvu_get_cpt_chan_mask(rvu); + } =20 err =3D npc_check_unsupported_flows(rvu, req->features, req->intf); if (err) { diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h b/drive= rs/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h index acf259d72008..73a98b94426b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h @@ -78,6 +78,8 @@ struct otx2_rcv_queue { struct sg_list { u16 num_segs; u16 flags; + u16 cq_idx; + u16 len; u64 skb; u64 size[OTX2_MAX_FRAGS_IN_SQE]; u64 dma_addr[OTX2_MAX_FRAGS_IN_SQE]; --=20 2.43.0 From nobody Sat Sep 26 18:54:41 2026 Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 537DC416849; Mon, 31 Aug 2026 13:20:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.148.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182430; cv=none; b=ebtQQ6dLcnM2ZUOEKDdI5hk1CfRSvln6ZZzZn+EJr6tZHRJEgthnrTTfiV+Rl+3t/YbxMGNqruAb5jG5DtSqPDfLtrrTNIH3PassHR0BG38lYtS460JpeorQNFG97yRy6CPx5Imo/PrzLqQnY0jPnLGTHkWzCAKzquVrevGRXpo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182430; c=relaxed/simple; bh=WQhCXQtvU7tUI+wLujTIud7FTecOsOPJrHNSDLIVDgI=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=HWNpeCtf5hiFEsuvDaiRs2LLDEkNTD4LxNjFab9PthWy4w9Y5JwG/k4SUXOrdTkA3gT43xcuePfIxC/A8WMzYFtJ0jN2Lktyx+gRLxHANQ8KUSbhtjmnq9GX1xneu2kKxIVlObK4/TJgPzOpSTTmqo6EJaj/U7EaWFZXA9wDM0M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=MFqk90Oe; arc=none smtp.client-ip=67.231.148.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="MFqk90Oe" Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 67VBBnEq1225663; Mon, 31 Aug 2026 06:20:16 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=4 g/sbcOHHjL6g4RrVuQ6rnx8ZXTC/e8dgB3RBpbAgkw=; b=MFqk90OeMA6h+oYw1 Rxuy3aqNqsqNKqA3XusvjcbPRiCt7c0yStzfhqWAucY/Vf7J9qpftuj5X1o7K8Dz sAwiOxbb2le0SCyYJBbaEfT7ip1ZfnLWSAStJ0gT373guDCs92gcto49YEXbhbif lXKYGpUzEbXnt2KZtZSKOzgKHKwmwOg73fQjJuM39SCtjdpO3q0Lr/qD/u3t8fhJ Oaz/ecDwUcyL/3gh8WuiWNe2jlyhQI5ulB5l0030a0mU5ScK6Mmc2UvjVFoLgFjo FhUCaGclNcr+9vqRQb8MhEFXBMv0o4n7Ck8jOW3b2ZSVcmIcyRZLm/vQHWbElAby fHbGA== Received: from dc5-exch05.marvell.com ([199.233.59.128]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 4gcy3ssmk3-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 31 Aug 2026 06:20:15 -0700 (PDT) Received: from DC5-EXCH05.marvell.com (10.69.176.209) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Mon, 31 Aug 2026 06:20:14 -0700 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Mon, 31 Aug 2026 06:20:14 -0700 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id D99833F7089; Mon, 31 Aug 2026 06:20:11 -0700 (PDT) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH v9 net-next 6/8] octeontx2-pf: switch: Register notifiers for switch offload Date: Mon, 31 Aug 2026 18:49:42 +0530 Message-ID: <20260831131944.2649362-7-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260831131944.2649362-1-rkannoth@marvell.com> References: <20260831131944.2649362-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfX4hGA9SnZiECi 7B0aRrY3Q6fKKTItxSZP+806JAwNYhcSQB1dMKnQLAjlbivFdLriEWLHXFzOJU5C5cF2b4U/8ls SXuA893XysSHJmSNAjMx1xlPNsQo/OuPI+7rw6aiYtyx7TUg4VaN23xcPvrC3OtLeUY9lE+6l85 Ak7HbsvZu5mZZTAkaQgGJmfMxig2SwvvMZxWVOkhkHpnBft+sI0Q7QMIRqLi7FAa48pTiXSt7Zz AmM5N6CcAE7XQ/QG0Cbb2j6m4B6RDbDyveYRmM55u1kQOG5g+ATwZRwwzbYplfgn4FzGV6F2961 JJ5xYeHuQGF6c5jjN6CdCPmkf03jhlHT4lIEIKUpdEjdVXRg1rGB8LiBZK3BRGcH7MnruZBqcQg nqohU2QSCdv8OXnqJQ+adbIlsFSEIbpRl0yPk5P1psZL5CgOVMxG1DownZz9L0A9DcESvQgdWxt b8Q0eLKcP05UXJsfKBg== X-Proofpoint-ORIG-GUID: O5Sn7w471WUjf43_74C1jzyTH23sB0wl X-Proofpoint-GUID: O5Sn7w471WUjf43_74C1jzyTH23sB0wl X-Authority-Analysis: v=2.4 cv=baVbluPB c=1 sm=1 tr=0 ts=6a957f8f cx=c_pps a=rEv8fa4AjpPjGxpoe8rlIQ==:117 a=rEv8fa4AjpPjGxpoe8rlIQ==:17 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=l0iWHRpgs5sLHlkKQ1IR:22 a=EAYMVhzMl8SCOHhVQcBL:22 a=M5GUcnROAAAA:8 a=ODqplUojrltCzwWjIakA:9 a=O8hF6Hzn-FEA:10 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-Spam-Info: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfX5gNJTajLKujk w9znKJKc/+/KkXVv00wkpVyBlfmjzAuxLe0BZvfJ9l5W0iHD4+OrjHV/VQ8yzocesoUIvnIzkTr XOmH7QFgKqX5Tbm5ehUxwFI19BkPtLk= X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-31_04,2026-08-27_02,2025-10-01_01 Content-Type: text/plain; charset="utf-8" The representor enables switch mode via devlink; register and unregister the switch notifier blocks when that mode is turned on or off so the PF can observe FIB routes, neighbour updates, IPv4/IPv6 address changes, netdev state, and switchdev FDB notifications. Add sw_nb_v4.c and sw_nb_v6.c for IPv4 and IPv6-specific handling, build sw_nb_v6.o only when CONFIG_IPV6 is set, and extend sw_nb.c with device filtering for Cavium ports behind bridges and VLANs. Initialize and tear down the existing sw_fdb, sw_fib, and sw_fl helpers together with notifier registration. Signed-off-by: Ratheesh Kannoth --- .../ethernet/marvell/octeontx2/nic/Makefile | 13 +- .../net/ethernet/marvell/octeontx2/nic/rep.c | 45 +- .../marvell/octeontx2/nic/switch/sw_nb.c | 541 +++++++++++++++++- .../marvell/octeontx2/nic/switch/sw_nb.h | 37 +- .../marvell/octeontx2/nic/switch/sw_nb_v4.c | 360 ++++++++++++ .../marvell/octeontx2/nic/switch/sw_nb_v4.h | 21 + .../marvell/octeontx2/nic/switch/sw_nb_v6.c | 301 ++++++++++ .../marvell/octeontx2/nic/switch/sw_nb_v6.h | 21 + 8 files changed, 1330 insertions(+), 9 deletions(-) create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb= _v4.c create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb= _v4.h create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb= _v6.c create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb= _v6.h diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile b/drivers/= net/ethernet/marvell/octeontx2/nic/Makefile index 27590b94133b..6050228be067 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile +++ b/drivers/net/ethernet/marvell/octeontx2/nic/Makefile @@ -11,7 +11,18 @@ rvu_nicpf-y :=3D otx2_pf.o otx2_common.o otx2_txrx.o otx= 2_ethtool.o \ otx2_flows.o otx2_tc.o cn10k.o cn20k.o otx2_dmac_flt.o \ otx2_devlink.o qos_sq.o qos.o otx2_xsk.o switch/sw_fdb.o \ switch/sw_fl.o -rvu_nicpf-$(CONFIG_OCTEONTX_SWITCH) +=3D switch/sw_nb.o switch/sw_fib.o +rvu_nicpf-$(CONFIG_OCTEONTX_SWITCH) +=3D switch/sw_nb.o switch/sw_fib.o \ + switch/sw_nb_v4.o +# sw_nb_v6.o calls IPv6 symbols exported by the ipv6 module; only link it +# when those symbols are reachable (IPv6 built-in, or both driver and IPv6 +# are modules). +ifeq ($(CONFIG_IPV6),y) +rvu_nicpf-$(CONFIG_OCTEONTX_SWITCH) +=3D switch/sw_nb_v6.o +else ifneq ($(CONFIG_IPV6),) +ifeq ($(CONFIG_OCTEONTX2_PF),m) +rvu_nicpf-$(CONFIG_OCTEONTX_SWITCH) +=3D switch/sw_nb_v6.o +endif +endif =20 rvu_nicvf-y :=3D otx2_vf.o rvu_rep-y :=3D rep.o diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c b/drivers/net= /ethernet/marvell/octeontx2/nic/rep.c index 257a2ae6a53e..96ec58c50843 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c @@ -15,6 +15,7 @@ #include "cn10k.h" #include "otx2_reg.h" #include "rep.h" +#include "switch/sw_nb.h" =20 #define DRV_NAME "rvu_rep" #define DRV_STRING "Marvell RVU Representor Driver" @@ -399,22 +400,62 @@ static void rvu_rep_get_stats64(struct net_device *de= v, =20 static int rvu_eswitch_config(struct otx2_nic *priv, u8 ena) { +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) + struct net_device *netdev =3D priv->netdev; +#endif struct devlink_port_attrs attrs =3D {}; struct esw_cfg_req *req; + int mbox_err; +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) + int err; +#endif =20 rvu_rep_devlink_set_switch_id(priv, &attrs.switch_id); =20 +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) + /* Disable unregisters PF notifiers before ESW_CFG clears rep_mode on + * the AF. unregister_*_notifier() removes each block synchronously, + * so there is no window where the AF considers the eswitch off while + * sw_nb_* handlers remain registered and could still send mailbox + * traffic (that race existed only when disable ran after the mailbox). + */ + if (ena) { + err =3D otx2_sw_nb_register(netdev); + if (err) + return err; + } else { + /* TODO: On disable, notifiers are unregistered before ESW_CFG. If + * mailbox allocation fails below, restore otx2_sw_nb_register() + * so software notifiers are not abandoned while hardware remains + * in eswitch mode. + */ + err =3D otx2_sw_nb_unregister(netdev); + if (err) + return err; + } +#endif + mutex_lock(&priv->mbox.lock); req =3D otx2_mbox_alloc_msg_esw_cfg(&priv->mbox); if (!req) { mutex_unlock(&priv->mbox.lock); +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) + if (ena) + otx2_sw_nb_unregister(netdev); +#endif return -ENOMEM; } req->ena =3D ena; memcpy(req->switch_id, attrs.switch_id.id, attrs.switch_id.id_len); - otx2_sync_mbox_msg(&priv->mbox); + mbox_err =3D otx2_sync_mbox_msg(&priv->mbox); mutex_unlock(&priv->mbox.lock); - return 0; + +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) + if (ena && mbox_err) + otx2_sw_nb_unregister(netdev); +#endif + + return mbox_err; } =20 static netdev_tx_t rvu_rep_xmit(struct sk_buff *skb, struct net_device *de= v) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c b/dr= ivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c index 426a42011930..b51d8d2d01b8 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c @@ -4,18 +4,555 @@ * Copyright (C) 2026 Marvell. * */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../otx2_reg.h" +#include "../otx2_common.h" +#include "../otx2_struct.h" +#include "../cn10k.h" #include "sw_nb.h" +#include "sw_fdb.h" +#include "sw_fib.h" +#include "sw_fl.h" +#include "sw_nb_v4.h" +#include "sw_nb_v6.h" =20 #if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) =20 -int otx2_sw_nb_unregister(void) +/* PF netdev for netdev_* logging when notifier info has no device */ +static struct net_device *sw_nb_pf_netdev; +/* Notifier registration is toggled only from rvu_eswitch_config(), which = is + * reached exclusively when switchdev mode is enabled on the RVU eswitch + * representor PF (PCI_DEVID_RVU_REP). The sole call path is: + * + * DEVLINK_CMD_ESWITCH_MODE_SET + * -> otx2_devlink_eswitch_mode_set() [otx2_rep_dev() only] + * -> rvu_rep_create() / rvu_rep_destroy() + * -> rvu_eswitch_config(ena =3D 1) -> otx2_sw_nb_register() + * -> rvu_eswitch_config(ena =3D 0) -> otx2_sw_nb_unregister() + * + * On disable, otx2_sw_nb_unregister() runs before the ESW_CFG mailbox so = flush + * paths in sw_fdb/fib/fl_deinit() can still reach hardware. + * + * Other OcteonTX2 netdev PFs/VFs also have a devlink, but their + * eswitch_mode_set handler returns -EOPNOTSUPP. The AF rvu_devlink + * eswitch_mode_set does not register these notifiers. There is exactly + * one RVU_REP PCI function (and netdev devlink) per RVU, and devlink + * core holds devlink->lock for the full DEVLINK_CMD_ESWITCH_MODE_SET + * handler, so this path cannot run concurrently on the same device. + * otx2_sw_nb_registered further ensures at most one active registration. + */ +static bool otx2_sw_nb_registered; + +static const char *sw_nb_cmd2str[OTX2_CMD_MAX] =3D { + [OTX2_DEV_UP] =3D "OTX2_DEV_UP", + [OTX2_DEV_DOWN] =3D "OTX2_DEV_DOWN", + [OTX2_DEV_CHANGE] =3D "OTX2_DEV_CHANGE", + [OTX2_NEIGH_UPDATE] =3D "OTX2_NEIGH_UPDATE", + [OTX2_FIB_ENTRY_REPLACE] =3D "OTX2_FIB_ENTRY_REPLACE", + [OTX2_FIB_ENTRY_ADD] =3D "OTX2_FIB_ENTRY_ADD", + [OTX2_FIB_ENTRY_DEL] =3D "OTX2_FIB_ENTRY_DEL", + [OTX2_FIB_ENTRY_APPEND] =3D "OTX2_FIB_ENTRY_APPEND", +}; + +const char *sw_nb_get_cmd2str(int cmd) +{ + return sw_nb_cmd2str[cmd]; +} +EXPORT_SYMBOL(sw_nb_get_cmd2str); + +bool sw_nb_is_cavium_dev(struct net_device *netdev) +{ + struct pci_dev *pdev; + struct device *dev; + + dev =3D netdev->dev.parent; + if (!dev || dev->bus !=3D &pci_bus_type) + return false; + + pdev =3D to_pci_dev(dev); + if (pdev->vendor !=3D PCI_VENDOR_ID_CAVIUM) + return false; + + return true; +} + +/* Resolve the Cavium PF netdev used to reach the switch AF for offload. + * + * For a bridge master netdev, any Cavium netdev enslaved to the bridge is + * sufficient: callers only need a PF netdev to obtain the switch AF mailb= ox + * context (pcifunc). Bridge-specific information is tagged separately in + * the offload entry (entry->bridge), so walking every lower netdev is not + * required here. + * + * Only a single level of netdev nesting is resolved (bridge lower dev or + * VLAN real dev). Nested topologies such as VLAN-over-bridge are not + * supported; offload will not work for those configurations. + */ +struct net_device *sw_nb_resolve_pf_dev(struct net_device *dev) +{ + struct net_device *pf_dev =3D dev; + struct list_head *iter; + + rcu_read_lock(); + + if (netif_is_bridge_master(dev)) { + iter =3D &dev->adj_list.lower; + pf_dev =3D netdev_next_lower_dev_rcu(dev, &iter); + if (!pf_dev) + pf_dev =3D dev; + } else if (is_vlan_dev(dev)) { + pf_dev =3D vlan_dev_real_dev(dev); + } + + rcu_read_unlock(); + + if (!sw_nb_is_cavium_dev(pf_dev)) + return NULL; + + return pf_dev; +} + +static int sw_nb_check_slaves(struct net_device *dev, + struct netdev_nested_priv *priv) { + int *cnt; + + if (!priv->flags) + return 0; + + priv->flags &=3D sw_nb_is_cavium_dev(dev); + if (priv->flags) { + cnt =3D priv->data; + (*cnt)++; + } + return 0; } =20 -int otx2_sw_nb_register(void) +/* Switch offload has no network namespace support. The global notifiers + * registered below are not scoped to a netns, and sw_nb_is_cavium_dev() + * matches any Cavium PCI netdev without checking dev_net(). All netdevs + * involved in offload (PF/VF ports, bridge members, VLANs, neighbours, + * and routes) must therefore reside in &init_net for offload to work. + */ +bool sw_nb_is_valid_dev(struct net_device *netdev) +{ + struct netdev_nested_priv priv; + struct net_device *br; + int cnt =3D 0; + bool valid; + + priv.flags =3D true; + priv.data =3D &cnt; + + rcu_read_lock(); + + if (netif_is_bridge_master(netdev) || is_vlan_dev(netdev)) { + netdev_walk_all_lower_dev_rcu(netdev, sw_nb_check_slaves, &priv); + valid =3D priv.flags && cnt; + rcu_read_unlock(); + return valid; + } + + if (netif_is_bridge_port(netdev)) { + br =3D netdev_master_upper_dev_get_rcu(netdev); + if (!br) { + rcu_read_unlock(); + return false; + } + netdev_walk_all_lower_dev_rcu(br, sw_nb_check_slaves, &priv); + valid =3D priv.flags && cnt; + rcu_read_unlock(); + return valid; + } + + rcu_read_unlock(); + + return sw_nb_is_cavium_dev(netdev); +} + +static int sw_nb_fdb_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev =3D switchdev_notifier_info_to_dev(ptr); + struct switchdev_notifier_fdb_info *fdb_info =3D ptr; + + if (!sw_nb_is_valid_dev(dev)) + return NOTIFY_DONE; + + switch (event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + if (fdb_info->is_local) + break; + break; + + case SWITCHDEV_FDB_DEL_TO_DEVICE: + if (fdb_info->is_local) + break; + break; + + default: + return NOTIFY_DONE; + } + + return NOTIFY_DONE; +} + +static struct notifier_block sw_nb_fdb =3D { + .notifier_call =3D sw_nb_fdb_event, +}; + +static void __maybe_unused +sw_nb_fib_event_dump(unsigned long event, void *ptr) +{ + struct fib_entry_notifier_info *fen_info =3D ptr; + struct net_device *log_dev; + struct fib_nh *fib_nh; + struct fib_info *fi; + int i; + + fi =3D fen_info->fi; + log_dev =3D (fi && fi->fib_nhs) ? fi->fib_nh->fib_nh_dev : sw_nb_pf_netde= v; + if (log_dev) + netdev_info(log_dev, "%s: FIB event=3D%lu dst=3D%pI4h dstlen=3D%d type= =3D%u\n", + __func__, event, &fen_info->dst, fen_info->dst_len, + fen_info->type); + + if (!fi) + return; + + fib_nh =3D fi->fib_nh; + for (i =3D 0; i < fi->fib_nhs; i++, fib_nh++) { + if (!fib_nh->fib_nh_dev) + continue; + netdev_info(fib_nh->fib_nh_dev, + "%s: dev=3D%s saddr=3D%pI4n gw=3D%pI4n\n", + __func__, fib_nh->fib_nh_dev->name, + &fib_nh->nh_saddr, &fib_nh->fib_nh_gw4); + } +} + +#define SWITCH_NB_FIB_EVENT_DUMP(...) \ + sw_nb_fib_event_dump(__VA_ARGS__) + +int sw_nb_fib_event_to_otx2_event(int event, struct net_device *netdev) +{ + switch (event) { + case FIB_EVENT_ENTRY_REPLACE: + return OTX2_FIB_ENTRY_REPLACE; + case FIB_EVENT_ENTRY_ADD: + return OTX2_FIB_ENTRY_ADD; + case FIB_EVENT_ENTRY_DEL: + return OTX2_FIB_ENTRY_DEL; + default: + break; + } + + netdev_err(netdev, "Wrong FIB event %d\n", event); + return -1; +} + +static int sw_nb_fib_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct fib_notifier_info *info =3D ptr; + + switch (event) { + case FIB_EVENT_ENTRY_REPLACE: + case FIB_EVENT_ENTRY_ADD: + case FIB_EVENT_ENTRY_DEL: + break; + default: + if (sw_nb_pf_netdev) + netdev_dbg(sw_nb_pf_netdev, + "%s: Won't process FIB event %lu\n", + __func__, event); + return NOTIFY_DONE; + } + + switch (info->family) { + case AF_INET: + return sw_nb_v4_fib_event(nb, event, ptr); +#if IS_REACHABLE(CONFIG_IPV6) + case AF_INET6: + return sw_nb_v6_fib_event(nb, event, ptr); +#endif + default: + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block sw_nb_fib =3D { + .notifier_call =3D sw_nb_fib_event, +}; + +static int sw_nb_net_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct neighbour *n =3D ptr; + + if (!sw_nb_is_valid_dev(n->dev)) + return NOTIFY_DONE; + + if (event !=3D NETEVENT_NEIGH_UPDATE) + return NOTIFY_DONE; + + switch (n->tbl->family) { + case AF_INET: + return sw_nb_net_v4_neigh_update(nb, event, ptr); +#if IS_REACHABLE(CONFIG_IPV6) + case AF_INET6: + return sw_nb_net_v6_neigh_update(nb, event, ptr); +#endif + default: + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block sw_nb_netevent =3D { + .notifier_call =3D sw_nb_net_event, + +}; + +int sw_nb_inetaddr_event_to_otx2_event(int event, struct net_device *netde= v) +{ + switch (event) { + case NETDEV_CHANGE: + return OTX2_DEV_CHANGE; + case NETDEV_UP: + return OTX2_DEV_UP; + case NETDEV_DOWN: + return OTX2_DEV_DOWN; + default: + break; + } + netdev_dbg(netdev, "%s: Wrong interaddr event %d\n", + __func__, event); + return -1; +} + +static struct notifier_block sw_nb_v4_inetaddr =3D { + .notifier_call =3D sw_nb_v4_inetaddr_event, +}; + +#if IS_REACHABLE(CONFIG_IPV6) +static struct notifier_block sw_nb_v6_inetaddr =3D { + .notifier_call =3D sw_nb_v6_inetaddr_event, +}; +#endif + +static int sw_nb_netdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev =3D netdev_notifier_info_to_dev(ptr); + struct in_device *idev; + struct inet6_dev *i6dev; + + if (event !=3D NETDEV_CHANGE && + event !=3D NETDEV_UP && + event !=3D NETDEV_DOWN) { + return NOTIFY_DONE; + } + + if (!sw_nb_is_valid_dev(dev)) + return NOTIFY_DONE; + + idev =3D __in_dev_get_rtnl(dev); + if (idev) + sw_nb_v4_netdev_event(unused, event, ptr); + +#if IS_REACHABLE(CONFIG_IPV6) + i6dev =3D __in6_dev_get(dev); + if (i6dev) + sw_nb_v6_netdev_event(unused, event, ptr); +#endif + + return NOTIFY_DONE; +} + +static struct notifier_block sw_nb_netdev =3D { + .notifier_call =3D sw_nb_netdev_event, +}; + +int otx2_sw_nb_unregister(struct net_device *netdev) +{ + int err, ret =3D 0; + + if (!otx2_sw_nb_registered) + return 0; + + err =3D unregister_switchdev_notifier(&sw_nb_fdb); + if (err) { + netdev_err(netdev, "Failed to unregister switchdev nb\n"); + ret =3D err; + } + + err =3D unregister_fib_notifier(&init_net, &sw_nb_fib); + if (err) { + netdev_err(netdev, "Failed to unregister fib nb\n"); + if (!ret) + ret =3D err; + } + + err =3D unregister_netevent_notifier(&sw_nb_netevent); + if (err) { + netdev_err(netdev, "Failed to unregister netevent\n"); + if (!ret) + ret =3D err; + } + + err =3D unregister_inetaddr_notifier(&sw_nb_v4_inetaddr); + if (err) { + netdev_err(netdev, "Failed to unregister addr event\n"); + if (!ret) + ret =3D err; + } + +#if IS_REACHABLE(CONFIG_IPV6) + err =3D unregister_inet6addr_notifier(&sw_nb_v6_inetaddr); + if (err) { + netdev_err(netdev, "Failed to unregister addr event\n"); + if (!ret) + ret =3D err; + } +#endif + + err =3D unregister_netdevice_notifier(&sw_nb_netdev); + if (err) { + netdev_err(netdev, "Failed to unregister netdev notifier\n"); + if (!ret) + ret =3D err; + } + + sw_fl_deinit(); + otx2_sw_fib_deinit(); + sw_fdb_deinit(); + + sw_nb_pf_netdev =3D NULL; + otx2_sw_nb_registered =3D false; + + return ret; +} +EXPORT_SYMBOL(otx2_sw_nb_unregister); + +/* Concurrent registration from multiple devlink instances cannot occur on= a + * given RVU: only the RVU_REP netdev devlink reaches this function (see + * comment above). The AF and PF/VF devlinks do not call otx2_sw_nb_regist= er(), + * and their eswitch_mode_set handlers return -EOPNOTSUPP. devlink core + * holds devlink->lock for the full DEVLINK_CMD_ESWITCH_MODE_SET handler, + * so two threads cannot enter here concurrently on that single rep devlin= k. + * A second call after successful registration returns -EBUSY before any + * notifier or workqueue state is modified. + */ +int otx2_sw_nb_register(struct net_device *netdev) { + int err; + + /* Notifier blocks are global and only one RVU_REP may register at a + * time (switch offload is init_net-wide; see comment at file top). + * A second RVU card gets -EBUSY here by design. Concurrent calls on + * the same RVU_REP cannot happen: only that netdev's devlink reaches + * this function (otx2_rep_dev()), and devlink core holds + * devlink->lock for the full DEVLINK_CMD_ESWITCH_MODE_SET handler. + * No extra lock is needed to protect the notifier chains. + */ + if (otx2_sw_nb_registered) + return -EBUSY; + + sw_nb_pf_netdev =3D netdev; + + err =3D sw_fdb_init(); + if (err) + goto err_clear; + + err =3D otx2_sw_fib_init(); + if (err) + goto err_fdb; + + err =3D sw_fl_init(); + if (err) + goto err_fib; + + err =3D register_switchdev_notifier(&sw_nb_fdb); + if (err) { + netdev_err(netdev, "Failed to register switchdev nb\n"); + goto err_helpers; + } + + err =3D register_fib_notifier(&init_net, &sw_nb_fib, NULL, NULL); + if (err) { + netdev_err(netdev, "Failed to register fb notifier block\n"); + goto err1; + } + + err =3D register_netevent_notifier(&sw_nb_netevent); + if (err) { + netdev_err(netdev, "Failed to register netevent\n"); + goto err2; + } + +#if IS_REACHABLE(CONFIG_IPV6) + err =3D register_inet6addr_notifier(&sw_nb_v6_inetaddr); + if (err) { + netdev_err(netdev, "Failed to register addr event\n"); + goto err3; + } +#endif + + err =3D register_inetaddr_notifier(&sw_nb_v4_inetaddr); + if (err) { + netdev_err(netdev, "Failed to register addr event\n"); + goto err4; + } + + err =3D register_netdevice_notifier(&sw_nb_netdev); + if (err) { + netdev_err(netdev, "Failed to register netdevice nb\n"); + goto err5; + } + + otx2_sw_nb_registered =3D true; + return 0; + +err5: + unregister_inetaddr_notifier(&sw_nb_v4_inetaddr); + +err4: +#if IS_REACHABLE(CONFIG_IPV6) + unregister_inet6addr_notifier(&sw_nb_v6_inetaddr); + +err3: +#endif + unregister_netevent_notifier(&sw_nb_netevent); + +err2: + unregister_fib_notifier(&init_net, &sw_nb_fib); + +err1: + unregister_switchdev_notifier(&sw_nb_fdb); + +err_helpers: + sw_fl_deinit(); +err_fib: + otx2_sw_fib_deinit(); +err_fdb: + sw_fdb_deinit(); +err_clear: + sw_nb_pf_netdev =3D NULL; + return err; } +EXPORT_SYMBOL(otx2_sw_nb_register); =20 #endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.h b/dr= ivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.h index 0ba29f76fd41..39435f23427c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.h @@ -9,12 +9,41 @@ =20 #include =20 +struct net_device; +struct otx2_nic; +struct af2pf_fdb_refresh_req; +struct msg_rsp; + #if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) -int otx2_sw_nb_register(void); -int otx2_sw_nb_unregister(void); +enum { + OTX2_DEV_UP =3D 1, + OTX2_DEV_DOWN, + OTX2_DEV_CHANGE, + OTX2_NEIGH_UPDATE, + OTX2_FIB_ENTRY_REPLACE, + OTX2_FIB_ENTRY_ADD, + OTX2_FIB_ENTRY_DEL, + OTX2_FIB_ENTRY_APPEND, + OTX2_CMD_MAX, +}; + +int otx2_sw_nb_register(struct net_device *netdev); +int otx2_sw_nb_unregister(struct net_device *netdev); +bool sw_nb_is_valid_dev(struct net_device *netdev); +struct net_device *sw_nb_resolve_pf_dev(struct net_device *dev); + +int otx2_mbox_up_handler_af2pf_fdb_refresh(struct otx2_nic *pf, + struct af2pf_fdb_refresh_req *req, + struct msg_rsp *rsp); + +bool sw_nb_is_cavium_dev(struct net_device *netdev); +int sw_nb_fib_event_to_otx2_event(int event, struct net_device *netdev); +int sw_nb_inetaddr_event_to_otx2_event(int event, struct net_device *netde= v); + +const char *sw_nb_get_cmd2str(int cmd); #else -static inline int otx2_sw_nb_register(void) { return 0; } -static inline int otx2_sw_nb_unregister(void) { return 0; } +static inline int otx2_sw_nb_register(struct net_device *netdev) { return = 0; } +static inline int otx2_sw_nb_unregister(struct net_device *netdev) { retur= n 0; } #endif =20 #endif /* SW_NB_H_ */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v4.c b= /drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v4.c new file mode 100644 index 000000000000..31009e00121f --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v4.c @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU switch driver + * + * Copyright (C) 2026 Marvell. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../otx2_reg.h" +#include "../otx2_common.h" +#include "../otx2_struct.h" +#include "../cn10k.h" +#include "sw_nb.h" +#include "sw_fdb.h" +#include "sw_fib.h" +#include "sw_fl.h" +#include "sw_nb_v4.h" + +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) + +int sw_nb_v4_netdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev =3D netdev_notifier_info_to_dev(ptr); + struct netdev_hw_addr *dev_addr; + struct net_device *pf_dev; + struct in_device *idev; + struct in_ifaddr *ifa; + struct fib_entry *entry; + struct otx2_nic *pf; + + if (!sw_nb_is_valid_dev(dev)) + return NOTIFY_DONE; + + idev =3D __in_dev_get_rtnl(dev); + if (!idev || !idev->ifa_list) + return NOTIFY_DONE; + + /* Switch offload supports a single IPv4 address per interface for now. */ + ifa =3D rtnl_dereference(idev->ifa_list); + + entry =3D kcalloc(1, sizeof(*entry), GFP_KERNEL); + if (!entry) + return NOTIFY_DONE; + + entry->cmd =3D sw_nb_inetaddr_event_to_otx2_event(event, dev); + entry->dst =3D ifa->ifa_address; + entry->dst_len =3D 32; + entry->mac_valid =3D 1; + entry->host =3D 1; + + pf_dev =3D sw_nb_resolve_pf_dev(dev); + if (!pf_dev) { + kfree(entry); + return NOTIFY_DONE; + } + + if (netif_is_bridge_master(dev)) { + entry->bridge =3D 1; + } else if (is_vlan_dev(dev)) { + entry->vlan_valid =3D 1; + entry->vlan_tag =3D cpu_to_be16(vlan_dev_vlan_id(dev)); + } + + pf =3D netdev_priv(pf_dev); + entry->port_id =3D pf->pcifunc; + + rcu_read_lock(); + for_each_dev_addr(dev, dev_addr) { + ether_addr_copy(entry->mac, dev_addr->addr); + break; + } + rcu_read_unlock(); + + netdev_dbg(dev, "%s: pushing netdev event from HOST interface address %pI= 4n, %pM, dev=3D%s\n", + __func__, &entry->dst, entry->mac, dev->name); + kfree(entry); + + return NOTIFY_DONE; +} + +int sw_nb_v4_inetaddr_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct in_ifaddr *ifa =3D (struct in_ifaddr *)ptr; + struct net_device *dev =3D ifa->ifa_dev->dev; + struct netdev_hw_addr *dev_addr; + struct net_device *pf_dev; + struct fib_entry *entry; + struct otx2_nic *pf; + + if (event !=3D NETDEV_CHANGE && + event !=3D NETDEV_UP && + event !=3D NETDEV_DOWN) { + return NOTIFY_DONE; + } + + if (!sw_nb_is_valid_dev(dev)) + return NOTIFY_DONE; + + /* On NETDEV_DOWN the deleted address is passed in ifa; ifa_list may + * already be empty when the last address is removed. + */ + entry =3D kcalloc(1, sizeof(*entry), GFP_ATOMIC); + if (!entry) + return NOTIFY_DONE; + + entry->cmd =3D sw_nb_inetaddr_event_to_otx2_event(event, dev); + entry->dst =3D ifa->ifa_address; + entry->dst_len =3D 32; + entry->mac_valid =3D 1; + entry->host =3D 1; + + pf_dev =3D sw_nb_resolve_pf_dev(dev); + if (!pf_dev) { + kfree(entry); + return NOTIFY_DONE; + } + + if (netif_is_bridge_master(dev)) { + entry->bridge =3D 1; + } else if (is_vlan_dev(dev)) { + entry->vlan_valid =3D 1; + entry->vlan_tag =3D cpu_to_be16(vlan_dev_vlan_id(dev)); + } + + pf =3D netdev_priv(pf_dev); + entry->port_id =3D pf->pcifunc; + + rcu_read_lock(); + for_each_dev_addr(dev, dev_addr) { + ether_addr_copy(entry->mac, dev_addr->addr); + break; + } + rcu_read_unlock(); + + netdev_dbg(dev, "%s: pushing inetaddr event from HOST interface address %= pI4n, %pM, %s\n", + __func__, &entry->dst, entry->mac, dev->name); + + kfree(entry); + return NOTIFY_DONE; +} + +int sw_nb_v4_fib_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct net_device *dev, *pf_dev =3D NULL, *nh_pf_dev; + struct fib_entry_notifier_info *fen_info =3D ptr; + struct fib_entry *entries, *iter; + struct netdev_hw_addr *dev_addr; + struct neighbour *neigh; + struct fib_nh *fib_nh; + struct fib_info *fi; + struct otx2_nic *pf; + __be32 *haddr; + int hcnt =3D 0; + int cnt, i; + + /* Process only UNICAST routes add or del */ + if (fen_info->type !=3D RTN_UNICAST) + return NOTIFY_DONE; + + fi =3D fen_info->fi; + if (!fi) + return NOTIFY_DONE; + + if (fi->fib_nh_is_v6) { + struct net_device *log_dev =3D (fi->fib_nhs > 0) ? + fi->fib_nh->fib_nh_dev : NULL; + + if (log_dev) + netdev_dbg(log_dev, "%s: Received v6 notification\n", + __func__); + return NOTIFY_DONE; + } + + /* TODO: External nexthop routes (fi->nh set, fi->fib_nhs =3D=3D 0) are n= ot + * yet supported for switch offload. Only embedded fi->fib_nh[] paths + * are walked below; nhid and nexthop-group installs are intentionally + * skipped until fib_info_num_path()/fib_info_nhc() handling is added. + */ + entries =3D kcalloc(fi->fib_nhs, sizeof(*entries), GFP_ATOMIC); + if (!entries) + return NOTIFY_DONE; + + haddr =3D kcalloc(fi->fib_nhs, sizeof(*haddr), GFP_ATOMIC); + if (!haddr) { + kfree(entries); + return NOTIFY_DONE; + } + + iter =3D entries; + fib_nh =3D fi->fib_nh; + for (i =3D 0; i < fi->fib_nhs; i++, fib_nh++) { + dev =3D fib_nh->fib_nh_dev; + + if (!dev) + continue; + + if (dev->type !=3D ARPHRD_ETHER) + continue; + + if (!sw_nb_is_valid_dev(dev)) + continue; + + iter->cmd =3D sw_nb_fib_event_to_otx2_event(event, dev); + iter->dst =3D htonl(fen_info->dst); + iter->dst_len =3D fen_info->dst_len; + iter->gw =3D fib_nh->fib_nh_gw4; + + netdev_dbg(dev, "%s: FIB route Rule cmd=3D%llu dst=3D%pI4n dst_len=3D%u = gw=3D%pI4n\n", + __func__, iter->cmd, &iter->dst, iter->dst_len, &iter->gw); + + nh_pf_dev =3D sw_nb_resolve_pf_dev(dev); + if (!nh_pf_dev) + continue; + pf_dev =3D nh_pf_dev; + + if (netif_is_bridge_master(dev)) { + iter->bridge =3D 1; + } else if (is_vlan_dev(dev)) { + iter->vlan_valid =3D 1; + iter->vlan_tag =3D cpu_to_be16(vlan_dev_vlan_id(dev)); + } + + pf =3D netdev_priv(pf_dev); + iter->port_id =3D pf->pcifunc; + + /* Point-to-point routes, including default routes with no + * gateway, are not supported for switch offload. + */ + if (!fib_nh->fib_nh_gw4) + continue; + iter->gw_valid =3D 1; + + if (fib_nh->nh_saddr) + haddr[hcnt++] =3D fib_nh->nh_saddr; + + rcu_read_lock(); + neigh =3D ip_neigh_gw4(fib_nh->fib_nh_dev, fib_nh->fib_nh_gw4); + if (!neigh || IS_ERR(neigh)) { + rcu_read_unlock(); + continue; + } + + neigh_ha_snapshot(iter->mac, neigh, fib_nh->fib_nh_dev); + if (is_valid_ether_addr(iter->mac)) + iter->mac_valid =3D 1; + + iter++; + rcu_read_unlock(); + } + + cnt =3D iter - entries; + if (!cnt) { + kfree(entries); + kfree(haddr); + return NOTIFY_DONE; + } + + if (pf_dev) + netdev_dbg(pf_dev, "pf_dev is %s cnt=3D%d\n", pf_dev->name, cnt); + kfree(entries); + + if (!hcnt) { + kfree(haddr); + return NOTIFY_DONE; + } + + if (!pf_dev) { + kfree(haddr); + return NOTIFY_DONE; + } + + entries =3D kcalloc(hcnt, sizeof(*entries), GFP_ATOMIC); + if (!entries) { + kfree(haddr); + return NOTIFY_DONE; + } + + iter =3D entries; + + /* Host routes reuse pf_dev/pf from the last resolved Cavium netdev: + * pf_dev only identifies the switch AF mailbox context for switchdev + * programming; any previously resolved Cavium netdev is sufficient. + */ + for (i =3D 0; i < hcnt; i++, iter++) { + iter->cmd =3D sw_nb_fib_event_to_otx2_event(event, pf_dev); + iter->dst =3D haddr[i]; + iter->dst_len =3D 32; + iter->mac_valid =3D 1; + iter->host =3D 1; + iter->port_id =3D pf->pcifunc; + + rcu_read_lock(); + for_each_dev_addr(pf_dev, dev_addr) { + ether_addr_copy(iter->mac, dev_addr->addr); + break; + } + rcu_read_unlock(); + + netdev_dbg(pf_dev, "%s: FIB host Rule cmd=3D%llu dst=3D%pI4n dst_len=3D%= u %s\n", + __func__, iter->cmd, &iter->dst, iter->dst_len, + pf_dev->name); + } + kfree(entries); + kfree(haddr); + return NOTIFY_DONE; +} + +int sw_nb_net_v4_neigh_update(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct net_device *pf_dev; + struct neighbour *n =3D ptr; + struct fib_entry *entry; + struct otx2_nic *pf; + + if (n->tbl !=3D &arp_tbl) + return NOTIFY_DONE; + + entry =3D kcalloc(1, sizeof(*entry), GFP_ATOMIC); + if (!entry) + return NOTIFY_DONE; + + entry->cmd =3D OTX2_NEIGH_UPDATE; + entry->dst =3D *(__be32 *)n->primary_key; + entry->dst_len =3D n->tbl->key_len * 8; + entry->mac_valid =3D 1; + entry->nud_state =3D n->nud_state; + neigh_ha_snapshot(entry->mac, n, n->dev); + + pf_dev =3D sw_nb_resolve_pf_dev(n->dev); + if (!pf_dev) { + kfree(entry); + return NOTIFY_DONE; + } + + if (netif_is_bridge_master(n->dev)) { + entry->bridge =3D 1; + } else if (is_vlan_dev(n->dev)) { + entry->vlan_valid =3D 1; + entry->vlan_tag =3D cpu_to_be16(vlan_dev_vlan_id(n->dev)); + } + + pf =3D netdev_priv(pf_dev); + entry->port_id =3D pf->pcifunc; + + kfree(entry); + return NOTIFY_DONE; +} + +#endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v4.h b= /drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v4.h new file mode 100644 index 000000000000..c6dbf4b93a9a --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v4.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell switch driver + * + * Copyright (C) 2026 Marvell. + * + */ +#ifndef SW_NB_V4_H_ +#define SW_NB_V4_H_ + +int sw_nb_v4_fib_event(struct notifier_block *nb, + unsigned long event, void *ptr); + +int sw_nb_net_v4_neigh_update(struct notifier_block *nb, + unsigned long event, void *ptr); + +int sw_nb_v4_inetaddr_event(struct notifier_block *nb, + unsigned long event, void *ptr); + +int sw_nb_v4_netdev_event(struct notifier_block *unused, + unsigned long event, void *ptr); +#endif // SW_NB_V4_H__ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v6.c b= /drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v6.c new file mode 100644 index 000000000000..3497e60aedbe --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v6.c @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU switch driver + * + * Copyright (C) 2026 Marvell. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../otx2_reg.h" +#include "../otx2_common.h" +#include "../otx2_struct.h" +#include "../cn10k.h" +#include "sw_nb.h" +#include "sw_fdb.h" +#include "sw_fib.h" +#include "sw_fl.h" +#include "sw_nb_v6.h" + +#if IS_ENABLED(CONFIG_IPV6) && IS_ENABLED(CONFIG_OCTEONTX_SWITCH) + +int sw_nb_v6_netdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev =3D netdev_notifier_info_to_dev(ptr); + struct netdev_hw_addr *dev_addr; + struct net_device *pf_dev; + struct inet6_ifaddr *ifp; + struct inet6_dev *i6dev; + struct fib_entry *entry; + struct in6_addr addr; + struct otx2_nic *pf; + bool found =3D false; + u32 prefix_len; + + i6dev =3D __in6_dev_get(dev); + if (!i6dev) + return NOTIFY_DONE; + + /* addr_list is RCU-protected; hold rcu_read_lock() while walking it. + * Address updates from SLAAC/DAD may occur under idev->lock without + * RTNL, so the list must be read with an RCU-safe helper. + */ + rcu_read_lock(); + /* Switch offload supports a single IPv6 address per interface for now. + * Skip link-local entries and use the first global address on the list. + */ + list_for_each_entry_rcu(ifp, &i6dev->addr_list, if_list) { + if (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL) + continue; + + addr =3D ifp->addr; + prefix_len =3D ifp->prefix_len; + found =3D true; + break; + } + rcu_read_unlock(); + + if (!found) + return NOTIFY_DONE; + + entry =3D kcalloc(1, sizeof(*entry), GFP_KERNEL); + if (!entry) + return NOTIFY_DONE; + + pf_dev =3D sw_nb_resolve_pf_dev(dev); + if (!pf_dev) { + kfree(entry); + return NOTIFY_DONE; + } + + entry->cmd =3D sw_nb_inetaddr_event_to_otx2_event(event, dev); + memcpy(entry->dst6, &addr, sizeof(entry->dst6)); + entry->dst6_plen =3D prefix_len; + entry->host =3D 1; + entry->ipv6 =3D 1; + + pf =3D netdev_priv(pf_dev); + entry->port_id =3D pf->pcifunc; + + rcu_read_lock(); + for_each_dev_addr(dev, dev_addr) { + entry->mac_valid =3D 1; + ether_addr_copy(entry->mac, dev_addr->addr); + break; + } + rcu_read_unlock(); + + netdev_dbg(dev, "netdev event addr=3D%pI6c plen=3D%u mac=3D%pM\n", + &addr, prefix_len, entry->mac); + kfree(entry); + return NOTIFY_DONE; +} + +int sw_nb_v6_fib_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct fib6_entry_notifier_info *f6_eni; + struct fib_notifier_info *info =3D ptr; + struct net_device *fib_dev, *pf_dev; + struct fib_entry *entry; + struct fib6_info *f6i; + struct neighbour *neigh; + struct fib6_nh *nh6; + struct rt6key *key; + struct otx2_nic *pf; + + f6_eni =3D container_of(info, struct fib6_entry_notifier_info, info); + f6i =3D f6_eni->rt; + + fib_dev =3D fib6_info_nh_dev(f6i); + + if (!fib_dev) + return NOTIFY_DONE; + + if (fib_dev->type !=3D ARPHRD_ETHER) + return NOTIFY_DONE; + + if (!sw_nb_is_valid_dev(fib_dev)) + return NOTIFY_DONE; + + if (f6i->fib6_type !=3D RTN_UNICAST) + return NOTIFY_DONE; + + key =3D &f6i->fib6_dst; + /* TODO: vlan and bridge support */ + if (ipv6_addr_type(&key->addr) & IPV6_ADDR_LINKLOCAL) + return NOTIFY_DONE; + + netdev_dbg(fib_dev, "fib6dst rt6key.addr=3D%pI6c len=3D%d\n", &key->addr, + key->plen); + + netdev_dbg(fib_dev, "fib6flags=3D%#x proto=3D%u type=3D%u\n", + f6i->fib6_flags, f6i->fib6_protocol, f6i->fib6_type); + + nh6 =3D f6i->nh ? nexthop_fib6_nh(f6i->nh) : f6i->fib6_nh; + if (nh6->fib_nh_gw_family !=3D AF_INET6) + return NOTIFY_DONE; + + netdev_dbg(nh6->fib_nh_dev ? nh6->fib_nh_dev : fib_dev, + "nh family=3D%u dev=3D%s gw=3D%pI6c gwfamily=3D%u\n", + nh6->fib_nh_family, + nh6->fib_nh_dev ? nh6->fib_nh_dev->name : "No dev", + &nh6->fib_nh_gw6, nh6->fib_nh_gw_family); + + pf_dev =3D sw_nb_resolve_pf_dev(fib_dev); + if (!pf_dev) + return NOTIFY_DONE; + + pf =3D netdev_priv(pf_dev); + + entry =3D kcalloc(1, sizeof(*entry), GFP_ATOMIC); + if (!entry) + return NOTIFY_DONE; + + entry->cmd =3D sw_nb_fib_event_to_otx2_event(event, fib_dev); + entry->ipv6 =3D 1; + entry->port_id =3D pf->pcifunc; + memcpy(entry->dst6, &key->addr, sizeof(entry->dst6)); + entry->dst6_plen =3D key->plen; + + memcpy(entry->gw6, &nh6->fib_nh_gw6, sizeof(nh6->fib_nh_gw6)); + entry->gw_valid =3D !!(ipv6_addr_type(&nh6->fib_nh_gw6) & IPV6_ADDR_UNICA= ST); + + /* TODO: No replay mechanism yet when the gateway neighbor is unresolved. + * If ip_neigh_gw6() returns NULL the route is skipped here; add replay + * from the neighbor update handler once nexthop resolution completes. + */ + rcu_read_lock(); + neigh =3D ip_neigh_gw6(fib_dev, &nh6->fib_nh_gw6); + if (!neigh || IS_ERR(neigh)) { + rcu_read_unlock(); + kfree(entry); + return NOTIFY_DONE; + } + + neigh_ha_snapshot(entry->mac, neigh, fib_dev); + if (is_valid_ether_addr(entry->mac)) { + entry->mac_valid =3D 1; + netdev_dbg(fib_dev, "fib found MAC=3D%pM\n", entry->mac); + } + + rcu_read_unlock(); + kfree(entry); + + return NOTIFY_DONE; +} + +int sw_nb_net_v6_neigh_update(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct net_device *pf_dev; + struct neighbour *n =3D ptr; + struct fib_entry *entry; + struct otx2_nic *pf; + + if (n->tbl !=3D &nd_tbl) + return NOTIFY_DONE; + + if (ipv6_addr_type((struct in6_addr *)n->primary_key) & IPV6_ADDR_LINKLOC= AL) + return NOTIFY_DONE; + + entry =3D kcalloc(1, sizeof(*entry), GFP_ATOMIC); + if (!entry) + return NOTIFY_DONE; + + pf_dev =3D sw_nb_resolve_pf_dev(n->dev); + if (!pf_dev) { + kfree(entry); + return NOTIFY_DONE; + } + + pf =3D netdev_priv(pf_dev); + + entry->cmd =3D OTX2_NEIGH_UPDATE; + entry->dst6_plen =3D n->tbl->key_len * 8; + memcpy(entry->dst6, (struct in6_addr *)n->primary_key, + sizeof(entry->dst6)); + entry->ipv6 =3D 1; + entry->nud_state =3D n->nud_state; + neigh_ha_snapshot(entry->mac, n, n->dev); + entry->mac_valid =3D 1; + entry->port_id =3D pf->pcifunc; + + netdev_dbg(n->dev, "v6 neigh update %pI6c mac=3D%pM plen=3D%u\n", + (struct in6_addr *)n->primary_key, entry->mac, + n->tbl->key_len * 8); + kfree(entry); + + return NOTIFY_DONE; +} + +int sw_nb_v6_inetaddr_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct inet6_ifaddr *ifa6 =3D (struct inet6_ifaddr *)ptr; + struct net_device *dev =3D ifa6->idev->dev; + struct netdev_hw_addr *dev_addr; + struct net_device *pf_dev; + struct fib_entry *entry; + struct otx2_nic *pf; + + if (event !=3D NETDEV_CHANGE && + event !=3D NETDEV_UP && + event !=3D NETDEV_DOWN) { + return NOTIFY_DONE; + } + + if (dev->type !=3D ARPHRD_ETHER) + return NOTIFY_DONE; + + if (!sw_nb_is_valid_dev(dev)) + return NOTIFY_DONE; + + if (ipv6_addr_type(&ifa6->addr) & IPV6_ADDR_LINKLOCAL) + return NOTIFY_DONE; + + entry =3D kcalloc(1, sizeof(*entry), GFP_ATOMIC); + if (!entry) + return NOTIFY_DONE; + + pf_dev =3D sw_nb_resolve_pf_dev(dev); + if (!pf_dev) { + kfree(entry); + return NOTIFY_DONE; + } + + pf =3D netdev_priv(pf_dev); + + entry->cmd =3D sw_nb_inetaddr_event_to_otx2_event(event, dev); + memcpy(entry->dst6, &ifa6->addr, sizeof(entry->dst6)); + entry->dst6_plen =3D ifa6->prefix_len; + entry->mac_valid =3D 1; + entry->host =3D 1; + entry->ipv6 =3D 1; + entry->port_id =3D pf->pcifunc; + + rcu_read_lock(); + for_each_dev_addr(dev, dev_addr) { + ether_addr_copy(entry->mac, dev_addr->addr); + entry->mac_valid =3D 1; + break; + } + rcu_read_unlock(); + + netdev_dbg(dev, "inetaddr addr=3D%pI6c len=3D%u %pM\n", + &ifa6->addr, ifa6->prefix_len, entry->mac); + kfree(entry); + + return NOTIFY_DONE; +} +#endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v6.h b= /drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v6.h new file mode 100644 index 000000000000..f73efc98c311 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v6.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell switch driver + * + * Copyright (C) 2026 Marvell. + * + */ +#ifndef SW_NB_V6_H_ +#define SW_NB_V6_H_ + +int sw_nb_v6_fib_event(struct notifier_block *nb, + unsigned long event, void *ptr); + +int sw_nb_net_v6_neigh_update(struct notifier_block *nb, + unsigned long event, void *ptr); + +int sw_nb_v6_inetaddr_event(struct notifier_block *nb, + unsigned long event, void *ptr); + +int sw_nb_v6_netdev_event(struct notifier_block *unused, + unsigned long event, void *ptr); +#endif // SW_NB_V6_H__ --=20 2.43.0 From nobody Sat Sep 26 18:54:41 2026 Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A7576415F06; Mon, 31 Aug 2026 13:20:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.156.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182431; cv=none; b=Y6LweSqGAL++u/yxb9aAnYzNag/NAIO8gt89PDjki9Ve9Hw+VUjnlxe2q+xpKq5TuPSoi0P6sWS6bhrFT0XOGCHgynJIndiVcXT80x1K4D4lha9kf0F5toduHZnpP8r9G4kNJXZGoJbsQeMvGCSpvqoPmUNEXmp1vje/7emIm28= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182431; c=relaxed/simple; bh=7x20ebveY98oy8Vhdh0DsgAxaDBW13ulgBI37JRbI4g=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=cPwkhhHLIStdvtGrr9+IiMC5ABF8cWyRz4WjqNfoED0n2bwlWPZZwVd/gZlVdqtuEOtRqyCDJjHBHOoFLvjRL4PRuRAhJmVc9wPepdsFjkmEEEkrd7IzLZZCopXXrxKBpoJNGgtZ/1wtA6DOWDWEwBknw6QjhJnyR+GHJhVZWho= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=YS2/jNHJ; arc=none smtp.client-ip=67.231.156.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="YS2/jNHJ" Received: from pps.filterd (m0431383.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 67VBCNOS668847; Mon, 31 Aug 2026 06:20:19 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=t jMjW7yoK3UhotIayoQq60B7JP4FFP2ZFu3bX40WrII=; b=YS2/jNHJHDFZkkOxZ EkZhpLVbiXbabVSGbRp6laY0SYF/YpTe1jlPbWLiGhCgkbOoabBlV8Z/P8DMJUoe TIqPAPaXR52vgoRNNoN+vOz9dWC/+AFrSaBVRmG2sKfpz1E8GMS0KZxeA3eFkqg0 JvZ3BiQ2t8HDKbCm0/c7vO7nnxfGIqznTa/IzcLbeISvRRsl9YqbGq1oWEHeZyAf MMFPUHk3JejnKQD+bYcVHBi84CmoZpaz2lrTIUD+XiDl28JY8q7XyM56ANRj+wjv 6XsPXl4IHqOJqqCCE0ebrxTI8F2XVHrEUJTMYHVsYaHSSe12x8s1/3GilqysoqoP Hc8QA== Received: from dc6wp-exch02.marvell.com ([4.21.29.225]) by mx0b-0016f401.pphosted.com (PPS) with ESMTPS id 4gcg68jmrv-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 31 Aug 2026 06:20:19 -0700 (PDT) Received: from DC6WP-EXCH02.marvell.com (10.76.176.209) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Mon, 31 Aug 2026 06:20:18 -0700 Received: from maili.marvell.com (10.69.176.80) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Mon, 31 Aug 2026 06:20:18 -0700 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id 5C1333F7089; Mon, 31 Aug 2026 06:20:15 -0700 (PDT) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH v9 net-next 7/8] octeontx2: switch: plumb bridge FDB updates through AF and switchdev Date: Mon, 31 Aug 2026 18:49:43 +0530 Message-ID: <20260831131944.2649362-8-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260831131944.2649362-1-rkannoth@marvell.com> References: <20260831131944.2649362-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: -A48U_sXPc05d8q1ZcdlKtFdvkS4nFCR X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfX7ZKM/SeBlm2N PyfDTlwId+9Po2M2YwacOESv4zjULcR7w7dq6N4NzD5Znzy6YFZP5IuXiHVUm1VFXnQeV2VLuxN NoHopD3MHmmHrrk6/jtF+7o0nQjXZKJI/q5IlEKnw8LB/qcrTQdwRKO8foWefLu158oYUAqoKhv 2WYhC6xzOlnKCrDzsxqZMHebKt10tvzqi7HNj8kePuMd7CYCwL4F6+pGG7Y8cHV7sAQAZtjHMQc kFgGYZQrZ6+GTqDS8HYUzrVK0fcTUC2JJfC7Cpa8vEfG9VYYeLMN1m5U1Ie3Is84+cFFLhgpd7C 4SuqzOj6c691T1vclnM3vJTKN155M4j9JNoYmbAkvXQ+c7EQid+Zr5EIcXMFOfWdOI4hueSq7do AutdCJOfkIG9ECxjWLwIGslS6TLNUQjP9mbQYEaaiV03Zbw5uOn8EnCINHsyPMn2egJa0pdyjs8 vz4LpfJKR22OM/EVZug== X-Authority-Analysis: v=2.4 cv=fZedDUQF c=1 sm=1 tr=0 ts=6a957f93 cx=c_pps a=gIfcoYsirJbf48DBMSPrZA==:117 a=gIfcoYsirJbf48DBMSPrZA==:17 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=l0iWHRpgs5sLHlkKQ1IR:22 a=qit2iCtTFQkLgVSMPQTB:22 a=M5GUcnROAAAA:8 a=zjSZ3cS-AAAA:8 a=3z2JWR2fr4yV80ubqD0A:9 a=OBjm3rFKGHvpk9ecZwUJ:22 a=ZdzWmiyDu4ucoLeQK2uw:22 X-Proofpoint-GUID: -A48U_sXPc05d8q1ZcdlKtFdvkS4nFCR X-Proofpoint-Spam-Info: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfX2yxGs6J88MUq sBqplqJLhW9sg00ygv6MDEYwDhoxncSUBv8BAAbSk5aZczccnvUS4W3PWtev7T4qLcq/BEPxRpb LmztdthKhy/SVkpCRr2QOVW6jaSBgU4= X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-31_04,2026-08-27_02,2025-10-01_01 Content-Type: text/plain; charset="utf-8" Handle switchdev FDB add and delete notifications on the PF by queuing work that sends fdb_notify mailbox messages to the AF. The AF queues those updates and pushes L2 rules toward the switchdev image with af2swdev notify messages when firmware is ready. Teach the AF swdev2af path to initialize L2 offload workqueues on firmware up/down and to accept refresh requests that enqueue FDB entries for AF to PF mailbox delivery. Add an AF to PF (and VF) upstream message for FDB refresh, handle it in the VF driver, and treat it like the CGX link event when acknowledging mailbox completion in the AF. On refresh, invoke the switchdev notifier so the host bridge can learn the updated FDB entry. Signed-off-by: Ratheesh Kannoth --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 2 + .../net/ethernet/marvell/octeontx2/af/rvu.c | 3 + .../marvell/octeontx2/af/switch/rvu_sw.c | 59 +- .../marvell/octeontx2/af/switch/rvu_sw.h | 2 + .../marvell/octeontx2/af/switch/rvu_sw_l2.c | 608 ++++++++++++++++++ .../marvell/octeontx2/af/switch/rvu_sw_l2.h | 4 + .../ethernet/marvell/octeontx2/nic/otx2_pf.c | 2 + .../ethernet/marvell/octeontx2/nic/otx2_vf.c | 49 ++ .../marvell/octeontx2/nic/switch/sw_fdb.c | 262 +++++++- .../marvell/octeontx2/nic/switch/sw_fdb.h | 3 + .../marvell/octeontx2/nic/switch/sw_nb.c | 12 +- .../marvell/octeontx2/nic/switch/sw_nb.h | 8 +- 12 files changed, 1004 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index 2aa1aa6599a5..8f7b2962a212 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -2015,6 +2015,7 @@ struct af2pf_fdb_refresh_req { struct mbox_msghdr hdr; u16 pcifunc; u8 mac[6]; + u64 flags; }; =20 struct iface_info { @@ -2054,6 +2055,7 @@ struct fl_info { struct swdev2af_notify_req { struct mbox_msghdr hdr; u64 msg_type; +/* Mutually exclusive message selectors (not a combinable bitmask). */ #define SWDEV2AF_MSG_TYPE_FW_STATUS BIT_ULL(0) #define SWDEV2AF_MSG_TYPE_REFRESH_FDB BIT_ULL(1) #define SWDEV2AF_MSG_TYPE_REFRESH_FL BIT_ULL(2) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/= ethernet/marvell/octeontx2/af/rvu.c index e4d13adc2896..9d0c99d4c064 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -23,6 +23,7 @@ #include "cn20k/reg.h" #include "cn20k/api.h" #include "cn20k/npc.h" +#include "switch/rvu_sw.h" =20 #define DRV_NAME "rvu_af" #define DRV_STRING "Marvell OcteonTX2 RVU Admin Function Driver" @@ -3863,8 +3864,10 @@ static void rvu_remove(struct pci_dev *pdev) rvu_cgx_exit(rvu); rvu_fwdata_exit(rvu); rvu_mcs_exit(rvu); + rvu_sw_shutdown(); rvu_mbox_destroy(&rvu->afpf_wq_info); rvu_disable_sriov(rvu); + rvu_sw_clear_shutdown(); rvu_reset_all_blocks(rvu); rvu_free_hw_resources(rvu); rvu_clear_rvum_blk_revid(rvu); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c b/dr= ivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c index 2451eb57ec4c..71f113bded5e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c @@ -9,6 +9,8 @@ =20 #include "rvu.h" #include "rvu_sw.h" +#include "rvu_sw_l2.h" +#include "rvu_sw_fl.h" =20 /* * rep_cnt and rep2pfvf_map are populated once when the representor driver @@ -33,9 +35,64 @@ u32 rvu_sw_port_id(struct rvu *rvu, u16 pcifunc) FIELD_PREP(GENMASK_ULL(15, 0), pcifunc); } =20 +static bool rvu_sw_swdev2af_msg_valid(u64 msg_type) +{ + return msg_type =3D=3D SWDEV2AF_MSG_TYPE_FW_STATUS || + msg_type =3D=3D SWDEV2AF_MSG_TYPE_REFRESH_FDB || + msg_type =3D=3D SWDEV2AF_MSG_TYPE_REFRESH_FL; +} + +static int rvu_sw_swdev2af_sender_check(struct rvu *rvu, + struct swdev2af_notify_req *req, + u64 msg_type) +{ + u16 sender =3D req->hdr.pcifunc; + + if (!rvu_sw_swdev2af_msg_valid(msg_type)) + return -EINVAL; + + if (msg_type =3D=3D SWDEV2AF_MSG_TYPE_FW_STATUS && req->fw_up) + return 0; + + if (!rvu_is_switch_pcifunc(rvu, sender)) + return -EPERM; + + return 0; +} + int rvu_mbox_handler_swdev2af_notify(struct rvu *rvu, struct swdev2af_notify_req *req, struct msg_rsp *rsp) { - return 0; + int rc; + + rc =3D rvu_sw_swdev2af_sender_check(rvu, req, req->msg_type); + if (rc) + return rc; + + switch (req->msg_type) { + case SWDEV2AF_MSG_TYPE_FW_STATUS: + rc =3D rvu_sw_l2_init_offl_wq(rvu, req->hdr.pcifunc, req->fw_up); + break; + + case SWDEV2AF_MSG_TYPE_REFRESH_FDB: + rc =3D rvu_sw_l2_fdb_list_entry_add(rvu, req->pcifunc, req->mac); + break; + + default: + rc =3D -EOPNOTSUPP; + break; + } + + return rc; +} + +void rvu_sw_shutdown(void) +{ + rvu_sw_l2_shutdown(); +} + +void rvu_sw_clear_shutdown(void) +{ + rvu_sw_l2_clear_shutdown(); } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.h b/dr= ivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.h index e9ad32c84576..539af01d917e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.h @@ -12,5 +12,7 @@ #define RVU_SW_INVALID_PORT_ID ((u32)~0U) =20 u32 rvu_sw_port_id(struct rvu *rvu, u16 pcifunc); +void rvu_sw_shutdown(void); +void rvu_sw_clear_shutdown(void); =20 #endif diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l2.c b= /drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l2.c index 5f805bfa81ed..448a442a6ffb 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l2.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l2.c @@ -4,11 +4,619 @@ * Copyright (C) 2026 Marvell. * */ + +#include #include "rvu.h" +#include "rvu_sw.h" +#include "rvu_sw_l2.h" + +#define M(_name, _id, _fn_name, _req_type, _rsp_type) \ +static struct _req_type __maybe_unused \ +*otx2_mbox_alloc_msg_ ## _fn_name(struct rvu *rvu, int devid) \ +{ \ + struct _req_type *req; \ + \ + req =3D (struct _req_type *)otx2_mbox_alloc_msg_rsp( \ + &rvu->afpf_wq_info.mbox_up, devid, sizeof(struct _req_type), \ + sizeof(struct _rsp_type)); \ + if (!req) \ + return NULL; \ + req->hdr.sig =3D OTX2_MBOX_REQ_SIG; \ + req->hdr.id =3D _id; \ + return req; \ +} + +MBOX_UP_AF2SWDEV_MESSAGES +MBOX_UP_AF2PF_FDB_REFRESH_MESSAGES +#undef M + +#define RVU_SW_L2_LIST_MAX 4096 + +struct l2_entry { + struct list_head list; + u64 flags; + u32 port_id; + u8 mac[ETH_ALEN]; +}; + +static bool going_down; +/* Serialize going_down, control workqueue alloc, and queue_work() so + * teardown cannot NULL the workqueue while a mailbox handler is between + * the going_down check and queue_work(). + */ +static DEFINE_MUTEX(rvu_sw_l2_ctrl_lock); + +static DEFINE_MUTEX(l2_offl_list_lock); +static LIST_HEAD(l2_offl_lh); +static atomic_t l2_offl_list_cnt =3D ATOMIC_INIT(0); + +static DEFINE_MUTEX(fdb_refresh_list_lock); +static LIST_HEAD(fdb_refresh_lh); +static atomic_t fdb_refresh_list_cnt =3D ATOMIC_INIT(0); + +struct rvu_sw_l2_work { + struct rvu *rvu; + struct work_struct work; +}; + +struct rvu_sw_l2_ctrl_work { + struct work_struct work; + struct rvu *rvu; + u16 pcifunc; + bool fw_up; +}; + +/* Work queue for switchdev message handling. There is only one RVU AF + * and one switch block per SoC; rvu_probe() enforces a single AF bind via + * device_bound, so one global workqueue instance per type is sufficient. + */ +static struct rvu_sw_l2_work l2_offl_work; +static struct workqueue_struct *rvu_sw_l2_offl_wq; + +static struct rvu_sw_l2_work fdb_refresh_work; +static struct workqueue_struct *fdb_refresh_wq; + +/* Serialize FW bring-up/teardown outside the AF mailbox handler. The + * handler runs under rvu->mbox_lock, while offload/refresh workers take + * the same lock to send messages; synchronous teardown there deadlocks. + */ +static struct workqueue_struct *rvu_sw_l2_ctrl_wq; + +static bool fw_is_up; +static DEFINE_SPINLOCK(rvu_sw_l2_state_lock); + +static void rvu_sw_l2_list_cnt_warn(struct device *dev, atomic_t *cnt, + const char *name) +{ + int n =3D atomic_read(cnt); + + if (n < 0) + dev_warn(dev, "L2 %s list count underflow: %d\n", name, n); + else if (n > RVU_SW_L2_LIST_MAX) + dev_warn(dev, "L2 %s list count overflow: %d (max %d)\n", + name, n, RVU_SW_L2_LIST_MAX); +} + +static void rvu_sw_l2_list_cnt_inc(struct device *dev, atomic_t *cnt, + const char *name) +{ + atomic_inc(cnt); + rvu_sw_l2_list_cnt_warn(dev, cnt, name); +} + +static void rvu_sw_l2_list_cnt_dec(struct device *dev, atomic_t *cnt, + const char *name) +{ + atomic_dec(cnt); + rvu_sw_l2_list_cnt_warn(dev, cnt, name); +} + +static void rvu_sw_l2_destroy_wqs(struct rvu *rvu) +{ + struct workqueue_struct *offl_wq, *refresh_wq; + struct l2_entry *entry; + + spin_lock_bh(&rvu_sw_l2_state_lock); + rvu->rswitch.flags &=3D ~RVU_SWITCH_FLAG_FW_READY; + fw_is_up =3D false; + spin_unlock_bh(&rvu_sw_l2_state_lock); + + mutex_lock(&fdb_refresh_list_lock); + refresh_wq =3D fdb_refresh_wq; + fdb_refresh_wq =3D NULL; + mutex_unlock(&fdb_refresh_list_lock); + + if (refresh_wq) { + cancel_work_sync(&fdb_refresh_work.work); + destroy_workqueue(refresh_wq); + + mutex_lock(&fdb_refresh_list_lock); + rvu_sw_l2_list_cnt_warn(rvu->dev, &fdb_refresh_list_cnt, + "fdb refresh"); + while (1) { + entry =3D list_first_entry_or_null(&fdb_refresh_lh, + struct l2_entry, list); + if (!entry) + break; + + list_del_init(&entry->list); + kfree(entry); + } + atomic_set(&fdb_refresh_list_cnt, 0); + mutex_unlock(&fdb_refresh_list_lock); + } + + mutex_lock(&l2_offl_list_lock); + offl_wq =3D rvu_sw_l2_offl_wq; + rvu_sw_l2_offl_wq =3D NULL; + mutex_unlock(&l2_offl_list_lock); + + if (offl_wq) { + cancel_work_sync(&l2_offl_work.work); + destroy_workqueue(offl_wq); + + mutex_lock(&l2_offl_list_lock); + rvu_sw_l2_list_cnt_warn(rvu->dev, &l2_offl_list_cnt, "offload"); + while (1) { + entry =3D list_first_entry_or_null(&l2_offl_lh, + struct l2_entry, list); + if (!entry) + break; + + list_del_init(&entry->list); + kfree(entry); + } + atomic_set(&l2_offl_list_cnt, 0); + mutex_unlock(&l2_offl_list_lock); + } + + spin_lock_bh(&rvu_sw_l2_state_lock); + rvu->rswitch.pcifunc =3D 0; + spin_unlock_bh(&rvu_sw_l2_state_lock); +} + +/* High-frequency link state transitions or aggressive FDB + * aging intervals can induce rapid fdb churn. To prevent + * thrashing, inhibit hardware offloading of these transient + * forwarding states to the switching ASIC. Events are queued + * at the tail and processed from the head; when enqueueing a + * new operation, drop older pending opposite operations for the + * same MAC and port that have not yet reached hardware. When an + * opposite entry is removed, the new operation is dropped as well. + */ +static bool rvu_sw_l2_offl_coalesce_pending_locked(struct rvu *rvu, + struct l2_entry *new_entry) +{ + u64 opposite =3D (new_entry->flags & OTX2_FDB_ADD) ? OTX2_FDB_DEL : OTX2_= FDB_ADD; + struct l2_entry *entry, *tmp; + bool coalesced =3D false; + + lockdep_assert_held(&l2_offl_list_lock); + + list_for_each_entry_safe(entry, tmp, &l2_offl_lh, list) { + if (!ether_addr_equal(new_entry->mac, entry->mac)) + continue; + + if (new_entry->port_id !=3D entry->port_id) + continue; + + if (!(entry->flags & opposite)) + continue; + + list_del_init(&entry->list); + rvu_sw_l2_list_cnt_dec(rvu->dev, &l2_offl_list_cnt, "offload"); + kfree(entry); + coalesced =3D true; + } + + return coalesced; +} + +static int rvu_sw_l2_offl_rule_push(struct rvu *rvu, struct l2_entry *l2_e= ntry) +{ + struct af2swdev_notify_req *req; + int swdev_pf; + + swdev_pf =3D rvu_get_pf(rvu->pdev, rvu->rswitch.pcifunc); + + mutex_lock(&rvu->mbox_lock); + req =3D otx2_mbox_alloc_msg_af2swdev_notify(rvu, swdev_pf); + if (!req) { + mutex_unlock(&rvu->mbox_lock); + return -ENOMEM; + } + + ether_addr_copy(req->mac, l2_entry->mac); + req->flags =3D l2_entry->flags; + req->port_id =3D l2_entry->port_id; + + otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, swdev_pf); + otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, swdev_pf); + + mutex_unlock(&rvu->mbox_lock); + return 0; +} + +static int rvu_sw_l2_fdb_refresh_send(struct rvu *rvu, u16 pcifunc, u8 *ma= c) +{ + struct af2pf_fdb_refresh_req *req; + int pf, vf; + + if (!is_pf_func_valid(rvu, pcifunc)) + return -EINVAL; + + pf =3D rvu_get_pf(rvu->pdev, pcifunc); + vf =3D (pcifunc & RVU_PFVF_FUNC_MASK) - 1; + + mutex_lock(&rvu->mbox_lock); + + /* + * FDB refresh topology (VM bridge + SR-IOV VF ports + HW offload): + * + * VM: br0 with eth0/eth1 (CGX VFs passed through via SR-IOV) + * Host: switch HW forwards between VF switch ports; accelerated + * traffic is not received on eth0/eth1 in the VM. + * + * br0 still maintains a software FDB with ageing. After the AF + * programs hardware, refresh must reach the VM so + * SWITCHDEV_FDB_ADD_TO_BRIDGE is raised on the bridge port netdev + * (eth0/eth1), keeping br0 FDB entries alive. + * + * For CGX VFs (pf !=3D 0), hdr.pcifunc carries the target VF + * identity so the parent PF mailbox forwards the message to the + * guest VF driver (otx2_pfaf_mbox_up_handler()). Routing refresh + * into the VM is intentional: the bridge owning the FDB is in the + * guest, not on a host representor. + * + * This differs from the host-side switchdev model where a Linux + * bridge on the host uses representor netdevs (RVU_REP) as ports. + * + * AF-managed VFs on PF 0 (e.g. LBK, pf =3D=3D 0): delivered directly + * via the AF VF mailbox; these VFs have no host PF mailbox. + */ + if (pf !=3D 0) { + if (pf >=3D rvu->afpf_wq_info.mbox_up.ndevs) { + mutex_unlock(&rvu->mbox_lock); + return -EINVAL; + } + + req =3D otx2_mbox_alloc_msg_af2pf_fdb_refresh(rvu, pf); + if (!req) { + mutex_unlock(&rvu->mbox_lock); + return -ENOMEM; + } + + req->hdr.pcifunc =3D pcifunc; + ether_addr_copy(req->mac, mac); + req->pcifunc =3D pcifunc; + req->flags =3D OTX2_FDB_ADD; + + otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, pf); + otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, pf); + } else { + if (vf < 0 || vf >=3D rvu->afvf_wq_info.mbox_up.ndevs) { + mutex_unlock(&rvu->mbox_lock); + return -EINVAL; + } + + req =3D (struct af2pf_fdb_refresh_req *) + otx2_mbox_alloc_msg_rsp(&rvu->afvf_wq_info.mbox_up, vf, + sizeof(*req), sizeof(struct msg_rsp)); + if (!req) { + mutex_unlock(&rvu->mbox_lock); + return -ENOMEM; + } + req->hdr.sig =3D OTX2_MBOX_REQ_SIG; + req->hdr.id =3D MBOX_MSG_AF2PF_FDB_REFRESH; + + req->hdr.pcifunc =3D pcifunc; + ether_addr_copy(req->mac, mac); + req->pcifunc =3D pcifunc; + req->flags =3D OTX2_FDB_ADD; + + otx2_mbox_wait_for_zero(&rvu->afvf_wq_info.mbox_up, vf); + otx2_mbox_msg_send_up(&rvu->afvf_wq_info.mbox_up, vf); + } + + mutex_unlock(&rvu->mbox_lock); + + return 0; +} + +static void rvu_sw_l2_fdb_refresh_wq_handler(struct work_struct *work) +{ + struct rvu_sw_l2_work *fdb_work; + struct l2_entry *l2_entry; + + fdb_work =3D container_of(work, struct rvu_sw_l2_work, work); + + while (1) { + mutex_lock(&fdb_refresh_list_lock); + l2_entry =3D list_first_entry_or_null(&fdb_refresh_lh, + struct l2_entry, list); + if (!l2_entry) { + mutex_unlock(&fdb_refresh_list_lock); + return; + } + + list_del_init(&l2_entry->list); + rvu_sw_l2_list_cnt_dec(fdb_work->rvu->dev, &fdb_refresh_list_cnt, + "fdb refresh"); + mutex_unlock(&fdb_refresh_list_lock); + + rvu_sw_l2_fdb_refresh_send(fdb_work->rvu, l2_entry->port_id, + l2_entry->mac); + kfree(l2_entry); + } +} + +static void rvu_sw_l2_offl_rule_wq_handler(struct work_struct *work) +{ + struct rvu_sw_l2_work *offl_work; + struct l2_entry *l2_entry; + int budget =3D 16; + + offl_work =3D container_of(work, struct rvu_sw_l2_work, work); + + while (budget--) { + mutex_lock(&l2_offl_list_lock); + l2_entry =3D list_first_entry_or_null(&l2_offl_lh, struct l2_entry, list= ); + if (!l2_entry) { + mutex_unlock(&l2_offl_list_lock); + return; + } + + list_del_init(&l2_entry->list); + rvu_sw_l2_list_cnt_dec(offl_work->rvu->dev, &l2_offl_list_cnt, + "offload"); + mutex_unlock(&l2_offl_list_lock); + + if (rvu_sw_l2_offl_rule_push(offl_work->rvu, l2_entry)) + dev_err(offl_work->rvu->dev, + "%s: Error to push l2 rule\n", + __func__); + /* + * TODO: Requeue l2_entry on transient rvu_sw_l2_offl_rule_push() + * errors (e.g. ENOMEM, -EBUSY) to keep hardware FDB in sync with + * the bridge. Drop-on-failure is known deferred work. + */ + kfree(l2_entry); + } + + mutex_lock(&l2_offl_list_lock); + if (rvu_sw_l2_offl_wq && atomic_read(&l2_offl_list_cnt)) + queue_work(rvu_sw_l2_offl_wq, &l2_offl_work.work); + mutex_unlock(&l2_offl_list_lock); +} + +static void rvu_sw_l2_ctrl_work_handler(struct work_struct *work) +{ + struct rvu_sw_l2_ctrl_work *ctrl; + struct rvu_switch *rswitch; + struct rvu *rvu; + u16 pcifunc; + bool fw_up; + + ctrl =3D container_of(work, struct rvu_sw_l2_ctrl_work, work); + rvu =3D ctrl->rvu; + pcifunc =3D ctrl->pcifunc; + fw_up =3D ctrl->fw_up; + kfree(ctrl); + + rswitch =3D &rvu->rswitch; + + if (!fw_up) { + rvu_sw_l2_destroy_wqs(rvu); + return; + } + + spin_lock_bh(&rvu_sw_l2_state_lock); + if (fw_is_up && rvu_sw_l2_offl_wq && fdb_refresh_wq) { + rswitch->pcifunc =3D pcifunc; + rswitch->flags |=3D RVU_SWITCH_FLAG_FW_READY; + spin_unlock_bh(&rvu_sw_l2_state_lock); + return; + } + spin_unlock_bh(&rvu_sw_l2_state_lock); + + if (rvu_sw_l2_offl_wq || fdb_refresh_wq) + rvu_sw_l2_destroy_wqs(rvu); + + l2_offl_work.rvu =3D rvu; + INIT_WORK(&l2_offl_work.work, rvu_sw_l2_offl_rule_wq_handler); + rvu_sw_l2_offl_wq =3D alloc_workqueue("swdev_rvu_sw_l2_offl_wq", 0, 0); + if (!rvu_sw_l2_offl_wq) { + dev_err(rvu->dev, "L2 offl workqueue allocation failed\n"); + return; + } + + fdb_refresh_work.rvu =3D rvu; + INIT_WORK(&fdb_refresh_work.work, rvu_sw_l2_fdb_refresh_wq_handler); + fdb_refresh_wq =3D alloc_workqueue("swdev_fdb_refresh_wq", 0, 0); + if (!fdb_refresh_wq) { + dev_err(rvu->dev, "fdb refresh workqueue allocation failed\n"); + destroy_workqueue(rvu_sw_l2_offl_wq); + rvu_sw_l2_offl_wq =3D NULL; + return; + } + + spin_lock_bh(&rvu_sw_l2_state_lock); + fw_is_up =3D true; + rswitch->pcifunc =3D pcifunc; + rswitch->flags |=3D RVU_SWITCH_FLAG_FW_READY; + spin_unlock_bh(&rvu_sw_l2_state_lock); +} + +int rvu_sw_l2_init_offl_wq(struct rvu *rvu, u16 pcifunc, bool fw_up) +{ + struct rvu_sw_l2_ctrl_work *ctrl; + struct workqueue_struct *wq; + int err =3D 0; + + mutex_lock(&rvu_sw_l2_ctrl_lock); + if (going_down) + goto unlock; + + if (!fw_up) { + spin_lock_bh(&rvu_sw_l2_state_lock); + rvu->rswitch.flags &=3D ~RVU_SWITCH_FLAG_FW_READY; + fw_is_up =3D false; + spin_unlock_bh(&rvu_sw_l2_state_lock); + } + + if (!rvu_sw_l2_ctrl_wq) { + rvu_sw_l2_ctrl_wq =3D alloc_ordered_workqueue("rvu_sw_l2_ctrl", + WQ_MEM_RECLAIM); + if (!rvu_sw_l2_ctrl_wq) { + err =3D -ENOMEM; + goto unlock; + } + } + wq =3D rvu_sw_l2_ctrl_wq; + + ctrl =3D kzalloc_obj(*ctrl); + if (!ctrl) { + err =3D -ENOMEM; + goto unlock; + } + + INIT_WORK(&ctrl->work, rvu_sw_l2_ctrl_work_handler); + ctrl->rvu =3D rvu; + ctrl->pcifunc =3D pcifunc; + ctrl->fw_up =3D fw_up; + + queue_work(wq, &ctrl->work); + +unlock: + mutex_unlock(&rvu_sw_l2_ctrl_lock); + return err; +} + +int rvu_sw_l2_fdb_list_entry_add(struct rvu *rvu, u16 pcifunc, u8 *mac) +{ + struct workqueue_struct *wq; + struct l2_entry *l2_entry; + + if (!is_pf_func_valid(rvu, pcifunc)) + return -EINVAL; + + if (atomic_read(&fdb_refresh_list_cnt) >=3D RVU_SW_L2_LIST_MAX) { + rvu_sw_l2_list_cnt_warn(rvu->dev, &fdb_refresh_list_cnt, + "fdb refresh"); + return -ENOMEM; + } + + l2_entry =3D kcalloc(1, sizeof(*l2_entry), GFP_KERNEL); + if (!l2_entry) + return -ENOMEM; + + l2_entry->port_id =3D pcifunc; + ether_addr_copy(l2_entry->mac, mac); + + mutex_lock(&fdb_refresh_list_lock); + wq =3D fdb_refresh_wq; + if (!wq) { + mutex_unlock(&fdb_refresh_list_lock); + kfree(l2_entry); + return -EINVAL; + } + + if (atomic_read(&fdb_refresh_list_cnt) >=3D RVU_SW_L2_LIST_MAX) { + rvu_sw_l2_list_cnt_warn(rvu->dev, &fdb_refresh_list_cnt, + "fdb refresh"); + mutex_unlock(&fdb_refresh_list_lock); + kfree(l2_entry); + return -ENOMEM; + } + list_add_tail(&l2_entry->list, &fdb_refresh_lh); + rvu_sw_l2_list_cnt_inc(rvu->dev, &fdb_refresh_list_cnt, "fdb refresh"); + queue_work(wq, &fdb_refresh_work.work); + mutex_unlock(&fdb_refresh_list_lock); + + return 0; +} =20 int rvu_mbox_handler_fdb_notify(struct rvu *rvu, struct fdb_notify_req *req, struct msg_rsp *rsp) { + struct workqueue_struct *wq; + struct l2_entry *l2_entry; + u32 port_id; + + spin_lock_bh(&rvu_sw_l2_state_lock); + if (!(rvu->rswitch.flags & RVU_SWITCH_FLAG_FW_READY)) { + spin_unlock_bh(&rvu_sw_l2_state_lock); + return 0; + } + spin_unlock_bh(&rvu_sw_l2_state_lock); + + port_id =3D rvu_sw_port_id(rvu, req->hdr.pcifunc); + if (port_id =3D=3D RVU_SW_INVALID_PORT_ID) + return -EINVAL; + + if (atomic_read(&l2_offl_list_cnt) >=3D RVU_SW_L2_LIST_MAX) { + rvu_sw_l2_list_cnt_warn(rvu->dev, &l2_offl_list_cnt, "offload"); + return -ENOMEM; + } + + l2_entry =3D kcalloc(1, sizeof(*l2_entry), GFP_KERNEL); + if (!l2_entry) + return -ENOMEM; + + l2_entry->port_id =3D port_id; + ether_addr_copy(l2_entry->mac, req->mac); + l2_entry->flags =3D req->flags; + + mutex_lock(&l2_offl_list_lock); + wq =3D rvu_sw_l2_offl_wq; + if (!wq) { + mutex_unlock(&l2_offl_list_lock); + kfree(l2_entry); + return 0; + } + + if (atomic_read(&l2_offl_list_cnt) >=3D RVU_SW_L2_LIST_MAX) { + rvu_sw_l2_list_cnt_warn(rvu->dev, &l2_offl_list_cnt, "offload"); + mutex_unlock(&l2_offl_list_lock); + kfree(l2_entry); + return -ENOMEM; + } + if (rvu_sw_l2_offl_coalesce_pending_locked(rvu, l2_entry)) { + mutex_unlock(&l2_offl_list_lock); + kfree(l2_entry); + return 0; + } + list_add_tail(&l2_entry->list, &l2_offl_lh); + rvu_sw_l2_list_cnt_inc(rvu->dev, &l2_offl_list_cnt, "offload"); + queue_work(wq, &l2_offl_work.work); + mutex_unlock(&l2_offl_list_lock); + return 0; } + +void rvu_sw_l2_shutdown(void) +{ + struct workqueue_struct *wq; + + mutex_lock(&rvu_sw_l2_ctrl_lock); + going_down =3D true; + wq =3D rvu_sw_l2_ctrl_wq; + rvu_sw_l2_ctrl_wq =3D NULL; + mutex_unlock(&rvu_sw_l2_ctrl_lock); + + if (wq) { + flush_workqueue(wq); + destroy_workqueue(wq); + } + + if (fdb_refresh_wq || rvu_sw_l2_offl_wq) + rvu_sw_l2_destroy_wqs(l2_offl_work.rvu); +} + +void rvu_sw_l2_clear_shutdown(void) +{ + mutex_lock(&rvu_sw_l2_ctrl_lock); + going_down =3D false; + mutex_unlock(&rvu_sw_l2_ctrl_lock); +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l2.h b= /drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l2.h index ff28612150c9..3c250272e026 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l2.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l2.h @@ -8,4 +8,8 @@ #ifndef RVU_SW_L2_H #define RVU_SW_L2_H =20 +int rvu_sw_l2_init_offl_wq(struct rvu *rvu, u16 pcifunc, bool fw_up); +int rvu_sw_l2_fdb_list_entry_add(struct rvu *rvu, u16 pcifunc, u8 *mac); +void rvu_sw_l2_shutdown(void); +void rvu_sw_l2_clear_shutdown(void); #endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers= /net/ethernet/marvell/octeontx2/nic/otx2_pf.c index c995f2900859..6ee19aca194c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c @@ -28,6 +28,7 @@ #include #include "cn10k_ipsec.h" #include "otx2_xsk.h" +#include "switch/sw_nb.h" =20 #define DRV_NAME "rvu_nicpf" #define DRV_STRING "Marvell RVU NIC Physical Function Driver" @@ -993,6 +994,7 @@ static int otx2_process_mbox_msg_up(struct otx2_nic *pf, MBOX_UP_CGX_MESSAGES MBOX_UP_MCS_MESSAGES MBOX_UP_REP_MESSAGES +MBOX_UP_AF2PF_FDB_REFRESH_MESSAGES #undef M break; default: diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers= /net/ethernet/marvell/octeontx2/nic/otx2_vf.c index fcdf891f90b5..1d86cac5a7e8 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c @@ -9,6 +9,7 @@ #include #include #include +#include =20 #include "otx2_common.h" #include "otx2_reg.h" @@ -114,6 +115,38 @@ static void otx2vf_vfaf_mbox_handler(struct work_struc= t *work) } } =20 +#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) +static int otx2vf_mbox_af2pf_fdb_refresh(struct otx2_nic *vf, + struct af2pf_fdb_refresh_req *req, + struct msg_rsp *rsp) +{ + struct switchdev_notifier_fdb_info item =3D {0}; + + /* VM bridge + HW offload: vf->netdev is a br0 port in the guest. + * SWITCHDEV_FDB_ADD_TO_BRIDGE on this netdev refreshes the guest + * bridge FDB even when accelerated traffic bypasses eth0/eth1 RX + * (see rvu_sw_l2_fdb_refresh_send()). + */ + item.addr =3D req->mac; + item.info.dev =3D vf->netdev; + if (req->flags & OTX2_FDB_DEL) + call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, + item.info.dev, &item.info, NULL); + else + call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, + item.info.dev, &item.info, NULL); + + return 0; +} +#else +static int otx2vf_mbox_af2pf_fdb_refresh(struct otx2_nic *vf, + struct af2pf_fdb_refresh_req *req, + struct msg_rsp *rsp) +{ + return 0; +} +#endif + static int otx2vf_process_mbox_msg_up(struct otx2_nic *vf, struct mbox_msghdr *req) { @@ -141,6 +174,22 @@ static int otx2vf_process_mbox_msg_up(struct otx2_nic = *vf, err =3D otx2_mbox_up_handler_cgx_link_event( vf, (struct cgx_link_info_msg *)req, rsp); return err; + + case MBOX_MSG_AF2PF_FDB_REFRESH: + rsp =3D (struct msg_rsp *)otx2_mbox_alloc_msg(&vf->mbox.mbox_up, 0, + sizeof(struct msg_rsp)); + if (!rsp) + return -ENOMEM; + + rsp->hdr.id =3D MBOX_MSG_AF2PF_FDB_REFRESH; + rsp->hdr.sig =3D OTX2_MBOX_RSP_SIG; + rsp->hdr.pcifunc =3D req->pcifunc; + rsp->hdr.rc =3D 0; + err =3D otx2vf_mbox_af2pf_fdb_refresh(vf, + (struct af2pf_fdb_refresh_req *)req, + rsp); + return err; + default: otx2_reply_invalid_msg(&vf->mbox.mbox_up, 0, 0, req->id); return -ENODEV; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fdb.c b/d= rivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fdb.c index 500451e85b50..e5e20b08ee8e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fdb.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fdb.c @@ -4,16 +4,276 @@ * Copyright (C) 2026 Marvell. * */ +#include +#include +#include +#include +#include +#include +#include + +#include "../otx2_reg.h" +#include "../otx2_common.h" +#include "../otx2_struct.h" +#include "../cn10k.h" +#include "../rep.h" +#include "sw_nb.h" #include "sw_fdb.h" =20 -#if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) +#if !IS_ENABLED(CONFIG_OCTEONTX_SWITCH) + +int otx2_mbox_up_handler_af2pf_fdb_refresh(struct otx2_nic *pf, + struct af2pf_fdb_refresh_req *req, + struct msg_rsp *rsp) +{ + return 0; +} + +#else + +#define SW_FDB_LIST_MAX 4096 + +static DEFINE_SPINLOCK(sw_fdb_llock); +static LIST_HEAD(sw_fdb_lh); +static atomic_t sw_fdb_list_cnt =3D ATOMIC_INIT(0); + +struct sw_fdb_list_entry { + struct list_head list; + u64 flags; + struct pci_dev *pdev; + struct net_device *dev; + netdevice_tracker dev_tracker; + u8 mac[ETH_ALEN]; + bool add_fdb; +}; + +static struct workqueue_struct *sw_fdb_wq; +static struct work_struct sw_fdb_work; + +static void sw_fdb_list_cnt_warn(struct net_device *netdev) +{ + int n =3D atomic_read(&sw_fdb_list_cnt); + + if (n < 0) + netdev_warn(netdev, "FDB list count underflow: %d\n", n); + else if (n > SW_FDB_LIST_MAX) + netdev_warn(netdev, "FDB list count overflow: %d (max %d)\n", + n, SW_FDB_LIST_MAX); +} + +static int sw_fdb_list_count(void) +{ + return atomic_read(&sw_fdb_list_cnt); +} + +static void sw_fdb_list_cnt_inc(struct net_device *netdev) +{ + atomic_inc(&sw_fdb_list_cnt); + sw_fdb_list_cnt_warn(netdev); +} + +static void sw_fdb_list_cnt_dec(struct net_device *netdev) +{ + atomic_dec(&sw_fdb_list_cnt); + sw_fdb_list_cnt_warn(netdev); +} + +static struct otx2_nic *sw_fdb_netdev_to_nic(struct net_device *dev) +{ + struct device *parent =3D dev->dev.parent; + + if (parent && parent->bus =3D=3D &pci_bus_type) { + struct pci_dev *pdev =3D to_pci_dev(parent); + + if (otx2_rep_dev(pdev)) { + struct rep_dev *rep =3D netdev_priv(dev); + + return rep->mdev; + } + } + + return netdev_priv(dev); +} + +static int sw_fdb_add_or_del(struct otx2_nic *pf, + const unsigned char *addr, + bool add_fdb) +{ + struct fdb_notify_req *req; + int rc; + + mutex_lock(&pf->mbox.lock); + req =3D otx2_mbox_alloc_msg_fdb_notify(&pf->mbox); + if (!req) { + rc =3D -ENOMEM; + goto out; + } + + ether_addr_copy(req->mac, addr); + req->flags =3D add_fdb ? OTX2_FDB_ADD : OTX2_FDB_DEL; + + rc =3D otx2_sync_mbox_msg(&pf->mbox); +out: + mutex_unlock(&pf->mbox.lock); + return rc; +} + +static void sw_fdb_entry_free(struct sw_fdb_list_entry *entry) +{ + netdev_put(entry->dev, &entry->dev_tracker); + pci_dev_put(entry->pdev); + kfree(entry); +} + +static void sw_fdb_wq_handler(struct work_struct *work) +{ + struct sw_fdb_list_entry *entry; + struct otx2_nic *pf; + struct workqueue_struct *wq; + LIST_HEAD(tlist); + + spin_lock(&sw_fdb_llock); + list_splice_init(&sw_fdb_lh, &tlist); + spin_unlock(&sw_fdb_llock); + + while ((entry =3D + list_first_entry_or_null(&tlist, + struct sw_fdb_list_entry, + list)) !=3D NULL) { + list_del_init(&entry->list); + sw_fdb_list_cnt_dec(entry->dev); + + spin_lock(&sw_fdb_llock); + wq =3D sw_fdb_wq; + spin_unlock(&sw_fdb_llock); + + pf =3D wq ? pci_get_drvdata(entry->pdev) : NULL; + if (pf && sw_fdb_add_or_del(pf, entry->mac, entry->add_fdb)) + netdev_err(entry->dev, + "Error to add/del fdb %pM entry\n", + entry->mac); + /* + * TODO: Requeue entry on transient sw_fdb_add_or_del() failure so + * the switch FDB stays aligned with the bridge. Drop-on-failure + * is known deferred work. + */ + sw_fdb_entry_free(entry); + } + + spin_lock(&sw_fdb_llock); + wq =3D sw_fdb_wq; + if (wq && !list_empty(&sw_fdb_lh)) + queue_work(wq, &sw_fdb_work); + spin_unlock(&sw_fdb_llock); +} + +int sw_fdb_add_to_list(struct net_device *dev, u8 *mac, bool add_fdb) +{ + struct otx2_nic *pf =3D sw_fdb_netdev_to_nic(dev); + struct sw_fdb_list_entry *entry; + struct workqueue_struct *wq; + + if (!pf) + return -EINVAL; + + if (sw_fdb_list_count() >=3D SW_FDB_LIST_MAX) + return -ENOMEM; + + entry =3D kcalloc(1, sizeof(*entry), GFP_ATOMIC); + if (!entry) + return -ENOMEM; + + ether_addr_copy(entry->mac, mac); + entry->add_fdb =3D add_fdb; + entry->pdev =3D pci_dev_get(pf->pdev); + entry->dev =3D dev; + netdev_hold(dev, &entry->dev_tracker, GFP_ATOMIC); + + spin_lock(&sw_fdb_llock); + wq =3D sw_fdb_wq; + if (!wq) { + spin_unlock(&sw_fdb_llock); + sw_fdb_entry_free(entry); + return -EINVAL; + } + + if (sw_fdb_list_count() >=3D SW_FDB_LIST_MAX) { + spin_unlock(&sw_fdb_llock); + sw_fdb_entry_free(entry); + return -ENOMEM; + } + + list_add_tail(&entry->list, &sw_fdb_lh); + sw_fdb_list_cnt_inc(dev); + queue_work(wq, &sw_fdb_work); + spin_unlock(&sw_fdb_llock); + + return 0; +} + int sw_fdb_init(void) { + INIT_WORK(&sw_fdb_work, sw_fdb_wq_handler); + sw_fdb_wq =3D alloc_workqueue("sw_fdb_wq", 0, 0); + if (!sw_fdb_wq) + return -ENOMEM; + return 0; } =20 void sw_fdb_deinit(void) { + struct sw_fdb_list_entry *entry; + struct workqueue_struct *wq; + LIST_HEAD(tlist); + + spin_lock(&sw_fdb_llock); + wq =3D sw_fdb_wq; + sw_fdb_wq =3D NULL; + spin_unlock(&sw_fdb_llock); + + if (!wq) + return; + + cancel_work_sync(&sw_fdb_work); + destroy_workqueue(wq); + + spin_lock(&sw_fdb_llock); + list_splice_init(&sw_fdb_lh, &tlist); + spin_unlock(&sw_fdb_llock); + + while ((entry =3D + list_first_entry_or_null(&tlist, + struct sw_fdb_list_entry, + list)) !=3D NULL) { + list_del_init(&entry->list); + sw_fdb_list_cnt_dec(entry->dev); + sw_fdb_entry_free(entry); + } } =20 +int otx2_mbox_up_handler_af2pf_fdb_refresh(struct otx2_nic *pf, + struct af2pf_fdb_refresh_req *req, + struct msg_rsp *rsp) +{ + struct switchdev_notifier_fdb_info item =3D {0}; + + /* FDB refresh is raised from the switch offload path (AF) after + * switchdev FDB updates. PF-local ports are refreshed on pf->netdev. + * TODO: When req->hdr.pcifunc targets a guest VF (VM-bridged offload), + * forward the refresh via the PF-VF mailbox instead of applying it to + * pf->netdev; otherwise guest-owned MACs may age out prematurely (see + * rvu_sw_l2_fdb_refresh_send()). + */ + item.addr =3D req->mac; + item.info.dev =3D pf->netdev; + if (req->flags & OTX2_FDB_DEL) + call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, + item.info.dev, &item.info, NULL); + else + call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, + item.info.dev, &item.info, NULL); + + return 0; +} #endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fdb.h b/d= rivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fdb.h index dc427e8ab7c6..3083135c782c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fdb.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fdb.h @@ -9,7 +9,10 @@ =20 #include =20 +struct net_device; + #if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) +int sw_fdb_add_to_list(struct net_device *dev, u8 *mac, bool add_fdb); void sw_fdb_deinit(void); int sw_fdb_init(void); #else diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c b/dr= ivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c index b51d8d2d01b8..c947f30becc8 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c @@ -191,13 +191,17 @@ static int sw_nb_fdb_event(struct notifier_block *unu= sed, =20 switch (event) { case SWITCHDEV_FDB_ADD_TO_DEVICE: - if (fdb_info->is_local) - break; - break; - case SWITCHDEV_FDB_DEL_TO_DEVICE: if (fdb_info->is_local) break; + /* dev is the bridge port that learned the FDB + * (SWITCHDEV_FDB_*_TO_DEVICE), not the bridge master. + * sw_nb_is_valid_dev() limits this to Cavium-offloaded + * setups; only Cavium PF/representor netdevs are supported + * as bridge ports today (VLAN/virt under bridge is TODO). + */ + sw_fdb_add_to_list(dev, (u8 *)fdb_info->addr, + event =3D=3D SWITCHDEV_FDB_ADD_TO_DEVICE); break; =20 default: diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.h b/dr= ivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.h index 39435f23427c..cb87c8ca56fe 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.h @@ -14,6 +14,10 @@ struct otx2_nic; struct af2pf_fdb_refresh_req; struct msg_rsp; =20 +int otx2_mbox_up_handler_af2pf_fdb_refresh(struct otx2_nic *pf, + struct af2pf_fdb_refresh_req *req, + struct msg_rsp *rsp); + #if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) enum { OTX2_DEV_UP =3D 1, @@ -32,10 +36,6 @@ int otx2_sw_nb_unregister(struct net_device *netdev); bool sw_nb_is_valid_dev(struct net_device *netdev); struct net_device *sw_nb_resolve_pf_dev(struct net_device *dev); =20 -int otx2_mbox_up_handler_af2pf_fdb_refresh(struct otx2_nic *pf, - struct af2pf_fdb_refresh_req *req, - struct msg_rsp *rsp); - bool sw_nb_is_cavium_dev(struct net_device *netdev); int sw_nb_fib_event_to_otx2_event(int event, struct net_device *netdev); int sw_nb_inetaddr_event_to_otx2_event(int event, struct net_device *netde= v); --=20 2.43.0 From nobody Sat Sep 26 18:54:41 2026 Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 752F34137A2; Mon, 31 Aug 2026 13:20:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.156.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182435; cv=none; b=i38VTBCDNuyqI8aEAn2JICEexnv+EtkKcWugjiAMiil3SKu2Jblly3vFBvuqpOeI56F3COz+ywdb9tzeuAds6knT8qG4AqGyzWFozOpYQRMFlYT+6R8Kg8s16ihYJwZlhI9EaiSLAy5uNxx9KSF4HkzBnrycWef+elcuGPj6Sv8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788182435; c=relaxed/simple; bh=U9fob+0AcBakT+kzdLlbxJwh8ZncMZN2DP7kvHyMa1Q=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=HzVREWJ0usCqGjDjjgAR0NTUJgwQtziFb4qbgNQGxCPFRIfTASVc9ZBYnfAoMROS8TbaiAPrMbRu1W58DXnCD+kwPbRHw/LWFu1sAEDkndR1aDMXCk6qDbgByM0PNjsWzOeYB6yYXRpiimml898DNgp7RsLe/Yl0ujSGFdjb+Zk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com; spf=pass smtp.mailfrom=marvell.com; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b=MKL+p47P; arc=none smtp.client-ip=67.231.156.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=marvell.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=marvell.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=marvell.com header.i=@marvell.com header.b="MKL+p47P" Received: from pps.filterd (m0431383.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 67VBCJdo668834; Mon, 31 Aug 2026 06:20:23 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=X n3AtDdfAthXBdjOI88bs8WZKEo0Br8Lt4WG9UpBztw=; b=MKL+p47PzW1hVDfPg AJBjZxxu9wCbJm44Gq55v+Mn+GKDaclxqbzYRRsyC/3nQZlmu+ksYKsqQJ9QNNuZ DEELwDCCwno7/NUpL78+2LxSVa2QXbiMRfm4o/Q4BfcFQIstnZhvhGj2tkL61rGw ZROI3JlNPQuUYRZKIBX/kuKGNbETj7bThLwy1U2rGUQCx9gZm7AOWt0V35jk6t5A 7vajwQNtZe0JSvNFi1TUg+lJjhIQoxevumm/UMcOXpp4O9w2MW6IjSUVbAD+yaMr LcQtJNDMbMhTsOazebOY3Rx4Mwutq9anjMv5zH7NltPLKmovoF2QmtLzRfnbAz7G 5KncA== Received: from dc5-exch05.marvell.com ([199.233.59.128]) by mx0b-0016f401.pphosted.com (PPS) with ESMTPS id 4gcg68jmry-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 31 Aug 2026 06:20:22 -0700 (PDT) Received: from DC5-EXCH05.marvell.com (10.69.176.209) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.25; Mon, 31 Aug 2026 06:20:21 -0700 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH05.marvell.com (10.69.176.209) with Microsoft SMTP Server id 15.2.1544.25 via Frontend Transport; Mon, 31 Aug 2026 06:20:21 -0700 Received: from rkannoth-OptiPlex-7090.. (unknown [10.28.36.165]) by maili.marvell.com (Postfix) with ESMTP id 960B13F7090; Mon, 31 Aug 2026 06:20:18 -0700 (PDT) From: Ratheesh Kannoth To: , CC: , , , , , , "Ratheesh Kannoth" Subject: [PATCH v9 net-next 8/8] octeontx2: switch: offload host FIB updates to switch via AF mailbox Date: Mon, 31 Aug 2026 18:49:44 +0530 Message-ID: <20260831131944.2649362-9-rkannoth@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260831131944.2649362-1-rkannoth@marvell.com> References: <20260831131944.2649362-1-rkannoth@marvell.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: Ca8KN7rdZbU4oBgP91QEKgOU8Eu6iTfJ X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfX4wSbYYq/aG/m MWn/7hHgTlSSV1+GwgP3nAAUd0TbUw5BuRAf7kO0IAL5XM/srNgS55H95WgR1j/HnsAK4lBgukq QavB0098hUGnVhFzuWHqRtwgrFVQRTRsdDGfSHTQSe0rxF72QkTl46QYob3xErquqqeLD7miR5j XEfH9tHHsu6Nua9JWmQpTyVnin1pU1NC9eC17PKpdyqYq/9CJljibqG8iTCqDsiQ8ArRlkmH5cn MjRL/UzID6pkHk6COEIaisKSXnAguVxDadEYdURHEXBWM2mHxpp/bOCS2In7Obq/Mzc0QChUmjI ypoJDEWpKnFQR73zkMNAtSPyaN26W84uCQqD7ijx+coe7LeM2H6gblpdfmdJBiADxZuHayi/jT9 GxQbH3qgr3DuFk9nl0T2Dfa80JZlDodCRn4ycFgPxES/FAkq1u6g51OZj1e/ubVmAQPnHjEwyzb 7/5V3CxJFMCsELFge8w== X-Authority-Analysis: v=2.4 cv=fZedDUQF c=1 sm=1 tr=0 ts=6a957f96 cx=c_pps a=rEv8fa4AjpPjGxpoe8rlIQ==:117 a=rEv8fa4AjpPjGxpoe8rlIQ==:17 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=l0iWHRpgs5sLHlkKQ1IR:22 a=qit2iCtTFQkLgVSMPQTB:22 a=M5GUcnROAAAA:8 a=na5_BN2stuqMQk1fQYAA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-GUID: Ca8KN7rdZbU4oBgP91QEKgOU8Eu6iTfJ X-Proofpoint-Spam-Info: AW1haW4tMjYwODMxMDExNSBTYWx0ZWRfXxMWb4ebc7rEQ 3h7Rjo1sCk2lbZJIXclyEs29H6fkp3ebqd1fcHjr+yafvkkLunDw2/5AWArk3dbK4MvW+AJZ8Qz jQOtYo9NiYwECPRd7zBuKnZwcwiz3RA= X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-31_04,2026-08-27_02,2025-10-01_01 Content-Type: text/plain; charset="utf-8" Queue IPv4/IPv6 FIB-derived updates from the switch notifier path and handle fib_notify in the RVU AF by batching fib_entry structures and sending them to the switch PF through the AF-to-switchdev FIB_CMD. Require the switch firmware to be ready before accepting offload work. Signed-off-by: Ratheesh Kannoth --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 8 +- .../marvell/octeontx2/af/switch/rvu_sw.c | 4 +- .../marvell/octeontx2/af/switch/rvu_sw_l3.c | 292 ++++++++++++++++++ .../marvell/octeontx2/af/switch/rvu_sw_l3.h | 2 + .../marvell/octeontx2/nic/switch/sw_fib.c | 242 +++++++++++++++ .../marvell/octeontx2/nic/switch/sw_fib.h | 14 + .../marvell/octeontx2/nic/switch/sw_nb.c | 8 +- .../marvell/octeontx2/nic/switch/sw_nb_v4.c | 192 +++++++----- .../marvell/octeontx2/nic/switch/sw_nb_v6.c | 21 +- .../marvell/octeontx2/nic/switch/sw_nb_v6.h | 31 +- 10 files changed, 720 insertions(+), 94 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net= /ethernet/marvell/octeontx2/af/mbox.h index 8f7b2962a212..d63dd57999ae 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -1915,18 +1915,20 @@ struct fib_entry { __be32 gw; __be32 gw6[4]; }; - u16 port_id; + u32 port_id; u8 nud_state; u8 rsvd3; u8 mac[ETH_ALEN]; u16 rsvd4; /* explicit tail padding */ }; =20 +#define RVU_SW_L3_ENTRY_MAX 12 + struct fib_notify_req { struct mbox_msghdr hdr; u16 cnt; u16 rsvd[3]; /* explicit padding for entry[] 8-byte alignment */ - struct fib_entry entry[16]; + struct fib_entry entry[RVU_SW_L3_ENTRY_MAX]; }; =20 struct fl_tuple { @@ -2000,7 +2002,7 @@ struct af2swdev_notify_req { struct { u8 cnt; u8 rsvd[7]; /* explicit padding before fib_entry[] */ - struct fib_entry entry[12]; + struct fib_entry entry[RVU_SW_L3_ENTRY_MAX]; }; =20 struct { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c b/dr= ivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c index 71f113bded5e..12f77ffc3eb7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c @@ -6,10 +6,10 @@ */ =20 #include - #include "rvu.h" #include "rvu_sw.h" #include "rvu_sw_l2.h" +#include "rvu_sw_l3.h" #include "rvu_sw_fl.h" =20 /* @@ -90,9 +90,11 @@ int rvu_mbox_handler_swdev2af_notify(struct rvu *rvu, void rvu_sw_shutdown(void) { rvu_sw_l2_shutdown(); + rvu_sw_l3_shutdown(); } =20 void rvu_sw_clear_shutdown(void) { rvu_sw_l2_clear_shutdown(); + rvu_sw_l3_clear_shutdown(); } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l3.c b= /drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l3.c index 2b798d5f0644..32735ae68e1d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l3.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l3.c @@ -4,11 +4,303 @@ * Copyright (C) 2026 Marvell. * */ + +#include #include "rvu.h" +#include "rvu_sw.h" +#include "rvu_sw_l3.h" + +static struct af2swdev_notify_req __maybe_unused +*otx2_mbox_alloc_msg_af2swdev_notify(struct rvu *rvu, int devid) +{ + struct af2swdev_notify_req *req; + + req =3D (struct af2swdev_notify_req *) + otx2_mbox_alloc_msg_rsp(&rvu->afpf_wq_info.mbox_up, devid, + sizeof(*req), sizeof(struct msg_rsp)); + if (!req) + return NULL; + req->hdr.sig =3D OTX2_MBOX_REQ_SIG; + req->hdr.id =3D MBOX_MSG_AF2SWDEV; + return req; +} + +struct l3_entry { + struct list_head list; + /* Always this AF driver's rvu; stored for clarity only (single RVU). */ + struct rvu *rvu; + u32 port_id; + int cnt; + struct fib_entry entry[]; +}; + +static DEFINE_MUTEX(l3_offl_llock); +static LIST_HEAD(l3_offl_lh); +static bool going_down; + +static struct workqueue_struct *sw_l3_offl_wq; +static void sw_l3_offl_work_handler(struct work_struct *work); +static DECLARE_DELAYED_WORK(l3_offl_work, sw_l3_offl_work_handler); + +/* + * FIB offload to the switch ASIC: one octeontx2 AF driver instance, one + * switch PF (switchdev), and one sw_l3_offl_wq per SoC. + */ + +static void rvu_sw_l3_drain_list(struct list_head *lh) +{ + struct l3_entry *entry; + + while ((entry =3D list_first_entry_or_null(lh, struct l3_entry, list))) { + list_del(&entry->list); + kfree(entry); + } +} + +static void rvu_sw_l3_queue_work_delay_locked(unsigned long delay_jiffies) +{ + lockdep_assert_held(&l3_offl_llock); + + if (sw_l3_offl_wq && !going_down) + queue_delayed_work(sw_l3_offl_wq, &l3_offl_work, delay_jiffies); +} + +static void rvu_sw_l3_queue_work_delay(unsigned long delay_jiffies) +{ + mutex_lock(&l3_offl_llock); + rvu_sw_l3_queue_work_delay_locked(delay_jiffies); + mutex_unlock(&l3_offl_llock); +} + +static void rvu_sw_l3_queue_work_locked(void) +{ + rvu_sw_l3_queue_work_delay_locked(msecs_to_jiffies(10)); +} + +static void rvu_sw_l3_queue_work(void) +{ + rvu_sw_l3_queue_work_delay(msecs_to_jiffies(10)); +} + +static int rvu_sw_l3_ensure_wq(void) +{ + lockdep_assert_held(&l3_offl_llock); + + if (going_down) + return -ENODEV; + + if (sw_l3_offl_wq) + return 0; + + sw_l3_offl_wq =3D alloc_workqueue("sw_af_fib_wq", 0, 0); + if (!sw_l3_offl_wq) + return -ENOMEM; + + return 0; +} + +static int rvu_sw_l3_offl_rule_push(struct list_head *lh) +{ + struct af2swdev_notify_req *req; + struct fib_entry *entry, *dst; + struct l3_entry *l3_entry; + struct rvu *rvu; + int tot_cnt =3D 0; + int swdev_pf; + int sz, cnt, i; + bool rc; + + BUILD_BUG_ON(sizeof_field(struct af2swdev_notify_req, entry) !=3D + sizeof(struct fib_entry) * RVU_SW_L3_ENTRY_MAX); + BUILD_BUG_ON(sizeof_field(struct fib_notify_req, entry) !=3D + sizeof(struct fib_entry) * RVU_SW_L3_ENTRY_MAX); + + l3_entry =3D list_first_entry_or_null(lh, struct l3_entry, list); + if (!l3_entry) + return 0; + + /* + * Octeontx2 has a single AF (one struct rvu) per RVU chip. All queued + * entries therefore share the same rvu and the same switch PF below. + * Host PF identity is carried per fib_entry (port_id), not by picking + * a different switch PF here. + */ + rvu =3D l3_entry->rvu; + swdev_pf =3D rvu_get_pf(rvu->pdev, rvu->rswitch.pcifunc); + + mutex_lock(&rvu->mbox_lock); + req =3D otx2_mbox_alloc_msg_af2swdev_notify(rvu, swdev_pf); + if (!req) { + mutex_unlock(&rvu->mbox_lock); + return -ENOMEM; + } + + dst =3D &req->entry[0]; + /* + * Batch fib_entry records from multiple host PF notifies into one + * af2swdev message. Safe on octeontx2: every l3_entry targets the + * same switch PF; egress port is encoded in each fib_entry.port_id. + * + * Entries are removed from lh and freed once copied into the mbox + * buffer, before the send attempt. If otx2_mbox_wait_for_zero() or + * the upstream send fails, that batch is lost with no replay path and + * the switch FIB may diverge from the host; tolerating that is a + * known limitation for now. + */ + while ((l3_entry =3D + list_first_entry_or_null(lh, + struct l3_entry, list)) !=3D NULL) { + entry =3D l3_entry->entry; + cnt =3D l3_entry->cnt; + + /* af2swdev_notify_req.entry[] holds RVU_SW_L3_ENTRY_MAX slots; + * stop before copying the next l3_entry when the mbox buffer + * would overflow. Leftovers stay on lh and are re-queued. + */ + if (tot_cnt + cnt > RVU_SW_L3_ENTRY_MAX) + break; + + sz =3D sizeof(*entry) * cnt; + + memcpy(dst, entry, sz); + for (i =3D 0; i < cnt; i++) + dst[i].port_id =3D l3_entry->port_id; + tot_cnt +=3D cnt; + dst +=3D cnt; + + list_del_init(&l3_entry->list); + kfree(l3_entry); + } + if (!tot_cnt) { + mutex_unlock(&rvu->mbox_lock); + return -EINVAL; + } + + req->flags =3D OTX2_FIB_CMD; + req->cnt =3D tot_cnt; + + rc =3D otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, swdev_pf); + if (rc) + otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, swdev_pf); + + mutex_unlock(&rvu->mbox_lock); + return rc ? 0 : -EFAULT; +} + +static void sw_l3_offl_work_handler(struct work_struct *work) +{ + struct list_head l3lh; + + INIT_LIST_HEAD(&l3lh); + + mutex_lock(&l3_offl_llock); + if (list_empty(&l3_offl_lh)) { + mutex_unlock(&l3_offl_llock); + return; + } + if (going_down) { + rvu_sw_l3_drain_list(&l3_offl_lh); + mutex_unlock(&l3_offl_llock); + return; + } + list_splice_init(&l3_offl_lh, &l3lh); + mutex_unlock(&l3_offl_llock); + + if (rvu_sw_l3_offl_rule_push(&l3lh)) + pr_err("%s: Error to push rules\n", __func__); + + /* rvu_sw_l3_offl_rule_push() may leave entries when a batch is full. */ + if (!list_empty(&l3lh)) { + mutex_lock(&l3_offl_llock); + if (!going_down && sw_l3_offl_wq) { + list_splice(&l3lh, &l3_offl_lh); + mutex_unlock(&l3_offl_llock); + rvu_sw_l3_queue_work_delay(msecs_to_jiffies(100)); + } else { + rvu_sw_l3_drain_list(&l3lh); + mutex_unlock(&l3_offl_llock); + } + return; + } + + mutex_lock(&l3_offl_llock); + if (!going_down && !list_empty(&l3_offl_lh)) + rvu_sw_l3_queue_work_locked(); + mutex_unlock(&l3_offl_llock); +} =20 int rvu_mbox_handler_fib_notify(struct rvu *rvu, struct fib_notify_req *req, struct msg_rsp *rsp) { + struct l3_entry *l3_entry; + int sz, rc; + + if (!(rvu->rswitch.flags & RVU_SWITCH_FLAG_FW_READY)) + return -EAGAIN; + + /* Reject notifies larger than the source fib_notify_req.entry[]. */ + if (!req->cnt || req->cnt > RVU_SW_L3_ENTRY_MAX) + return -EINVAL; + + sz =3D req->cnt * sizeof(struct fib_entry); + + l3_entry =3D kcalloc(1, sizeof(*l3_entry) + sz, GFP_KERNEL); + if (!l3_entry) + return -ENOMEM; + + l3_entry->port_id =3D rvu_sw_port_id(rvu, req->hdr.pcifunc); + l3_entry->rvu =3D rvu; + l3_entry->cnt =3D req->cnt; + INIT_LIST_HEAD(&l3_entry->list); + memcpy(l3_entry->entry, req->entry, sz); + + /* Host PFs on this RVU share one AF and one switch PF offload path. */ + mutex_lock(&l3_offl_llock); + if (going_down) { + mutex_unlock(&l3_offl_llock); + kfree(l3_entry); + return -ENODEV; + } + + rc =3D rvu_sw_l3_ensure_wq(); + if (rc) { + mutex_unlock(&l3_offl_llock); + kfree(l3_entry); + return rc; + } + + list_add_tail(&l3_entry->list, &l3_offl_lh); + mutex_unlock(&l3_offl_llock); + rvu_sw_l3_queue_work(); + return 0; } + +void rvu_sw_l3_shutdown(void) +{ + struct workqueue_struct *wq; + + mutex_lock(&l3_offl_llock); + going_down =3D true; + wq =3D sw_l3_offl_wq; + sw_l3_offl_wq =3D NULL; + mutex_unlock(&l3_offl_llock); + + if (!wq) + return; + + cancel_delayed_work_sync(&l3_offl_work); + destroy_workqueue(wq); + + mutex_lock(&l3_offl_llock); + rvu_sw_l3_drain_list(&l3_offl_lh); + mutex_unlock(&l3_offl_llock); +} + +void rvu_sw_l3_clear_shutdown(void) +{ + mutex_lock(&l3_offl_llock); + going_down =3D false; + mutex_unlock(&l3_offl_llock); +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l3.h b= /drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l3.h index ac8c4f9ba5ac..03836560077f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l3.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_l3.h @@ -8,4 +8,6 @@ #ifndef RVU_SW_L3_H #define RVU_SW_L3_H =20 +void rvu_sw_l3_shutdown(void); +void rvu_sw_l3_clear_shutdown(void); #endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fib.c b/d= rivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fib.c index f4c47111d763..318f7b68b8e4 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fib.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fib.c @@ -8,13 +8,255 @@ =20 #if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) =20 +#include +#include +#include +#include +#include +#include +#include + +#include "../otx2_reg.h" +#include "../otx2_common.h" +#include "../otx2_struct.h" +#include "../cn10k.h" +#include "sw_nb.h" + +#define SW_FIB_LIST_MAX 4096 +#define SW_FIB_NOTIFY_RETRY_MAX 100 + +/* + * One switch PF registers notifiers via otx2_sw_nb_register(); a second c= all + * returns -EBUSY. A single sw_fib_wq therefore serves the one switchdev + * instance on octeontx2, matching the FDB offload path. + */ +static DEFINE_SPINLOCK(sw_fib_llock); +static LIST_HEAD(sw_fib_lh); +static atomic_t sw_fib_list_cnt =3D ATOMIC_INIT(0); + +static struct workqueue_struct *sw_fib_wq; +static void sw_fib_work_handler(struct work_struct *work); +static DECLARE_DELAYED_WORK(sw_fib_work, sw_fib_work_handler); + +struct sw_fib_list_entry { + struct list_head lh; + struct otx2_nic *pf; + netdevice_tracker dev_tracker; + int cnt; + int retries; + struct fib_entry *entry; +}; + +static void sw_fib_list_cnt_warn(struct net_device *netdev) +{ + int n =3D atomic_read(&sw_fib_list_cnt); + + if (n < 0) + netdev_warn(netdev, "FIB list count underflow: %d\n", n); + else if (n > SW_FIB_LIST_MAX) + netdev_warn(netdev, "FIB list count overflow: %d (max %d)\n", + n, SW_FIB_LIST_MAX); +} + +static int sw_fib_list_count(void) +{ + return atomic_read(&sw_fib_list_cnt); +} + +static void sw_fib_list_cnt_inc(struct net_device *netdev) +{ + atomic_inc(&sw_fib_list_cnt); + sw_fib_list_cnt_warn(netdev); +} + +static void sw_fib_list_cnt_dec(struct net_device *netdev) +{ + atomic_dec(&sw_fib_list_cnt); + sw_fib_list_cnt_warn(netdev); +} + +static void sw_fib_list_entry_destroy(struct sw_fib_list_entry *lentry) +{ + struct net_device *dev =3D lentry->pf->netdev; + + sw_fib_list_cnt_dec(dev); + netdev_put(dev, &lentry->dev_tracker); + kfree(lentry->entry); + kfree(lentry); +} + +static int sw_fib_notify(struct otx2_nic *pf, + int cnt, + struct fib_entry *entry) +{ + struct fib_notify_req *req; + int rc; + + if (cnt > RVU_SW_L3_ENTRY_MAX) + return -EINVAL; + + mutex_lock(&pf->mbox.lock); + req =3D otx2_mbox_alloc_msg_fib_notify(&pf->mbox); + if (!req) { + rc =3D -ENOMEM; + goto out; + } + + req->cnt =3D cnt; + memcpy(req->entry, entry, sizeof(*entry) * cnt); + + rc =3D otx2_sync_mbox_msg(&pf->mbox); +out: + mutex_unlock(&pf->mbox.lock); + return rc; +} + +static void sw_fib_work_handler(struct work_struct *work) +{ + struct sw_fib_list_entry *lentry; + LIST_HEAD(tlist); + + spin_lock_bh(&sw_fib_llock); + list_splice_init(&sw_fib_lh, &tlist); + spin_unlock_bh(&sw_fib_llock); + + while ((lentry =3D + list_first_entry_or_null(&tlist, + struct sw_fib_list_entry, lh)) !=3D NULL) { + list_del_init(&lentry->lh); + if (sw_fib_notify(lentry->pf, lentry->cnt, lentry->entry)) { + struct net_device *dev =3D lentry->pf->netdev; + + lentry->retries++; + spin_lock_bh(&sw_fib_llock); + if (sw_fib_wq && lentry->retries < SW_FIB_NOTIFY_RETRY_MAX) { + /* + * TODO: Preserve strict FIB notify ordering on + * retry. Requeuing a failed ADD at the tail + * while continuing the batch lets a later DEL + * for the same route succeed first; when the + * ADD is retried the switch can keep a stale + * route the kernel already deleted. + */ + netdev_err(dev, + "Failed to notify FIB update to AF, will retry (%d/%d)\n", + lentry->retries, SW_FIB_NOTIFY_RETRY_MAX); + list_add_tail(&lentry->lh, &sw_fib_lh); + queue_delayed_work(sw_fib_wq, &sw_fib_work, + msecs_to_jiffies(100)); + spin_unlock_bh(&sw_fib_llock); + continue; + } + spin_unlock_bh(&sw_fib_llock); + netdev_err(dev, + "Failed to notify FIB update to AF, giving up after %d tries\n", + lentry->retries); + sw_fib_list_entry_destroy(lentry); + continue; + } + sw_fib_list_entry_destroy(lentry); + } + + spin_lock_bh(&sw_fib_llock); + if (!list_empty(&sw_fib_lh) && sw_fib_wq) + queue_delayed_work(sw_fib_wq, &sw_fib_work, + msecs_to_jiffies(10)); + spin_unlock_bh(&sw_fib_llock); +} + +int sw_fib_add_to_list(struct net_device *dev, + struct fib_entry *entry, int cnt) +{ + struct otx2_nic *pf =3D netdev_priv(dev); + struct sw_fib_list_entry *lentry; + struct workqueue_struct *wq; + + if (cnt <=3D 0 || cnt > RVU_SW_L3_ENTRY_MAX) { + kfree(entry); + return -EINVAL; + } + + spin_lock_bh(&sw_fib_llock); + if (!sw_fib_wq) { + spin_unlock_bh(&sw_fib_llock); + kfree(entry); + return -EINVAL; + } + spin_unlock_bh(&sw_fib_llock); + + if (sw_fib_list_count() >=3D SW_FIB_LIST_MAX) { + kfree(entry); + return -ENOMEM; + } + + lentry =3D kcalloc(1, sizeof(*lentry), GFP_ATOMIC); + if (!lentry) { + kfree(entry); + return -ENOMEM; + } + + lentry->pf =3D pf; + lentry->cnt =3D cnt; + lentry->entry =3D entry; + INIT_LIST_HEAD(&lentry->lh); + netdev_hold(dev, &lentry->dev_tracker, GFP_ATOMIC); + + spin_lock_bh(&sw_fib_llock); + wq =3D sw_fib_wq; + if (wq) { + list_add_tail(&lentry->lh, &sw_fib_lh); + sw_fib_list_cnt_inc(dev); + queue_delayed_work(wq, &sw_fib_work, + msecs_to_jiffies(10)); + } + spin_unlock_bh(&sw_fib_llock); + + if (!wq) { + netdev_put(dev, &lentry->dev_tracker); + kfree(lentry); + kfree(entry); + return -EINVAL; + } + + return 0; +} + int otx2_sw_fib_init(void) { + sw_fib_wq =3D alloc_workqueue("sw_pf_fib_wq", 0, 0); + if (!sw_fib_wq) + return -ENOMEM; + return 0; } =20 void otx2_sw_fib_deinit(void) { + struct sw_fib_list_entry *lentry; + struct workqueue_struct *wq; + LIST_HEAD(tlist); + + spin_lock_bh(&sw_fib_llock); + wq =3D sw_fib_wq; + sw_fib_wq =3D NULL; + spin_unlock_bh(&sw_fib_llock); + + if (!wq) + return; + + cancel_delayed_work_sync(&sw_fib_work); + destroy_workqueue(wq); + + spin_lock_bh(&sw_fib_llock); + list_splice_init(&sw_fib_lh, &tlist); + spin_unlock_bh(&sw_fib_llock); + + while ((lentry =3D + list_first_entry_or_null(&tlist, + struct sw_fib_list_entry, lh)) !=3D NULL) { + list_del_init(&lentry->lh); + sw_fib_list_entry_destroy(lentry); + } } =20 #endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fib.h b/d= rivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fib.h index 448d5612133e..046fdee42674 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fib.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fib.h @@ -8,11 +8,25 @@ #define SW_FIB_H_ =20 #include +#include + +struct fib_entry; +struct net_device; =20 #if IS_ENABLED(CONFIG_OCTEONTX_SWITCH) +int sw_fib_add_to_list(struct net_device *dev, + struct fib_entry *entry, int cnt); void otx2_sw_fib_deinit(void); int otx2_sw_fib_init(void); #else +static inline int sw_fib_add_to_list(struct net_device *dev, + struct fib_entry *entry, int cnt) +{ + (void)dev; + (void)cnt; + kfree(entry); + return 0; +} static inline void otx2_sw_fib_deinit(void) {} static inline int otx2_sw_fib_init(void) { return 0; } #endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c b/dr= ivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c index c947f30becc8..b512d4152ac8 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c @@ -185,6 +185,7 @@ static int sw_nb_fdb_event(struct notifier_block *unuse= d, { struct net_device *dev =3D switchdev_notifier_info_to_dev(ptr); struct switchdev_notifier_fdb_info *fdb_info =3D ptr; + int rc =3D 0; =20 if (!sw_nb_is_valid_dev(dev)) return NOTIFY_DONE; @@ -200,14 +201,17 @@ static int sw_nb_fdb_event(struct notifier_block *unu= sed, * setups; only Cavium PF/representor netdevs are supported * as bridge ports today (VLAN/virt under bridge is TODO). */ - sw_fdb_add_to_list(dev, (u8 *)fdb_info->addr, - event =3D=3D SWITCHDEV_FDB_ADD_TO_DEVICE); + rc =3D sw_fdb_add_to_list(dev, (u8 *)fdb_info->addr, + event =3D=3D SWITCHDEV_FDB_ADD_TO_DEVICE); break; =20 default: return NOTIFY_DONE; } =20 + if (rc) + netdev_err(dev, "%s: Error to add to list\n", __func__); + return NOTIFY_DONE; } =20 diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v4.c b= /drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v4.c index 31009e00121f..7ee3a98fc50d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v4.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v4.c @@ -12,6 +12,7 @@ #include #include #include +#include =20 #include "../otx2_reg.h" #include "../otx2_common.h" @@ -43,7 +44,13 @@ int sw_nb_v4_netdev_event(struct notifier_block *unused, if (!idev || !idev->ifa_list) return NOTIFY_DONE; =20 - /* Switch offload supports a single IPv4 address per interface for now. */ + if (!sw_nb_is_valid_dev(dev)) + return NOTIFY_DONE; + + /* Switch offload supports a single IPv4 address per interface for + * now. Only the head of ifa_list is offloaded on netdev events; + * secondary addresses are not supported by the hardware path. + */ ifa =3D rtnl_dereference(idev->ifa_list); =20 entry =3D kcalloc(1, sizeof(*entry), GFP_KERNEL); @@ -69,6 +76,10 @@ int sw_nb_v4_netdev_event(struct notifier_block *unused, entry->vlan_tag =3D cpu_to_be16(vlan_dev_vlan_id(dev)); } =20 + /* Switch offload is only enabled on OcteonTX2/CN10K SoCs. pf_dev is an + * octeontx2 PF or representor netdev, so netdev_priv() is otx2_nic even + * though sw_nb_is_cavium_dev() matches the shared Cavium PCI vendor ID. + */ pf =3D netdev_priv(pf_dev); entry->port_id =3D pf->pcifunc; =20 @@ -81,7 +92,7 @@ int sw_nb_v4_netdev_event(struct notifier_block *unused, =20 netdev_dbg(dev, "%s: pushing netdev event from HOST interface address %pI= 4n, %pM, dev=3D%s\n", __func__, &entry->dst, entry->mac, dev->name); - kfree(entry); + sw_fib_add_to_list(pf_dev, entry, 1); =20 return NOTIFY_DONE; } @@ -106,7 +117,8 @@ int sw_nb_v4_inetaddr_event(struct notifier_block *nb, return NOTIFY_DONE; =20 /* On NETDEV_DOWN the deleted address is passed in ifa; ifa_list may - * already be empty when the last address is removed. + * already be empty when the last address is unlinked before the + * notifier runs. */ entry =3D kcalloc(1, sizeof(*entry), GFP_ATOMIC); if (!entry) @@ -144,24 +156,27 @@ int sw_nb_v4_inetaddr_event(struct notifier_block *nb, netdev_dbg(dev, "%s: pushing inetaddr event from HOST interface address %= pI4n, %pM, %s\n", __func__, &entry->dst, entry->mac, dev->name); =20 - kfree(entry); + sw_fib_add_to_list(pf_dev, entry, 1); return NOTIFY_DONE; } =20 int sw_nb_v4_fib_event(struct notifier_block *nb, unsigned long event, void *ptr) { - struct net_device *dev, *pf_dev =3D NULL, *nh_pf_dev; struct fib_entry_notifier_info *fen_info =3D ptr; - struct fib_entry *entries, *iter; + struct net_device *host_pf_dev =3D NULL; struct netdev_hw_addr *dev_addr; + struct net_device *nh_pf_dev; + struct fib_nh_common *nhc; struct neighbour *neigh; + struct fib_entry *entry; + struct net_device *dev; struct fib_nh *fib_nh; struct fib_info *fi; struct otx2_nic *pf; + int i, cnt, nhs; __be32 *haddr; int hcnt =3D 0; - int cnt, i; =20 /* Process only UNICAST routes add or del */ if (fen_info->type !=3D RTN_UNICAST) @@ -171,13 +186,17 @@ int sw_nb_v4_fib_event(struct notifier_block *nb, if (!fi) return NOTIFY_DONE; =20 + nhs =3D fib_info_num_path(fi); + if (fi->fib_nh_is_v6) { - struct net_device *log_dev =3D (fi->fib_nhs > 0) ? - fi->fib_nh->fib_nh_dev : NULL; + if (nhs > 0) { + nhc =3D fib_info_nhc(fi, 0); =20 - if (log_dev) - netdev_dbg(log_dev, "%s: Received v6 notification\n", - __func__); + if (nhc->nhc_dev) + netdev_dbg(nhc->nhc_dev, + "%s: Received v6 notification\n", + __func__); + } return NOTIFY_DONE; } =20 @@ -186,19 +205,16 @@ int sw_nb_v4_fib_event(struct notifier_block *nb, * are walked below; nhid and nexthop-group installs are intentionally * skipped until fib_info_num_path()/fib_info_nhc() handling is added. */ - entries =3D kcalloc(fi->fib_nhs, sizeof(*entries), GFP_ATOMIC); - if (!entries) + if (!nhs) return NOTIFY_DONE; =20 - haddr =3D kcalloc(fi->fib_nhs, sizeof(*haddr), GFP_ATOMIC); - if (!haddr) { - kfree(entries); + haddr =3D kcalloc(nhs, sizeof(*haddr), GFP_ATOMIC); + if (!haddr) return NOTIFY_DONE; - } =20 - iter =3D entries; - fib_nh =3D fi->fib_nh; - for (i =3D 0; i < fi->fib_nhs; i++, fib_nh++) { + for (i =3D 0; i < nhs; i++) { + nhc =3D fib_info_nhc(fi, i); + fib_nh =3D container_of(nhc, struct fib_nh, nh_common); dev =3D fib_nh->fib_nh_dev; =20 if (!dev) @@ -210,107 +226,118 @@ int sw_nb_v4_fib_event(struct notifier_block *nb, if (!sw_nb_is_valid_dev(dev)) continue; =20 - iter->cmd =3D sw_nb_fib_event_to_otx2_event(event, dev); - iter->dst =3D htonl(fen_info->dst); - iter->dst_len =3D fen_info->dst_len; - iter->gw =3D fib_nh->fib_nh_gw4; - - netdev_dbg(dev, "%s: FIB route Rule cmd=3D%llu dst=3D%pI4n dst_len=3D%u = gw=3D%pI4n\n", - __func__, iter->cmd, &iter->dst, iter->dst_len, &iter->gw); - nh_pf_dev =3D sw_nb_resolve_pf_dev(dev); if (!nh_pf_dev) continue; - pf_dev =3D nh_pf_dev; + + entry =3D kcalloc(1, sizeof(*entry), GFP_ATOMIC); + if (!entry) + break; + + entry->cmd =3D sw_nb_fib_event_to_otx2_event(event, dev); + entry->dst =3D htonl(fen_info->dst); + entry->dst_len =3D fen_info->dst_len; + entry->gw =3D fib_nh->fib_nh_gw4; =20 if (netif_is_bridge_master(dev)) { - iter->bridge =3D 1; + entry->bridge =3D 1; } else if (is_vlan_dev(dev)) { - iter->vlan_valid =3D 1; - iter->vlan_tag =3D cpu_to_be16(vlan_dev_vlan_id(dev)); + entry->vlan_valid =3D 1; + entry->vlan_tag =3D cpu_to_be16(vlan_dev_vlan_id(dev)); } =20 - pf =3D netdev_priv(pf_dev); - iter->port_id =3D pf->pcifunc; + pf =3D netdev_priv(nh_pf_dev); + entry->port_id =3D pf->pcifunc; =20 /* Point-to-point routes, including default routes with no * gateway, are not supported for switch offload. */ - if (!fib_nh->fib_nh_gw4) + if (!fib_nh->fib_nh_gw4) { + if (!entry->dst && !entry->dst_len) { + kfree(entry); + continue; + } + sw_fib_add_to_list(nh_pf_dev, entry, 1); continue; - iter->gw_valid =3D 1; + } + + entry->gw_valid =3D 1; =20 if (fib_nh->nh_saddr) haddr[hcnt++] =3D fib_nh->nh_saddr; =20 + /* TODO: No replay mechanism yet when the gateway neighbor is + * unresolved. If ip_neigh_gw4() returns NULL the route is + * skipped here; sw_nb_net_v4_neigh_update() only pushes the + * MAC and does not replay the dropped route configuration. + */ rcu_read_lock(); neigh =3D ip_neigh_gw4(fib_nh->fib_nh_dev, fib_nh->fib_nh_gw4); - if (!neigh || IS_ERR(neigh)) { + if (IS_ERR_OR_NULL(neigh)) { rcu_read_unlock(); + kfree(entry); continue; } =20 - neigh_ha_snapshot(iter->mac, neigh, fib_nh->fib_nh_dev); - if (is_valid_ether_addr(iter->mac)) - iter->mac_valid =3D 1; - - iter++; + neigh_ha_snapshot(entry->mac, neigh, fib_nh->fib_nh_dev); + if (is_valid_ether_addr(entry->mac)) + entry->mac_valid =3D 1; rcu_read_unlock(); - } =20 - cnt =3D iter - entries; - if (!cnt) { - kfree(entries); - kfree(haddr); - return NOTIFY_DONE; + netdev_dbg(dev, "%s: FIB route Rule cmd=3D%llu dst=3D%pI4n dst_len=3D%u = gw=3D%pI4n\n", + __func__, entry->cmd, &entry->dst, entry->dst_len, + &entry->gw); + sw_fib_add_to_list(nh_pf_dev, entry, 1); } =20 - if (pf_dev) - netdev_dbg(pf_dev, "pf_dev is %s cnt=3D%d\n", pf_dev->name, cnt); - kfree(entries); - if (!hcnt) { kfree(haddr); return NOTIFY_DONE; } =20 - if (!pf_dev) { - kfree(haddr); - return NOTIFY_DONE; - } + for (i =3D 0; i < hcnt; i++) { + host_pf_dev =3D NULL; + for (cnt =3D 0; cnt < nhs; cnt++) { + nhc =3D fib_info_nhc(fi, cnt); + fib_nh =3D container_of(nhc, struct fib_nh, nh_common); + if (fib_nh->nh_saddr !=3D haddr[i]) + continue; + /* Skip blackhole or unresolved nexthops with no device. */ + if (!fib_nh->fib_nh_dev) + continue; + host_pf_dev =3D sw_nb_resolve_pf_dev(fib_nh->fib_nh_dev); + break; + } =20 - entries =3D kcalloc(hcnt, sizeof(*entries), GFP_ATOMIC); - if (!entries) { - kfree(haddr); - return NOTIFY_DONE; - } + if (!host_pf_dev) + continue; =20 - iter =3D entries; + entry =3D kcalloc(1, sizeof(*entry), GFP_ATOMIC); + if (!entry) + break; =20 - /* Host routes reuse pf_dev/pf from the last resolved Cavium netdev: - * pf_dev only identifies the switch AF mailbox context for switchdev - * programming; any previously resolved Cavium netdev is sufficient. - */ - for (i =3D 0; i < hcnt; i++, iter++) { - iter->cmd =3D sw_nb_fib_event_to_otx2_event(event, pf_dev); - iter->dst =3D haddr[i]; - iter->dst_len =3D 32; - iter->mac_valid =3D 1; - iter->host =3D 1; - iter->port_id =3D pf->pcifunc; + pf =3D netdev_priv(host_pf_dev); + entry->cmd =3D sw_nb_fib_event_to_otx2_event(event, host_pf_dev); + entry->dst =3D haddr[i]; + entry->dst_len =3D 32; + entry->mac_valid =3D 1; + entry->host =3D 1; + entry->port_id =3D pf->pcifunc; =20 rcu_read_lock(); - for_each_dev_addr(pf_dev, dev_addr) { - ether_addr_copy(iter->mac, dev_addr->addr); + for_each_dev_addr(host_pf_dev, dev_addr) { + ether_addr_copy(entry->mac, dev_addr->addr); break; } rcu_read_unlock(); =20 - netdev_dbg(pf_dev, "%s: FIB host Rule cmd=3D%llu dst=3D%pI4n dst_len=3D%= u %s\n", - __func__, iter->cmd, &iter->dst, iter->dst_len, - pf_dev->name); + netdev_dbg(host_pf_dev, + "%s: FIB host Rule cmd=3D%llu dst=3D%pI4n dst_len=3D%u %s\n", + __func__, entry->cmd, &entry->dst, entry->dst_len, + host_pf_dev->name); + sw_fib_add_to_list(host_pf_dev, entry, 1); } - kfree(entries); + kfree(haddr); return NOTIFY_DONE; } @@ -326,6 +353,9 @@ int sw_nb_net_v4_neigh_update(struct notifier_block *nb, if (n->tbl !=3D &arp_tbl) return NOTIFY_DONE; =20 + if (!sw_nb_is_valid_dev(n->dev)) + return NOTIFY_DONE; + entry =3D kcalloc(1, sizeof(*entry), GFP_ATOMIC); if (!entry) return NOTIFY_DONE; @@ -353,7 +383,7 @@ int sw_nb_net_v4_neigh_update(struct notifier_block *nb, pf =3D netdev_priv(pf_dev); entry->port_id =3D pf->pcifunc; =20 - kfree(entry); + sw_fib_add_to_list(pf_dev, entry, 1); return NOTIFY_DONE; } =20 diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v6.c b= /drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v6.c index 3497e60aedbe..2648bde47c18 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v6.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v6.c @@ -97,15 +97,15 @@ int sw_nb_v6_netdev_event(struct notifier_block *unused, =20 netdev_dbg(dev, "netdev event addr=3D%pI6c plen=3D%u mac=3D%pM\n", &addr, prefix_len, entry->mac); - kfree(entry); + sw_fib_add_to_list(pf_dev, entry, 1); return NOTIFY_DONE; } =20 int sw_nb_v6_fib_event(struct notifier_block *nb, unsigned long event, void *ptr) { - struct fib6_entry_notifier_info *f6_eni; struct fib_notifier_info *info =3D ptr; + struct fib6_entry_notifier_info *f6_eni; struct net_device *fib_dev, *pf_dev; struct fib_entry *entry; struct fib6_info *f6i; @@ -143,6 +143,11 @@ int sw_nb_v6_fib_event(struct notifier_block *nb, f6i->fib6_flags, f6i->fib6_protocol, f6i->fib6_type); =20 nh6 =3D f6i->nh ? nexthop_fib6_nh(f6i->nh) : f6i->fib6_nh; + /* + * TODO: Offload directly connected IPv6 subnets without an IPv6 + * gateway. fib_nh_gw_family is only AF_INET6 when RTF_GATEWAY is set, + * so connected routes are dropped here today. + */ if (nh6->fib_nh_gw_family !=3D AF_INET6) return NOTIFY_DONE; =20 @@ -174,10 +179,14 @@ int sw_nb_v6_fib_event(struct notifier_block *nb, /* TODO: No replay mechanism yet when the gateway neighbor is unresolved. * If ip_neigh_gw6() returns NULL the route is skipped here; add replay * from the neighbor update handler once nexthop resolution completes. + * + * TODO: Bypass gateway neighbour lookup for directly connected IPv6 + * routes, similar to sw_nb_v4_fib_event(). Unconditional ip_neigh_gw6() + * is incorrect when no gateway is configured. */ rcu_read_lock(); neigh =3D ip_neigh_gw6(fib_dev, &nh6->fib_nh_gw6); - if (!neigh || IS_ERR(neigh)) { + if (IS_ERR_OR_NULL(neigh)) { rcu_read_unlock(); kfree(entry); return NOTIFY_DONE; @@ -189,8 +198,8 @@ int sw_nb_v6_fib_event(struct notifier_block *nb, netdev_dbg(fib_dev, "fib found MAC=3D%pM\n", entry->mac); } =20 + sw_fib_add_to_list(pf_dev, entry, 1); rcu_read_unlock(); - kfree(entry); =20 return NOTIFY_DONE; } @@ -234,7 +243,7 @@ int sw_nb_net_v6_neigh_update(struct notifier_block *nb, netdev_dbg(n->dev, "v6 neigh update %pI6c mac=3D%pM plen=3D%u\n", (struct in6_addr *)n->primary_key, entry->mac, n->tbl->key_len * 8); - kfree(entry); + sw_fib_add_to_list(pf_dev, entry, 1); =20 return NOTIFY_DONE; } @@ -294,7 +303,7 @@ int sw_nb_v6_inetaddr_event(struct notifier_block *nb, =20 netdev_dbg(dev, "inetaddr addr=3D%pI6c len=3D%u %pM\n", &ifa6->addr, ifa6->prefix_len, entry->mac); - kfree(entry); + sw_fib_add_to_list(pf_dev, entry, 1); =20 return NOTIFY_DONE; } diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v6.h b= /drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v6.h index f73efc98c311..78c0df5eb880 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v6.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb_v6.h @@ -7,6 +7,9 @@ #ifndef SW_NB_V6_H_ #define SW_NB_V6_H_ =20 +#include + +#if IS_ENABLED(CONFIG_IPV6) int sw_nb_v6_fib_event(struct notifier_block *nb, unsigned long event, void *ptr); =20 @@ -18,4 +21,30 @@ int sw_nb_v6_inetaddr_event(struct notifier_block *nb, =20 int sw_nb_v6_netdev_event(struct notifier_block *unused, unsigned long event, void *ptr); -#endif // SW_NB_V6_H__ +#else +static inline int sw_nb_v6_fib_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + return NOTIFY_DONE; +} + +static inline int sw_nb_net_v6_neigh_update(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + return NOTIFY_DONE; +} + +static inline int sw_nb_v6_inetaddr_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + return NOTIFY_DONE; +} + +static inline int sw_nb_v6_netdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + return NOTIFY_DONE; +} +#endif + +#endif /* SW_NB_V6_H_ */ --=20 2.43.0