@@ -384,6 +384,7 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
384
384
int flags , u16 vid )
385
385
{
386
386
u32 ale_entry [ALE_ENTRY_WORDS ] = {0 , 0 , 0 };
387
+ int mcast_members ;
387
388
int idx ;
388
389
389
390
idx = cpsw_ale_match_addr (ale , addr , (flags & ALE_VLAN ) ? vid : 0 );
@@ -392,11 +393,15 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
392
393
393
394
cpsw_ale_read (ale , idx , ale_entry );
394
395
395
- if (port_mask )
396
- cpsw_ale_set_port_mask (ale_entry , port_mask ,
396
+ if (port_mask ) {
397
+ mcast_members = cpsw_ale_get_port_mask (ale_entry ,
398
+ ale -> port_mask_bits );
399
+ mcast_members &= ~port_mask ;
400
+ cpsw_ale_set_port_mask (ale_entry , mcast_members ,
397
401
ale -> port_mask_bits );
398
- else
402
+ } else {
399
403
cpsw_ale_set_entry_type (ale_entry , ALE_TYPE_FREE );
404
+ }
400
405
401
406
cpsw_ale_write (ale , idx , ale_entry );
402
407
return 0 ;
@@ -428,7 +433,7 @@ static void cpsw_ale_set_vlan_untag(struct cpsw_ale *ale, u32 *ale_entry,
428
433
bitmap_clear (ale -> p0_untag_vid_mask , vid , 1 );
429
434
}
430
435
431
- int cpsw_ale_add_vlan (struct cpsw_ale * ale , u16 vid , int port , int untag ,
436
+ int cpsw_ale_add_vlan (struct cpsw_ale * ale , u16 vid , int port_mask , int untag ,
432
437
int reg_mcast , int unreg_mcast )
433
438
{
434
439
u32 ale_entry [ALE_ENTRY_WORDS ] = {0 , 0 , 0 };
@@ -450,7 +455,8 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
450
455
} else {
451
456
cpsw_ale_set_vlan_mcast (ale , ale_entry , reg_mcast , unreg_mcast );
452
457
}
453
- cpsw_ale_set_vlan_member_list (ale_entry , port , ale -> vlan_field_bits );
458
+ cpsw_ale_set_vlan_member_list (ale_entry , port_mask ,
459
+ ale -> vlan_field_bits );
454
460
455
461
if (idx < 0 )
456
462
idx = cpsw_ale_match_free (ale );
@@ -463,6 +469,41 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
463
469
return 0 ;
464
470
}
465
471
472
+ static void cpsw_ale_del_vlan_modify (struct cpsw_ale * ale , u32 * ale_entry ,
473
+ u16 vid , int port_mask )
474
+ {
475
+ int reg_mcast , unreg_mcast ;
476
+ int members , untag ;
477
+
478
+ members = cpsw_ale_get_vlan_member_list (ale_entry ,
479
+ ale -> vlan_field_bits );
480
+ members &= ~port_mask ;
481
+
482
+ untag = cpsw_ale_get_vlan_untag_force (ale_entry ,
483
+ ale -> vlan_field_bits );
484
+ reg_mcast = cpsw_ale_get_vlan_reg_mcast (ale_entry ,
485
+ ale -> vlan_field_bits );
486
+ unreg_mcast = cpsw_ale_get_vlan_unreg_mcast (ale_entry ,
487
+ ale -> vlan_field_bits );
488
+ untag &= members ;
489
+ reg_mcast &= members ;
490
+ unreg_mcast &= members ;
491
+
492
+ cpsw_ale_set_vlan_untag (ale , ale_entry , vid , untag );
493
+
494
+ if (!ale -> params .nu_switch_ale ) {
495
+ cpsw_ale_set_vlan_reg_mcast (ale_entry , reg_mcast ,
496
+ ale -> vlan_field_bits );
497
+ cpsw_ale_set_vlan_unreg_mcast (ale_entry , unreg_mcast ,
498
+ ale -> vlan_field_bits );
499
+ } else {
500
+ cpsw_ale_set_vlan_mcast (ale , ale_entry , reg_mcast ,
501
+ unreg_mcast );
502
+ }
503
+ cpsw_ale_set_vlan_member_list (ale_entry , members ,
504
+ ale -> vlan_field_bits );
505
+ }
506
+
466
507
int cpsw_ale_del_vlan (struct cpsw_ale * ale , u16 vid , int port_mask )
467
508
{
468
509
u32 ale_entry [ALE_ENTRY_WORDS ] = {0 , 0 , 0 };
@@ -473,18 +514,84 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
473
514
return - ENOENT ;
474
515
475
516
cpsw_ale_read (ale , idx , ale_entry );
476
- cpsw_ale_set_vlan_untag (ale , ale_entry , vid , 0 );
477
517
478
- if (port_mask )
479
- cpsw_ale_set_vlan_member_list ( ale_entry , port_mask ,
480
- ale -> vlan_field_bits );
481
- else
518
+ if (port_mask ) {
519
+ cpsw_ale_del_vlan_modify ( ale , ale_entry , vid , port_mask );
520
+ } else {
521
+ cpsw_ale_set_vlan_untag ( ale , ale_entry , vid , 0 );
482
522
cpsw_ale_set_entry_type (ale_entry , ALE_TYPE_FREE );
523
+ }
483
524
484
525
cpsw_ale_write (ale , idx , ale_entry );
526
+
485
527
return 0 ;
486
528
}
487
529
530
+ int cpsw_ale_vlan_add_modify (struct cpsw_ale * ale , u16 vid , int port_mask ,
531
+ int untag_mask , int reg_mask , int unreg_mask )
532
+ {
533
+ u32 ale_entry [ALE_ENTRY_WORDS ] = {0 , 0 , 0 };
534
+ int reg_mcast_members , unreg_mcast_members ;
535
+ int vlan_members , untag_members ;
536
+ int idx , ret = 0 ;
537
+
538
+ idx = cpsw_ale_match_vlan (ale , vid );
539
+ if (idx >= 0 )
540
+ cpsw_ale_read (ale , idx , ale_entry );
541
+
542
+ vlan_members = cpsw_ale_get_vlan_member_list (ale_entry ,
543
+ ale -> vlan_field_bits );
544
+ reg_mcast_members = cpsw_ale_get_vlan_reg_mcast (ale_entry ,
545
+ ale -> vlan_field_bits );
546
+ unreg_mcast_members =
547
+ cpsw_ale_get_vlan_unreg_mcast (ale_entry ,
548
+ ale -> vlan_field_bits );
549
+ untag_members = cpsw_ale_get_vlan_untag_force (ale_entry ,
550
+ ale -> vlan_field_bits );
551
+
552
+ vlan_members |= port_mask ;
553
+ untag_members = (untag_members & ~port_mask ) | untag_mask ;
554
+ reg_mcast_members = (reg_mcast_members & ~port_mask ) | reg_mask ;
555
+ unreg_mcast_members = (unreg_mcast_members & ~port_mask ) | unreg_mask ;
556
+
557
+ ret = cpsw_ale_add_vlan (ale , vid , vlan_members , untag_members ,
558
+ reg_mcast_members , unreg_mcast_members );
559
+ if (ret ) {
560
+ dev_err (ale -> params .dev , "Unable to add vlan\n" );
561
+ return ret ;
562
+ }
563
+ dev_dbg (ale -> params .dev , "port mask 0x%x untag 0x%x\n" , vlan_members ,
564
+ untag_mask );
565
+
566
+ return ret ;
567
+ }
568
+
569
+ void cpsw_ale_set_unreg_mcast (struct cpsw_ale * ale , int unreg_mcast_mask ,
570
+ bool add )
571
+ {
572
+ u32 ale_entry [ALE_ENTRY_WORDS ];
573
+ int unreg_members = 0 ;
574
+ int type , idx ;
575
+
576
+ for (idx = 0 ; idx < ale -> params .ale_entries ; idx ++ ) {
577
+ cpsw_ale_read (ale , idx , ale_entry );
578
+ type = cpsw_ale_get_entry_type (ale_entry );
579
+ if (type != ALE_TYPE_VLAN )
580
+ continue ;
581
+
582
+ unreg_members =
583
+ cpsw_ale_get_vlan_unreg_mcast (ale_entry ,
584
+ ale -> vlan_field_bits );
585
+ if (add )
586
+ unreg_members |= unreg_mcast_mask ;
587
+ else
588
+ unreg_members &= ~unreg_mcast_mask ;
589
+ cpsw_ale_set_vlan_unreg_mcast (ale_entry , unreg_members ,
590
+ ale -> vlan_field_bits );
591
+ cpsw_ale_write (ale , idx , ale_entry );
592
+ }
593
+ }
594
+
488
595
void cpsw_ale_set_allmulti (struct cpsw_ale * ale , int allmulti , int port )
489
596
{
490
597
u32 ale_entry [ALE_ENTRY_WORDS ];
0 commit comments