@@ -29,6 +29,8 @@ struct mlxsw_sp_acl_erp_core {
29
29
30
30
struct mlxsw_sp_acl_erp_key {
31
31
char mask [MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN ];
32
+ #define __MASK_LEN 0x38
33
+ #define __MASK_IDX (i ) (__MASK_LEN - (i) - 1)
32
34
bool ctcam ;
33
35
};
34
36
@@ -58,6 +60,7 @@ struct mlxsw_sp_acl_erp_table {
58
60
unsigned int num_atcam_erps ;
59
61
unsigned int num_max_atcam_erps ;
60
62
unsigned int num_ctcam_erps ;
63
+ unsigned int num_deltas ;
61
64
struct objagg * objagg ;
62
65
};
63
66
@@ -629,7 +632,7 @@ __mlxsw_sp_acl_erp_table_other_inc(struct mlxsw_sp_acl_erp_table *erp_table,
629
632
{
630
633
int err ;
631
634
632
- /* If there are C-TCAM eRPs in use we need to transition
635
+ /* If there are C-TCAM eRP or deltas in use we need to transition
633
636
* the region to use eRP table, if it is not already done
634
637
*/
635
638
if (erp_table -> ops != & erp_two_masks_ops &&
@@ -639,7 +642,7 @@ __mlxsw_sp_acl_erp_table_other_inc(struct mlxsw_sp_acl_erp_table *erp_table,
639
642
return err ;
640
643
}
641
644
642
- /* When C-TCAM is used, the eRP table must be used */
645
+ /* When C-TCAM or deltas are used, the eRP table must be used */
643
646
if (erp_table -> ops != & erp_multiple_masks_ops )
644
647
erp_table -> ops = & erp_multiple_masks_ops ;
645
648
@@ -654,17 +657,23 @@ static int mlxsw_sp_acl_erp_ctcam_inc(struct mlxsw_sp_acl_erp_table *erp_table)
654
657
& erp_table -> num_ctcam_erps );
655
658
}
656
659
660
+ static int mlxsw_sp_acl_erp_delta_inc (struct mlxsw_sp_acl_erp_table * erp_table )
661
+ {
662
+ return __mlxsw_sp_acl_erp_table_other_inc (erp_table ,
663
+ & erp_table -> num_deltas );
664
+ }
665
+
657
666
static void
658
667
__mlxsw_sp_acl_erp_table_other_dec (struct mlxsw_sp_acl_erp_table * erp_table ,
659
668
unsigned int * dec_num )
660
669
{
661
670
(* dec_num )-- ;
662
671
663
- /* If there are no C-TCAM eRPs in use, the state we
672
+ /* If there are no C-TCAM eRP or deltas in use, the state we
664
673
* transition to depends on the number of A-TCAM eRPs currently
665
674
* in use.
666
675
*/
667
- if (erp_table -> num_ctcam_erps > 0 )
676
+ if (erp_table -> num_ctcam_erps > 0 || erp_table -> num_deltas > 0 )
668
677
return ;
669
678
670
679
switch (erp_table -> num_atcam_erps ) {
@@ -706,6 +715,12 @@ static void mlxsw_sp_acl_erp_ctcam_dec(struct mlxsw_sp_acl_erp_table *erp_table)
706
715
& erp_table -> num_ctcam_erps );
707
716
}
708
717
718
+ static void mlxsw_sp_acl_erp_delta_dec (struct mlxsw_sp_acl_erp_table * erp_table )
719
+ {
720
+ __mlxsw_sp_acl_erp_table_other_dec (erp_table ,
721
+ & erp_table -> num_deltas );
722
+ }
723
+
709
724
static struct mlxsw_sp_acl_erp *
710
725
mlxsw_sp_acl_erp_ctcam_mask_create (struct mlxsw_sp_acl_erp_table * erp_table ,
711
726
struct mlxsw_sp_acl_erp_key * key )
@@ -813,7 +828,8 @@ mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
813
828
mlxsw_sp_acl_erp_index_put (erp_table , erp -> index );
814
829
mlxsw_sp_acl_erp_generic_destroy (erp );
815
830
816
- if (erp_table -> num_atcam_erps == 2 && erp_table -> num_ctcam_erps == 0 )
831
+ if (erp_table -> num_atcam_erps == 2 && erp_table -> num_ctcam_erps == 0 &&
832
+ erp_table -> num_deltas == 0 )
817
833
erp_table -> ops = & erp_two_masks_ops ;
818
834
}
819
835
@@ -961,14 +977,179 @@ u8 mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask *erp_mask)
961
977
return erp -> id ;
962
978
}
963
979
980
+ struct mlxsw_sp_acl_erp_delta {
981
+ struct mlxsw_sp_acl_erp_key key ;
982
+ u16 start ;
983
+ u8 mask ;
984
+ };
985
+
986
+ u16 mlxsw_sp_acl_erp_delta_start (const struct mlxsw_sp_acl_erp_delta * delta )
987
+ {
988
+ return delta -> start ;
989
+ }
990
+
991
+ u8 mlxsw_sp_acl_erp_delta_mask (const struct mlxsw_sp_acl_erp_delta * delta )
992
+ {
993
+ return delta -> mask ;
994
+ }
995
+
996
+ u8 mlxsw_sp_acl_erp_delta_value (const struct mlxsw_sp_acl_erp_delta * delta ,
997
+ const char * enc_key )
998
+ {
999
+ u16 start = delta -> start ;
1000
+ u8 mask = delta -> mask ;
1001
+ u16 tmp ;
1002
+
1003
+ if (!mask )
1004
+ return 0 ;
1005
+
1006
+ tmp = (unsigned char ) enc_key [__MASK_IDX (start / 8 )];
1007
+ if (start / 8 + 1 < __MASK_LEN )
1008
+ tmp |= (unsigned char ) enc_key [__MASK_IDX (start / 8 + 1 )] << 8 ;
1009
+ tmp >>= start % 8 ;
1010
+ tmp &= mask ;
1011
+ return tmp ;
1012
+ }
1013
+
1014
+ void mlxsw_sp_acl_erp_delta_clear (const struct mlxsw_sp_acl_erp_delta * delta ,
1015
+ const char * enc_key )
1016
+ {
1017
+ u16 start = delta -> start ;
1018
+ u8 mask = delta -> mask ;
1019
+ unsigned char * byte ;
1020
+ u16 tmp ;
1021
+
1022
+ tmp = mask ;
1023
+ tmp <<= start % 8 ;
1024
+ tmp = ~tmp ;
1025
+
1026
+ byte = (unsigned char * ) & enc_key [__MASK_IDX (start / 8 )];
1027
+ * byte &= tmp & 0xff ;
1028
+ if (start / 8 + 1 < __MASK_LEN ) {
1029
+ byte = (unsigned char * ) & enc_key [__MASK_IDX (start / 8 + 1 )];
1030
+ * byte &= (tmp >> 8 ) & 0xff ;
1031
+ }
1032
+ }
1033
+
1034
+ static const struct mlxsw_sp_acl_erp_delta
1035
+ mlxsw_sp_acl_erp_delta_default = {};
1036
+
1037
+ const struct mlxsw_sp_acl_erp_delta *
1038
+ mlxsw_sp_acl_erp_delta (const struct mlxsw_sp_acl_erp_mask * erp_mask )
1039
+ {
1040
+ struct objagg_obj * objagg_obj = (struct objagg_obj * ) erp_mask ;
1041
+ const struct mlxsw_sp_acl_erp_delta * delta ;
1042
+
1043
+ delta = objagg_obj_delta_priv (objagg_obj );
1044
+ if (!delta )
1045
+ delta = & mlxsw_sp_acl_erp_delta_default ;
1046
+ return delta ;
1047
+ }
1048
+
1049
+ static int
1050
+ mlxsw_sp_acl_erp_delta_fill (const struct mlxsw_sp_acl_erp_key * parent_key ,
1051
+ const struct mlxsw_sp_acl_erp_key * key ,
1052
+ u16 * delta_start , u8 * delta_mask )
1053
+ {
1054
+ int offset = 0 ;
1055
+ int si = -1 ;
1056
+ u16 pmask ;
1057
+ u16 mask ;
1058
+ int i ;
1059
+
1060
+ /* The difference between 2 masks can be up to 8 consecutive bits. */
1061
+ for (i = 0 ; i < __MASK_LEN ; i ++ ) {
1062
+ if (parent_key -> mask [__MASK_IDX (i )] == key -> mask [__MASK_IDX (i )])
1063
+ continue ;
1064
+ if (si == -1 )
1065
+ si = i ;
1066
+ else if (si != i - 1 )
1067
+ return - EINVAL ;
1068
+ }
1069
+ if (si == -1 ) {
1070
+ /* The masks are the same, this cannot happen.
1071
+ * That means the caller is broken.
1072
+ */
1073
+ WARN_ON (1 );
1074
+ * delta_start = 0 ;
1075
+ * delta_mask = 0 ;
1076
+ return 0 ;
1077
+ }
1078
+ pmask = (unsigned char ) parent_key -> mask [__MASK_IDX (si )];
1079
+ mask = (unsigned char ) key -> mask [__MASK_IDX (si )];
1080
+ if (si + 1 < __MASK_LEN ) {
1081
+ pmask |= (unsigned char ) parent_key -> mask [__MASK_IDX (si + 1 )] << 8 ;
1082
+ mask |= (unsigned char ) key -> mask [__MASK_IDX (si + 1 )] << 8 ;
1083
+ }
1084
+
1085
+ if ((pmask ^ mask ) & pmask )
1086
+ return - EINVAL ;
1087
+ mask &= ~pmask ;
1088
+ while (!(mask & (1 << offset )))
1089
+ offset ++ ;
1090
+ while (!(mask & 1 ))
1091
+ mask >>= 1 ;
1092
+ if (mask & 0xff00 )
1093
+ return - EINVAL ;
1094
+
1095
+ * delta_start = si * 8 + offset ;
1096
+ * delta_mask = mask ;
1097
+
1098
+ return 0 ;
1099
+ }
1100
+
964
1101
static void * mlxsw_sp_acl_erp_delta_create (void * priv , void * parent_obj ,
965
1102
void * obj )
966
1103
{
967
- return ERR_PTR (- EOPNOTSUPP );
1104
+ struct mlxsw_sp_acl_erp_key * parent_key = parent_obj ;
1105
+ struct mlxsw_sp_acl_atcam_region * aregion = priv ;
1106
+ struct mlxsw_sp_acl_erp_table * erp_table = aregion -> erp_table ;
1107
+ struct mlxsw_sp_acl_erp_key * key = obj ;
1108
+ struct mlxsw_sp_acl_erp_delta * delta ;
1109
+ u16 delta_start ;
1110
+ u8 delta_mask ;
1111
+ int err ;
1112
+
1113
+ if (parent_key -> ctcam || key -> ctcam )
1114
+ return ERR_PTR (- EINVAL );
1115
+ err = mlxsw_sp_acl_erp_delta_fill (parent_key , key ,
1116
+ & delta_start , & delta_mask );
1117
+ if (err )
1118
+ return ERR_PTR (- EINVAL );
1119
+
1120
+ delta = kzalloc (sizeof (* delta ), GFP_KERNEL );
1121
+ if (!delta )
1122
+ return ERR_PTR (- ENOMEM );
1123
+ delta -> start = delta_start ;
1124
+ delta -> mask = delta_mask ;
1125
+
1126
+ err = mlxsw_sp_acl_erp_delta_inc (erp_table );
1127
+ if (err )
1128
+ goto err_erp_delta_inc ;
1129
+
1130
+ memcpy (& delta -> key , key , sizeof (* key ));
1131
+ err = mlxsw_sp_acl_erp_master_mask_set (erp_table , & delta -> key );
1132
+ if (err )
1133
+ goto err_master_mask_set ;
1134
+
1135
+ return delta ;
1136
+
1137
+ err_master_mask_set :
1138
+ mlxsw_sp_acl_erp_delta_dec (erp_table );
1139
+ err_erp_delta_inc :
1140
+ kfree (delta );
1141
+ return ERR_PTR (err );
968
1142
}
969
1143
970
1144
static void mlxsw_sp_acl_erp_delta_destroy (void * priv , void * delta_priv )
971
1145
{
1146
+ struct mlxsw_sp_acl_erp_delta * delta = delta_priv ;
1147
+ struct mlxsw_sp_acl_atcam_region * aregion = priv ;
1148
+ struct mlxsw_sp_acl_erp_table * erp_table = aregion -> erp_table ;
1149
+
1150
+ mlxsw_sp_acl_erp_master_mask_clear (erp_table , & delta -> key );
1151
+ mlxsw_sp_acl_erp_delta_dec (erp_table );
1152
+ kfree (delta );
972
1153
}
973
1154
974
1155
static void * mlxsw_sp_acl_erp_root_create (void * priv , void * obj )
0 commit comments