[PATCH net-next v2 08/11] cxgb4: Add T7 support to the filter infrastructure.
From: Potnuri Bharat Teja <bharat@chelsio.com>
Date: 2026-09-21 14:00:41
Subsystem:
cxgb4 ethernet driver (cxgb4), networking drivers, the rest · Maintainers:
Potnuri Bharat Teja, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
T7 introduces a number of changes in filter-related register fields, firmware work request formats and CPL definitions. Update the filter code to use the appropriate T7-specific encodings while preserving existing behavior on earlier adapters. The changes include: - Use T7 reply channel and queue number encodings in filter-related CPL requests. - Add T7-specific filter capability validation using the new TP filter field definitions. - Enable validation and programming of the SYN-only filter field, which is supported on T7. - Adjust FW_FILTER_WR construction to match T7 semantics where the RX channel is no longer programmed through the legacy field. - Add support for T7 active-open filter requests using the T7 CPL layout and T7 filter tuple encoding. - Update filter resource handling to work correctly across T6 and T7 devices. Signed-off-by: Potnuri Bharat Teja <bharat@chelsio.com> --- .../net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 214 ++++++++++++------ 1 file changed, 141 insertions(+), 73 deletions(-)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
index 657d96b9e2f6..c9182c69cc7e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c@@ -66,9 +66,14 @@ static int set_tcb_field(struct adapter *adap, struct filter_entry *f, req = (struct cpl_set_tcb_field *)__skb_put_zero(skb, sizeof(*req)); INIT_TP_WR_CPL(req, CPL_SET_TCB_FIELD, ftid); - req->reply_ctrl = htons(REPLY_CHAN_V(0) | - QUEUENO_V(adap->sge.fw_evtq.abs_id) | - NO_REPLY_V(no_reply)); + if (CHELSIO_CHIP_VERSION(adap->params.chip) >= CHELSIO_T7) + req->reply_ctrl = htons(T7_REPLY_CHAN_V(0) | + T7_QUEUENO_V(adap->sge.fw_evtq.abs_id) | + NO_REPLY_V(no_reply)); + else + req->reply_ctrl = htons(REPLY_CHAN_V(0) | + QUEUENO_V(adap->sge.fw_evtq.abs_id) | + NO_REPLY_V(no_reply)); req->word_cookie = htons(TCB_WORD_V(word) | TCB_COOKIE_V(ftid)); req->mask = cpu_to_be64(mask); req->val = cpu_to_be64(val);
@@ -249,32 +254,53 @@ static int validate_filter(struct net_device *dev, struct ch_filter_specification *fs) { struct adapter *adapter = netdev2adap(dev); - u32 fconf, iconf; + u32 fconf, iconf, chip_ver; + chip_ver = CHELSIO_CHIP_VERSION(adapter->params.chip); /* Check for unconfigured fields being used. */ iconf = adapter->params.tp.ingress_config; fconf = fs->hash ? adapter->params.tp.filter_mask : adapter->params.tp.vlan_pri_map; - if (unsupported(fconf, FCOE_F, fs->val.fcoe, fs->mask.fcoe) || - unsupported(fconf, PORT_F, fs->val.iport, fs->mask.iport) || - unsupported(fconf, TOS_F, fs->val.tos, fs->mask.tos) || - unsupported(fconf, ETHERTYPE_F, fs->val.ethtype, - fs->mask.ethtype) || - unsupported(fconf, MACMATCH_F, fs->val.macidx, fs->mask.macidx) || - unsupported(fconf, MPSHITTYPE_F, fs->val.matchtype, - fs->mask.matchtype) || - unsupported(fconf, FRAGMENTATION_F, fs->val.frag, fs->mask.frag) || - unsupported(fconf, PROTOCOL_F, fs->val.proto, fs->mask.proto) || - unsupported(fconf, VNIC_ID_F, fs->val.pfvf_vld, - fs->mask.pfvf_vld) || - unsupported(fconf, VNIC_ID_F, fs->val.ovlan_vld, - fs->mask.ovlan_vld) || - unsupported(fconf, VNIC_ID_F, fs->val.encap_vld, - fs->mask.encap_vld) || - unsupported(fconf, VLAN_F, fs->val.ivlan_vld, fs->mask.ivlan_vld)) - return -EOPNOTSUPP; - + if (chip_ver >= CHELSIO_T7) { + if (unsupported(fconf, T7_FCOE_F, fs->val.fcoe, fs->mask.fcoe) || + unsupported(fconf, T7_PORT_F, fs->val.iport, fs->mask.iport) || + unsupported(fconf, T7_TOS_F, fs->val.tos, fs->mask.tos) || + unsupported(fconf, T7_ETHERTYPE_F, fs->val.ethtype, + fs->mask.ethtype) || + unsupported(fconf, T7_MACMATCH_F, fs->val.macidx, fs->mask.macidx) || + unsupported(fconf, T7_MPSHITTYPE_F, fs->val.matchtype, + fs->mask.matchtype) || + unsupported(fconf, T7_FRAGMENTATION_F, fs->val.frag, fs->mask.frag) || + unsupported(fconf, T7_PROTOCOL_F, fs->val.proto, fs->mask.proto) || + unsupported(fconf, T7_VNIC_ID_F, fs->val.pfvf_vld, + fs->mask.pfvf_vld) || + unsupported(fconf, T7_VNIC_ID_F, fs->val.ovlan_vld, + fs->mask.ovlan_vld) || + unsupported(fconf, T7_VNIC_ID_F, fs->val.encap_vld, + fs->mask.encap_vld) || + unsupported(fconf, T7_VLAN_F, fs->val.ivlan_vld, fs->mask.ivlan_vld)) + return -EOPNOTSUPP; + } else { + if (unsupported(fconf, FCOE_F, fs->val.fcoe, fs->mask.fcoe) || + unsupported(fconf, PORT_F, fs->val.iport, fs->mask.iport) || + unsupported(fconf, TOS_F, fs->val.tos, fs->mask.tos) || + unsupported(fconf, ETHERTYPE_F, fs->val.ethtype, + fs->mask.ethtype) || + unsupported(fconf, MACMATCH_F, fs->val.macidx, fs->mask.macidx) || + unsupported(fconf, MPSHITTYPE_F, fs->val.matchtype, + fs->mask.matchtype) || + unsupported(fconf, FRAGMENTATION_F, fs->val.frag, fs->mask.frag) || + unsupported(fconf, PROTOCOL_F, fs->val.proto, fs->mask.proto) || + unsupported(fconf, VNIC_ID_F, fs->val.pfvf_vld, + fs->mask.pfvf_vld) || + unsupported(fconf, VNIC_ID_F, fs->val.ovlan_vld, + fs->mask.ovlan_vld) || + unsupported(fconf, VNIC_ID_F, fs->val.encap_vld, + fs->mask.encap_vld) || + unsupported(fconf, VLAN_F, fs->val.ivlan_vld, fs->mask.ivlan_vld)) + return -EOPNOTSUPP; + } /* T4 inconveniently uses the same FT_VNIC_ID_W bits for both the Outer * VLAN Tag and PF/VF/VFvld fields based on VNIC_F being set * in TP_INGRESS_CONFIG. Hense the somewhat crazy checks
@@ -793,9 +819,12 @@ static int del_filter_wr(struct adapter *adapter, int fidx) int set_filter_wr(struct adapter *adapter, int fidx) { struct fw_filter2_wr *fwr; + unsigned int chip_ver; struct filter_entry *f; struct sk_buff *skb; + chip_ver = CHELSIO_CHIP_VERSION(adapter->params.chip); + if (fidx < adapter->tids.nhpftids) f = &adapter->tids.hpftid_tab[fidx]; else
@@ -883,8 +912,10 @@ int set_filter_wr(struct adapter *adapter, int fidx) if (f->fs.newsmac) fwr->smac_sel = f->smt->idx; fwr->rx_chan_rx_rpl_iq = - htons(FW_FILTER_WR_RX_CHAN_V(0) | - FW_FILTER_WR_RX_RPL_IQ_V(adapter->sge.fw_evtq.abs_id)); + htons(FW_FILTER_WR_RX_RPL_IQ_V(adapter->sge.fw_evtq.abs_id)); + if (chip_ver <= CHELSIO_T6) + fwr->rx_chan_rx_rpl_iq |= + htons(FW_FILTER_WR_RX_CHAN_V(cxgb4_port_e2cchan(f->dev))); fwr->maci_to_matchtypem = htonl(FW_FILTER_WR_MACI_V(f->fs.val.macidx) | FW_FILTER_WR_MACIM_V(f->fs.mask.macidx) |
@@ -993,7 +1024,9 @@ void clear_filter(struct adapter *adap, struct filter_entry *f) t4_free_encap_mac_filt(adap, pi->viid, f->fs.val.ovlan & 0x1ff, 0); - if ((f->fs.hash || is_t6(adap->params.chip)) && f->fs.type) + if ((f->fs.hash || + (CHELSIO_CHIP_VERSION(adap->params.chip) >= CHELSIO_T6)) && + f->fs.type) cxgb4_clip_release(f->dev, (const u32 *)&f->fs.val.lip, 1); /* The zeroing of the filter rule below clears the filter valid,
@@ -1296,20 +1329,16 @@ static void mk_act_open_req6(struct filter_entry *f, struct sk_buff *skb, unsigned int qid_filterid, struct adapter *adap) { struct cpl_t6_act_open_req6 *t6req = NULL; + struct cpl_t7_act_open_req6 *t7req = NULL; struct cpl_act_open_req6 *req = NULL; + u32 chip_ver; + __be32 opt2; + __be64 opt0; - t6req = (struct cpl_t6_act_open_req6 *)__skb_put(skb, sizeof(*t6req)); - INIT_TP_WR(t6req, 0); - req = (struct cpl_act_open_req6 *)t6req; - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6, qid_filterid)); - req->local_port = cpu_to_be16(f->fs.val.lport); - req->peer_port = cpu_to_be16(f->fs.val.fport); - req->local_ip_hi = *(__be64 *)(&f->fs.val.lip); - req->local_ip_lo = *(((__be64 *)&f->fs.val.lip) + 1); - req->peer_ip_hi = *(__be64 *)(&f->fs.val.fip); - req->peer_ip_lo = *(((__be64 *)&f->fs.val.fip) + 1); - req->opt0 = cpu_to_be64(NAGLE_V(f->fs.newvlan == VLAN_REMOVE || - f->fs.newvlan == VLAN_REWRITE) | + chip_ver = CHELSIO_CHIP_VERSION(adap->params.chip); + + opt0 = cpu_to_be64(NAGLE_V(f->fs.newvlan == VLAN_REMOVE || + f->fs.newvlan == VLAN_REWRITE) | DELACK_V(f->fs.hitcnts) | L2T_IDX_V(f->l2t ? f->l2t->idx : 0) | SMAC_SEL_V((cxgb4_port_viid(f->dev) &
@@ -1319,52 +1348,90 @@ static void mk_act_open_req6(struct filter_entry *f, struct sk_buff *skb, ULP_MODE_V(f->fs.nat_mode ? ULP_MODE_TCPDDP : ULP_MODE_NONE) | TCAM_BYPASS_F | NON_OFFLOAD_F); - t6req->params = cpu_to_be64(FILTER_TUPLE_V(hash_filter_ntuple(&f->fs, - f->dev))); - t6req->opt2 = htonl(RSS_QUEUE_VALID_F | - RSS_QUEUE_V(f->fs.iq) | - TX_QUEUE_V(f->fs.nat_mode) | - T5_OPT_2_VALID_F | - RX_CHANNEL_V(cxgb4_port_e2cchan(f->dev)) | - PACE_V((f->fs.maskhash) | + opt2 = cpu_to_be32(RSS_QUEUE_VALID_F | + RSS_QUEUE_V(f->fs.iq) | + TX_QUEUE_V(f->fs.nat_mode) | + T5_OPT_2_VALID_F | + RX_CHANNEL_V(cxgb4_port_e2cchan(f->dev)) | + PACE_V((f->fs.maskhash) | ((f->fs.dirsteerhash) << 1))); + + if (chip_ver >= CHELSIO_T7) { + t7req = (struct cpl_t7_act_open_req6 *)__skb_put(skb, sizeof(*t7req)); + INIT_TP_WR(t7req, 0); + req = (struct cpl_act_open_req6 *)t7req; + t7req->opt0 = opt0; + t7req->opt2 = opt2; + t7req->params = cpu_to_be64(T7_FILTER_TUPLE_V(hash_filter_ntuple(&f->fs, f->dev))); + } else { + t6req = (struct cpl_t6_act_open_req6 *)__skb_put(skb, sizeof(*t6req)); + INIT_TP_WR(t6req, 0); + req = (struct cpl_act_open_req6 *)t6req; + t6req->opt0 = opt0; + t6req->opt2 = opt2; + t6req->params = cpu_to_be64(FILTER_TUPLE_V(hash_filter_ntuple(&f->fs, f->dev))); + } + + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6, qid_filterid)); + req->local_port = cpu_to_be16(f->fs.val.lport); + req->peer_port = cpu_to_be16(f->fs.val.fport); + req->local_ip_hi = *(__be64 *)(&f->fs.val.lip); + req->local_ip_lo = *(((__be64 *)&f->fs.val.lip) + 1); + req->peer_ip_hi = *(__be64 *)(&f->fs.val.fip); + req->peer_ip_lo = *(((__be64 *)&f->fs.val.fip) + 1); } static void mk_act_open_req(struct filter_entry *f, struct sk_buff *skb, unsigned int qid_filterid, struct adapter *adap) { struct cpl_t6_act_open_req *t6req = NULL; + struct cpl_t7_act_open_req *t7req = NULL; struct cpl_act_open_req *req = NULL; + u32 chip_ver; + __be32 opt2; + __be64 opt0; + + chip_ver = CHELSIO_CHIP_VERSION(adap->params.chip); + + opt0 = cpu_to_be64(NAGLE_V(f->fs.newvlan == VLAN_REMOVE || + f->fs.newvlan == VLAN_REWRITE) | + DELACK_V(f->fs.hitcnts) | + L2T_IDX_V(f->l2t ? f->l2t->idx : 0) | + SMAC_SEL_V((cxgb4_port_viid(f->dev) & + 0x7F) << 1) | + TX_CHAN_V(f->fs.eport) | + NO_CONG_V(f->fs.rpttid) | + ULP_MODE_V(f->fs.nat_mode ? + ULP_MODE_TCPDDP : ULP_MODE_NONE) | + TCAM_BYPASS_F | NON_OFFLOAD_F); + opt2 = cpu_to_be32(RSS_QUEUE_VALID_F | + RSS_QUEUE_V(f->fs.iq) | + TX_QUEUE_V(f->fs.nat_mode) | + T5_OPT_2_VALID_F | + RX_CHANNEL_V(cxgb4_port_e2cchan(f->dev)) | + PACE_V((f->fs.maskhash) | + ((f->fs.dirsteerhash) << 1))); + if (chip_ver >= CHELSIO_T7) { + t7req = (struct cpl_t7_act_open_req *)__skb_put(skb, sizeof(*t7req)); + INIT_TP_WR(t7req, 0); + req = (struct cpl_act_open_req *)t7req; + t7req->opt0 = opt0; + t7req->opt2 = opt2; + t7req->params = cpu_to_be64(T7_FILTER_TUPLE_V(hash_filter_ntuple(&f->fs, f->dev))); + } else { + t6req = (struct cpl_t6_act_open_req *)__skb_put(skb, sizeof(*t6req)); + INIT_TP_WR(t6req, 0); + req = (struct cpl_act_open_req *)t6req; + t6req->opt0 = opt0; + t6req->opt2 = opt2; + t6req->params = cpu_to_be64(FILTER_TUPLE_V(hash_filter_ntuple(&f->fs, f->dev))); + } - t6req = (struct cpl_t6_act_open_req *)__skb_put(skb, sizeof(*t6req)); - INIT_TP_WR(t6req, 0); - req = (struct cpl_act_open_req *)t6req; OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, qid_filterid)); req->local_port = cpu_to_be16(f->fs.val.lport); req->peer_port = cpu_to_be16(f->fs.val.fport); memcpy(&req->local_ip, f->fs.val.lip, 4); memcpy(&req->peer_ip, f->fs.val.fip, 4); - req->opt0 = cpu_to_be64(NAGLE_V(f->fs.newvlan == VLAN_REMOVE || - f->fs.newvlan == VLAN_REWRITE) | - DELACK_V(f->fs.hitcnts) | - L2T_IDX_V(f->l2t ? f->l2t->idx : 0) | - SMAC_SEL_V((cxgb4_port_viid(f->dev) & - 0x7F) << 1) | - TX_CHAN_V(f->fs.eport) | - NO_CONG_V(f->fs.rpttid) | - ULP_MODE_V(f->fs.nat_mode ? - ULP_MODE_TCPDDP : ULP_MODE_NONE) | - TCAM_BYPASS_F | NON_OFFLOAD_F); - - t6req->params = cpu_to_be64(FILTER_TUPLE_V(hash_filter_ntuple(&f->fs, - f->dev))); - t6req->opt2 = htonl(RSS_QUEUE_VALID_F | - RSS_QUEUE_V(f->fs.iq) | - TX_QUEUE_V(f->fs.nat_mode) | - T5_OPT_2_VALID_F | - RX_CHANNEL_V(cxgb4_port_e2cchan(f->dev)) | - PACE_V((f->fs.maskhash) | - ((f->fs.dirsteerhash) << 1))); } static int cxgb4_set_hash_filter(struct net_device *dev,
@@ -1663,7 +1730,7 @@ int __cxgb4_set_filter(struct net_device *dev, int ftid, if (ret) goto free_tid; - if (is_t6(adapter->params.chip) && fs->type && + if (chip_ver >= CHELSIO_T6 && fs->type && ipv6_addr_type((const struct in6_addr *)fs->val.lip) != IPV6_ADDR_ANY) { ret = cxgb4_clip_get(dev, (const u32 *)&fs->val.lip, 1);
@@ -2140,12 +2207,13 @@ void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl) void init_hash_filter(struct adapter *adap) { - u32 reg; + u32 reg, chip_ver; + chip_ver = CHELSIO_CHIP_VERSION(adap->params.chip); /* On T6, verify the necessary register configs and warn the user in * case of improper config */ - if (is_t6(adap->params.chip)) { + if (chip_ver >= CHELSIO_T6) { if (is_offload(adap)) { if (!(t4_read_reg(adap, TP_GLOBAL_CONFIG_A) & ACTIVEFILTERCOUNTS_F)) {
--
2.47.3