@@ -29,6 +29,8 @@ struct mlxsw_sp_acl_erp_core {
2929
3030struct mlxsw_sp_acl_erp_key {
3131 char mask [MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN ];
32+ #define __MASK_LEN 0x38
33+ #define __MASK_IDX (i ) (__MASK_LEN - (i) - 1)
3234 bool ctcam ;
3335};
3436
@@ -58,6 +60,7 @@ struct mlxsw_sp_acl_erp_table {
5860 unsigned int num_atcam_erps ;
5961 unsigned int num_max_atcam_erps ;
6062 unsigned int num_ctcam_erps ;
63+ unsigned int num_deltas ;
6164 struct objagg * objagg ;
6265};
6366
@@ -629,7 +632,7 @@ __mlxsw_sp_acl_erp_table_other_inc(struct mlxsw_sp_acl_erp_table *erp_table,
629632{
630633 int err ;
631634
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
633636 * the region to use eRP table, if it is not already done
634637 */
635638 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,
639642 return err ;
640643 }
641644
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 */
643646 if (erp_table -> ops != & erp_multiple_masks_ops )
644647 erp_table -> ops = & erp_multiple_masks_ops ;
645648
@@ -654,17 +657,23 @@ static int mlxsw_sp_acl_erp_ctcam_inc(struct mlxsw_sp_acl_erp_table *erp_table)
654657 & erp_table -> num_ctcam_erps );
655658}
656659
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+
657666static void
658667__mlxsw_sp_acl_erp_table_other_dec (struct mlxsw_sp_acl_erp_table * erp_table ,
659668 unsigned int * dec_num )
660669{
661670 (* dec_num )-- ;
662671
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
664673 * transition to depends on the number of A-TCAM eRPs currently
665674 * in use.
666675 */
667- if (erp_table -> num_ctcam_erps > 0 )
676+ if (erp_table -> num_ctcam_erps > 0 || erp_table -> num_deltas > 0 )
668677 return ;
669678
670679 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)
706715 & erp_table -> num_ctcam_erps );
707716}
708717
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+
709724static struct mlxsw_sp_acl_erp *
710725mlxsw_sp_acl_erp_ctcam_mask_create (struct mlxsw_sp_acl_erp_table * erp_table ,
711726 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,
813828 mlxsw_sp_acl_erp_index_put (erp_table , erp -> index );
814829 mlxsw_sp_acl_erp_generic_destroy (erp );
815830
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 )
817833 erp_table -> ops = & erp_two_masks_ops ;
818834}
819835
@@ -961,14 +977,179 @@ u8 mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask *erp_mask)
961977 return erp -> id ;
962978}
963979
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+
9641101static void * mlxsw_sp_acl_erp_delta_create (void * priv , void * parent_obj ,
9651102 void * obj )
9661103{
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 );
9681142}
9691143
9701144static void mlxsw_sp_acl_erp_delta_destroy (void * priv , void * delta_priv )
9711145{
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 );
9721153}
9731154
9741155static void * mlxsw_sp_acl_erp_root_create (void * priv , void * obj )
0 commit comments