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

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

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
Extension
.c
Size
155046 bytes
Lines
5634
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 (IS_ERR(dest[*i].ft)) {
			err = PTR_ERR(dest[*i].ft);
			goto err_indir_tbl_get;
		}
	}

	if (mlx5_esw_indir_table_decap_vport(attr)) {
		err = esw_setup_decap_indir(esw, attr);
		if (err)
			goto err_indir_tbl_get;
	}

	return 0;

err_indir_tbl_get:
	esw_put_dest_tables_loop(esw, attr, esw_attr->split_count, j);
	return err;
}

static void esw_cleanup_indir_table(struct mlx5_eswitch *esw, struct mlx5_flow_attr *attr)
{
	struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;

	esw_put_dest_tables_loop(esw, attr, esw_attr->split_count, esw_attr->out_count);
	esw_cleanup_decap_indir(esw, attr);
}

static void
esw_cleanup_chain_dest(struct mlx5_fs_chains *chains, u32 chain, u32 prio, u32 level)
{
	mlx5_chains_put_table(chains, chain, prio, level);
}

static bool esw_same_vhca_id(struct mlx5_core_dev *mdev1, struct mlx5_core_dev *mdev2)
{
	return MLX5_CAP_GEN(mdev1, vhca_id) == MLX5_CAP_GEN(mdev2, vhca_id);
}

static bool esw_setup_uplink_fwd_ipsec_needed(struct mlx5_eswitch *esw,
					      struct mlx5_esw_flow_attr *esw_attr,
					      int attr_idx)
{
	if (esw->offloads.ft_ipsec_tx_pol &&
	    esw_attr->dests[attr_idx].vport_valid &&
	    esw_attr->dests[attr_idx].vport == MLX5_VPORT_UPLINK &&
	    /* To be aligned with software, encryption is needed only for tunnel device */
	    (esw_attr->dests[attr_idx].flags & MLX5_ESW_DEST_ENCAP_VALID) &&
	    esw_attr->dests[attr_idx].vport != esw_attr->in_rep->vport &&
	    esw_same_vhca_id(esw_attr->dests[attr_idx].mdev, esw->dev))
		return true;

	return false;
}

static bool esw_flow_dests_fwd_ipsec_check(struct mlx5_eswitch *esw,
					   struct mlx5_esw_flow_attr *esw_attr)
{
	int i;

	if (!esw->offloads.ft_ipsec_tx_pol)
		return true;

	for (i = 0; i < esw_attr->split_count; i++)
		if (esw_setup_uplink_fwd_ipsec_needed(esw, esw_attr, i))
			return false;

	for (i = esw_attr->split_count; i < esw_attr->out_count; i++)
		if (esw_setup_uplink_fwd_ipsec_needed(esw, esw_attr, i) &&
		    (esw_attr->out_count - esw_attr->split_count > 1))
			return false;

	return true;
}

static void
esw_setup_dest_fwd_vport(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
			 struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
			 int attr_idx, int dest_idx, bool pkt_reformat)
{
	dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
	dest[dest_idx].vport.num = esw_attr->dests[attr_idx].vport;
	if (MLX5_CAP_ESW(esw->dev, merged_eswitch)) {
		dest[dest_idx].vport.vhca_id =
			MLX5_CAP_GEN(esw_attr->dests[attr_idx].mdev, vhca_id);
		dest[dest_idx].vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
		if (dest[dest_idx].vport.num == MLX5_VPORT_UPLINK &&
		    mlx5_lag_is_mpesw(esw->dev))
			dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_UPLINK;
	}
	if (esw_attr->dests[attr_idx].flags & MLX5_ESW_DEST_ENCAP_VALID) {

Annotation

Implementation Notes