Skip to content

Commit eb690ef

Browse files
ahduyckkuba-moo
authored andcommitted
eth: fbnic: Add L2 address programming
Program the Rx TCAM to control L2 forwarding. Since we are in full control of the NIC we need to make sure we include BMC forwarding in the rules. When host is not present BMC will program the TCAM to get onto the network but once we take ownership it's up to Linux driver to make sure BMC L2 addresses are handled correctly. Co-developed-by: Sanman Pradhan <[email protected]> Signed-off-by: Sanman Pradhan <[email protected]> Signed-off-by: Alexander Duyck <[email protected]> Link: https://patch.msgid.link/172079943202.1778861.4410412697614789017.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Jakub Kicinski <[email protected]>
1 parent a29b8eb commit eb690ef

File tree

9 files changed

+678
-0
lines changed

9 files changed

+678
-0
lines changed

drivers/net/ethernet/meta/fbnic/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ fbnic-y := fbnic_devlink.o \
1414
fbnic_netdev.o \
1515
fbnic_pci.o \
1616
fbnic_phylink.o \
17+
fbnic_rpc.o \
1718
fbnic_tlv.o \
1819
fbnic_txrx.o

drivers/net/ethernet/meta/fbnic/fbnic.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "fbnic_csr.h"
1313
#include "fbnic_fw.h"
1414
#include "fbnic_mac.h"
15+
#include "fbnic_rpc.h"
1516

1617
struct fbnic_dev {
1718
struct device *dev;
@@ -39,6 +40,10 @@ struct fbnic_dev {
3940
u32 mps;
4041
u32 readrq;
4142

43+
/* Local copy of the devices TCAM */
44+
struct fbnic_mac_addr mac_addr[FBNIC_RPC_TCAM_MACDA_NUM_ENTRIES];
45+
u8 mac_addr_boundary;
46+
4247
/* Number of TCQs/RCQs available on hardware */
4348
u16 max_num_queues;
4449
};

drivers/net/ethernet/meta/fbnic/fbnic_csr.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,8 +537,22 @@ enum {
537537
#define FBNIC_RPC_RMI_CONFIG_FCS_PRESENT CSR_BIT(8)
538538
#define FBNIC_RPC_RMI_CONFIG_ENABLE CSR_BIT(12)
539539
#define FBNIC_RPC_RMI_CONFIG_MTU CSR_GENMASK(31, 16)
540+
#define FBNIC_RPC_TCAM_MACDA_VALIDATE 0x0852d /* 0x214b4 */
540541
#define FBNIC_CSR_END_RPC 0x0856b /* CSR section delimiter */
541542

543+
/* RPC RAM Registers */
544+
545+
#define FBNIC_CSR_START_RPC_RAM 0x08800 /* CSR section delimiter */
546+
#define FBNIC_RPC_ACT_TBL_NUM_ENTRIES 64
547+
548+
/* TCAM Tables */
549+
#define FBNIC_RPC_TCAM_VALIDATE CSR_BIT(31)
550+
#define FBNIC_RPC_TCAM_MACDA(m, n) \
551+
(0x08b80 + 0x20 * (n) + (m)) /* 0x022e00 + 128*n + 4*m */
552+
#define FBNIC_RPC_TCAM_MACDA_VALUE CSR_GENMASK(15, 0)
553+
#define FBNIC_RPC_TCAM_MACDA_MASK CSR_GENMASK(31, 16)
554+
#define FBNIC_CSR_END_RPC_RAM 0x08f1f /* CSR section delimiter */
555+
542556
/* Fab Registers */
543557
#define FBNIC_CSR_START_FAB 0x0C000 /* CSR section delimiter */
544558
#define FBNIC_FAB_AXI4_AR_SPACER_2_CFG 0x0C005 /* 0x30014 */

drivers/net/ethernet/meta/fbnic/fbnic_devlink.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ struct fbnic_dev *fbnic_devlink_alloc(struct pci_dev *pdev)
6868
fbd->mps = pcie_get_mps(pdev);
6969
fbd->readrq = pcie_get_readrq(pdev);
7070

71+
fbd->mac_addr_boundary = FBNIC_RPC_TCAM_MACDA_DEFAULT_BOUNDARY;
72+
7173
return fbd;
7274
}
7375

drivers/net/ethernet/meta/fbnic/fbnic_netdev.c

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ int __fbnic_open(struct fbnic_net *fbn)
4848
err = fbnic_pcs_irq_enable(fbd);
4949
if (err)
5050
goto release_ownership;
51+
/* Pull the BMC config and initialize the RPC */
52+
fbnic_bmc_rpc_init(fbd);
5153

5254
return 0;
5355
release_ownership:
@@ -86,12 +88,240 @@ static int fbnic_stop(struct net_device *netdev)
8688
return 0;
8789
}
8890

91+
static int fbnic_uc_sync(struct net_device *netdev, const unsigned char *addr)
92+
{
93+
struct fbnic_net *fbn = netdev_priv(netdev);
94+
struct fbnic_mac_addr *avail_addr;
95+
96+
if (WARN_ON(!is_valid_ether_addr(addr)))
97+
return -EADDRNOTAVAIL;
98+
99+
avail_addr = __fbnic_uc_sync(fbn->fbd, addr);
100+
if (!avail_addr)
101+
return -ENOSPC;
102+
103+
/* Add type flag indicating this address is in use by the host */
104+
set_bit(FBNIC_MAC_ADDR_T_UNICAST, avail_addr->act_tcam);
105+
106+
return 0;
107+
}
108+
109+
static int fbnic_uc_unsync(struct net_device *netdev, const unsigned char *addr)
110+
{
111+
struct fbnic_net *fbn = netdev_priv(netdev);
112+
struct fbnic_dev *fbd = fbn->fbd;
113+
int i, ret;
114+
115+
/* Scan from middle of list to bottom, filling bottom up.
116+
* Skip the first entry which is reserved for dev_addr and
117+
* leave the last entry to use for promiscuous filtering.
118+
*/
119+
for (i = fbd->mac_addr_boundary, ret = -ENOENT;
120+
i < FBNIC_RPC_TCAM_MACDA_HOST_ADDR_IDX && ret; i++) {
121+
struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];
122+
123+
if (!ether_addr_equal(mac_addr->value.addr8, addr))
124+
continue;
125+
126+
ret = __fbnic_uc_unsync(mac_addr);
127+
}
128+
129+
return ret;
130+
}
131+
132+
static int fbnic_mc_sync(struct net_device *netdev, const unsigned char *addr)
133+
{
134+
struct fbnic_net *fbn = netdev_priv(netdev);
135+
struct fbnic_mac_addr *avail_addr;
136+
137+
if (WARN_ON(!is_multicast_ether_addr(addr)))
138+
return -EADDRNOTAVAIL;
139+
140+
avail_addr = __fbnic_mc_sync(fbn->fbd, addr);
141+
if (!avail_addr)
142+
return -ENOSPC;
143+
144+
/* Add type flag indicating this address is in use by the host */
145+
set_bit(FBNIC_MAC_ADDR_T_MULTICAST, avail_addr->act_tcam);
146+
147+
return 0;
148+
}
149+
150+
static int fbnic_mc_unsync(struct net_device *netdev, const unsigned char *addr)
151+
{
152+
struct fbnic_net *fbn = netdev_priv(netdev);
153+
struct fbnic_dev *fbd = fbn->fbd;
154+
int i, ret;
155+
156+
/* Scan from middle of list to top, filling top down.
157+
* Skip over the address reserved for the BMC MAC and
158+
* exclude index 0 as that belongs to the broadcast address
159+
*/
160+
for (i = fbd->mac_addr_boundary, ret = -ENOENT;
161+
--i > FBNIC_RPC_TCAM_MACDA_BROADCAST_IDX && ret;) {
162+
struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];
163+
164+
if (!ether_addr_equal(mac_addr->value.addr8, addr))
165+
continue;
166+
167+
ret = __fbnic_mc_unsync(mac_addr);
168+
}
169+
170+
return ret;
171+
}
172+
173+
void __fbnic_set_rx_mode(struct net_device *netdev)
174+
{
175+
struct fbnic_net *fbn = netdev_priv(netdev);
176+
bool uc_promisc = false, mc_promisc = false;
177+
struct fbnic_dev *fbd = fbn->fbd;
178+
struct fbnic_mac_addr *mac_addr;
179+
int err;
180+
181+
/* Populate host address from dev_addr */
182+
mac_addr = &fbd->mac_addr[FBNIC_RPC_TCAM_MACDA_HOST_ADDR_IDX];
183+
if (!ether_addr_equal(mac_addr->value.addr8, netdev->dev_addr) ||
184+
mac_addr->state != FBNIC_TCAM_S_VALID) {
185+
ether_addr_copy(mac_addr->value.addr8, netdev->dev_addr);
186+
mac_addr->state = FBNIC_TCAM_S_UPDATE;
187+
set_bit(FBNIC_MAC_ADDR_T_UNICAST, mac_addr->act_tcam);
188+
}
189+
190+
/* Populate broadcast address if broadcast is enabled */
191+
mac_addr = &fbd->mac_addr[FBNIC_RPC_TCAM_MACDA_BROADCAST_IDX];
192+
if (netdev->flags & IFF_BROADCAST) {
193+
if (!is_broadcast_ether_addr(mac_addr->value.addr8) ||
194+
mac_addr->state != FBNIC_TCAM_S_VALID) {
195+
eth_broadcast_addr(mac_addr->value.addr8);
196+
mac_addr->state = FBNIC_TCAM_S_ADD;
197+
}
198+
set_bit(FBNIC_MAC_ADDR_T_BROADCAST, mac_addr->act_tcam);
199+
} else if (mac_addr->state == FBNIC_TCAM_S_VALID) {
200+
__fbnic_xc_unsync(mac_addr, FBNIC_MAC_ADDR_T_BROADCAST);
201+
}
202+
203+
/* Synchronize unicast and multicast address lists */
204+
err = __dev_uc_sync(netdev, fbnic_uc_sync, fbnic_uc_unsync);
205+
if (err == -ENOSPC)
206+
uc_promisc = true;
207+
err = __dev_mc_sync(netdev, fbnic_mc_sync, fbnic_mc_unsync);
208+
if (err == -ENOSPC)
209+
mc_promisc = true;
210+
211+
uc_promisc |= !!(netdev->flags & IFF_PROMISC);
212+
mc_promisc |= !!(netdev->flags & IFF_ALLMULTI) || uc_promisc;
213+
214+
/* Populate last TCAM entry with promiscuous entry and 0/1 bit mask */
215+
mac_addr = &fbd->mac_addr[FBNIC_RPC_TCAM_MACDA_PROMISC_IDX];
216+
if (uc_promisc) {
217+
if (!is_zero_ether_addr(mac_addr->value.addr8) ||
218+
mac_addr->state != FBNIC_TCAM_S_VALID) {
219+
eth_zero_addr(mac_addr->value.addr8);
220+
eth_broadcast_addr(mac_addr->mask.addr8);
221+
clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI,
222+
mac_addr->act_tcam);
223+
set_bit(FBNIC_MAC_ADDR_T_PROMISC,
224+
mac_addr->act_tcam);
225+
mac_addr->state = FBNIC_TCAM_S_ADD;
226+
}
227+
} else if (mc_promisc &&
228+
(!fbnic_bmc_present(fbd) || !fbd->fw_cap.all_multi)) {
229+
/* We have to add a special handler for multicast as the
230+
* BMC may have an all-multi rule already in place. As such
231+
* adding a rule ourselves won't do any good so we will have
232+
* to modify the rules for the ALL MULTI below if the BMC
233+
* already has the rule in place.
234+
*/
235+
if (!is_multicast_ether_addr(mac_addr->value.addr8) ||
236+
mac_addr->state != FBNIC_TCAM_S_VALID) {
237+
eth_zero_addr(mac_addr->value.addr8);
238+
eth_broadcast_addr(mac_addr->mask.addr8);
239+
mac_addr->value.addr8[0] ^= 1;
240+
mac_addr->mask.addr8[0] ^= 1;
241+
set_bit(FBNIC_MAC_ADDR_T_ALLMULTI,
242+
mac_addr->act_tcam);
243+
clear_bit(FBNIC_MAC_ADDR_T_PROMISC,
244+
mac_addr->act_tcam);
245+
mac_addr->state = FBNIC_TCAM_S_ADD;
246+
}
247+
} else if (mac_addr->state == FBNIC_TCAM_S_VALID) {
248+
if (test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam)) {
249+
clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI,
250+
mac_addr->act_tcam);
251+
clear_bit(FBNIC_MAC_ADDR_T_PROMISC,
252+
mac_addr->act_tcam);
253+
} else {
254+
mac_addr->state = FBNIC_TCAM_S_DELETE;
255+
}
256+
}
257+
258+
/* Add rules for BMC all multicast if it is enabled */
259+
fbnic_bmc_rpc_all_multi_config(fbd, mc_promisc);
260+
261+
/* Sift out any unshared BMC rules and place them in BMC only section */
262+
fbnic_sift_macda(fbd);
263+
264+
/* Write updates to hardware */
265+
fbnic_write_macda(fbd);
266+
}
267+
268+
static void fbnic_set_rx_mode(struct net_device *netdev)
269+
{
270+
/* No need to update the hardware if we are not running */
271+
if (netif_running(netdev))
272+
__fbnic_set_rx_mode(netdev);
273+
}
274+
275+
static int fbnic_set_mac(struct net_device *netdev, void *p)
276+
{
277+
struct sockaddr *addr = p;
278+
279+
if (!is_valid_ether_addr(addr->sa_data))
280+
return -EADDRNOTAVAIL;
281+
282+
eth_hw_addr_set(netdev, addr->sa_data);
283+
284+
fbnic_set_rx_mode(netdev);
285+
286+
return 0;
287+
}
288+
289+
void fbnic_clear_rx_mode(struct net_device *netdev)
290+
{
291+
struct fbnic_net *fbn = netdev_priv(netdev);
292+
struct fbnic_dev *fbd = fbn->fbd;
293+
int idx;
294+
295+
for (idx = ARRAY_SIZE(fbd->mac_addr); idx--;) {
296+
struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[idx];
297+
298+
if (mac_addr->state != FBNIC_TCAM_S_VALID)
299+
continue;
300+
301+
bitmap_clear(mac_addr->act_tcam,
302+
FBNIC_MAC_ADDR_T_HOST_START,
303+
FBNIC_MAC_ADDR_T_HOST_LEN);
304+
305+
if (bitmap_empty(mac_addr->act_tcam,
306+
FBNIC_RPC_TCAM_ACT_NUM_ENTRIES))
307+
mac_addr->state = FBNIC_TCAM_S_DELETE;
308+
}
309+
310+
/* Write updates to hardware */
311+
fbnic_write_macda(fbd);
312+
313+
__dev_uc_unsync(netdev, NULL);
314+
__dev_mc_unsync(netdev, NULL);
315+
}
316+
89317
static const struct net_device_ops fbnic_netdev_ops = {
90318
.ndo_open = fbnic_open,
91319
.ndo_stop = fbnic_stop,
92320
.ndo_validate_addr = eth_validate_addr,
93321
.ndo_start_xmit = fbnic_xmit_frame,
94322
.ndo_features_check = fbnic_features_check,
323+
.ndo_set_mac_address = fbnic_set_mac,
324+
.ndo_set_rx_mode = fbnic_set_rx_mode,
95325
};
96326

97327
void fbnic_reset_queues(struct fbnic_net *fbn,

drivers/net/ethernet/meta/fbnic/fbnic_netdev.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,8 @@ void fbnic_netdev_unregister(struct net_device *netdev);
4949
void fbnic_reset_queues(struct fbnic_net *fbn,
5050
unsigned int tx, unsigned int rx);
5151

52+
void __fbnic_set_rx_mode(struct net_device *netdev);
53+
void fbnic_clear_rx_mode(struct net_device *netdev);
54+
5255
int fbnic_phylink_init(struct net_device *netdev);
5356
#endif /* _FBNIC_NETDEV_H_ */

drivers/net/ethernet/meta/fbnic/fbnic_pci.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ void fbnic_up(struct fbnic_net *fbn)
133133

134134
fbnic_fill(fbn);
135135

136+
__fbnic_set_rx_mode(fbn->netdev);
137+
136138
/* Enable Tx/Rx processing */
137139
fbnic_napi_enable(fbn);
138140
netif_tx_start_all_queues(fbn->netdev);
@@ -148,6 +150,7 @@ static void fbnic_down_noidle(struct fbnic_net *fbn)
148150
fbnic_napi_disable(fbn);
149151
netif_tx_disable(fbn->netdev);
150152

153+
fbnic_clear_rx_mode(fbn->netdev);
151154
fbnic_disable(fbn);
152155
}
153156

0 commit comments

Comments
 (0)