drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c
Extension
.c
Size
7783 bytes
Lines
274
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct mlxsw_sp2_kvdl_part_info {
	u8 res_type;
	/* For each defined partititon we need to know how many
	 * usage bits we need and how many indexes there are
	 * represented by a single bit. This could be got from FW
	 * querying appropriate resources. So have the resource
	 * ids for this purpose in partition definition.
	 */
	enum mlxsw_res_id usage_bit_count_res_id;
	enum mlxsw_res_id index_range_res_id;
};

#define MLXSW_SP2_KVDL_PART_INFO(_entry_type, _res_type,			\
				 _usage_bit_count_res_id, _index_range_res_id)	\
[MLXSW_SP_KVDL_ENTRY_TYPE_##_entry_type] = {					\
	.res_type = _res_type,							\
	.usage_bit_count_res_id = MLXSW_RES_ID_##_usage_bit_count_res_id,	\
	.index_range_res_id = MLXSW_RES_ID_##_index_range_res_id,		\
}

static const struct mlxsw_sp2_kvdl_part_info mlxsw_sp2_kvdl_parts_info[] = {
	MLXSW_SP2_KVDL_PART_INFO(ADJ, 0x21, KVD_SIZE, MAX_KVD_LINEAR_RANGE),
	MLXSW_SP2_KVDL_PART_INFO(ACTSET, 0x23, MAX_KVD_ACTION_SETS,
				 MAX_KVD_ACTION_SETS),
	MLXSW_SP2_KVDL_PART_INFO(PBS, 0x24, KVD_SIZE, KVD_SIZE),
	MLXSW_SP2_KVDL_PART_INFO(MCRIGR, 0x26, KVD_SIZE, KVD_SIZE),
	MLXSW_SP2_KVDL_PART_INFO(IPV6_ADDRESS, 0x28, KVD_SIZE, KVD_SIZE),
	MLXSW_SP2_KVDL_PART_INFO(TNUMT, 0x29, KVD_SIZE, KVD_SIZE),
};

#define MLXSW_SP2_KVDL_PARTS_INFO_LEN ARRAY_SIZE(mlxsw_sp2_kvdl_parts_info)

struct mlxsw_sp2_kvdl_part {
	const struct mlxsw_sp2_kvdl_part_info *info;
	unsigned int usage_bit_count;
	unsigned int indexes_per_usage_bit;
	unsigned int last_allocated_bit;
	unsigned long usage[];	/* Usage bits */
};

struct mlxsw_sp2_kvdl {
	struct mlxsw_sp2_kvdl_part *parts[MLXSW_SP2_KVDL_PARTS_INFO_LEN];
};

static int mlxsw_sp2_kvdl_part_find_zero_bits(struct mlxsw_sp2_kvdl_part *part,
					      unsigned int bit_count,
					      unsigned int *p_bit)
{
	unsigned int start_bit;
	unsigned int bit;
	unsigned int i;
	bool wrap = false;

	start_bit = part->last_allocated_bit + 1;
	if (start_bit == part->usage_bit_count)
		start_bit = 0;
	bit = start_bit;
again:
	bit = find_next_zero_bit(part->usage, part->usage_bit_count, bit);
	if (!wrap && bit + bit_count >= part->usage_bit_count) {
		wrap = true;
		bit = 0;
		goto again;
	}
	if (wrap && bit + bit_count >= start_bit)
		return -ENOBUFS;
	for (i = 0; i < bit_count; i++) {
		if (test_bit(bit + i, part->usage)) {
			bit += bit_count;
			goto again;
		}
	}
	*p_bit = bit;
	return 0;
}

static int mlxsw_sp2_kvdl_part_alloc(struct mlxsw_sp2_kvdl_part *part,
				     unsigned int size,
				     u32 *p_kvdl_index)
{
	unsigned int bit_count;
	unsigned int bit;
	unsigned int i;
	int err;

	bit_count = DIV_ROUND_UP(size, part->indexes_per_usage_bit);
	err = mlxsw_sp2_kvdl_part_find_zero_bits(part, bit_count, &bit);
	if (err)
		return err;
	for (i = 0; i < bit_count; i++)

Annotation

Implementation Notes