// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
|
/* Copyright (c) 2019 Mellanox Technologies. */
|
|
#include "en/params.h"
|
|
static inline bool mlx5e_rx_is_xdp(struct mlx5e_params *params,
|
struct mlx5e_xsk_param *xsk)
|
{
|
return params->xdp_prog || xsk;
|
}
|
|
u16 mlx5e_get_linear_rq_headroom(struct mlx5e_params *params,
|
struct mlx5e_xsk_param *xsk)
|
{
|
u16 headroom;
|
|
if (xsk)
|
return xsk->headroom;
|
|
headroom = NET_IP_ALIGN;
|
if (mlx5e_rx_is_xdp(params, xsk))
|
headroom += XDP_PACKET_HEADROOM;
|
else
|
headroom += MLX5_RX_HEADROOM;
|
|
return headroom;
|
}
|
|
u32 mlx5e_rx_get_min_frag_sz(struct mlx5e_params *params,
|
struct mlx5e_xsk_param *xsk)
|
{
|
u32 hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
|
u16 linear_rq_headroom = mlx5e_get_linear_rq_headroom(params, xsk);
|
|
return linear_rq_headroom + hw_mtu;
|
}
|
|
u32 mlx5e_rx_get_linear_frag_sz(struct mlx5e_params *params,
|
struct mlx5e_xsk_param *xsk)
|
{
|
u32 frag_sz = mlx5e_rx_get_min_frag_sz(params, xsk);
|
|
/* AF_XDP doesn't build SKBs in place. */
|
if (!xsk)
|
frag_sz = MLX5_SKB_FRAG_SZ(frag_sz);
|
|
/* XDP in mlx5e doesn't support multiple packets per page. AF_XDP is a
|
* special case. It can run with frames smaller than a page, as it
|
* doesn't allocate pages dynamically. However, here we pretend that
|
* fragments are page-sized: it allows to treat XSK frames like pages
|
* by redirecting alloc and free operations to XSK rings and by using
|
* the fact there are no multiple packets per "page" (which is a frame).
|
* The latter is important, because frames may come in a random order,
|
* and we will have trouble assemblying a real page of multiple frames.
|
*/
|
if (mlx5e_rx_is_xdp(params, xsk))
|
frag_sz = max_t(u32, frag_sz, PAGE_SIZE);
|
|
/* Even if we can go with a smaller fragment size, we must not put
|
* multiple packets into a single frame.
|
*/
|
if (xsk)
|
frag_sz = max_t(u32, frag_sz, xsk->chunk_size);
|
|
return frag_sz;
|
}
|
|
u8 mlx5e_mpwqe_log_pkts_per_wqe(struct mlx5e_params *params,
|
struct mlx5e_xsk_param *xsk)
|
{
|
u32 linear_frag_sz = mlx5e_rx_get_linear_frag_sz(params, xsk);
|
|
return MLX5_MPWRQ_LOG_WQE_SZ - order_base_2(linear_frag_sz);
|
}
|
|
bool mlx5e_rx_is_linear_skb(struct mlx5e_params *params,
|
struct mlx5e_xsk_param *xsk)
|
{
|
/* AF_XDP allocates SKBs on XDP_PASS - ensure they don't occupy more
|
* than one page. For this, check both with and without xsk.
|
*/
|
u32 linear_frag_sz = max(mlx5e_rx_get_linear_frag_sz(params, xsk),
|
mlx5e_rx_get_linear_frag_sz(params, NULL));
|
|
return !params->lro_en && linear_frag_sz <= PAGE_SIZE;
|
}
|
|
#define MLX5_MAX_MPWQE_LOG_WQE_STRIDE_SZ ((BIT(__mlx5_bit_sz(wq, log_wqe_stride_size)) - 1) + \
|
MLX5_MPWQE_LOG_STRIDE_SZ_BASE)
|
bool mlx5e_rx_mpwqe_is_linear_skb(struct mlx5_core_dev *mdev,
|
struct mlx5e_params *params,
|
struct mlx5e_xsk_param *xsk)
|
{
|
u32 linear_frag_sz = mlx5e_rx_get_linear_frag_sz(params, xsk);
|
s8 signed_log_num_strides_param;
|
u8 log_num_strides;
|
|
if (!mlx5e_rx_is_linear_skb(params, xsk))
|
return false;
|
|
if (order_base_2(linear_frag_sz) > MLX5_MAX_MPWQE_LOG_WQE_STRIDE_SZ)
|
return false;
|
|
if (MLX5_CAP_GEN(mdev, ext_stride_num_range))
|
return true;
|
|
log_num_strides = MLX5_MPWRQ_LOG_WQE_SZ - order_base_2(linear_frag_sz);
|
signed_log_num_strides_param =
|
(s8)log_num_strides - MLX5_MPWQE_LOG_NUM_STRIDES_BASE;
|
|
return signed_log_num_strides_param >= 0;
|
}
|
|
u8 mlx5e_mpwqe_get_log_rq_size(struct mlx5e_params *params,
|
struct mlx5e_xsk_param *xsk)
|
{
|
u8 log_pkts_per_wqe = mlx5e_mpwqe_log_pkts_per_wqe(params, xsk);
|
|
/* Numbers are unsigned, don't subtract to avoid underflow. */
|
if (params->log_rq_mtu_frames <
|
log_pkts_per_wqe + MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE_MPW)
|
return MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE_MPW;
|
|
return params->log_rq_mtu_frames - log_pkts_per_wqe;
|
}
|
|
u8 mlx5e_mpwqe_get_log_stride_size(struct mlx5_core_dev *mdev,
|
struct mlx5e_params *params,
|
struct mlx5e_xsk_param *xsk)
|
{
|
if (mlx5e_rx_mpwqe_is_linear_skb(mdev, params, xsk))
|
return order_base_2(mlx5e_rx_get_linear_frag_sz(params, xsk));
|
|
return MLX5_MPWRQ_DEF_LOG_STRIDE_SZ(mdev);
|
}
|
|
u8 mlx5e_mpwqe_get_log_num_strides(struct mlx5_core_dev *mdev,
|
struct mlx5e_params *params,
|
struct mlx5e_xsk_param *xsk)
|
{
|
return MLX5_MPWRQ_LOG_WQE_SZ -
|
mlx5e_mpwqe_get_log_stride_size(mdev, params, xsk);
|
}
|
|
u16 mlx5e_get_rq_headroom(struct mlx5_core_dev *mdev,
|
struct mlx5e_params *params,
|
struct mlx5e_xsk_param *xsk)
|
{
|
bool is_linear_skb = (params->rq_wq_type == MLX5_WQ_TYPE_CYCLIC) ?
|
mlx5e_rx_is_linear_skb(params, xsk) :
|
mlx5e_rx_mpwqe_is_linear_skb(mdev, params, xsk);
|
|
return is_linear_skb ? mlx5e_get_linear_rq_headroom(params, xsk) : 0;
|
}
|