xref: /linux/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1eb690ef8SAlexander Duyck // SPDX-License-Identifier: GPL-2.0
2eb690ef8SAlexander Duyck /* Copyright (c) Meta Platforms, Inc. and affiliates. */
3eb690ef8SAlexander Duyck 
4eb690ef8SAlexander Duyck #include <linux/etherdevice.h>
5*355440a6SAlexander Duyck #include <linux/ethtool.h>
6eb690ef8SAlexander Duyck 
7eb690ef8SAlexander Duyck #include "fbnic.h"
8eb690ef8SAlexander Duyck #include "fbnic_netdev.h"
9eb690ef8SAlexander Duyck #include "fbnic_rpc.h"
10eb690ef8SAlexander Duyck 
fbnic_reset_indir_tbl(struct fbnic_net * fbn)11*355440a6SAlexander Duyck void fbnic_reset_indir_tbl(struct fbnic_net *fbn)
12*355440a6SAlexander Duyck {
13*355440a6SAlexander Duyck 	unsigned int num_rx = fbn->num_rx_queues;
14*355440a6SAlexander Duyck 	unsigned int i;
15*355440a6SAlexander Duyck 
16*355440a6SAlexander Duyck 	for (i = 0; i < FBNIC_RPC_RSS_TBL_SIZE; i++) {
17*355440a6SAlexander Duyck 		fbn->indir_tbl[0][i] = ethtool_rxfh_indir_default(i, num_rx);
18*355440a6SAlexander Duyck 		fbn->indir_tbl[1][i] = ethtool_rxfh_indir_default(i, num_rx);
19*355440a6SAlexander Duyck 	}
20*355440a6SAlexander Duyck }
21*355440a6SAlexander Duyck 
fbnic_rss_key_fill(u32 * buffer)22*355440a6SAlexander Duyck void fbnic_rss_key_fill(u32 *buffer)
23*355440a6SAlexander Duyck {
24*355440a6SAlexander Duyck 	static u32 rss_key[FBNIC_RPC_RSS_KEY_DWORD_LEN];
25*355440a6SAlexander Duyck 
26*355440a6SAlexander Duyck 	net_get_random_once(rss_key, sizeof(rss_key));
27*355440a6SAlexander Duyck 	rss_key[FBNIC_RPC_RSS_KEY_LAST_IDX] &= FBNIC_RPC_RSS_KEY_LAST_MASK;
28*355440a6SAlexander Duyck 
29*355440a6SAlexander Duyck 	memcpy(buffer, rss_key, sizeof(rss_key));
30*355440a6SAlexander Duyck }
31*355440a6SAlexander Duyck 
32*355440a6SAlexander Duyck #define RX_HASH_OPT_L4 \
33*355440a6SAlexander Duyck 	(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)
34*355440a6SAlexander Duyck #define RX_HASH_OPT_L3 \
35*355440a6SAlexander Duyck 	(RXH_IP_SRC | RXH_IP_DST)
36*355440a6SAlexander Duyck #define RX_HASH_OPT_L2 RXH_L2DA
37*355440a6SAlexander Duyck 
fbnic_rss_init_en_mask(struct fbnic_net * fbn)38*355440a6SAlexander Duyck void fbnic_rss_init_en_mask(struct fbnic_net *fbn)
39*355440a6SAlexander Duyck {
40*355440a6SAlexander Duyck 	fbn->rss_flow_hash[FBNIC_TCP4_HASH_OPT] = RX_HASH_OPT_L4;
41*355440a6SAlexander Duyck 	fbn->rss_flow_hash[FBNIC_TCP6_HASH_OPT] = RX_HASH_OPT_L4;
42*355440a6SAlexander Duyck 
43*355440a6SAlexander Duyck 	fbn->rss_flow_hash[FBNIC_UDP4_HASH_OPT] = RX_HASH_OPT_L3;
44*355440a6SAlexander Duyck 	fbn->rss_flow_hash[FBNIC_UDP6_HASH_OPT] = RX_HASH_OPT_L3;
45*355440a6SAlexander Duyck 	fbn->rss_flow_hash[FBNIC_IPV4_HASH_OPT] = RX_HASH_OPT_L3;
46*355440a6SAlexander Duyck 	fbn->rss_flow_hash[FBNIC_IPV6_HASH_OPT] = RX_HASH_OPT_L3;
47*355440a6SAlexander Duyck 
48*355440a6SAlexander Duyck 	fbn->rss_flow_hash[FBNIC_ETHER_HASH_OPT] = RX_HASH_OPT_L2;
49*355440a6SAlexander Duyck }
50*355440a6SAlexander Duyck 
fbnic_rss_disable_hw(struct fbnic_dev * fbd)51*355440a6SAlexander Duyck void fbnic_rss_disable_hw(struct fbnic_dev *fbd)
52*355440a6SAlexander Duyck {
53*355440a6SAlexander Duyck 	/* Disable RPC by clearing enable bit and configuration */
54*355440a6SAlexander Duyck 	if (!fbnic_bmc_present(fbd))
55*355440a6SAlexander Duyck 		wr32(fbd, FBNIC_RPC_RMI_CONFIG,
56*355440a6SAlexander Duyck 		     FIELD_PREP(FBNIC_RPC_RMI_CONFIG_OH_BYTES, 20));
57*355440a6SAlexander Duyck }
58*355440a6SAlexander Duyck 
59*355440a6SAlexander Duyck #define FBNIC_FH_2_RSSEM_BIT(_fh, _rssem, _val)		\
60*355440a6SAlexander Duyck 	FIELD_PREP(FBNIC_RPC_ACT_TBL1_RSS_ENA_##_rssem,	\
61*355440a6SAlexander Duyck 		   FIELD_GET(RXH_##_fh, _val))
fbnic_flow_hash_2_rss_en_mask(struct fbnic_net * fbn,int flow_type)62*355440a6SAlexander Duyck static u16 fbnic_flow_hash_2_rss_en_mask(struct fbnic_net *fbn, int flow_type)
63*355440a6SAlexander Duyck {
64*355440a6SAlexander Duyck 	u32 flow_hash = fbn->rss_flow_hash[flow_type];
65*355440a6SAlexander Duyck 	u32 rss_en_mask = 0;
66*355440a6SAlexander Duyck 
67*355440a6SAlexander Duyck 	rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(L2DA, L2_DA, flow_hash);
68*355440a6SAlexander Duyck 	rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(IP_SRC, IP_SRC, flow_hash);
69*355440a6SAlexander Duyck 	rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(IP_DST, IP_DST, flow_hash);
70*355440a6SAlexander Duyck 	rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(L4_B_0_1, L4_SRC, flow_hash);
71*355440a6SAlexander Duyck 	rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(L4_B_2_3, L4_DST, flow_hash);
72*355440a6SAlexander Duyck 
73*355440a6SAlexander Duyck 	return rss_en_mask;
74*355440a6SAlexander Duyck }
75*355440a6SAlexander Duyck 
fbnic_rss_reinit_hw(struct fbnic_dev * fbd,struct fbnic_net * fbn)76*355440a6SAlexander Duyck void fbnic_rss_reinit_hw(struct fbnic_dev *fbd, struct fbnic_net *fbn)
77*355440a6SAlexander Duyck {
78*355440a6SAlexander Duyck 	unsigned int i;
79*355440a6SAlexander Duyck 
80*355440a6SAlexander Duyck 	for (i = 0; i < FBNIC_RPC_RSS_TBL_SIZE; i++) {
81*355440a6SAlexander Duyck 		wr32(fbd, FBNIC_RPC_RSS_TBL(0, i), fbn->indir_tbl[0][i]);
82*355440a6SAlexander Duyck 		wr32(fbd, FBNIC_RPC_RSS_TBL(1, i), fbn->indir_tbl[1][i]);
83*355440a6SAlexander Duyck 	}
84*355440a6SAlexander Duyck 
85*355440a6SAlexander Duyck 	for (i = 0; i < FBNIC_RPC_RSS_KEY_DWORD_LEN; i++)
86*355440a6SAlexander Duyck 		wr32(fbd, FBNIC_RPC_RSS_KEY(i), fbn->rss_key[i]);
87*355440a6SAlexander Duyck 
88*355440a6SAlexander Duyck 	/* Default action for this to drop w/ no destination */
89*355440a6SAlexander Duyck 	wr32(fbd, FBNIC_RPC_ACT_TBL0_DEFAULT, FBNIC_RPC_ACT_TBL0_DROP);
90*355440a6SAlexander Duyck 	wrfl(fbd);
91*355440a6SAlexander Duyck 
92*355440a6SAlexander Duyck 	wr32(fbd, FBNIC_RPC_ACT_TBL1_DEFAULT, 0);
93*355440a6SAlexander Duyck 
94*355440a6SAlexander Duyck 	/* If it isn't already enabled set the RMI Config value to enable RPC */
95*355440a6SAlexander Duyck 	wr32(fbd, FBNIC_RPC_RMI_CONFIG,
96*355440a6SAlexander Duyck 	     FIELD_PREP(FBNIC_RPC_RMI_CONFIG_MTU, FBNIC_MAX_JUMBO_FRAME_SIZE) |
97*355440a6SAlexander Duyck 	     FIELD_PREP(FBNIC_RPC_RMI_CONFIG_OH_BYTES, 20) |
98*355440a6SAlexander Duyck 	     FBNIC_RPC_RMI_CONFIG_ENABLE);
99*355440a6SAlexander Duyck }
100*355440a6SAlexander Duyck 
fbnic_bmc_rpc_all_multi_config(struct fbnic_dev * fbd,bool enable_host)101eb690ef8SAlexander Duyck void fbnic_bmc_rpc_all_multi_config(struct fbnic_dev *fbd,
102eb690ef8SAlexander Duyck 				    bool enable_host)
103eb690ef8SAlexander Duyck {
104*355440a6SAlexander Duyck 	struct fbnic_act_tcam *act_tcam;
105eb690ef8SAlexander Duyck 	struct fbnic_mac_addr *mac_addr;
106*355440a6SAlexander Duyck 	int j;
107eb690ef8SAlexander Duyck 
108eb690ef8SAlexander Duyck 	/* We need to add the all multicast filter at the end of the
109eb690ef8SAlexander Duyck 	 * multicast address list. This way if there are any that are
110eb690ef8SAlexander Duyck 	 * shared between the host and the BMC they can be directed to
111eb690ef8SAlexander Duyck 	 * both. Otherwise the remainder just get sent directly to the
112eb690ef8SAlexander Duyck 	 * BMC.
113eb690ef8SAlexander Duyck 	 */
114eb690ef8SAlexander Duyck 	mac_addr = &fbd->mac_addr[fbd->mac_addr_boundary - 1];
115eb690ef8SAlexander Duyck 	if (fbnic_bmc_present(fbd) && fbd->fw_cap.all_multi) {
116eb690ef8SAlexander Duyck 		if (mac_addr->state != FBNIC_TCAM_S_VALID) {
117eb690ef8SAlexander Duyck 			eth_zero_addr(mac_addr->value.addr8);
118eb690ef8SAlexander Duyck 			eth_broadcast_addr(mac_addr->mask.addr8);
119eb690ef8SAlexander Duyck 			mac_addr->value.addr8[0] ^= 1;
120eb690ef8SAlexander Duyck 			mac_addr->mask.addr8[0] ^= 1;
121eb690ef8SAlexander Duyck 			set_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam);
122eb690ef8SAlexander Duyck 			mac_addr->state = FBNIC_TCAM_S_ADD;
123eb690ef8SAlexander Duyck 		}
124eb690ef8SAlexander Duyck 		if (enable_host)
125eb690ef8SAlexander Duyck 			set_bit(FBNIC_MAC_ADDR_T_ALLMULTI,
126eb690ef8SAlexander Duyck 				mac_addr->act_tcam);
127eb690ef8SAlexander Duyck 		else
128eb690ef8SAlexander Duyck 			clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI,
129eb690ef8SAlexander Duyck 				  mac_addr->act_tcam);
130eb690ef8SAlexander Duyck 	} else if (!test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam) &&
131eb690ef8SAlexander Duyck 		   !is_zero_ether_addr(mac_addr->mask.addr8) &&
132eb690ef8SAlexander Duyck 		   mac_addr->state == FBNIC_TCAM_S_VALID) {
133eb690ef8SAlexander Duyck 		clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI, mac_addr->act_tcam);
134eb690ef8SAlexander Duyck 		clear_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam);
135eb690ef8SAlexander Duyck 		mac_addr->state = FBNIC_TCAM_S_DELETE;
136eb690ef8SAlexander Duyck 	}
137*355440a6SAlexander Duyck 
138*355440a6SAlexander Duyck 	/* We have to add a special handler for multicast as the
139*355440a6SAlexander Duyck 	 * BMC may have an all-multi rule already in place. As such
140*355440a6SAlexander Duyck 	 * adding a rule ourselves won't do any good so we will have
141*355440a6SAlexander Duyck 	 * to modify the rules for the ALL MULTI below if the BMC
142*355440a6SAlexander Duyck 	 * already has the rule in place.
143*355440a6SAlexander Duyck 	 */
144*355440a6SAlexander Duyck 	act_tcam = &fbd->act_tcam[FBNIC_RPC_ACT_TBL_BMC_ALL_MULTI_OFFSET];
145*355440a6SAlexander Duyck 
146*355440a6SAlexander Duyck 	/* If we are not enabling the rule just delete it. We will fall
147*355440a6SAlexander Duyck 	 * back to the RSS rules that support the multicast addresses.
148*355440a6SAlexander Duyck 	 */
149*355440a6SAlexander Duyck 	if (!fbnic_bmc_present(fbd) || !fbd->fw_cap.all_multi || enable_host) {
150*355440a6SAlexander Duyck 		if (act_tcam->state == FBNIC_TCAM_S_VALID)
151*355440a6SAlexander Duyck 			act_tcam->state = FBNIC_TCAM_S_DELETE;
152*355440a6SAlexander Duyck 		return;
153*355440a6SAlexander Duyck 	}
154*355440a6SAlexander Duyck 
155*355440a6SAlexander Duyck 	/* Rewrite TCAM rule 23 to handle BMC all-multi traffic */
156*355440a6SAlexander Duyck 	act_tcam->dest = FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,
157*355440a6SAlexander Duyck 				    FBNIC_RPC_ACT_TBL0_DEST_BMC);
158*355440a6SAlexander Duyck 	act_tcam->mask.tcam[0] = 0xffff;
159*355440a6SAlexander Duyck 
160*355440a6SAlexander Duyck 	/* MACDA 0 - 3 is reserved for the BMC MAC address */
161*355440a6SAlexander Duyck 	act_tcam->value.tcam[1] =
162*355440a6SAlexander Duyck 			FIELD_PREP(FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX,
163*355440a6SAlexander Duyck 				   fbd->mac_addr_boundary - 1) |
164*355440a6SAlexander Duyck 			FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID;
165*355440a6SAlexander Duyck 	act_tcam->mask.tcam[1] = 0xffff &
166*355440a6SAlexander Duyck 			 ~FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX &
167*355440a6SAlexander Duyck 			 ~FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID;
168*355440a6SAlexander Duyck 
169*355440a6SAlexander Duyck 	for (j = 2; j < FBNIC_RPC_TCAM_ACT_WORD_LEN; j++)
170*355440a6SAlexander Duyck 		act_tcam->mask.tcam[j] = 0xffff;
171*355440a6SAlexander Duyck 
172*355440a6SAlexander Duyck 	act_tcam->state = FBNIC_TCAM_S_UPDATE;
173eb690ef8SAlexander Duyck }
174eb690ef8SAlexander Duyck 
fbnic_bmc_rpc_init(struct fbnic_dev * fbd)175eb690ef8SAlexander Duyck void fbnic_bmc_rpc_init(struct fbnic_dev *fbd)
176eb690ef8SAlexander Duyck {
177eb690ef8SAlexander Duyck 	int i = FBNIC_RPC_TCAM_MACDA_BMC_ADDR_IDX;
178*355440a6SAlexander Duyck 	struct fbnic_act_tcam *act_tcam;
179eb690ef8SAlexander Duyck 	struct fbnic_mac_addr *mac_addr;
180eb690ef8SAlexander Duyck 	int j;
181eb690ef8SAlexander Duyck 
182eb690ef8SAlexander Duyck 	/* Check if BMC is present */
183eb690ef8SAlexander Duyck 	if (!fbnic_bmc_present(fbd))
184eb690ef8SAlexander Duyck 		return;
185eb690ef8SAlexander Duyck 
186eb690ef8SAlexander Duyck 	/* Fetch BMC MAC addresses from firmware capabilities */
187eb690ef8SAlexander Duyck 	for (j = 0; j < 4; j++) {
188eb690ef8SAlexander Duyck 		u8 *bmc_mac = fbd->fw_cap.bmc_mac_addr[j];
189eb690ef8SAlexander Duyck 
190eb690ef8SAlexander Duyck 		/* Validate BMC MAC addresses */
191eb690ef8SAlexander Duyck 		if (is_zero_ether_addr(bmc_mac))
192eb690ef8SAlexander Duyck 			continue;
193eb690ef8SAlexander Duyck 
194eb690ef8SAlexander Duyck 		if (is_multicast_ether_addr(bmc_mac))
195eb690ef8SAlexander Duyck 			mac_addr = __fbnic_mc_sync(fbd, bmc_mac);
196eb690ef8SAlexander Duyck 		else
197eb690ef8SAlexander Duyck 			mac_addr = &fbd->mac_addr[i++];
198eb690ef8SAlexander Duyck 
199eb690ef8SAlexander Duyck 		if (!mac_addr) {
200eb690ef8SAlexander Duyck 			netdev_err(fbd->netdev,
201eb690ef8SAlexander Duyck 				   "No slot for BMC MAC address[%d]\n", j);
202eb690ef8SAlexander Duyck 			continue;
203eb690ef8SAlexander Duyck 		}
204eb690ef8SAlexander Duyck 
205eb690ef8SAlexander Duyck 		ether_addr_copy(mac_addr->value.addr8, bmc_mac);
206eb690ef8SAlexander Duyck 		eth_zero_addr(mac_addr->mask.addr8);
207eb690ef8SAlexander Duyck 
208eb690ef8SAlexander Duyck 		set_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam);
209eb690ef8SAlexander Duyck 		mac_addr->state = FBNIC_TCAM_S_ADD;
210eb690ef8SAlexander Duyck 	}
211eb690ef8SAlexander Duyck 
212eb690ef8SAlexander Duyck 	/* Validate Broadcast is also present, record it and tag it */
213eb690ef8SAlexander Duyck 	mac_addr = &fbd->mac_addr[FBNIC_RPC_TCAM_MACDA_BROADCAST_IDX];
214eb690ef8SAlexander Duyck 	eth_broadcast_addr(mac_addr->value.addr8);
215eb690ef8SAlexander Duyck 	set_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam);
216eb690ef8SAlexander Duyck 	mac_addr->state = FBNIC_TCAM_S_ADD;
217eb690ef8SAlexander Duyck 
218*355440a6SAlexander Duyck 	/* Rewrite TCAM rule 0 if it isn't present to relocate BMC rules */
219*355440a6SAlexander Duyck 	act_tcam = &fbd->act_tcam[FBNIC_RPC_ACT_TBL_BMC_OFFSET];
220*355440a6SAlexander Duyck 	act_tcam->dest = FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,
221*355440a6SAlexander Duyck 				    FBNIC_RPC_ACT_TBL0_DEST_BMC);
222*355440a6SAlexander Duyck 	act_tcam->mask.tcam[0] = 0xffff;
223*355440a6SAlexander Duyck 
224*355440a6SAlexander Duyck 	/* MACDA 0 - 3 is reserved for the BMC MAC address
225*355440a6SAlexander Duyck 	 * to account for that we have to mask out the lower 2 bits
226*355440a6SAlexander Duyck 	 * of the macda by performing an &= with 0x1c.
227*355440a6SAlexander Duyck 	 */
228*355440a6SAlexander Duyck 	act_tcam->value.tcam[1] = FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID;
229*355440a6SAlexander Duyck 	act_tcam->mask.tcam[1] = 0xffff &
230*355440a6SAlexander Duyck 			~FIELD_PREP(FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX, 0x1c) &
231*355440a6SAlexander Duyck 			~FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID;
232*355440a6SAlexander Duyck 
233*355440a6SAlexander Duyck 	for (j = 2; j < FBNIC_RPC_TCAM_ACT_WORD_LEN; j++)
234*355440a6SAlexander Duyck 		act_tcam->mask.tcam[j] = 0xffff;
235*355440a6SAlexander Duyck 
236*355440a6SAlexander Duyck 	act_tcam->state = FBNIC_TCAM_S_UPDATE;
237*355440a6SAlexander Duyck 
238eb690ef8SAlexander Duyck 	fbnic_bmc_rpc_all_multi_config(fbd, false);
239eb690ef8SAlexander Duyck }
240eb690ef8SAlexander Duyck 
241*355440a6SAlexander Duyck #define FBNIC_ACT1_INIT(_l4, _udp, _ip, _v6)		\
242*355440a6SAlexander Duyck 	(((_l4) ? FBNIC_RPC_TCAM_ACT1_L4_VALID : 0) |	\
243*355440a6SAlexander Duyck 	 ((_udp) ? FBNIC_RPC_TCAM_ACT1_L4_IS_UDP : 0) |	\
244*355440a6SAlexander Duyck 	 ((_ip) ? FBNIC_RPC_TCAM_ACT1_IP_VALID : 0) |	\
245*355440a6SAlexander Duyck 	 ((_v6) ? FBNIC_RPC_TCAM_ACT1_IP_IS_V6 : 0))
246*355440a6SAlexander Duyck 
fbnic_rss_reinit(struct fbnic_dev * fbd,struct fbnic_net * fbn)247*355440a6SAlexander Duyck void fbnic_rss_reinit(struct fbnic_dev *fbd, struct fbnic_net *fbn)
248*355440a6SAlexander Duyck {
249*355440a6SAlexander Duyck 	static const u32 act1_value[FBNIC_NUM_HASH_OPT] = {
250*355440a6SAlexander Duyck 		FBNIC_ACT1_INIT(1, 1, 1, 1),	/* UDP6 */
251*355440a6SAlexander Duyck 		FBNIC_ACT1_INIT(1, 1, 1, 0),	/* UDP4 */
252*355440a6SAlexander Duyck 		FBNIC_ACT1_INIT(1, 0, 1, 1),	/* TCP6 */
253*355440a6SAlexander Duyck 		FBNIC_ACT1_INIT(1, 0, 1, 0),	/* TCP4 */
254*355440a6SAlexander Duyck 		FBNIC_ACT1_INIT(0, 0, 1, 1),	/* IP6 */
255*355440a6SAlexander Duyck 		FBNIC_ACT1_INIT(0, 0, 1, 0),	/* IP4 */
256*355440a6SAlexander Duyck 		0				/* Ether */
257*355440a6SAlexander Duyck 	};
258*355440a6SAlexander Duyck 	unsigned int i;
259*355440a6SAlexander Duyck 
260*355440a6SAlexander Duyck 	/* To support scenarios where a BMC is present we must write the
261*355440a6SAlexander Duyck 	 * rules twice, once for the unicast cases, and once again for
262*355440a6SAlexander Duyck 	 * the broadcast/multicast cases as we have to support 2 destinations.
263*355440a6SAlexander Duyck 	 */
264*355440a6SAlexander Duyck 	BUILD_BUG_ON(FBNIC_RSS_EN_NUM_UNICAST * 2 != FBNIC_RSS_EN_NUM_ENTRIES);
265*355440a6SAlexander Duyck 	BUILD_BUG_ON(ARRAY_SIZE(act1_value) != FBNIC_NUM_HASH_OPT);
266*355440a6SAlexander Duyck 
267*355440a6SAlexander Duyck 	/* Program RSS hash enable mask for host in action TCAM/table. */
268*355440a6SAlexander Duyck 	for (i = fbnic_bmc_present(fbd) ? 0 : FBNIC_RSS_EN_NUM_UNICAST;
269*355440a6SAlexander Duyck 	     i < FBNIC_RSS_EN_NUM_ENTRIES; i++) {
270*355440a6SAlexander Duyck 		unsigned int idx = i + FBNIC_RPC_ACT_TBL_RSS_OFFSET;
271*355440a6SAlexander Duyck 		struct fbnic_act_tcam *act_tcam = &fbd->act_tcam[idx];
272*355440a6SAlexander Duyck 		u32 flow_hash, dest, rss_en_mask;
273*355440a6SAlexander Duyck 		int flow_type, j;
274*355440a6SAlexander Duyck 		u16 value = 0;
275*355440a6SAlexander Duyck 
276*355440a6SAlexander Duyck 		flow_type = i % FBNIC_RSS_EN_NUM_UNICAST;
277*355440a6SAlexander Duyck 		flow_hash = fbn->rss_flow_hash[flow_type];
278*355440a6SAlexander Duyck 
279*355440a6SAlexander Duyck 		/* Set DEST_HOST based on absence of RXH_DISCARD */
280*355440a6SAlexander Duyck 		dest = FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,
281*355440a6SAlexander Duyck 				  !(RXH_DISCARD & flow_hash) ?
282*355440a6SAlexander Duyck 				  FBNIC_RPC_ACT_TBL0_DEST_HOST : 0);
283*355440a6SAlexander Duyck 
284*355440a6SAlexander Duyck 		if (i >= FBNIC_RSS_EN_NUM_UNICAST && fbnic_bmc_present(fbd))
285*355440a6SAlexander Duyck 			dest |= FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,
286*355440a6SAlexander Duyck 					   FBNIC_RPC_ACT_TBL0_DEST_BMC);
287*355440a6SAlexander Duyck 
288*355440a6SAlexander Duyck 		if (!dest)
289*355440a6SAlexander Duyck 			dest = FBNIC_RPC_ACT_TBL0_DROP;
290*355440a6SAlexander Duyck 
291*355440a6SAlexander Duyck 		if (act1_value[flow_type] & FBNIC_RPC_TCAM_ACT1_L4_VALID)
292*355440a6SAlexander Duyck 			dest |= FIELD_PREP(FBNIC_RPC_ACT_TBL0_DMA_HINT,
293*355440a6SAlexander Duyck 					   FBNIC_RCD_HDR_AL_DMA_HINT_L4);
294*355440a6SAlexander Duyck 
295*355440a6SAlexander Duyck 		rss_en_mask = fbnic_flow_hash_2_rss_en_mask(fbn, flow_type);
296*355440a6SAlexander Duyck 
297*355440a6SAlexander Duyck 		act_tcam->dest = dest;
298*355440a6SAlexander Duyck 		act_tcam->rss_en_mask = rss_en_mask;
299*355440a6SAlexander Duyck 		act_tcam->state = FBNIC_TCAM_S_UPDATE;
300*355440a6SAlexander Duyck 
301*355440a6SAlexander Duyck 		act_tcam->mask.tcam[0] = 0xffff;
302*355440a6SAlexander Duyck 
303*355440a6SAlexander Duyck 		/* We reserve the upper 8 MACDA TCAM entries for host
304*355440a6SAlexander Duyck 		 * unicast. So we set the value to 24, and the mask the
305*355440a6SAlexander Duyck 		 * lower bits so that the lower entries can be used as
306*355440a6SAlexander Duyck 		 * multicast or BMC addresses.
307*355440a6SAlexander Duyck 		 */
308*355440a6SAlexander Duyck 		if (i < FBNIC_RSS_EN_NUM_UNICAST)
309*355440a6SAlexander Duyck 			value = FIELD_PREP(FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX,
310*355440a6SAlexander Duyck 					   fbd->mac_addr_boundary);
311*355440a6SAlexander Duyck 		value |= FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID;
312*355440a6SAlexander Duyck 
313*355440a6SAlexander Duyck 		flow_type = i % FBNIC_RSS_EN_NUM_UNICAST;
314*355440a6SAlexander Duyck 		value |= act1_value[flow_type];
315*355440a6SAlexander Duyck 
316*355440a6SAlexander Duyck 		act_tcam->value.tcam[1] = value;
317*355440a6SAlexander Duyck 		act_tcam->mask.tcam[1] = ~value;
318*355440a6SAlexander Duyck 
319*355440a6SAlexander Duyck 		for (j = 2; j < FBNIC_RPC_TCAM_ACT_WORD_LEN; j++)
320*355440a6SAlexander Duyck 			act_tcam->mask.tcam[j] = 0xffff;
321*355440a6SAlexander Duyck 
322*355440a6SAlexander Duyck 		act_tcam->state = FBNIC_TCAM_S_UPDATE;
323*355440a6SAlexander Duyck 	}
324*355440a6SAlexander Duyck }
325*355440a6SAlexander Duyck 
__fbnic_uc_sync(struct fbnic_dev * fbd,const unsigned char * addr)326eb690ef8SAlexander Duyck struct fbnic_mac_addr *__fbnic_uc_sync(struct fbnic_dev *fbd,
327eb690ef8SAlexander Duyck 				       const unsigned char *addr)
328eb690ef8SAlexander Duyck {
329eb690ef8SAlexander Duyck 	struct fbnic_mac_addr *avail_addr = NULL;
330eb690ef8SAlexander Duyck 	unsigned int i;
331eb690ef8SAlexander Duyck 
332eb690ef8SAlexander Duyck 	/* Scan from middle of list to bottom, filling bottom up.
333eb690ef8SAlexander Duyck 	 * Skip the first entry which is reserved for dev_addr and
334eb690ef8SAlexander Duyck 	 * leave the last entry to use for promiscuous filtering.
335eb690ef8SAlexander Duyck 	 */
336eb690ef8SAlexander Duyck 	for (i = fbd->mac_addr_boundary - 1;
337eb690ef8SAlexander Duyck 	     i < FBNIC_RPC_TCAM_MACDA_HOST_ADDR_IDX; i++) {
338eb690ef8SAlexander Duyck 		struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];
339eb690ef8SAlexander Duyck 
340eb690ef8SAlexander Duyck 		if (mac_addr->state == FBNIC_TCAM_S_DISABLED) {
341eb690ef8SAlexander Duyck 			avail_addr = mac_addr;
342eb690ef8SAlexander Duyck 		} else if (ether_addr_equal(mac_addr->value.addr8, addr)) {
343eb690ef8SAlexander Duyck 			avail_addr = mac_addr;
344eb690ef8SAlexander Duyck 			break;
345eb690ef8SAlexander Duyck 		}
346eb690ef8SAlexander Duyck 	}
347eb690ef8SAlexander Duyck 
348eb690ef8SAlexander Duyck 	if (avail_addr && avail_addr->state == FBNIC_TCAM_S_DISABLED) {
349eb690ef8SAlexander Duyck 		ether_addr_copy(avail_addr->value.addr8, addr);
350eb690ef8SAlexander Duyck 		eth_zero_addr(avail_addr->mask.addr8);
351eb690ef8SAlexander Duyck 		avail_addr->state = FBNIC_TCAM_S_ADD;
352eb690ef8SAlexander Duyck 	}
353eb690ef8SAlexander Duyck 
354eb690ef8SAlexander Duyck 	return avail_addr;
355eb690ef8SAlexander Duyck }
356eb690ef8SAlexander Duyck 
__fbnic_mc_sync(struct fbnic_dev * fbd,const unsigned char * addr)357eb690ef8SAlexander Duyck struct fbnic_mac_addr *__fbnic_mc_sync(struct fbnic_dev *fbd,
358eb690ef8SAlexander Duyck 				       const unsigned char *addr)
359eb690ef8SAlexander Duyck {
360eb690ef8SAlexander Duyck 	struct fbnic_mac_addr *avail_addr = NULL;
361eb690ef8SAlexander Duyck 	unsigned int i;
362eb690ef8SAlexander Duyck 
363eb690ef8SAlexander Duyck 	/* Scan from middle of list to top, filling top down.
364eb690ef8SAlexander Duyck 	 * Skip over the address reserved for the BMC MAC and
365eb690ef8SAlexander Duyck 	 * exclude index 0 as that belongs to the broadcast address
366eb690ef8SAlexander Duyck 	 */
367eb690ef8SAlexander Duyck 	for (i = fbd->mac_addr_boundary;
368eb690ef8SAlexander Duyck 	     --i > FBNIC_RPC_TCAM_MACDA_BROADCAST_IDX;) {
369eb690ef8SAlexander Duyck 		struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];
370eb690ef8SAlexander Duyck 
371eb690ef8SAlexander Duyck 		if (mac_addr->state == FBNIC_TCAM_S_DISABLED) {
372eb690ef8SAlexander Duyck 			avail_addr = mac_addr;
373eb690ef8SAlexander Duyck 		} else if (ether_addr_equal(mac_addr->value.addr8, addr)) {
374eb690ef8SAlexander Duyck 			avail_addr = mac_addr;
375eb690ef8SAlexander Duyck 			break;
376eb690ef8SAlexander Duyck 		}
377eb690ef8SAlexander Duyck 	}
378eb690ef8SAlexander Duyck 
379eb690ef8SAlexander Duyck 	/* Scan the BMC addresses to see if it may have already
380eb690ef8SAlexander Duyck 	 * reserved the address.
381eb690ef8SAlexander Duyck 	 */
382eb690ef8SAlexander Duyck 	while (--i) {
383eb690ef8SAlexander Duyck 		struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];
384eb690ef8SAlexander Duyck 
385eb690ef8SAlexander Duyck 		if (!is_zero_ether_addr(mac_addr->mask.addr8))
386eb690ef8SAlexander Duyck 			continue;
387eb690ef8SAlexander Duyck 
388eb690ef8SAlexander Duyck 		/* Only move on if we find a match */
389eb690ef8SAlexander Duyck 		if (!ether_addr_equal(mac_addr->value.addr8, addr))
390eb690ef8SAlexander Duyck 			continue;
391eb690ef8SAlexander Duyck 
392eb690ef8SAlexander Duyck 		/* We need to pull this address to the shared area */
393eb690ef8SAlexander Duyck 		if (avail_addr) {
394eb690ef8SAlexander Duyck 			memcpy(avail_addr, mac_addr, sizeof(*mac_addr));
395eb690ef8SAlexander Duyck 			mac_addr->state = FBNIC_TCAM_S_DELETE;
396eb690ef8SAlexander Duyck 			avail_addr->state = FBNIC_TCAM_S_ADD;
397eb690ef8SAlexander Duyck 		}
398eb690ef8SAlexander Duyck 
399eb690ef8SAlexander Duyck 		break;
400eb690ef8SAlexander Duyck 	}
401eb690ef8SAlexander Duyck 
402eb690ef8SAlexander Duyck 	if (avail_addr && avail_addr->state == FBNIC_TCAM_S_DISABLED) {
403eb690ef8SAlexander Duyck 		ether_addr_copy(avail_addr->value.addr8, addr);
404eb690ef8SAlexander Duyck 		eth_zero_addr(avail_addr->mask.addr8);
405eb690ef8SAlexander Duyck 		avail_addr->state = FBNIC_TCAM_S_ADD;
406eb690ef8SAlexander Duyck 	}
407eb690ef8SAlexander Duyck 
408eb690ef8SAlexander Duyck 	return avail_addr;
409eb690ef8SAlexander Duyck }
410eb690ef8SAlexander Duyck 
__fbnic_xc_unsync(struct fbnic_mac_addr * mac_addr,unsigned int tcam_idx)411eb690ef8SAlexander Duyck int __fbnic_xc_unsync(struct fbnic_mac_addr *mac_addr, unsigned int tcam_idx)
412eb690ef8SAlexander Duyck {
413eb690ef8SAlexander Duyck 	if (!test_and_clear_bit(tcam_idx, mac_addr->act_tcam))
414eb690ef8SAlexander Duyck 		return -ENOENT;
415eb690ef8SAlexander Duyck 
416eb690ef8SAlexander Duyck 	if (bitmap_empty(mac_addr->act_tcam, FBNIC_RPC_TCAM_ACT_NUM_ENTRIES))
417eb690ef8SAlexander Duyck 		mac_addr->state = FBNIC_TCAM_S_DELETE;
418eb690ef8SAlexander Duyck 
419eb690ef8SAlexander Duyck 	return 0;
420eb690ef8SAlexander Duyck }
421eb690ef8SAlexander Duyck 
fbnic_sift_macda(struct fbnic_dev * fbd)422eb690ef8SAlexander Duyck void fbnic_sift_macda(struct fbnic_dev *fbd)
423eb690ef8SAlexander Duyck {
424eb690ef8SAlexander Duyck 	int dest, src;
425eb690ef8SAlexander Duyck 
426eb690ef8SAlexander Duyck 	/* Move BMC only addresses back into BMC region */
427eb690ef8SAlexander Duyck 	for (dest = FBNIC_RPC_TCAM_MACDA_BMC_ADDR_IDX,
428eb690ef8SAlexander Duyck 	     src = FBNIC_RPC_TCAM_MACDA_MULTICAST_IDX;
429eb690ef8SAlexander Duyck 	     ++dest < FBNIC_RPC_TCAM_MACDA_BROADCAST_IDX &&
430eb690ef8SAlexander Duyck 	     src < fbd->mac_addr_boundary;) {
431eb690ef8SAlexander Duyck 		struct fbnic_mac_addr *dest_addr = &fbd->mac_addr[dest];
432eb690ef8SAlexander Duyck 
433eb690ef8SAlexander Duyck 		if (dest_addr->state != FBNIC_TCAM_S_DISABLED)
434eb690ef8SAlexander Duyck 			continue;
435eb690ef8SAlexander Duyck 
436eb690ef8SAlexander Duyck 		while (src < fbd->mac_addr_boundary) {
437eb690ef8SAlexander Duyck 			struct fbnic_mac_addr *src_addr = &fbd->mac_addr[src++];
438eb690ef8SAlexander Duyck 
439eb690ef8SAlexander Duyck 			/* Verify BMC bit is set */
440eb690ef8SAlexander Duyck 			if (!test_bit(FBNIC_MAC_ADDR_T_BMC, src_addr->act_tcam))
441eb690ef8SAlexander Duyck 				continue;
442eb690ef8SAlexander Duyck 
443eb690ef8SAlexander Duyck 			/* Verify filter isn't already disabled */
444eb690ef8SAlexander Duyck 			if (src_addr->state == FBNIC_TCAM_S_DISABLED ||
445eb690ef8SAlexander Duyck 			    src_addr->state == FBNIC_TCAM_S_DELETE)
446eb690ef8SAlexander Duyck 				continue;
447eb690ef8SAlexander Duyck 
448eb690ef8SAlexander Duyck 			/* Verify only BMC bit is set */
449eb690ef8SAlexander Duyck 			if (bitmap_weight(src_addr->act_tcam,
450eb690ef8SAlexander Duyck 					  FBNIC_RPC_TCAM_ACT_NUM_ENTRIES) != 1)
451eb690ef8SAlexander Duyck 				continue;
452eb690ef8SAlexander Duyck 
453eb690ef8SAlexander Duyck 			/* Verify we are not moving wildcard address */
454eb690ef8SAlexander Duyck 			if (!is_zero_ether_addr(src_addr->mask.addr8))
455eb690ef8SAlexander Duyck 				continue;
456eb690ef8SAlexander Duyck 
457eb690ef8SAlexander Duyck 			memcpy(dest_addr, src_addr, sizeof(*src_addr));
458eb690ef8SAlexander Duyck 			src_addr->state = FBNIC_TCAM_S_DELETE;
459eb690ef8SAlexander Duyck 			dest_addr->state = FBNIC_TCAM_S_ADD;
460eb690ef8SAlexander Duyck 		}
461eb690ef8SAlexander Duyck 	}
462eb690ef8SAlexander Duyck }
463eb690ef8SAlexander Duyck 
fbnic_clear_macda_entry(struct fbnic_dev * fbd,unsigned int idx)464eb690ef8SAlexander Duyck static void fbnic_clear_macda_entry(struct fbnic_dev *fbd, unsigned int idx)
465eb690ef8SAlexander Duyck {
466eb690ef8SAlexander Duyck 	int i;
467eb690ef8SAlexander Duyck 
468eb690ef8SAlexander Duyck 	/* Invalidate entry and clear addr state info */
469eb690ef8SAlexander Duyck 	for (i = 0; i <= FBNIC_RPC_TCAM_MACDA_WORD_LEN; i++)
470eb690ef8SAlexander Duyck 		wr32(fbd, FBNIC_RPC_TCAM_MACDA(idx, i), 0);
471eb690ef8SAlexander Duyck }
472eb690ef8SAlexander Duyck 
fbnic_clear_macda(struct fbnic_dev * fbd)473*355440a6SAlexander Duyck static void fbnic_clear_macda(struct fbnic_dev *fbd)
474*355440a6SAlexander Duyck {
475*355440a6SAlexander Duyck 	int idx;
476*355440a6SAlexander Duyck 
477*355440a6SAlexander Duyck 	for (idx = ARRAY_SIZE(fbd->mac_addr); idx--;) {
478*355440a6SAlexander Duyck 		struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[idx];
479*355440a6SAlexander Duyck 
480*355440a6SAlexander Duyck 		if (mac_addr->state == FBNIC_TCAM_S_DISABLED)
481*355440a6SAlexander Duyck 			continue;
482*355440a6SAlexander Duyck 
483*355440a6SAlexander Duyck 		if (test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam)) {
484*355440a6SAlexander Duyck 			if (fbnic_bmc_present(fbd))
485*355440a6SAlexander Duyck 				continue;
486*355440a6SAlexander Duyck 			dev_warn_once(fbd->dev,
487*355440a6SAlexander Duyck 				      "Found BMC MAC address w/ BMC not present\n");
488*355440a6SAlexander Duyck 		}
489*355440a6SAlexander Duyck 
490*355440a6SAlexander Duyck 		fbnic_clear_macda_entry(fbd, idx);
491*355440a6SAlexander Duyck 
492*355440a6SAlexander Duyck 		/* If rule was already destined for deletion just wipe it now */
493*355440a6SAlexander Duyck 		if (mac_addr->state == FBNIC_TCAM_S_DELETE) {
494*355440a6SAlexander Duyck 			memset(mac_addr, 0, sizeof(*mac_addr));
495*355440a6SAlexander Duyck 			continue;
496*355440a6SAlexander Duyck 		}
497*355440a6SAlexander Duyck 
498*355440a6SAlexander Duyck 		/* Change state to update so that we will rewrite
499*355440a6SAlexander Duyck 		 * this tcam the next time fbnic_write_macda is called.
500*355440a6SAlexander Duyck 		 */
501*355440a6SAlexander Duyck 		mac_addr->state = FBNIC_TCAM_S_UPDATE;
502*355440a6SAlexander Duyck 	}
503*355440a6SAlexander Duyck }
504*355440a6SAlexander Duyck 
fbnic_write_macda_entry(struct fbnic_dev * fbd,unsigned int idx,struct fbnic_mac_addr * mac_addr)505eb690ef8SAlexander Duyck static void fbnic_write_macda_entry(struct fbnic_dev *fbd, unsigned int idx,
506eb690ef8SAlexander Duyck 				    struct fbnic_mac_addr *mac_addr)
507eb690ef8SAlexander Duyck {
508eb690ef8SAlexander Duyck 	__be16 *mask, *value;
509eb690ef8SAlexander Duyck 	int i;
510eb690ef8SAlexander Duyck 
511eb690ef8SAlexander Duyck 	mask = &mac_addr->mask.addr16[FBNIC_RPC_TCAM_MACDA_WORD_LEN - 1];
512eb690ef8SAlexander Duyck 	value = &mac_addr->value.addr16[FBNIC_RPC_TCAM_MACDA_WORD_LEN - 1];
513eb690ef8SAlexander Duyck 
514eb690ef8SAlexander Duyck 	for (i = 0; i < FBNIC_RPC_TCAM_MACDA_WORD_LEN; i++)
515eb690ef8SAlexander Duyck 		wr32(fbd, FBNIC_RPC_TCAM_MACDA(idx, i),
516eb690ef8SAlexander Duyck 		     FIELD_PREP(FBNIC_RPC_TCAM_MACDA_MASK, ntohs(*mask--)) |
517eb690ef8SAlexander Duyck 		     FIELD_PREP(FBNIC_RPC_TCAM_MACDA_VALUE, ntohs(*value--)));
518eb690ef8SAlexander Duyck 
519eb690ef8SAlexander Duyck 	wrfl(fbd);
520eb690ef8SAlexander Duyck 
521eb690ef8SAlexander Duyck 	wr32(fbd, FBNIC_RPC_TCAM_MACDA(idx, i), FBNIC_RPC_TCAM_VALIDATE);
522eb690ef8SAlexander Duyck }
523eb690ef8SAlexander Duyck 
fbnic_write_macda(struct fbnic_dev * fbd)524eb690ef8SAlexander Duyck void fbnic_write_macda(struct fbnic_dev *fbd)
525eb690ef8SAlexander Duyck {
526eb690ef8SAlexander Duyck 	int idx;
527eb690ef8SAlexander Duyck 
528eb690ef8SAlexander Duyck 	for (idx = ARRAY_SIZE(fbd->mac_addr); idx--;) {
529eb690ef8SAlexander Duyck 		struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[idx];
530eb690ef8SAlexander Duyck 
531eb690ef8SAlexander Duyck 		/* Check if update flag is set else exit. */
532eb690ef8SAlexander Duyck 		if (!(mac_addr->state & FBNIC_TCAM_S_UPDATE))
533eb690ef8SAlexander Duyck 			continue;
534eb690ef8SAlexander Duyck 
535eb690ef8SAlexander Duyck 		/* Clear by writing 0s. */
536eb690ef8SAlexander Duyck 		if (mac_addr->state == FBNIC_TCAM_S_DELETE) {
537eb690ef8SAlexander Duyck 			/* Invalidate entry and clear addr state info */
538eb690ef8SAlexander Duyck 			fbnic_clear_macda_entry(fbd, idx);
539eb690ef8SAlexander Duyck 			memset(mac_addr, 0, sizeof(*mac_addr));
540eb690ef8SAlexander Duyck 
541eb690ef8SAlexander Duyck 			continue;
542eb690ef8SAlexander Duyck 		}
543eb690ef8SAlexander Duyck 
544eb690ef8SAlexander Duyck 		fbnic_write_macda_entry(fbd, idx, mac_addr);
545eb690ef8SAlexander Duyck 
546eb690ef8SAlexander Duyck 		mac_addr->state = FBNIC_TCAM_S_VALID;
547eb690ef8SAlexander Duyck 	}
548eb690ef8SAlexander Duyck }
549*355440a6SAlexander Duyck 
fbnic_clear_act_tcam(struct fbnic_dev * fbd,unsigned int idx)550*355440a6SAlexander Duyck static void fbnic_clear_act_tcam(struct fbnic_dev *fbd, unsigned int idx)
551*355440a6SAlexander Duyck {
552*355440a6SAlexander Duyck 	int i;
553*355440a6SAlexander Duyck 
554*355440a6SAlexander Duyck 	/* Invalidate entry and clear addr state info */
555*355440a6SAlexander Duyck 	for (i = 0; i <= FBNIC_RPC_TCAM_ACT_WORD_LEN; i++)
556*355440a6SAlexander Duyck 		wr32(fbd, FBNIC_RPC_TCAM_ACT(idx, i), 0);
557*355440a6SAlexander Duyck }
558*355440a6SAlexander Duyck 
fbnic_clear_rules(struct fbnic_dev * fbd)559*355440a6SAlexander Duyck void fbnic_clear_rules(struct fbnic_dev *fbd)
560*355440a6SAlexander Duyck {
561*355440a6SAlexander Duyck 	u32 dest = FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,
562*355440a6SAlexander Duyck 			      FBNIC_RPC_ACT_TBL0_DEST_BMC);
563*355440a6SAlexander Duyck 	int i = FBNIC_RPC_TCAM_ACT_NUM_ENTRIES - 1;
564*355440a6SAlexander Duyck 	struct fbnic_act_tcam *act_tcam;
565*355440a6SAlexander Duyck 
566*355440a6SAlexander Duyck 	/* Clear MAC rules */
567*355440a6SAlexander Duyck 	fbnic_clear_macda(fbd);
568*355440a6SAlexander Duyck 
569*355440a6SAlexander Duyck 	/* If BMC is present we need to preserve the last rule which
570*355440a6SAlexander Duyck 	 * will be used to route traffic to the BMC if it is received.
571*355440a6SAlexander Duyck 	 *
572*355440a6SAlexander Duyck 	 * At this point it should be the only MAC address in the MACDA
573*355440a6SAlexander Duyck 	 * so any unicast or multicast traffic received should be routed
574*355440a6SAlexander Duyck 	 * to it. So leave the last rule in place.
575*355440a6SAlexander Duyck 	 *
576*355440a6SAlexander Duyck 	 * It will be rewritten to add the host again when we bring
577*355440a6SAlexander Duyck 	 * the interface back up.
578*355440a6SAlexander Duyck 	 */
579*355440a6SAlexander Duyck 	if (fbnic_bmc_present(fbd)) {
580*355440a6SAlexander Duyck 		act_tcam = &fbd->act_tcam[i];
581*355440a6SAlexander Duyck 
582*355440a6SAlexander Duyck 		if (act_tcam->state == FBNIC_TCAM_S_VALID &&
583*355440a6SAlexander Duyck 		    (act_tcam->dest & dest)) {
584*355440a6SAlexander Duyck 			wr32(fbd, FBNIC_RPC_ACT_TBL0(i), dest);
585*355440a6SAlexander Duyck 			wr32(fbd, FBNIC_RPC_ACT_TBL1(i), 0);
586*355440a6SAlexander Duyck 
587*355440a6SAlexander Duyck 			act_tcam->state = FBNIC_TCAM_S_UPDATE;
588*355440a6SAlexander Duyck 
589*355440a6SAlexander Duyck 			i--;
590*355440a6SAlexander Duyck 		}
591*355440a6SAlexander Duyck 	}
592*355440a6SAlexander Duyck 
593*355440a6SAlexander Duyck 	/* Work from the bottom up deleting all other rules from hardware */
594*355440a6SAlexander Duyck 	do {
595*355440a6SAlexander Duyck 		act_tcam = &fbd->act_tcam[i];
596*355440a6SAlexander Duyck 
597*355440a6SAlexander Duyck 		if (act_tcam->state != FBNIC_TCAM_S_VALID)
598*355440a6SAlexander Duyck 			continue;
599*355440a6SAlexander Duyck 
600*355440a6SAlexander Duyck 		fbnic_clear_act_tcam(fbd, i);
601*355440a6SAlexander Duyck 		act_tcam->state = FBNIC_TCAM_S_UPDATE;
602*355440a6SAlexander Duyck 	} while (i--);
603*355440a6SAlexander Duyck }
604*355440a6SAlexander Duyck 
fbnic_delete_act_tcam(struct fbnic_dev * fbd,unsigned int idx)605*355440a6SAlexander Duyck static void fbnic_delete_act_tcam(struct fbnic_dev *fbd, unsigned int idx)
606*355440a6SAlexander Duyck {
607*355440a6SAlexander Duyck 	fbnic_clear_act_tcam(fbd, idx);
608*355440a6SAlexander Duyck 	memset(&fbd->act_tcam[idx], 0, sizeof(struct fbnic_act_tcam));
609*355440a6SAlexander Duyck }
610*355440a6SAlexander Duyck 
fbnic_update_act_tcam(struct fbnic_dev * fbd,unsigned int idx)611*355440a6SAlexander Duyck static void fbnic_update_act_tcam(struct fbnic_dev *fbd, unsigned int idx)
612*355440a6SAlexander Duyck {
613*355440a6SAlexander Duyck 	struct fbnic_act_tcam *act_tcam = &fbd->act_tcam[idx];
614*355440a6SAlexander Duyck 	int i;
615*355440a6SAlexander Duyck 
616*355440a6SAlexander Duyck 	/* Update entry by writing the destination and RSS mask */
617*355440a6SAlexander Duyck 	wr32(fbd, FBNIC_RPC_ACT_TBL0(idx), act_tcam->dest);
618*355440a6SAlexander Duyck 	wr32(fbd, FBNIC_RPC_ACT_TBL1(idx), act_tcam->rss_en_mask);
619*355440a6SAlexander Duyck 
620*355440a6SAlexander Duyck 	/* Write new TCAM rule to hardware */
621*355440a6SAlexander Duyck 	for (i = 0; i < FBNIC_RPC_TCAM_ACT_WORD_LEN; i++)
622*355440a6SAlexander Duyck 		wr32(fbd, FBNIC_RPC_TCAM_ACT(idx, i),
623*355440a6SAlexander Duyck 		     FIELD_PREP(FBNIC_RPC_TCAM_ACT_MASK,
624*355440a6SAlexander Duyck 				act_tcam->mask.tcam[i]) |
625*355440a6SAlexander Duyck 		     FIELD_PREP(FBNIC_RPC_TCAM_ACT_VALUE,
626*355440a6SAlexander Duyck 				act_tcam->value.tcam[i]));
627*355440a6SAlexander Duyck 
628*355440a6SAlexander Duyck 	wrfl(fbd);
629*355440a6SAlexander Duyck 
630*355440a6SAlexander Duyck 	wr32(fbd, FBNIC_RPC_TCAM_ACT(idx, i), FBNIC_RPC_TCAM_VALIDATE);
631*355440a6SAlexander Duyck 	act_tcam->state = FBNIC_TCAM_S_VALID;
632*355440a6SAlexander Duyck }
633*355440a6SAlexander Duyck 
fbnic_write_rules(struct fbnic_dev * fbd)634*355440a6SAlexander Duyck void fbnic_write_rules(struct fbnic_dev *fbd)
635*355440a6SAlexander Duyck {
636*355440a6SAlexander Duyck 	int i;
637*355440a6SAlexander Duyck 
638*355440a6SAlexander Duyck 	/* Flush any pending action table rules */
639*355440a6SAlexander Duyck 	for (i = 0; i < FBNIC_RPC_ACT_TBL_NUM_ENTRIES; i++) {
640*355440a6SAlexander Duyck 		struct fbnic_act_tcam *act_tcam = &fbd->act_tcam[i];
641*355440a6SAlexander Duyck 
642*355440a6SAlexander Duyck 		/* Check if update flag is set else exit. */
643*355440a6SAlexander Duyck 		if (!(act_tcam->state & FBNIC_TCAM_S_UPDATE))
644*355440a6SAlexander Duyck 			continue;
645*355440a6SAlexander Duyck 
646*355440a6SAlexander Duyck 		if (act_tcam->state == FBNIC_TCAM_S_DELETE)
647*355440a6SAlexander Duyck 			fbnic_delete_act_tcam(fbd, i);
648*355440a6SAlexander Duyck 		else
649*355440a6SAlexander Duyck 			fbnic_update_act_tcam(fbd, i);
650*355440a6SAlexander Duyck 	}
651*355440a6SAlexander Duyck }
652