[PATCH iwl-next v3 4/8] ice: allow overriding lan_en, lb_en in switch

Jakub Slepecki
2026-01-20T10:34:50Z

Currently, lan_en and lb_en are determined based on switching mode,
destination MAC, and the lookup type, action type and flags of the rule
in question. This gives little to no options for the user (such as
ice_fltr.c) to enforce rules to behave in a specific way.

Such functionality is needed to work with pairs of rules, for example,
when handling MAC forward to LAN together with MAC,VLAN forward to
loopback rules pair. This case could not be easily deduced in a context
of a single filter without adding some guessing logic or a specialized
flag.

Add a slightly more generic flag to the lan_en and lb_en themselves
for the ice_fltr.c to request specific destination flags later on,
for example, to override both values:

struct ice_fltr_info fi;
fi.lb_en = ICE_FLTR_INFO_LB_LAN_FORCE_ENABLED;
fi.lan_en = ICE_FLTR_INFO_LB_LAN_FORCE_DISABLED;

Signed-off-by: Jakub Slepecki <jakub.slepecki@intel.com>
---
I considered a resend or bumping the old thread, because we did not finish
the discussion last time with Aleksandr, but I feel like this version
addresses most if not all of the points that were made. One exception is
that I did not split the fields, but that was only one of the solutions.
Nonetheless, this should be overall a good starting point for a
discussion.

Changes in v3:
- LB_LAN masks and values no longer rely on boolean promotion.
- ice_fill_sw_info() deals with u8 the entire time instead of building
building lb_en and lan_en values at the end from booleans.

Changes in v2:
- Use FIELD_GET et al. when handling fi.lb_en and fi.lan_en.
- Rename /LB_LAN/s/_MASK/_M/ because one of uses would need to break
line
---
drivers/net/ethernet/intel/ice/ice_switch.c | 25 +++++++++++++--------
drivers/net/ethernet/intel/ice/ice_switch.h | 19 +++++++++++++---
2 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c
index 04e5d653efce..3caccd798220 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.c
+++ b/drivers/net/ethernet/intel/ice/ice_switch.c
@@ -2534,12 +2534,14 @@ int ice_get_initial_sw_cfg(struct ice_hw *hw)
*
* This helper function populates the lb_en and lan_en elements of the provided
* ice_fltr_info struct using the switch's type and characteristics of the
- * switch rule being configured.
+ * switch rule being configured. Elements are updated only if their FORCE bit
+ * is not set.
*/
static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi)
{
- fi->lb_en = false;
- fi->lan_en = false;
+ u8 lan_en = fi->lan_en;
+ u8 lb_en = fi->lb_en;
+
if ((fi->flag & ICE_FLTR_TX) &&
(fi->fltr_act == ICE_FWD_TO_VSI ||
fi->fltr_act == ICE_FWD_TO_VSI_LIST ||
@@ -2549,7 +2551,7 @@ static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi)
* packets to the internal switch that will be dropped.
*/
if (fi->lkup_type != ICE_SW_LKUP_VLAN)
- fi->lb_en = true;
+ FIELD_MODIFY(ICE_FLTR_INFO_LB_LAN_VALUE_M, &lb_en, 1);

/* Set lan_en to TRUE if
* 1. The switch is a VEB AND
@@ -2578,14 +2580,19 @@ static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi)
!is_unicast_ether_addr(fi->l_data.mac.mac_addr)) ||
(fi->lkup_type == ICE_SW_LKUP_MAC_VLAN &&
!is_unicast_ether_addr(fi->l_data.mac.mac_addr)))
- fi->lan_en = true;
+ FIELD_MODIFY(ICE_FLTR_INFO_LB_LAN_VALUE_M,
+ &lan_en, 1);
} else {
- fi->lan_en = true;
+ FIELD_MODIFY(ICE_FLTR_INFO_LB_LAN_VALUE_M, &lan_en, 1);
}
}

if (fi->flag & ICE_FLTR_TX_ONLY)
- fi->lan_en = false;
+ FIELD_MODIFY(ICE_FLTR_INFO_LB_LAN_VALUE_M, &lan_en, 0);
+ if (!FIELD_GET(ICE_FLTR_INFO_LB_LAN_FORCE_M, lb_en))
+ fi->lb_en = lb_en;
+ if (!FIELD_GET(ICE_FLTR_INFO_LB_LAN_FORCE_M, lan_en))
+ fi->lan_en = lan_en;
}

/**
@@ -2669,9 +2676,9 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
return;
}

- if (f_info->lb_en)
+ if (FIELD_GET(ICE_FLTR_INFO_LB_LAN_VALUE_M, f_info->lb_en))
act |= ICE_SINGLE_ACT_LB_ENABLE;
- if (f_info->lan_en)
+ if (FIELD_GET(ICE_FLTR_INFO_LB_LAN_VALUE_M, f_info->lan_en))
act |= ICE_SINGLE_ACT_LAN_ENABLE;

switch (f_info->lkup_type) {
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h
index 671d7a5f359f..137eae878ab1 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.h
+++ b/drivers/net/ethernet/intel/ice/ice_switch.h
@@ -72,6 +72,14 @@ enum ice_src_id {
ICE_SRC_ID_LPORT,
};

+#define ICE_FLTR_INFO_LB_LAN_VALUE_M BIT(0)
+#define ICE_FLTR_INFO_LB_LAN_FORCE_M BIT(1)
+#define ICE_FLTR_INFO_LB_LAN_FORCE_ENABLED \
+ (FIELD_PREP_CONST(ICE_FLTR_INFO_LB_LAN_VALUE_M, 1) | \
+ FIELD_PREP_CONST(ICE_FLTR_INFO_LB_LAN_FORCE_M, 1))
+#define ICE_FLTR_INFO_LB_LAN_FORCE_DISABLED \
+ (FIELD_PREP_CONST(ICE_FLTR_INFO_LB_LAN_FORCE_M, 1))
+
struct ice_fltr_info {
/* Look up information: how to look up packet */
enum ice_sw_lkup_type lkup_type;
@@ -131,9 +139,14 @@ struct ice_fltr_info {
*/
u8 qgrp_size;

- /* Rule creations populate these indicators basing on the switch type */
- u8 lb_en; /* Indicate if packet can be looped back */
- u8 lan_en; /* Indicate if packet can be forwarded to the uplink */
+ /* Following members have two bits: VALUE and FORCE. Rule creation will
+ * populate VALUE bit of these members based on switch type, but only if
+ * their FORCE bit is not set.
+ *
+ * See ICE_FLTR_INFO_LB_LAN_VALUE_M and ICE_FLTR_INFO_LB_LAN_FORCE_M.
+ */
+ u8 lb_en; /* VALUE bit: packet can be looped back */
+ u8 lan_en; /* VALUE bit: packet can be forwarded to the uplink */
};

struct ice_update_recipe_lkup_idx_params {
--
2.43.0