Commit 14cd01c2 authored by Paolo Abeni's avatar Paolo Abeni
Browse files

Merge branch 'fbnic-synchronize-address-handling-with-bmc'

Alexander Duyck says:

====================
fbnic: Synchronize address handling with BMC

The fbnic driver needs to communicate with the BMC if it is operating on
the RMII-based transport (RBT) of the same port the host is on. To enable
this we need to add rules that will route BMC traffic to the RBT/BMC and
the BMC and firmware need to configure rules on the RBT side of the
interface to route traffic from the BMC to the host instead of the MAC.

To enable that this patch set addresses two issues. First it will cause the
TCAM to be reconfigured in the event that the BMC was not previously
present when the driver was loaded, but the FW sends a notification that
the FW capabilities have changed and a BMC w/ various MAC addresses is now
present. Second it adds support for sending a message to the firmware so
that if the host adds additional MAC addresses the FW can be made aware and
route traffic for those addresses from the RBT to the host instead of the
MAC.
====================

Link: https://patch.msgid.link/175623715978.2246365.7798520806218461199.stgit@ahduyck-xeon-server.home.arpa


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 84482586 cee8d21d
Loading
Loading
Loading
Loading
+106 −0
Original line number Diff line number Diff line
@@ -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)
{
+21 −2
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@ struct fbnic_fw_cap {
	u8	active_slot;
	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;
@@ -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_ */
+10 −50
Original line number Diff line number Diff line
@@ -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--;) {
+2 −2
Original line number Diff line number Diff line
@@ -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);
+4 −2
Original line number Diff line number Diff line
@@ -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);

Loading