drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c
Extension
.c
Size
9775 bytes
Lines
336
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 mlx5_termtbl_handle {
	struct hlist_node termtbl_hlist;

	struct mlx5_flow_table *termtbl;
	struct mlx5_flow_act flow_act;
	struct mlx5_flow_destination dest;

	struct mlx5_flow_handle *rule;
	int ref_count;
};

static u32
mlx5_eswitch_termtbl_hash(struct mlx5_flow_act *flow_act,
			  struct mlx5_flow_destination *dest)
{
	u32 hash;

	hash = jhash_1word(flow_act->action, 0);
	hash = jhash((const void *)&flow_act->vlan,
		     sizeof(flow_act->vlan), hash);
	hash = jhash((const void *)&dest->vport.num,
		     sizeof(dest->vport.num), hash);
	hash = jhash((const void *)&dest->vport.vhca_id,
		     sizeof(dest->vport.num), hash);
	if (flow_act->pkt_reformat)
		hash = jhash(flow_act->pkt_reformat,
			     sizeof(*flow_act->pkt_reformat),
			     hash);
	return hash;
}

static int
mlx5_eswitch_termtbl_cmp(struct mlx5_flow_act *flow_act1,
			 struct mlx5_flow_destination *dest1,
			 struct mlx5_flow_act *flow_act2,
			 struct mlx5_flow_destination *dest2)
{
	int ret;

	ret = flow_act1->action != flow_act2->action ||
	      dest1->vport.num != dest2->vport.num ||
	      dest1->vport.vhca_id != dest2->vport.vhca_id ||
	      memcmp(&flow_act1->vlan, &flow_act2->vlan,
		     sizeof(flow_act1->vlan));
	if (ret)
		return ret;

	if (flow_act1->pkt_reformat && flow_act2->pkt_reformat)
		return memcmp(flow_act1->pkt_reformat, flow_act2->pkt_reformat,
			      sizeof(*flow_act1->pkt_reformat));

	return !(flow_act1->pkt_reformat == flow_act2->pkt_reformat);
}

static int
mlx5_eswitch_termtbl_create(struct mlx5_core_dev *dev,
			    struct mlx5_termtbl_handle *tt,
			    struct mlx5_flow_act *flow_act)
{
	struct mlx5_flow_table_attr ft_attr = {};
	struct mlx5_flow_namespace *root_ns;
	int err, err2;

	root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
	if (!root_ns) {
		esw_warn(dev, "Failed to get FDB flow namespace\n");
		return -EOPNOTSUPP;
	}

	/* As this is the terminating action then the termination table is the
	 * same prio as the slow path
	 */
	ft_attr.flags = MLX5_FLOW_TABLE_TERMINATION | MLX5_FLOW_TABLE_UNMANAGED |
			MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
	ft_attr.prio = FDB_TC_OFFLOAD;
	ft_attr.max_fte = 1;
	ft_attr.level = 1;
	ft_attr.autogroup.max_num_groups = 1;
	tt->termtbl = mlx5_create_auto_grouped_flow_table(root_ns, &ft_attr);
	if (IS_ERR(tt->termtbl)) {
		err = PTR_ERR(tt->termtbl);
		esw_warn(dev, "Failed to create termination table, err %pe\n", tt->termtbl);
		return err;
	}

	tt->rule = mlx5_add_flow_rules(tt->termtbl, NULL, flow_act,
				       &tt->dest, 1);
	if (IS_ERR(tt->rule)) {
		err = PTR_ERR(tt->rule);
		esw_warn(dev, "Failed to create termination table rule, err %pe\n", tt->rule);

Annotation

Implementation Notes