diff options
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/Makefile | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/resources.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c | 120 |
4 files changed, 136 insertions, 1 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile index c57e293cca25..c2d6d64ffe4b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Makefile +++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile @@ -28,7 +28,8 @@ mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \ spectrum_qdisc.o spectrum_span.o \ spectrum_nve.o spectrum_nve_vxlan.o \ spectrum_dpipe.o spectrum_trap.o \ - spectrum_ethtool.o spectrum_policer.o + spectrum_ethtool.o spectrum_policer.o \ + spectrum_pgt.o mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o mlxsw_spectrum-$(CONFIG_PTP_1588_CLOCK) += spectrum_ptp.o obj-$(CONFIG_MLXSW_MINIMAL) += mlxsw_minimal.o diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h index daacf6291253..826e47fb4586 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/resources.h +++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h @@ -11,6 +11,7 @@ enum mlxsw_res_id { MLXSW_RES_ID_KVD_SIZE, MLXSW_RES_ID_KVD_SINGLE_MIN_SIZE, MLXSW_RES_ID_KVD_DOUBLE_MIN_SIZE, + MLXSW_RES_ID_PGT_SIZE, MLXSW_RES_ID_MAX_KVD_LINEAR_RANGE, MLXSW_RES_ID_MAX_KVD_ACTION_SETS, MLXSW_RES_ID_MAX_TRAP_GROUPS, @@ -69,6 +70,7 @@ static u16 mlxsw_res_ids[] = { [MLXSW_RES_ID_KVD_SIZE] = 0x1001, [MLXSW_RES_ID_KVD_SINGLE_MIN_SIZE] = 0x1002, [MLXSW_RES_ID_KVD_DOUBLE_MIN_SIZE] = 0x1003, + [MLXSW_RES_ID_PGT_SIZE] = 0x1004, [MLXSW_RES_ID_MAX_KVD_LINEAR_RANGE] = 0x1005, [MLXSW_RES_ID_MAX_KVD_ACTION_SETS] = 0x1007, [MLXSW_RES_ID_MAX_TRAP_GROUPS] = 0x2201, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 828d5a265157..b42b23d09ab2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -143,6 +143,7 @@ struct mlxsw_sp_ptp_ops; struct mlxsw_sp_span_ops; struct mlxsw_sp_qdisc_state; struct mlxsw_sp_mall_entry; +struct mlxsw_sp_pgt; struct mlxsw_sp_port_mapping { u8 module; @@ -217,6 +218,7 @@ struct mlxsw_sp { struct rhashtable ipv6_addr_ht; struct mutex ipv6_addr_ht_lock; /* Protects ipv6_addr_ht */ bool ubridge; + struct mlxsw_sp_pgt *pgt; }; struct mlxsw_sp_ptp_ops { @@ -1448,4 +1450,14 @@ int mlxsw_sp_policers_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_policers_fini(struct mlxsw_sp *mlxsw_sp); int mlxsw_sp_policer_resources_register(struct mlxsw_core *mlxsw_core); +/* spectrum_pgt.c */ +int mlxsw_sp_pgt_mid_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_mid); +void mlxsw_sp_pgt_mid_free(struct mlxsw_sp *mlxsw_sp, u16 mid_base); +int mlxsw_sp_pgt_mid_alloc_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, + u16 count); +void mlxsw_sp_pgt_mid_free_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, + u16 count); +int mlxsw_sp_pgt_init(struct mlxsw_sp *mlxsw_sp); +void mlxsw_sp_pgt_fini(struct mlxsw_sp *mlxsw_sp); + #endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c new file mode 100644 index 000000000000..27db277bc906 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ + +#include <linux/refcount.h> +#include <linux/idr.h> + +#include "spectrum.h" +#include "reg.h" + +struct mlxsw_sp_pgt { + struct idr pgt_idr; + u16 end_index; /* Exclusive. */ + struct mutex lock; /* Protects PGT. */ +}; + +int mlxsw_sp_pgt_mid_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_mid) +{ + int index, err = 0; + + mutex_lock(&mlxsw_sp->pgt->lock); + index = idr_alloc(&mlxsw_sp->pgt->pgt_idr, NULL, 0, + mlxsw_sp->pgt->end_index, GFP_KERNEL); + + if (index < 0) { + err = index; + goto err_idr_alloc; + } + + *p_mid = index; + mutex_unlock(&mlxsw_sp->pgt->lock); + return 0; + +err_idr_alloc: + mutex_unlock(&mlxsw_sp->pgt->lock); + return err; +} + +void mlxsw_sp_pgt_mid_free(struct mlxsw_sp *mlxsw_sp, u16 mid_base) +{ + mutex_lock(&mlxsw_sp->pgt->lock); + WARN_ON(idr_remove(&mlxsw_sp->pgt->pgt_idr, mid_base)); + mutex_unlock(&mlxsw_sp->pgt->lock); +} + +int +mlxsw_sp_pgt_mid_alloc_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, u16 count) +{ + unsigned int idr_cursor; + int i, err; + + mutex_lock(&mlxsw_sp->pgt->lock); + + /* This function is supposed to be called several times as part of + * driver init, in specific order. Verify that the mid_index is the + * first free index in the idr, to be able to free the indexes in case + * of error. + */ + idr_cursor = idr_get_cursor(&mlxsw_sp->pgt->pgt_idr); + if (WARN_ON(idr_cursor != mid_base)) { + err = -EINVAL; + goto err_idr_cursor; + } + + for (i = 0; i < count; i++) { + err = idr_alloc_cyclic(&mlxsw_sp->pgt->pgt_idr, NULL, + mid_base, mid_base + count, GFP_KERNEL); + if (err < 0) + goto err_idr_alloc_cyclic; + } + + mutex_unlock(&mlxsw_sp->pgt->lock); + return 0; + +err_idr_alloc_cyclic: + for (i--; i >= 0; i--) + idr_remove(&mlxsw_sp->pgt->pgt_idr, mid_base + i); +err_idr_cursor: + mutex_unlock(&mlxsw_sp->pgt->lock); + return err; +} + +void +mlxsw_sp_pgt_mid_free_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, u16 count) +{ + struct idr *pgt_idr = &mlxsw_sp->pgt->pgt_idr; + int i; + + mutex_lock(&mlxsw_sp->pgt->lock); + + for (i = 0; i < count; i++) + WARN_ON_ONCE(idr_remove(pgt_idr, mid_base + i)); + + mutex_unlock(&mlxsw_sp->pgt->lock); +} + +int mlxsw_sp_pgt_init(struct mlxsw_sp *mlxsw_sp) +{ + struct mlxsw_sp_pgt *pgt; + + if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, PGT_SIZE)) + return -EIO; + + pgt = kzalloc(sizeof(*mlxsw_sp->pgt), GFP_KERNEL); + if (!pgt) + return -ENOMEM; + + idr_init(&pgt->pgt_idr); + pgt->end_index = MLXSW_CORE_RES_GET(mlxsw_sp->core, PGT_SIZE); + mutex_init(&pgt->lock); + mlxsw_sp->pgt = pgt; + return 0; +} + +void mlxsw_sp_pgt_fini(struct mlxsw_sp *mlxsw_sp) +{ + mutex_destroy(&mlxsw_sp->pgt->lock); + WARN_ON(!idr_is_empty(&mlxsw_sp->pgt->pgt_idr)); + idr_destroy(&mlxsw_sp->pgt->pgt_idr); + kfree(mlxsw_sp->pgt); +} |