]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
fbnic: Push local unicast MAC addresses to FW to populate TCAMs
authorAlexander Duyck <alexanderduyck@fb.com>
Tue, 26 Aug 2025 19:45:07 +0000 (12:45 -0700)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 28 Aug 2025 12:51:07 +0000 (14:51 +0200)
The MACDA TCAM can only be accessed by one entity at a time and as such we
cannot have simultaneous reads from the firmware to probe for changes from
the host. As such we have to send a message indicating what the state of
the MACDA is to the firmware when we updated it so that the firmware can
sync up the TCAMs it owns to route BMC packets to the host.

To support that we are adding a new message that is invoked when we write
the MACDA that will notify the firmware of updates from the host and allow
it to sync up the TCAM configuration to match the one on the host side.

Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/175623750782.2246365.9178255870985916357.stgit@ahduyck-xeon-server.home.arpa
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/meta/fbnic/fbnic_fw.c
drivers/net/ethernet/meta/fbnic/fbnic_fw.h
drivers/net/ethernet/meta/fbnic/fbnic_rpc.c

index c7d255a095f0ecf97f0b17136ad8df690582c54a..6e580654493cf217ba2f7cb6da80e13da7f31e65 100644 (file)
@@ -1413,6 +1413,109 @@ void fbnic_mbx_flush_tx(struct fbnic_dev *fbd)
        } while (time_is_after_jiffies(timeout));
 }
 
+int fbnic_fw_xmit_rpc_macda_sync(struct fbnic_dev *fbd)
+{
+       struct fbnic_tlv_msg *mac_array;
+       int i, addr_count = 0, err;
+       struct fbnic_tlv_msg *msg;
+       u32 rx_flags = 0;
+
+       /* Nothing to do if there is no FW to sync with */
+       if (!fbd->mbx[FBNIC_IPC_MBX_TX_IDX].ready)
+               return 0;
+
+       msg = fbnic_tlv_msg_alloc(FBNIC_TLV_MSG_ID_RPC_MAC_SYNC_REQ);
+       if (!msg)
+               return -ENOMEM;
+
+       mac_array = fbnic_tlv_attr_nest_start(msg,
+                                             FBNIC_FW_RPC_MAC_SYNC_UC_ARRAY);
+       if (!mac_array)
+               goto free_message_nospc;
+
+       /* Populate the unicast MAC addrs and capture PROMISC/ALLMULTI flags */
+       for (addr_count = 0, i = FBNIC_RPC_TCAM_MACDA_PROMISC_IDX;
+            i >= fbd->mac_addr_boundary; i--) {
+               struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];
+
+               if (mac_addr->state != FBNIC_TCAM_S_VALID)
+                       continue;
+               if (test_bit(FBNIC_MAC_ADDR_T_ALLMULTI, mac_addr->act_tcam))
+                       rx_flags |= FW_RPC_MAC_SYNC_RX_FLAGS_ALLMULTI;
+               if (test_bit(FBNIC_MAC_ADDR_T_PROMISC, mac_addr->act_tcam))
+                       rx_flags |= FW_RPC_MAC_SYNC_RX_FLAGS_PROMISC;
+               if (!test_bit(FBNIC_MAC_ADDR_T_UNICAST, mac_addr->act_tcam))
+                       continue;
+               if (addr_count == FW_RPC_MAC_SYNC_UC_ARRAY_SIZE) {
+                       rx_flags |= FW_RPC_MAC_SYNC_RX_FLAGS_PROMISC;
+                       continue;
+               }
+
+               err = fbnic_tlv_attr_put_value(mac_array,
+                                              FBNIC_FW_RPC_MAC_SYNC_MAC_ADDR,
+                                              mac_addr->value.addr8,
+                                              ETH_ALEN);
+               if (err)
+                       goto free_message;
+               addr_count++;
+       }
+
+       /* Close array */
+       fbnic_tlv_attr_nest_stop(msg);
+
+       mac_array = fbnic_tlv_attr_nest_start(msg,
+                                             FBNIC_FW_RPC_MAC_SYNC_MC_ARRAY);
+       if (!mac_array)
+               goto free_message_nospc;
+
+       /* Repeat for multicast addrs, record BROADCAST/ALLMULTI flags */
+       for (addr_count = 0, i = FBNIC_RPC_TCAM_MACDA_BROADCAST_IDX;
+            i < fbd->mac_addr_boundary; i++) {
+               struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];
+
+               if (mac_addr->state != FBNIC_TCAM_S_VALID)
+                       continue;
+               if (test_bit(FBNIC_MAC_ADDR_T_BROADCAST, mac_addr->act_tcam))
+                       rx_flags |= FW_RPC_MAC_SYNC_RX_FLAGS_BROADCAST;
+               if (test_bit(FBNIC_MAC_ADDR_T_ALLMULTI, mac_addr->act_tcam))
+                       rx_flags |= FW_RPC_MAC_SYNC_RX_FLAGS_ALLMULTI;
+               if (!test_bit(FBNIC_MAC_ADDR_T_MULTICAST, mac_addr->act_tcam))
+                       continue;
+               if (addr_count == FW_RPC_MAC_SYNC_MC_ARRAY_SIZE) {
+                       rx_flags |= FW_RPC_MAC_SYNC_RX_FLAGS_ALLMULTI;
+                       continue;
+               }
+
+               err = fbnic_tlv_attr_put_value(mac_array,
+                                              FBNIC_FW_RPC_MAC_SYNC_MAC_ADDR,
+                                              mac_addr->value.addr8,
+                                              ETH_ALEN);
+               if (err)
+                       goto free_message;
+               addr_count++;
+       }
+
+       /* Close array */
+       fbnic_tlv_attr_nest_stop(msg);
+
+       /* Report flags at end of list */
+       err = fbnic_tlv_attr_put_int(msg, FBNIC_FW_RPC_MAC_SYNC_RX_FLAGS,
+                                    rx_flags);
+       if (err)
+               goto free_message;
+
+       /* Send message of to FW notifying it of current RPC config */
+       err = fbnic_mbx_map_tlv_msg(fbd, msg);
+       if (err)
+               goto free_message;
+       return 0;
+free_message_nospc:
+       err = -ENOSPC;
+free_message:
+       free_page((unsigned long)msg);
+       return err;
+}
+
 void fbnic_get_fw_ver_commit_str(struct fbnic_dev *fbd, char *fw_version,
                                 const size_t str_sz)
 {
index e9a2bf489944ac4596d7a1bada0be9293e811089..ec67b80809b0bba74722143b268653cde7a77105 100644 (file)
@@ -53,6 +53,7 @@ struct fbnic_fw_cap {
        u8      bmc_mac_addr[4][ETH_ALEN];
        u8      bmc_present             : 1;
        u8      need_bmc_tcam_reinit    : 1;
+       u8      need_bmc_macda_sync     : 1;
        u8      all_multi               : 1;
        u8      link_speed;
        u8      link_fec;
@@ -98,6 +99,7 @@ int fbnic_fw_xmit_tsene_read_msg(struct fbnic_dev *fbd,
                                 struct fbnic_fw_completion *cmpl_data);
 int fbnic_fw_xmit_send_logs(struct fbnic_dev *fbd, bool enable,
                            bool send_log_history);
+int fbnic_fw_xmit_rpc_macda_sync(struct fbnic_dev *fbd);
 struct fbnic_fw_completion *fbnic_fw_alloc_cmpl(u32 msg_type);
 void fbnic_fw_put_cmpl(struct fbnic_fw_completion *cmpl_data);
 
@@ -144,6 +146,7 @@ enum {
        FBNIC_TLV_MSG_ID_LOG_SEND_LOGS_REQ              = 0x43,
        FBNIC_TLV_MSG_ID_LOG_MSG_REQ                    = 0x44,
        FBNIC_TLV_MSG_ID_LOG_MSG_RESP                   = 0x45,
+       FBNIC_TLV_MSG_ID_RPC_MAC_SYNC_REQ               = 0x46,
 };
 
 #define FBNIC_FW_CAP_RESP_VERSION_MAJOR                CSR_GENMASK(31, 24)
@@ -236,4 +239,19 @@ enum {
        FBNIC_FW_LOG_MSG_MAX
 };
 
+enum {
+       FBNIC_FW_RPC_MAC_SYNC_RX_FLAGS          = 0x0,
+       FBNIC_FW_RPC_MAC_SYNC_UC_ARRAY          = 0x1,
+       FBNIC_FW_RPC_MAC_SYNC_MC_ARRAY          = 0x2,
+       FBNIC_FW_RPC_MAC_SYNC_MAC_ADDR          = 0x3,
+       FBNIC_FW_RPC_MAC_SYNC_MSG_MAX
+};
+
+#define FW_RPC_MAC_SYNC_RX_FLAGS_PROMISC       1
+#define FW_RPC_MAC_SYNC_RX_FLAGS_ALLMULTI      2
+#define FW_RPC_MAC_SYNC_RX_FLAGS_BROADCAST     4
+
+#define FW_RPC_MAC_SYNC_UC_ARRAY_SIZE          8
+#define FW_RPC_MAC_SYNC_MC_ARRAY_SIZE          8
+
 #endif /* _FBNIC_FW_H_ */
index d821625d602cedd5adb551449a64fa219f2b2ad2..4284b3cb7fccfd4208cdbf58e26f30316a139624 100644 (file)
@@ -240,11 +240,21 @@ void fbnic_bmc_rpc_init(struct fbnic_dev *fbd)
 
 void fbnic_bmc_rpc_check(struct fbnic_dev *fbd)
 {
+       int err;
+
        if (fbd->fw_cap.need_bmc_tcam_reinit) {
                fbnic_bmc_rpc_init(fbd);
                __fbnic_set_rx_mode(fbd);
                fbd->fw_cap.need_bmc_tcam_reinit = false;
        }
+
+       if (fbd->fw_cap.need_bmc_macda_sync) {
+               err = fbnic_fw_xmit_rpc_macda_sync(fbd);
+               if (err)
+                       dev_warn(fbd->dev,
+                                "Writing MACDA table to FW failed, err: %d\n", err);
+               fbd->fw_cap.need_bmc_macda_sync = false;
+       }
 }
 
 #define FBNIC_ACT1_INIT(_l4, _udp, _ip, _v6)           \
@@ -607,7 +617,7 @@ static void fbnic_write_macda_entry(struct fbnic_dev *fbd, unsigned int idx,
 
 void fbnic_write_macda(struct fbnic_dev *fbd)
 {
-       int idx;
+       int idx, updates = 0;
 
        for (idx = ARRAY_SIZE(fbd->mac_addr); idx--;) {
                struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[idx];
@@ -616,6 +626,9 @@ void fbnic_write_macda(struct fbnic_dev *fbd)
                if (!(mac_addr->state & FBNIC_TCAM_S_UPDATE))
                        continue;
 
+               /* Record update count */
+               updates++;
+
                /* Clear by writing 0s. */
                if (mac_addr->state == FBNIC_TCAM_S_DELETE) {
                        /* Invalidate entry and clear addr state info */
@@ -629,6 +642,14 @@ void fbnic_write_macda(struct fbnic_dev *fbd)
 
                mac_addr->state = FBNIC_TCAM_S_VALID;
        }
+
+       /* If reinitializing the BMC TCAM we are doing an initial update */
+       if (fbd->fw_cap.need_bmc_tcam_reinit)
+               updates++;
+
+       /* If needed notify firmware of changes to MACDA TCAM */
+       if (updates != 0 && fbnic_bmc_present(fbd))
+               fbd->fw_cap.need_bmc_macda_sync = true;
 }
 
 static void fbnic_clear_act_tcam(struct fbnic_dev *fbd, unsigned int idx)