@@ -170,33 +170,81 @@ static void mlx4_en_do_set_mac(struct work_struct *work)
170
170
static void mlx4_en_clear_list (struct net_device * dev )
171
171
{
172
172
struct mlx4_en_priv * priv = netdev_priv (dev );
173
+ struct mlx4_en_mc_list * tmp , * mc_to_del ;
173
174
174
- kfree (priv -> mc_addrs );
175
- priv -> mc_addrs = NULL ;
176
- priv -> mc_addrs_cnt = 0 ;
175
+ list_for_each_entry_safe (mc_to_del , tmp , & priv -> mc_list , list ) {
176
+ list_del (& mc_to_del -> list );
177
+ kfree (mc_to_del );
178
+ }
177
179
}
178
180
179
181
static void mlx4_en_cache_mclist (struct net_device * dev )
180
182
{
181
183
struct mlx4_en_priv * priv = netdev_priv (dev );
182
184
struct netdev_hw_addr * ha ;
183
- char * mc_addrs ;
184
- int mc_addrs_cnt = netdev_mc_count (dev );
185
- int i ;
185
+ struct mlx4_en_mc_list * tmp ;
186
186
187
- mc_addrs = kmalloc (mc_addrs_cnt * ETH_ALEN , GFP_ATOMIC );
188
- if (!mc_addrs ) {
189
- en_err (priv , "failed to allocate multicast list\n" );
190
- return ;
191
- }
192
- i = 0 ;
193
- netdev_for_each_mc_addr (ha , dev )
194
- memcpy (mc_addrs + i ++ * ETH_ALEN , ha -> addr , ETH_ALEN );
195
187
mlx4_en_clear_list (dev );
196
- priv -> mc_addrs = mc_addrs ;
197
- priv -> mc_addrs_cnt = mc_addrs_cnt ;
188
+ netdev_for_each_mc_addr (ha , dev ) {
189
+ tmp = kzalloc (sizeof (struct mlx4_en_mc_list ), GFP_ATOMIC );
190
+ if (!tmp ) {
191
+ en_err (priv , "failed to allocate multicast list\n" );
192
+ mlx4_en_clear_list (dev );
193
+ return ;
194
+ }
195
+ memcpy (tmp -> addr , ha -> addr , ETH_ALEN );
196
+ list_add_tail (& tmp -> list , & priv -> mc_list );
197
+ }
198
198
}
199
199
200
+ static void update_mclist_flags (struct mlx4_en_priv * priv ,
201
+ struct list_head * dst ,
202
+ struct list_head * src )
203
+ {
204
+ struct mlx4_en_mc_list * dst_tmp , * src_tmp , * new_mc ;
205
+ bool found ;
206
+
207
+ /* Find all the entries that should be removed from dst,
208
+ * These are the entries that are not found in src
209
+ */
210
+ list_for_each_entry (dst_tmp , dst , list ) {
211
+ found = false;
212
+ list_for_each_entry (src_tmp , src , list ) {
213
+ if (!memcmp (dst_tmp -> addr , src_tmp -> addr , ETH_ALEN )) {
214
+ found = true;
215
+ break ;
216
+ }
217
+ }
218
+ if (!found )
219
+ dst_tmp -> action = MCLIST_REM ;
220
+ }
221
+
222
+ /* Add entries that exist in src but not in dst
223
+ * mark them as need to add
224
+ */
225
+ list_for_each_entry (src_tmp , src , list ) {
226
+ found = false;
227
+ list_for_each_entry (dst_tmp , dst , list ) {
228
+ if (!memcmp (dst_tmp -> addr , src_tmp -> addr , ETH_ALEN )) {
229
+ dst_tmp -> action = MCLIST_NONE ;
230
+ found = true;
231
+ break ;
232
+ }
233
+ }
234
+ if (!found ) {
235
+ new_mc = kmalloc (sizeof (struct mlx4_en_mc_list ),
236
+ GFP_KERNEL );
237
+ if (!new_mc ) {
238
+ en_err (priv , "Failed to allocate current multicast list\n" );
239
+ return ;
240
+ }
241
+ memcpy (new_mc , src_tmp ,
242
+ sizeof (struct mlx4_en_mc_list ));
243
+ new_mc -> action = MCLIST_ADD ;
244
+ list_add_tail (& new_mc -> list , dst );
245
+ }
246
+ }
247
+ }
200
248
201
249
static void mlx4_en_set_multicast (struct net_device * dev )
202
250
{
@@ -214,6 +262,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
214
262
mcast_task );
215
263
struct mlx4_en_dev * mdev = priv -> mdev ;
216
264
struct net_device * dev = priv -> dev ;
265
+ struct mlx4_en_mc_list * mclist , * tmp ;
217
266
u64 mcast_addr = 0 ;
218
267
u8 mc_list [16 ] = {0 };
219
268
int err ;
@@ -336,7 +385,6 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
336
385
priv -> flags |= MLX4_EN_FLAG_MC_PROMISC ;
337
386
}
338
387
} else {
339
- int i ;
340
388
/* Disable Multicast promisc */
341
389
if (priv -> flags & MLX4_EN_FLAG_MC_PROMISC ) {
342
390
err = mlx4_multicast_promisc_remove (mdev -> dev , priv -> base_qpn ,
@@ -351,13 +399,6 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
351
399
if (err )
352
400
en_err (priv , "Failed disabling multicast filter\n" );
353
401
354
- /* Detach our qp from all the multicast addresses */
355
- for (i = 0 ; i < priv -> mc_addrs_cnt ; i ++ ) {
356
- memcpy (& mc_list [10 ], priv -> mc_addrs + i * ETH_ALEN , ETH_ALEN );
357
- mc_list [5 ] = priv -> port ;
358
- mlx4_multicast_detach (mdev -> dev , & priv -> rss_map .indir_qp ,
359
- mc_list , MLX4_PROT_ETH );
360
- }
361
402
/* Flush mcast filter and init it with broadcast address */
362
403
mlx4_SET_MCAST_FLTR (mdev -> dev , priv -> port , ETH_BCAST ,
363
404
1 , MLX4_MCAST_CONFIG );
@@ -367,20 +408,47 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
367
408
netif_tx_lock_bh (dev );
368
409
mlx4_en_cache_mclist (dev );
369
410
netif_tx_unlock_bh (dev );
370
- for (i = 0 ; i < priv -> mc_addrs_cnt ; i ++ ) {
371
- mcast_addr =
372
- mlx4_en_mac_to_u64 (priv -> mc_addrs + i * ETH_ALEN );
373
- memcpy (& mc_list [10 ], priv -> mc_addrs + i * ETH_ALEN , ETH_ALEN );
374
- mc_list [5 ] = priv -> port ;
375
- mlx4_multicast_attach (mdev -> dev , & priv -> rss_map .indir_qp ,
376
- mc_list , 0 , MLX4_PROT_ETH );
411
+ list_for_each_entry (mclist , & priv -> mc_list , list ) {
412
+ mcast_addr = mlx4_en_mac_to_u64 (mclist -> addr );
377
413
mlx4_SET_MCAST_FLTR (mdev -> dev , priv -> port ,
378
414
mcast_addr , 0 , MLX4_MCAST_CONFIG );
379
415
}
380
416
err = mlx4_SET_MCAST_FLTR (mdev -> dev , priv -> port , 0 ,
381
417
0 , MLX4_MCAST_ENABLE );
382
418
if (err )
383
419
en_err (priv , "Failed enabling multicast filter\n" );
420
+
421
+ update_mclist_flags (priv , & priv -> curr_list , & priv -> mc_list );
422
+ list_for_each_entry_safe (mclist , tmp , & priv -> curr_list , list ) {
423
+ if (mclist -> action == MCLIST_REM ) {
424
+ /* detach this address and delete from list */
425
+ memcpy (& mc_list [10 ], mclist -> addr , ETH_ALEN );
426
+ mc_list [5 ] = priv -> port ;
427
+ err = mlx4_multicast_detach (mdev -> dev ,
428
+ & priv -> rss_map .indir_qp ,
429
+ mc_list ,
430
+ MLX4_PROT_ETH );
431
+ if (err )
432
+ en_err (priv , "Fail to detach multicast address\n" );
433
+
434
+ /* remove from list */
435
+ list_del (& mclist -> list );
436
+ kfree (mclist );
437
+ }
438
+
439
+ if (mclist -> action == MCLIST_ADD ) {
440
+ /* attach the address */
441
+ memcpy (& mc_list [10 ], mclist -> addr , ETH_ALEN );
442
+ mc_list [5 ] = priv -> port ;
443
+ err = mlx4_multicast_attach (mdev -> dev ,
444
+ & priv -> rss_map .indir_qp ,
445
+ mc_list , 0 ,
446
+ MLX4_PROT_ETH );
447
+ if (err )
448
+ en_err (priv , "Fail to attach multicast address\n" );
449
+
450
+ }
451
+ }
384
452
}
385
453
out :
386
454
mutex_unlock (& mdev -> state_lock );
@@ -605,6 +673,9 @@ int mlx4_en_start_port(struct net_device *dev)
605
673
return 0 ;
606
674
}
607
675
676
+ INIT_LIST_HEAD (& priv -> mc_list );
677
+ INIT_LIST_HEAD (& priv -> curr_list );
678
+
608
679
/* Calculate Rx buf size */
609
680
dev -> mtu = min (dev -> mtu , priv -> max_mtu );
610
681
mlx4_en_calc_rx_buf (dev );
@@ -760,6 +831,7 @@ void mlx4_en_stop_port(struct net_device *dev)
760
831
{
761
832
struct mlx4_en_priv * priv = netdev_priv (dev );
762
833
struct mlx4_en_dev * mdev = priv -> mdev ;
834
+ struct mlx4_en_mc_list * mclist , * tmp ;
763
835
int i ;
764
836
u8 mc_list [16 ] = {0 };
765
837
@@ -781,13 +853,18 @@ void mlx4_en_stop_port(struct net_device *dev)
781
853
mc_list [5 ] = priv -> port ;
782
854
mlx4_multicast_detach (mdev -> dev , & priv -> rss_map .indir_qp , mc_list ,
783
855
MLX4_PROT_ETH );
784
- for ( i = 0 ; i < priv -> mc_addrs_cnt ; i ++ ) {
785
- memcpy (& mc_list [10 ], priv -> mc_addrs + i * ETH_ALEN , ETH_ALEN );
856
+ list_for_each_entry ( mclist , & priv -> curr_list , list ) {
857
+ memcpy (& mc_list [10 ], mclist -> addr , ETH_ALEN );
786
858
mc_list [5 ] = priv -> port ;
787
859
mlx4_multicast_detach (mdev -> dev , & priv -> rss_map .indir_qp ,
788
860
mc_list , MLX4_PROT_ETH );
789
861
}
790
862
mlx4_en_clear_list (dev );
863
+ list_for_each_entry_safe (mclist , tmp , & priv -> curr_list , list ) {
864
+ list_del (& mclist -> list );
865
+ kfree (mclist );
866
+ }
867
+
791
868
/* Flush multicast filter */
792
869
mlx4_SET_MCAST_FLTR (mdev -> dev , priv -> port , 0 , 1 , MLX4_MCAST_CONFIG );
793
870
0 commit comments