@@ -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 ;
5355release_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+
89317static 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
97327void fbnic_reset_queues (struct fbnic_net * fbn ,
0 commit comments