0001
0002
0003
0004 #include <linux/kernel.h>
0005 #include <linux/bitops.h>
0006
0007 #include "spectrum.h"
0008 #include "core.h"
0009 #include "reg.h"
0010 #include "resources.h"
0011
0012 struct mlxsw_sp2_kvdl_part_info {
0013 u8 res_type;
0014
0015
0016
0017
0018
0019
0020 enum mlxsw_res_id usage_bit_count_res_id;
0021 enum mlxsw_res_id index_range_res_id;
0022 };
0023
0024 #define MLXSW_SP2_KVDL_PART_INFO(_entry_type, _res_type, \
0025 _usage_bit_count_res_id, _index_range_res_id) \
0026 [MLXSW_SP_KVDL_ENTRY_TYPE_##_entry_type] = { \
0027 .res_type = _res_type, \
0028 .usage_bit_count_res_id = MLXSW_RES_ID_##_usage_bit_count_res_id, \
0029 .index_range_res_id = MLXSW_RES_ID_##_index_range_res_id, \
0030 }
0031
0032 static const struct mlxsw_sp2_kvdl_part_info mlxsw_sp2_kvdl_parts_info[] = {
0033 MLXSW_SP2_KVDL_PART_INFO(ADJ, 0x21, KVD_SIZE, MAX_KVD_LINEAR_RANGE),
0034 MLXSW_SP2_KVDL_PART_INFO(ACTSET, 0x23, MAX_KVD_ACTION_SETS,
0035 MAX_KVD_ACTION_SETS),
0036 MLXSW_SP2_KVDL_PART_INFO(PBS, 0x24, KVD_SIZE, KVD_SIZE),
0037 MLXSW_SP2_KVDL_PART_INFO(MCRIGR, 0x26, KVD_SIZE, KVD_SIZE),
0038 MLXSW_SP2_KVDL_PART_INFO(IPV6_ADDRESS, 0x28, KVD_SIZE, KVD_SIZE),
0039 MLXSW_SP2_KVDL_PART_INFO(TNUMT, 0x29, KVD_SIZE, KVD_SIZE),
0040 };
0041
0042 #define MLXSW_SP2_KVDL_PARTS_INFO_LEN ARRAY_SIZE(mlxsw_sp2_kvdl_parts_info)
0043
0044 struct mlxsw_sp2_kvdl_part {
0045 const struct mlxsw_sp2_kvdl_part_info *info;
0046 unsigned int usage_bit_count;
0047 unsigned int indexes_per_usage_bit;
0048 unsigned int last_allocated_bit;
0049 unsigned long usage[];
0050 };
0051
0052 struct mlxsw_sp2_kvdl {
0053 struct mlxsw_sp2_kvdl_part *parts[MLXSW_SP2_KVDL_PARTS_INFO_LEN];
0054 };
0055
0056 static int mlxsw_sp2_kvdl_part_find_zero_bits(struct mlxsw_sp2_kvdl_part *part,
0057 unsigned int bit_count,
0058 unsigned int *p_bit)
0059 {
0060 unsigned int start_bit;
0061 unsigned int bit;
0062 unsigned int i;
0063 bool wrap = false;
0064
0065 start_bit = part->last_allocated_bit + 1;
0066 if (start_bit == part->usage_bit_count)
0067 start_bit = 0;
0068 bit = start_bit;
0069 again:
0070 bit = find_next_zero_bit(part->usage, part->usage_bit_count, bit);
0071 if (!wrap && bit + bit_count >= part->usage_bit_count) {
0072 wrap = true;
0073 bit = 0;
0074 goto again;
0075 }
0076 if (wrap && bit + bit_count >= start_bit)
0077 return -ENOBUFS;
0078 for (i = 0; i < bit_count; i++) {
0079 if (test_bit(bit + i, part->usage)) {
0080 bit += bit_count;
0081 goto again;
0082 }
0083 }
0084 *p_bit = bit;
0085 return 0;
0086 }
0087
0088 static int mlxsw_sp2_kvdl_part_alloc(struct mlxsw_sp2_kvdl_part *part,
0089 unsigned int size,
0090 u32 *p_kvdl_index)
0091 {
0092 unsigned int bit_count;
0093 unsigned int bit;
0094 unsigned int i;
0095 int err;
0096
0097 bit_count = DIV_ROUND_UP(size, part->indexes_per_usage_bit);
0098 err = mlxsw_sp2_kvdl_part_find_zero_bits(part, bit_count, &bit);
0099 if (err)
0100 return err;
0101 for (i = 0; i < bit_count; i++)
0102 __set_bit(bit + i, part->usage);
0103 *p_kvdl_index = bit * part->indexes_per_usage_bit;
0104 return 0;
0105 }
0106
0107 static int mlxsw_sp2_kvdl_rec_del(struct mlxsw_sp *mlxsw_sp, u8 res_type,
0108 u16 size, u32 kvdl_index)
0109 {
0110 char *iedr_pl;
0111 int err;
0112
0113 iedr_pl = kmalloc(MLXSW_REG_IEDR_LEN, GFP_KERNEL);
0114 if (!iedr_pl)
0115 return -ENOMEM;
0116
0117 mlxsw_reg_iedr_pack(iedr_pl);
0118 mlxsw_reg_iedr_rec_pack(iedr_pl, 0, res_type, size, kvdl_index);
0119 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(iedr), iedr_pl);
0120 kfree(iedr_pl);
0121 return err;
0122 }
0123
0124 static void mlxsw_sp2_kvdl_part_free(struct mlxsw_sp *mlxsw_sp,
0125 struct mlxsw_sp2_kvdl_part *part,
0126 unsigned int size, u32 kvdl_index)
0127 {
0128 unsigned int bit_count;
0129 unsigned int bit;
0130 unsigned int i;
0131 int err;
0132
0133
0134 err = mlxsw_sp2_kvdl_rec_del(mlxsw_sp, part->info->res_type,
0135 size, kvdl_index);
0136 if (err)
0137 return;
0138
0139 bit_count = DIV_ROUND_UP(size, part->indexes_per_usage_bit);
0140 bit = kvdl_index / part->indexes_per_usage_bit;
0141 for (i = 0; i < bit_count; i++)
0142 __clear_bit(bit + i, part->usage);
0143 }
0144
0145 static int mlxsw_sp2_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, void *priv,
0146 enum mlxsw_sp_kvdl_entry_type type,
0147 unsigned int entry_count,
0148 u32 *p_entry_index)
0149 {
0150 unsigned int size = entry_count * mlxsw_sp_kvdl_entry_size(type);
0151 struct mlxsw_sp2_kvdl *kvdl = priv;
0152 struct mlxsw_sp2_kvdl_part *part = kvdl->parts[type];
0153
0154 return mlxsw_sp2_kvdl_part_alloc(part, size, p_entry_index);
0155 }
0156
0157 static void mlxsw_sp2_kvdl_free(struct mlxsw_sp *mlxsw_sp, void *priv,
0158 enum mlxsw_sp_kvdl_entry_type type,
0159 unsigned int entry_count,
0160 int entry_index)
0161 {
0162 unsigned int size = entry_count * mlxsw_sp_kvdl_entry_size(type);
0163 struct mlxsw_sp2_kvdl *kvdl = priv;
0164 struct mlxsw_sp2_kvdl_part *part = kvdl->parts[type];
0165
0166 return mlxsw_sp2_kvdl_part_free(mlxsw_sp, part, size, entry_index);
0167 }
0168
0169 static int mlxsw_sp2_kvdl_alloc_size_query(struct mlxsw_sp *mlxsw_sp,
0170 void *priv,
0171 enum mlxsw_sp_kvdl_entry_type type,
0172 unsigned int entry_count,
0173 unsigned int *p_alloc_count)
0174 {
0175 *p_alloc_count = entry_count;
0176 return 0;
0177 }
0178
0179 static struct mlxsw_sp2_kvdl_part *
0180 mlxsw_sp2_kvdl_part_init(struct mlxsw_sp *mlxsw_sp,
0181 const struct mlxsw_sp2_kvdl_part_info *info)
0182 {
0183 unsigned int indexes_per_usage_bit;
0184 struct mlxsw_sp2_kvdl_part *part;
0185 unsigned int index_range;
0186 unsigned int usage_bit_count;
0187 size_t usage_size;
0188
0189 if (!mlxsw_core_res_valid(mlxsw_sp->core,
0190 info->usage_bit_count_res_id) ||
0191 !mlxsw_core_res_valid(mlxsw_sp->core,
0192 info->index_range_res_id))
0193 return ERR_PTR(-EIO);
0194 usage_bit_count = mlxsw_core_res_get(mlxsw_sp->core,
0195 info->usage_bit_count_res_id);
0196 index_range = mlxsw_core_res_get(mlxsw_sp->core,
0197 info->index_range_res_id);
0198
0199
0200
0201
0202
0203 indexes_per_usage_bit = index_range / usage_bit_count;
0204
0205 usage_size = BITS_TO_LONGS(usage_bit_count) * sizeof(unsigned long);
0206 part = kzalloc(sizeof(*part) + usage_size, GFP_KERNEL);
0207 if (!part)
0208 return ERR_PTR(-ENOMEM);
0209 part->info = info;
0210 part->usage_bit_count = usage_bit_count;
0211 part->indexes_per_usage_bit = indexes_per_usage_bit;
0212 part->last_allocated_bit = usage_bit_count - 1;
0213 return part;
0214 }
0215
0216 static void mlxsw_sp2_kvdl_part_fini(struct mlxsw_sp2_kvdl_part *part)
0217 {
0218 kfree(part);
0219 }
0220
0221 static int mlxsw_sp2_kvdl_parts_init(struct mlxsw_sp *mlxsw_sp,
0222 struct mlxsw_sp2_kvdl *kvdl)
0223 {
0224 const struct mlxsw_sp2_kvdl_part_info *info;
0225 int i;
0226 int err;
0227
0228 for (i = 0; i < MLXSW_SP2_KVDL_PARTS_INFO_LEN; i++) {
0229 info = &mlxsw_sp2_kvdl_parts_info[i];
0230 kvdl->parts[i] = mlxsw_sp2_kvdl_part_init(mlxsw_sp, info);
0231 if (IS_ERR(kvdl->parts[i])) {
0232 err = PTR_ERR(kvdl->parts[i]);
0233 goto err_kvdl_part_init;
0234 }
0235 }
0236 return 0;
0237
0238 err_kvdl_part_init:
0239 for (i--; i >= 0; i--)
0240 mlxsw_sp2_kvdl_part_fini(kvdl->parts[i]);
0241 return err;
0242 }
0243
0244 static void mlxsw_sp2_kvdl_parts_fini(struct mlxsw_sp2_kvdl *kvdl)
0245 {
0246 int i;
0247
0248 for (i = 0; i < MLXSW_SP2_KVDL_PARTS_INFO_LEN; i++)
0249 mlxsw_sp2_kvdl_part_fini(kvdl->parts[i]);
0250 }
0251
0252 static int mlxsw_sp2_kvdl_init(struct mlxsw_sp *mlxsw_sp, void *priv)
0253 {
0254 struct mlxsw_sp2_kvdl *kvdl = priv;
0255
0256 return mlxsw_sp2_kvdl_parts_init(mlxsw_sp, kvdl);
0257 }
0258
0259 static void mlxsw_sp2_kvdl_fini(struct mlxsw_sp *mlxsw_sp, void *priv)
0260 {
0261 struct mlxsw_sp2_kvdl *kvdl = priv;
0262
0263 mlxsw_sp2_kvdl_parts_fini(kvdl);
0264 }
0265
0266 const struct mlxsw_sp_kvdl_ops mlxsw_sp2_kvdl_ops = {
0267 .priv_size = sizeof(struct mlxsw_sp2_kvdl),
0268 .init = mlxsw_sp2_kvdl_init,
0269 .fini = mlxsw_sp2_kvdl_fini,
0270 .alloc = mlxsw_sp2_kvdl_alloc,
0271 .free = mlxsw_sp2_kvdl_free,
0272 .alloc_size_query = mlxsw_sp2_kvdl_alloc_size_query,
0273 };