xref: /openbmc/linux/drivers/net/ethernet/mellanox/mlxsw/spectrum1_mr_tcam.c (revision 3eb66e91a25497065c5322b1268cbc3953642227)
1*9948a064SJiri Pirko // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*9948a064SJiri Pirko /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
38fae4392SJiri Pirko 
48fae4392SJiri Pirko #include <linux/kernel.h>
58fae4392SJiri Pirko #include <linux/parman.h>
68fae4392SJiri Pirko 
78fae4392SJiri Pirko #include "reg.h"
88fae4392SJiri Pirko #include "spectrum.h"
98fae4392SJiri Pirko #include "core_acl_flex_actions.h"
108fae4392SJiri Pirko #include "spectrum_mr.h"
118fae4392SJiri Pirko 
128fae4392SJiri Pirko struct mlxsw_sp1_mr_tcam_region {
138fae4392SJiri Pirko 	struct mlxsw_sp *mlxsw_sp;
148fae4392SJiri Pirko 	enum mlxsw_reg_rtar_key_type rtar_key_type;
158fae4392SJiri Pirko 	struct parman *parman;
168fae4392SJiri Pirko 	struct parman_prio *parman_prios;
178fae4392SJiri Pirko };
188fae4392SJiri Pirko 
198fae4392SJiri Pirko struct mlxsw_sp1_mr_tcam {
208fae4392SJiri Pirko 	struct mlxsw_sp1_mr_tcam_region tcam_regions[MLXSW_SP_L3_PROTO_MAX];
218fae4392SJiri Pirko };
228fae4392SJiri Pirko 
238fae4392SJiri Pirko struct mlxsw_sp1_mr_tcam_route {
248fae4392SJiri Pirko 	struct parman_item parman_item;
258fae4392SJiri Pirko 	struct parman_prio *parman_prio;
268fae4392SJiri Pirko };
278fae4392SJiri Pirko 
mlxsw_sp1_mr_tcam_route_replace(struct mlxsw_sp * mlxsw_sp,struct parman_item * parman_item,struct mlxsw_sp_mr_route_key * key,struct mlxsw_afa_block * afa_block)288fae4392SJiri Pirko static int mlxsw_sp1_mr_tcam_route_replace(struct mlxsw_sp *mlxsw_sp,
298fae4392SJiri Pirko 					   struct parman_item *parman_item,
308fae4392SJiri Pirko 					   struct mlxsw_sp_mr_route_key *key,
318fae4392SJiri Pirko 					   struct mlxsw_afa_block *afa_block)
328fae4392SJiri Pirko {
338fae4392SJiri Pirko 	char rmft2_pl[MLXSW_REG_RMFT2_LEN];
348fae4392SJiri Pirko 
358fae4392SJiri Pirko 	switch (key->proto) {
368fae4392SJiri Pirko 	case MLXSW_SP_L3_PROTO_IPV4:
378fae4392SJiri Pirko 		mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, true, parman_item->index,
388fae4392SJiri Pirko 					  key->vrid,
398fae4392SJiri Pirko 					  MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
408fae4392SJiri Pirko 					  ntohl(key->group.addr4),
418fae4392SJiri Pirko 					  ntohl(key->group_mask.addr4),
428fae4392SJiri Pirko 					  ntohl(key->source.addr4),
438fae4392SJiri Pirko 					  ntohl(key->source_mask.addr4),
448fae4392SJiri Pirko 					  mlxsw_afa_block_first_set(afa_block));
458fae4392SJiri Pirko 		break;
468fae4392SJiri Pirko 	case MLXSW_SP_L3_PROTO_IPV6:
478fae4392SJiri Pirko 		mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, true, parman_item->index,
488fae4392SJiri Pirko 					  key->vrid,
498fae4392SJiri Pirko 					  MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
508fae4392SJiri Pirko 					  key->group.addr6,
518fae4392SJiri Pirko 					  key->group_mask.addr6,
528fae4392SJiri Pirko 					  key->source.addr6,
538fae4392SJiri Pirko 					  key->source_mask.addr6,
548fae4392SJiri Pirko 					  mlxsw_afa_block_first_set(afa_block));
558fae4392SJiri Pirko 	}
568fae4392SJiri Pirko 
578fae4392SJiri Pirko 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
588fae4392SJiri Pirko }
598fae4392SJiri Pirko 
mlxsw_sp1_mr_tcam_route_remove(struct mlxsw_sp * mlxsw_sp,struct parman_item * parman_item,struct mlxsw_sp_mr_route_key * key)608fae4392SJiri Pirko static int mlxsw_sp1_mr_tcam_route_remove(struct mlxsw_sp *mlxsw_sp,
618fae4392SJiri Pirko 					  struct parman_item *parman_item,
628fae4392SJiri Pirko 					  struct mlxsw_sp_mr_route_key *key)
638fae4392SJiri Pirko {
648fae4392SJiri Pirko 	struct in6_addr zero_addr = IN6ADDR_ANY_INIT;
658fae4392SJiri Pirko 	char rmft2_pl[MLXSW_REG_RMFT2_LEN];
668fae4392SJiri Pirko 
678fae4392SJiri Pirko 	switch (key->proto) {
688fae4392SJiri Pirko 	case MLXSW_SP_L3_PROTO_IPV4:
698fae4392SJiri Pirko 		mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, false, parman_item->index,
708fae4392SJiri Pirko 					  key->vrid, 0, 0, 0, 0, 0, 0, NULL);
718fae4392SJiri Pirko 		break;
728fae4392SJiri Pirko 	case MLXSW_SP_L3_PROTO_IPV6:
738fae4392SJiri Pirko 		mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, false, parman_item->index,
748fae4392SJiri Pirko 					  key->vrid, 0, 0, zero_addr, zero_addr,
758fae4392SJiri Pirko 					  zero_addr, zero_addr, NULL);
768fae4392SJiri Pirko 		break;
778fae4392SJiri Pirko 	}
788fae4392SJiri Pirko 
798fae4392SJiri Pirko 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
808fae4392SJiri Pirko }
818fae4392SJiri Pirko 
828fae4392SJiri Pirko static struct mlxsw_sp1_mr_tcam_region *
mlxsw_sp1_mr_tcam_protocol_region(struct mlxsw_sp1_mr_tcam * mr_tcam,enum mlxsw_sp_l3proto proto)838fae4392SJiri Pirko mlxsw_sp1_mr_tcam_protocol_region(struct mlxsw_sp1_mr_tcam *mr_tcam,
848fae4392SJiri Pirko 				  enum mlxsw_sp_l3proto proto)
858fae4392SJiri Pirko {
868fae4392SJiri Pirko 	return &mr_tcam->tcam_regions[proto];
878fae4392SJiri Pirko }
888fae4392SJiri Pirko 
898fae4392SJiri Pirko static int
mlxsw_sp1_mr_tcam_route_parman_item_add(struct mlxsw_sp1_mr_tcam * mr_tcam,struct mlxsw_sp1_mr_tcam_route * route,struct mlxsw_sp_mr_route_key * key,enum mlxsw_sp_mr_route_prio prio)908fae4392SJiri Pirko mlxsw_sp1_mr_tcam_route_parman_item_add(struct mlxsw_sp1_mr_tcam *mr_tcam,
918fae4392SJiri Pirko 					struct mlxsw_sp1_mr_tcam_route *route,
928fae4392SJiri Pirko 					struct mlxsw_sp_mr_route_key *key,
938fae4392SJiri Pirko 					enum mlxsw_sp_mr_route_prio prio)
948fae4392SJiri Pirko {
958fae4392SJiri Pirko 	struct mlxsw_sp1_mr_tcam_region *tcam_region;
968fae4392SJiri Pirko 	int err;
978fae4392SJiri Pirko 
988fae4392SJiri Pirko 	tcam_region = mlxsw_sp1_mr_tcam_protocol_region(mr_tcam, key->proto);
998fae4392SJiri Pirko 	err = parman_item_add(tcam_region->parman,
1008fae4392SJiri Pirko 			      &tcam_region->parman_prios[prio],
1018fae4392SJiri Pirko 			      &route->parman_item);
1028fae4392SJiri Pirko 	if (err)
1038fae4392SJiri Pirko 		return err;
1048fae4392SJiri Pirko 
1058fae4392SJiri Pirko 	route->parman_prio = &tcam_region->parman_prios[prio];
1068fae4392SJiri Pirko 	return 0;
1078fae4392SJiri Pirko }
1088fae4392SJiri Pirko 
1098fae4392SJiri Pirko static void
mlxsw_sp1_mr_tcam_route_parman_item_remove(struct mlxsw_sp1_mr_tcam * mr_tcam,struct mlxsw_sp1_mr_tcam_route * route,struct mlxsw_sp_mr_route_key * key)1108fae4392SJiri Pirko mlxsw_sp1_mr_tcam_route_parman_item_remove(struct mlxsw_sp1_mr_tcam *mr_tcam,
1118fae4392SJiri Pirko 					   struct mlxsw_sp1_mr_tcam_route *route,
1128fae4392SJiri Pirko 					   struct mlxsw_sp_mr_route_key *key)
1138fae4392SJiri Pirko {
1148fae4392SJiri Pirko 	struct mlxsw_sp1_mr_tcam_region *tcam_region;
1158fae4392SJiri Pirko 
1168fae4392SJiri Pirko 	tcam_region = mlxsw_sp1_mr_tcam_protocol_region(mr_tcam, key->proto);
1178fae4392SJiri Pirko 	parman_item_remove(tcam_region->parman,
1188fae4392SJiri Pirko 			   route->parman_prio, &route->parman_item);
1198fae4392SJiri Pirko }
1208fae4392SJiri Pirko 
1218fae4392SJiri Pirko static int
mlxsw_sp1_mr_tcam_route_create(struct mlxsw_sp * mlxsw_sp,void * priv,void * route_priv,struct mlxsw_sp_mr_route_key * key,struct mlxsw_afa_block * afa_block,enum mlxsw_sp_mr_route_prio prio)1228fae4392SJiri Pirko mlxsw_sp1_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
1238fae4392SJiri Pirko 			       void *route_priv,
1248fae4392SJiri Pirko 			       struct mlxsw_sp_mr_route_key *key,
1258fae4392SJiri Pirko 			       struct mlxsw_afa_block *afa_block,
1268fae4392SJiri Pirko 			       enum mlxsw_sp_mr_route_prio prio)
1278fae4392SJiri Pirko {
1288fae4392SJiri Pirko 	struct mlxsw_sp1_mr_tcam_route *route = route_priv;
1298fae4392SJiri Pirko 	struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
1308fae4392SJiri Pirko 	int err;
1318fae4392SJiri Pirko 
1328fae4392SJiri Pirko 	err = mlxsw_sp1_mr_tcam_route_parman_item_add(mr_tcam, route,
1338fae4392SJiri Pirko 						      key, prio);
1348fae4392SJiri Pirko 	if (err)
1358fae4392SJiri Pirko 		return err;
1368fae4392SJiri Pirko 
1378fae4392SJiri Pirko 	err = mlxsw_sp1_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
1388fae4392SJiri Pirko 					      key, afa_block);
1398fae4392SJiri Pirko 	if (err)
1408fae4392SJiri Pirko 		goto err_route_replace;
1418fae4392SJiri Pirko 	return 0;
1428fae4392SJiri Pirko 
1438fae4392SJiri Pirko err_route_replace:
1448fae4392SJiri Pirko 	mlxsw_sp1_mr_tcam_route_parman_item_remove(mr_tcam, route, key);
1458fae4392SJiri Pirko 	return err;
1468fae4392SJiri Pirko }
1478fae4392SJiri Pirko 
1488fae4392SJiri Pirko static void
mlxsw_sp1_mr_tcam_route_destroy(struct mlxsw_sp * mlxsw_sp,void * priv,void * route_priv,struct mlxsw_sp_mr_route_key * key)1498fae4392SJiri Pirko mlxsw_sp1_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
1508fae4392SJiri Pirko 				void *route_priv,
1518fae4392SJiri Pirko 				struct mlxsw_sp_mr_route_key *key)
1528fae4392SJiri Pirko {
1538fae4392SJiri Pirko 	struct mlxsw_sp1_mr_tcam_route *route = route_priv;
1548fae4392SJiri Pirko 	struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
1558fae4392SJiri Pirko 
1568fae4392SJiri Pirko 	mlxsw_sp1_mr_tcam_route_remove(mlxsw_sp, &route->parman_item, key);
1578fae4392SJiri Pirko 	mlxsw_sp1_mr_tcam_route_parman_item_remove(mr_tcam, route, key);
1588fae4392SJiri Pirko }
1598fae4392SJiri Pirko 
1608fae4392SJiri Pirko static int
mlxsw_sp1_mr_tcam_route_update(struct mlxsw_sp * mlxsw_sp,void * route_priv,struct mlxsw_sp_mr_route_key * key,struct mlxsw_afa_block * afa_block)1618fae4392SJiri Pirko mlxsw_sp1_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
1628fae4392SJiri Pirko 			       void *route_priv,
1638fae4392SJiri Pirko 			       struct mlxsw_sp_mr_route_key *key,
1648fae4392SJiri Pirko 			       struct mlxsw_afa_block *afa_block)
1658fae4392SJiri Pirko {
1668fae4392SJiri Pirko 	struct mlxsw_sp1_mr_tcam_route *route = route_priv;
1678fae4392SJiri Pirko 
1688fae4392SJiri Pirko 	return mlxsw_sp1_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
1698fae4392SJiri Pirko 					       key, afa_block);
1708fae4392SJiri Pirko }
1718fae4392SJiri Pirko 
1728fae4392SJiri Pirko #define MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT 16
1738fae4392SJiri Pirko #define MLXSW_SP1_MR_TCAM_REGION_RESIZE_STEP 16
1748fae4392SJiri Pirko 
1758fae4392SJiri Pirko static int
mlxsw_sp1_mr_tcam_region_alloc(struct mlxsw_sp1_mr_tcam_region * mr_tcam_region)1768fae4392SJiri Pirko mlxsw_sp1_mr_tcam_region_alloc(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
1778fae4392SJiri Pirko {
1788fae4392SJiri Pirko 	struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
1798fae4392SJiri Pirko 	char rtar_pl[MLXSW_REG_RTAR_LEN];
1808fae4392SJiri Pirko 
1818fae4392SJiri Pirko 	mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_ALLOCATE,
1828fae4392SJiri Pirko 			    mr_tcam_region->rtar_key_type,
1838fae4392SJiri Pirko 			    MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT);
1848fae4392SJiri Pirko 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
1858fae4392SJiri Pirko }
1868fae4392SJiri Pirko 
1878fae4392SJiri Pirko static void
mlxsw_sp1_mr_tcam_region_free(struct mlxsw_sp1_mr_tcam_region * mr_tcam_region)1888fae4392SJiri Pirko mlxsw_sp1_mr_tcam_region_free(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
1898fae4392SJiri Pirko {
1908fae4392SJiri Pirko 	struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
1918fae4392SJiri Pirko 	char rtar_pl[MLXSW_REG_RTAR_LEN];
1928fae4392SJiri Pirko 
1938fae4392SJiri Pirko 	mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_DEALLOCATE,
1948fae4392SJiri Pirko 			    mr_tcam_region->rtar_key_type, 0);
1958fae4392SJiri Pirko 	mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
1968fae4392SJiri Pirko }
1978fae4392SJiri Pirko 
mlxsw_sp1_mr_tcam_region_parman_resize(void * priv,unsigned long new_count)1988fae4392SJiri Pirko static int mlxsw_sp1_mr_tcam_region_parman_resize(void *priv,
1998fae4392SJiri Pirko 						  unsigned long new_count)
2008fae4392SJiri Pirko {
2018fae4392SJiri Pirko 	struct mlxsw_sp1_mr_tcam_region *mr_tcam_region = priv;
2028fae4392SJiri Pirko 	struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
2038fae4392SJiri Pirko 	char rtar_pl[MLXSW_REG_RTAR_LEN];
2048fae4392SJiri Pirko 	u64 max_tcam_rules;
2058fae4392SJiri Pirko 
2068fae4392SJiri Pirko 	max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES);
2078fae4392SJiri Pirko 	if (new_count > max_tcam_rules)
2088fae4392SJiri Pirko 		return -EINVAL;
2098fae4392SJiri Pirko 	mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_RESIZE,
2108fae4392SJiri Pirko 			    mr_tcam_region->rtar_key_type, new_count);
2118fae4392SJiri Pirko 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
2128fae4392SJiri Pirko }
2138fae4392SJiri Pirko 
mlxsw_sp1_mr_tcam_region_parman_move(void * priv,unsigned long from_index,unsigned long to_index,unsigned long count)2148fae4392SJiri Pirko static void mlxsw_sp1_mr_tcam_region_parman_move(void *priv,
2158fae4392SJiri Pirko 						 unsigned long from_index,
2168fae4392SJiri Pirko 						 unsigned long to_index,
2178fae4392SJiri Pirko 						 unsigned long count)
2188fae4392SJiri Pirko {
2198fae4392SJiri Pirko 	struct mlxsw_sp1_mr_tcam_region *mr_tcam_region = priv;
2208fae4392SJiri Pirko 	struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
2218fae4392SJiri Pirko 	char rrcr_pl[MLXSW_REG_RRCR_LEN];
2228fae4392SJiri Pirko 
2238fae4392SJiri Pirko 	mlxsw_reg_rrcr_pack(rrcr_pl, MLXSW_REG_RRCR_OP_MOVE,
2248fae4392SJiri Pirko 			    from_index, count,
2258fae4392SJiri Pirko 			    mr_tcam_region->rtar_key_type, to_index);
2268fae4392SJiri Pirko 	mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rrcr), rrcr_pl);
2278fae4392SJiri Pirko }
2288fae4392SJiri Pirko 
2298fae4392SJiri Pirko static const struct parman_ops mlxsw_sp1_mr_tcam_region_parman_ops = {
2308fae4392SJiri Pirko 	.base_count	= MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT,
2318fae4392SJiri Pirko 	.resize_step	= MLXSW_SP1_MR_TCAM_REGION_RESIZE_STEP,
2328fae4392SJiri Pirko 	.resize		= mlxsw_sp1_mr_tcam_region_parman_resize,
2338fae4392SJiri Pirko 	.move		= mlxsw_sp1_mr_tcam_region_parman_move,
2348fae4392SJiri Pirko 	.algo		= PARMAN_ALGO_TYPE_LSORT,
2358fae4392SJiri Pirko };
2368fae4392SJiri Pirko 
2378fae4392SJiri Pirko static int
mlxsw_sp1_mr_tcam_region_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp1_mr_tcam_region * mr_tcam_region,enum mlxsw_reg_rtar_key_type rtar_key_type)2388fae4392SJiri Pirko mlxsw_sp1_mr_tcam_region_init(struct mlxsw_sp *mlxsw_sp,
2398fae4392SJiri Pirko 			      struct mlxsw_sp1_mr_tcam_region *mr_tcam_region,
2408fae4392SJiri Pirko 			      enum mlxsw_reg_rtar_key_type rtar_key_type)
2418fae4392SJiri Pirko {
2428fae4392SJiri Pirko 	struct parman_prio *parman_prios;
2438fae4392SJiri Pirko 	struct parman *parman;
2448fae4392SJiri Pirko 	int err;
2458fae4392SJiri Pirko 	int i;
2468fae4392SJiri Pirko 
2478fae4392SJiri Pirko 	mr_tcam_region->rtar_key_type = rtar_key_type;
2488fae4392SJiri Pirko 	mr_tcam_region->mlxsw_sp = mlxsw_sp;
2498fae4392SJiri Pirko 
2508fae4392SJiri Pirko 	err = mlxsw_sp1_mr_tcam_region_alloc(mr_tcam_region);
2518fae4392SJiri Pirko 	if (err)
2528fae4392SJiri Pirko 		return err;
2538fae4392SJiri Pirko 
2548fae4392SJiri Pirko 	parman = parman_create(&mlxsw_sp1_mr_tcam_region_parman_ops,
2558fae4392SJiri Pirko 			       mr_tcam_region);
2568fae4392SJiri Pirko 	if (!parman) {
2578fae4392SJiri Pirko 		err = -ENOMEM;
2588fae4392SJiri Pirko 		goto err_parman_create;
2598fae4392SJiri Pirko 	}
2608fae4392SJiri Pirko 	mr_tcam_region->parman = parman;
2618fae4392SJiri Pirko 
2628fae4392SJiri Pirko 	parman_prios = kmalloc_array(MLXSW_SP_MR_ROUTE_PRIO_MAX + 1,
2638fae4392SJiri Pirko 				     sizeof(*parman_prios), GFP_KERNEL);
2648fae4392SJiri Pirko 	if (!parman_prios) {
2658fae4392SJiri Pirko 		err = -ENOMEM;
2668fae4392SJiri Pirko 		goto err_parman_prios_alloc;
2678fae4392SJiri Pirko 	}
2688fae4392SJiri Pirko 	mr_tcam_region->parman_prios = parman_prios;
2698fae4392SJiri Pirko 
2708fae4392SJiri Pirko 	for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
2718fae4392SJiri Pirko 		parman_prio_init(mr_tcam_region->parman,
2728fae4392SJiri Pirko 				 &mr_tcam_region->parman_prios[i], i);
2738fae4392SJiri Pirko 	return 0;
2748fae4392SJiri Pirko 
2758fae4392SJiri Pirko err_parman_prios_alloc:
2768fae4392SJiri Pirko 	parman_destroy(parman);
2778fae4392SJiri Pirko err_parman_create:
2788fae4392SJiri Pirko 	mlxsw_sp1_mr_tcam_region_free(mr_tcam_region);
2798fae4392SJiri Pirko 	return err;
2808fae4392SJiri Pirko }
2818fae4392SJiri Pirko 
2828fae4392SJiri Pirko static void
mlxsw_sp1_mr_tcam_region_fini(struct mlxsw_sp1_mr_tcam_region * mr_tcam_region)2838fae4392SJiri Pirko mlxsw_sp1_mr_tcam_region_fini(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
2848fae4392SJiri Pirko {
2858fae4392SJiri Pirko 	int i;
2868fae4392SJiri Pirko 
2878fae4392SJiri Pirko 	for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
2888fae4392SJiri Pirko 		parman_prio_fini(&mr_tcam_region->parman_prios[i]);
2898fae4392SJiri Pirko 	kfree(mr_tcam_region->parman_prios);
2908fae4392SJiri Pirko 	parman_destroy(mr_tcam_region->parman);
2918fae4392SJiri Pirko 	mlxsw_sp1_mr_tcam_region_free(mr_tcam_region);
2928fae4392SJiri Pirko }
2938fae4392SJiri Pirko 
mlxsw_sp1_mr_tcam_init(struct mlxsw_sp * mlxsw_sp,void * priv)2948fae4392SJiri Pirko static int mlxsw_sp1_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
2958fae4392SJiri Pirko {
2968fae4392SJiri Pirko 	struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
2978fae4392SJiri Pirko 	struct mlxsw_sp1_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
2988fae4392SJiri Pirko 	u32 rtar_key;
2998fae4392SJiri Pirko 	int err;
3008fae4392SJiri Pirko 
3018fae4392SJiri Pirko 	if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_TCAM_RULES))
3028fae4392SJiri Pirko 		return -EIO;
3038fae4392SJiri Pirko 
3048fae4392SJiri Pirko 	rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV4_MULTICAST;
3058fae4392SJiri Pirko 	err = mlxsw_sp1_mr_tcam_region_init(mlxsw_sp,
3068fae4392SJiri Pirko 					    &region[MLXSW_SP_L3_PROTO_IPV4],
3078fae4392SJiri Pirko 					    rtar_key);
3088fae4392SJiri Pirko 	if (err)
3098fae4392SJiri Pirko 		return err;
3108fae4392SJiri Pirko 
3118fae4392SJiri Pirko 	rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV6_MULTICAST;
3128fae4392SJiri Pirko 	err = mlxsw_sp1_mr_tcam_region_init(mlxsw_sp,
3138fae4392SJiri Pirko 					    &region[MLXSW_SP_L3_PROTO_IPV6],
3148fae4392SJiri Pirko 					    rtar_key);
3158fae4392SJiri Pirko 	if (err)
3168fae4392SJiri Pirko 		goto err_ipv6_region_init;
3178fae4392SJiri Pirko 
3188fae4392SJiri Pirko 	return 0;
3198fae4392SJiri Pirko 
3208fae4392SJiri Pirko err_ipv6_region_init:
3218fae4392SJiri Pirko 	mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
3228fae4392SJiri Pirko 	return err;
3238fae4392SJiri Pirko }
3248fae4392SJiri Pirko 
mlxsw_sp1_mr_tcam_fini(void * priv)3258fae4392SJiri Pirko static void mlxsw_sp1_mr_tcam_fini(void *priv)
3268fae4392SJiri Pirko {
3278fae4392SJiri Pirko 	struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
3288fae4392SJiri Pirko 	struct mlxsw_sp1_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
3298fae4392SJiri Pirko 
3308fae4392SJiri Pirko 	mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV6]);
3318fae4392SJiri Pirko 	mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
3328fae4392SJiri Pirko }
3338fae4392SJiri Pirko 
3348fae4392SJiri Pirko const struct mlxsw_sp_mr_tcam_ops mlxsw_sp1_mr_tcam_ops = {
3358fae4392SJiri Pirko 	.priv_size = sizeof(struct mlxsw_sp1_mr_tcam),
3368fae4392SJiri Pirko 	.init = mlxsw_sp1_mr_tcam_init,
3378fae4392SJiri Pirko 	.fini = mlxsw_sp1_mr_tcam_fini,
3388fae4392SJiri Pirko 	.route_priv_size = sizeof(struct mlxsw_sp1_mr_tcam_route),
3398fae4392SJiri Pirko 	.route_create = mlxsw_sp1_mr_tcam_route_create,
3408fae4392SJiri Pirko 	.route_destroy = mlxsw_sp1_mr_tcam_route_destroy,
3418fae4392SJiri Pirko 	.route_update = mlxsw_sp1_mr_tcam_route_update,
3428fae4392SJiri Pirko };
343