diff options
-rw-r--r-- | drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 106 | ||||
-rw-r--r-- | drivers/net/ethernet/meta/fbnic/fbnic_fw.h | 23 | ||||
-rw-r--r-- | drivers/net/ethernet/meta/fbnic/fbnic_netdev.c | 60 | ||||
-rw-r--r-- | drivers/net/ethernet/meta/fbnic/fbnic_netdev.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/meta/fbnic/fbnic_pci.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/meta/fbnic/fbnic_rpc.c | 86 | ||||
-rw-r--r-- | drivers/net/ethernet/meta/fbnic/fbnic_rpc.h | 4 |
7 files changed, 225 insertions, 64 deletions
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c index 0c55be7d2547..6e580654493c 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c @@ -653,6 +653,9 @@ static int fbnic_fw_parse_cap_resp(void *opaque, struct fbnic_tlv_msg **results) fbd->fw_cap.anti_rollback_version = fta_get_uint(results, FBNIC_FW_CAP_RESP_ANTI_ROLLBACK_VERSION); + /* Always assume we need a BMC reinit */ + fbd->fw_cap.need_bmc_tcam_reinit = true; + return 0; } @@ -1410,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) { diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h index fde331696fdd..ec67b80809b0 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h @@ -51,8 +51,10 @@ struct fbnic_fw_cap { } stored; u8 active_slot; u8 bmc_mac_addr[4][ETH_ALEN]; - u8 bmc_present : 1; - u8 all_multi : 1; + 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; u32 anti_rollback_version; @@ -97,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); @@ -143,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) @@ -235,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_ */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c index 98602bc3b39f..0cf1ea927cc0 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c @@ -179,11 +179,10 @@ static int fbnic_mc_unsync(struct net_device *netdev, const unsigned char *addr) return ret; } -void __fbnic_set_rx_mode(struct net_device *netdev) +void __fbnic_set_rx_mode(struct fbnic_dev *fbd) { - struct fbnic_net *fbn = netdev_priv(netdev); bool uc_promisc = false, mc_promisc = false; - struct fbnic_dev *fbd = fbn->fbd; + struct net_device *netdev = fbd->netdev; struct fbnic_mac_addr *mac_addr; int err; @@ -220,49 +219,8 @@ void __fbnic_set_rx_mode(struct net_device *netdev) uc_promisc |= !!(netdev->flags & IFF_PROMISC); mc_promisc |= !!(netdev->flags & IFF_ALLMULTI) || uc_promisc; - /* Populate last TCAM entry with promiscuous entry and 0/1 bit mask */ - mac_addr = &fbd->mac_addr[FBNIC_RPC_TCAM_MACDA_PROMISC_IDX]; - if (uc_promisc) { - if (!is_zero_ether_addr(mac_addr->value.addr8) || - mac_addr->state != FBNIC_TCAM_S_VALID) { - eth_zero_addr(mac_addr->value.addr8); - eth_broadcast_addr(mac_addr->mask.addr8); - clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI, - mac_addr->act_tcam); - set_bit(FBNIC_MAC_ADDR_T_PROMISC, - mac_addr->act_tcam); - mac_addr->state = FBNIC_TCAM_S_ADD; - } - } else if (mc_promisc && - (!fbnic_bmc_present(fbd) || !fbd->fw_cap.all_multi)) { - /* We have to add a special handler for multicast as the - * BMC may have an all-multi rule already in place. As such - * adding a rule ourselves won't do any good so we will have - * to modify the rules for the ALL MULTI below if the BMC - * already has the rule in place. - */ - if (!is_multicast_ether_addr(mac_addr->value.addr8) || - mac_addr->state != FBNIC_TCAM_S_VALID) { - eth_zero_addr(mac_addr->value.addr8); - eth_broadcast_addr(mac_addr->mask.addr8); - mac_addr->value.addr8[0] ^= 1; - mac_addr->mask.addr8[0] ^= 1; - set_bit(FBNIC_MAC_ADDR_T_ALLMULTI, - mac_addr->act_tcam); - clear_bit(FBNIC_MAC_ADDR_T_PROMISC, - mac_addr->act_tcam); - mac_addr->state = FBNIC_TCAM_S_ADD; - } - } else if (mac_addr->state == FBNIC_TCAM_S_VALID) { - if (test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam)) { - clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI, - mac_addr->act_tcam); - clear_bit(FBNIC_MAC_ADDR_T_PROMISC, - mac_addr->act_tcam); - } else { - mac_addr->state = FBNIC_TCAM_S_DELETE; - } - } + /* Update the promiscuous rules */ + fbnic_promisc_sync(fbd, uc_promisc, mc_promisc); /* Add rules for BMC all multicast if it is enabled */ fbnic_bmc_rpc_all_multi_config(fbd, mc_promisc); @@ -278,9 +236,12 @@ void __fbnic_set_rx_mode(struct net_device *netdev) static void fbnic_set_rx_mode(struct net_device *netdev) { + struct fbnic_net *fbn = netdev_priv(netdev); + struct fbnic_dev *fbd = fbn->fbd; + /* No need to update the hardware if we are not running */ if (netif_running(netdev)) - __fbnic_set_rx_mode(netdev); + __fbnic_set_rx_mode(fbd); } static int fbnic_set_mac(struct net_device *netdev, void *p) @@ -297,10 +258,9 @@ static int fbnic_set_mac(struct net_device *netdev, void *p) return 0; } -void fbnic_clear_rx_mode(struct net_device *netdev) +void fbnic_clear_rx_mode(struct fbnic_dev *fbd) { - struct fbnic_net *fbn = netdev_priv(netdev); - struct fbnic_dev *fbd = fbn->fbd; + struct net_device *netdev = fbd->netdev; int idx; for (idx = ARRAY_SIZE(fbd->mac_addr); idx--;) { diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h index 0a6347f28210..e84e0527c3a9 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h @@ -94,8 +94,8 @@ void fbnic_time_init(struct fbnic_net *fbn); int fbnic_time_start(struct fbnic_net *fbn); void fbnic_time_stop(struct fbnic_net *fbn); -void __fbnic_set_rx_mode(struct net_device *netdev); -void fbnic_clear_rx_mode(struct net_device *netdev); +void __fbnic_set_rx_mode(struct fbnic_dev *fbd); +void fbnic_clear_rx_mode(struct fbnic_dev *fbd); void fbnic_phylink_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c index ef7928b18ac0..b3c27c566f52 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c @@ -137,7 +137,7 @@ void fbnic_up(struct fbnic_net *fbn) fbnic_rss_reinit_hw(fbn->fbd, fbn); - __fbnic_set_rx_mode(fbn->netdev); + __fbnic_set_rx_mode(fbn->fbd); /* Enable Tx/Rx processing */ fbnic_napi_enable(fbn); @@ -154,7 +154,7 @@ void fbnic_down_noidle(struct fbnic_net *fbn) fbnic_napi_disable(fbn); netif_tx_disable(fbn->netdev); - fbnic_clear_rx_mode(fbn->netdev); + fbnic_clear_rx_mode(fbn->fbd); fbnic_clear_rules(fbn->fbd); fbnic_rss_disable_hw(fbn->fbd); fbnic_disable(fbn); @@ -206,6 +206,8 @@ static void fbnic_service_task(struct work_struct *work) fbnic_health_check(fbd); + fbnic_bmc_rpc_check(fbd); + if (netif_carrier_ok(fbd->netdev)) fbnic_napi_depletion_check(fbd->netdev); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c index a4dc1024c0c2..4284b3cb7fcc 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c @@ -6,6 +6,7 @@ #include <net/ipv6.h> #include "fbnic.h" +#include "fbnic_fw.h" #include "fbnic_netdev.h" #include "fbnic_rpc.h" @@ -131,12 +132,9 @@ void fbnic_bmc_rpc_all_multi_config(struct fbnic_dev *fbd, else clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI, mac_addr->act_tcam); - } else if (!test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam) && - !is_zero_ether_addr(mac_addr->mask.addr8) && - mac_addr->state == FBNIC_TCAM_S_VALID) { - clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI, mac_addr->act_tcam); - clear_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam); - mac_addr->state = FBNIC_TCAM_S_DELETE; + } else { + __fbnic_xc_unsync(mac_addr, FBNIC_MAC_ADDR_T_BMC); + __fbnic_xc_unsync(mac_addr, FBNIC_MAC_ADDR_T_ALLMULTI); } /* We have to add a special handler for multicast as the @@ -238,8 +236,25 @@ void fbnic_bmc_rpc_init(struct fbnic_dev *fbd) act_tcam->mask.tcam[j] = 0xffff; act_tcam->state = FBNIC_TCAM_S_UPDATE; +} - fbnic_bmc_rpc_all_multi_config(fbd, false); +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) \ @@ -454,6 +469,50 @@ int __fbnic_xc_unsync(struct fbnic_mac_addr *mac_addr, unsigned int tcam_idx) return 0; } +void fbnic_promisc_sync(struct fbnic_dev *fbd, + bool uc_promisc, bool mc_promisc) +{ + struct fbnic_mac_addr *mac_addr; + + /* Populate last TCAM entry with promiscuous entry and 0/1 bit mask */ + mac_addr = &fbd->mac_addr[FBNIC_RPC_TCAM_MACDA_PROMISC_IDX]; + if (uc_promisc) { + if (!is_zero_ether_addr(mac_addr->value.addr8) || + mac_addr->state != FBNIC_TCAM_S_VALID) { + eth_zero_addr(mac_addr->value.addr8); + eth_broadcast_addr(mac_addr->mask.addr8); + clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI, + mac_addr->act_tcam); + set_bit(FBNIC_MAC_ADDR_T_PROMISC, + mac_addr->act_tcam); + mac_addr->state = FBNIC_TCAM_S_ADD; + } + } else if (mc_promisc && + (!fbnic_bmc_present(fbd) || !fbd->fw_cap.all_multi)) { + /* We have to add a special handler for multicast as the + * BMC may have an all-multi rule already in place. As such + * adding a rule ourselves won't do any good so we will have + * to modify the rules for the ALL MULTI below if the BMC + * already has the rule in place. + */ + if (!is_multicast_ether_addr(mac_addr->value.addr8) || + mac_addr->state != FBNIC_TCAM_S_VALID) { + eth_zero_addr(mac_addr->value.addr8); + eth_broadcast_addr(mac_addr->mask.addr8); + mac_addr->value.addr8[0] ^= 1; + mac_addr->mask.addr8[0] ^= 1; + set_bit(FBNIC_MAC_ADDR_T_ALLMULTI, + mac_addr->act_tcam); + clear_bit(FBNIC_MAC_ADDR_T_PROMISC, + mac_addr->act_tcam); + mac_addr->state = FBNIC_TCAM_S_ADD; + } + } else if (mac_addr->state == FBNIC_TCAM_S_VALID) { + __fbnic_xc_unsync(mac_addr, FBNIC_MAC_ADDR_T_ALLMULTI); + __fbnic_xc_unsync(mac_addr, FBNIC_MAC_ADDR_T_PROMISC); + } +} + void fbnic_sift_macda(struct fbnic_dev *fbd) { int dest, src; @@ -558,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]; @@ -567,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 */ @@ -580,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) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.h b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.h index 6892414195c3..3d4925b2ac75 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.h @@ -184,6 +184,7 @@ struct fbnic_net; void fbnic_bmc_rpc_init(struct fbnic_dev *fbd); void fbnic_bmc_rpc_all_multi_config(struct fbnic_dev *fbd, bool enable_host); +void fbnic_bmc_rpc_check(struct fbnic_dev *fbd); void fbnic_reset_indir_tbl(struct fbnic_net *fbn); void fbnic_rss_key_fill(u32 *buffer); @@ -201,6 +202,9 @@ struct fbnic_mac_addr *__fbnic_mc_sync(struct fbnic_dev *fbd, void fbnic_sift_macda(struct fbnic_dev *fbd); void fbnic_write_macda(struct fbnic_dev *fbd); +void fbnic_promisc_sync(struct fbnic_dev *fbd, + bool uc_promisc, bool mc_promisc); + struct fbnic_ip_addr *__fbnic_ip4_sync(struct fbnic_dev *fbd, struct fbnic_ip_addr *ip_addr, const struct in_addr *addr, |