drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c
Extension
.c
Size
31272 bytes
Lines
1102
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

if (ret == -E2BIG) {
			is_complex = true;
			mlx5hws_dbg(ctx, "Matcher definer layout: need complex matcher\n");
		} else {
			mlx5hws_err(ctx, "Failed to calculate matcher definer layout\n");
		}
	} else {
		kfree(mt->fc);
	}

	mlx5hws_match_template_destroy(mt);

	return is_complex;
}

bool mlx5hws_bwc_match_params_is_complex(struct mlx5hws_context *ctx,
					 u8 match_criteria_enable,
					 struct mlx5hws_match_parameters *mask)
{
	return hws_match_params_exceeds_definer(ctx, match_criteria_enable,
						mask, true);
}

static int
hws_get_last_set_dword_idx(const struct mlx5hws_match_parameters *mask)
{
	int i;

	for (i = mask->match_sz / 4 - 1; i >= 0; i--)
		if (mask->match_buf[i])
			return i;

	return -1;
}

static bool hws_match_mask_is_empty(const struct mlx5hws_match_parameters *mask)
{
	return hws_get_last_set_dword_idx(mask) == -1;
}

static bool hws_dword_is_inner_ipaddr_off(int dword_off)
{
	/* IPv4 and IPv6 addresses share the same entry via a union, and the
	 * source and dest addresses are contiguous in the fte_match_param. So
	 * we need to check 8 words.
	 */
	static const int inner_ip_dword_off =
		__mlx5_dw_off(fte_match_param, inner_headers.src_ipv4_src_ipv6);

	return dword_off >= inner_ip_dword_off &&
	       dword_off < inner_ip_dword_off + 8;
}

static bool hws_dword_is_outer_ipaddr_off(int dword_off)
{
	static const int outer_ip_dword_off =
		__mlx5_dw_off(fte_match_param, outer_headers.src_ipv4_src_ipv6);

	return dword_off >= outer_ip_dword_off &&
	       dword_off < outer_ip_dword_off + 8;
}

static void hws_add_dword_to_mask(struct mlx5hws_match_parameters *mask,
				  const struct mlx5hws_match_parameters *orig,
				  int dword_idx, bool *added_inner_ipv,
				  bool *added_outer_ipv)
{
	mask->match_buf[dword_idx] |= orig->match_buf[dword_idx];

	*added_inner_ipv = false;
	*added_outer_ipv = false;

	/* Any IP address fragment must be accompanied by a match on IP version.
	 * Use the `added_ipv` variables to keep track if we added IP versions
	 * specifically for this dword, so that we can roll them back if the
	 * match params become too large to fit into a definer.
	 */
	if (hws_dword_is_inner_ipaddr_off(dword_idx) &&
	    !MLX5_GET(fte_match_param, mask->match_buf,
		      inner_headers.ip_version)) {
		MLX5_SET(fte_match_param, mask->match_buf,
			 inner_headers.ip_version, 0xf);
		*added_inner_ipv = true;
	}
	if (hws_dword_is_outer_ipaddr_off(dword_idx) &&
	    !MLX5_GET(fte_match_param, mask->match_buf,
		      outer_headers.ip_version)) {
		MLX5_SET(fte_match_param, mask->match_buf,
			 outer_headers.ip_version, 0xf);
		*added_outer_ipv = true;

Annotation

Implementation Notes