+#define MLX5_MAX_TCP_HDR_OFFSET ((unsigned int)(sizeof(struct rte_ether_hdr) + \
+ sizeof(struct rte_vlan_hdr) * 2 + \
+ sizeof(struct rte_ipv6_hdr)))
+#define MAX_TCP_OPTION_SIZE 40u
+#define MLX5_MAX_LRO_HEADER_FIX ((unsigned int)(MLX5_MAX_TCP_HDR_OFFSET + \
+ sizeof(struct rte_tcp_hdr) + \
+ MAX_TCP_OPTION_SIZE))
+
+/**
+ * Adjust the maximum LRO massage size.
+ *
+ * @param dev
+ * Pointer to Ethernet device.
+ * @param idx
+ * RX queue index.
+ * @param max_lro_size
+ * The maximum size for LRO packet.
+ */
+static void
+mlx5_max_lro_msg_size_adjust(struct rte_eth_dev *dev, uint16_t idx,
+ uint32_t max_lro_size)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+
+ if (priv->sh->cdev->config.hca_attr.lro_max_msg_sz_mode ==
+ MLX5_LRO_MAX_MSG_SIZE_START_FROM_L4 && max_lro_size >
+ MLX5_MAX_TCP_HDR_OFFSET)
+ max_lro_size -= MLX5_MAX_TCP_HDR_OFFSET;
+ max_lro_size = RTE_MIN(max_lro_size, MLX5_MAX_LRO_SIZE);
+ MLX5_ASSERT(max_lro_size >= MLX5_LRO_SEG_CHUNK_SIZE);
+ max_lro_size /= MLX5_LRO_SEG_CHUNK_SIZE;
+ if (priv->max_lro_msg_size)
+ priv->max_lro_msg_size =
+ RTE_MIN((uint32_t)priv->max_lro_msg_size, max_lro_size);
+ else
+ priv->max_lro_msg_size = max_lro_size;
+ DRV_LOG(DEBUG,
+ "port %u Rx Queue %u max LRO message size adjusted to %u bytes",
+ dev->data->port_id, idx,
+ priv->max_lro_msg_size * MLX5_LRO_SEG_CHUNK_SIZE);
+}
+
+/**
+ * Prepare both size and number of stride for Multi-Packet RQ.
+ *
+ * @param dev
+ * Pointer to Ethernet device.
+ * @param idx
+ * RX queue index.
+ * @param desc
+ * Number of descriptors to configure in queue.
+ * @param rx_seg_en
+ * Indicator if Rx segment enables, if so Multi-Packet RQ doesn't enable.
+ * @param min_mbuf_size
+ * Non scatter min mbuf size, max_rx_pktlen plus overhead.
+ * @param actual_log_stride_num
+ * Log number of strides to configure for this queue.
+ * @param actual_log_stride_size
+ * Log stride size to configure for this queue.
+ *
+ * @return
+ * 0 if Multi-Packet RQ is supported, otherwise -1.
+ */
+static int
+mlx5_mprq_prepare(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
+ bool rx_seg_en, uint32_t min_mbuf_size,
+ uint32_t *actual_log_stride_num,
+ uint32_t *actual_log_stride_size)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_port_config *config = &priv->config;
+ struct mlx5_dev_cap *dev_cap = &priv->sh->dev_cap;
+ uint32_t log_min_stride_num = dev_cap->mprq.log_min_stride_num;
+ uint32_t log_max_stride_num = dev_cap->mprq.log_max_stride_num;
+ uint32_t log_def_stride_num =
+ RTE_MIN(RTE_MAX(MLX5_MPRQ_DEFAULT_LOG_STRIDE_NUM,
+ log_min_stride_num),
+ log_max_stride_num);
+ uint32_t log_min_stride_size = dev_cap->mprq.log_min_stride_size;
+ uint32_t log_max_stride_size = dev_cap->mprq.log_max_stride_size;
+ uint32_t log_def_stride_size =
+ RTE_MIN(RTE_MAX(MLX5_MPRQ_DEFAULT_LOG_STRIDE_SIZE,
+ log_min_stride_size),
+ log_max_stride_size);
+ uint32_t log_stride_wqe_size;
+
+ if (mlx5_check_mprq_support(dev) != 1 || rx_seg_en)
+ goto unsupport;
+ /* Checks if chosen number of strides is in supported range. */
+ if (config->mprq.log_stride_num > log_max_stride_num ||
+ config->mprq.log_stride_num < log_min_stride_num) {
+ *actual_log_stride_num = log_def_stride_num;
+ DRV_LOG(WARNING,
+ "Port %u Rx queue %u number of strides for Multi-Packet RQ is out of range, setting default value (%u)",
+ dev->data->port_id, idx, RTE_BIT32(log_def_stride_num));
+ } else {
+ *actual_log_stride_num = config->mprq.log_stride_num;
+ }
+ if (config->mprq.log_stride_size) {
+ /* Checks if chosen size of stride is in supported range. */
+ if (config->mprq.log_stride_size > log_max_stride_size ||
+ config->mprq.log_stride_size < log_min_stride_size) {
+ *actual_log_stride_size = log_def_stride_size;
+ DRV_LOG(WARNING,
+ "Port %u Rx queue %u size of a stride for Multi-Packet RQ is out of range, setting default value (%u)",
+ dev->data->port_id, idx,
+ RTE_BIT32(log_def_stride_size));
+ } else {
+ *actual_log_stride_size = config->mprq.log_stride_size;
+ }
+ } else {
+ if (min_mbuf_size <= RTE_BIT32(log_max_stride_size))
+ *actual_log_stride_size = log2above(min_mbuf_size);
+ else
+ goto unsupport;
+ }
+ log_stride_wqe_size = *actual_log_stride_num + *actual_log_stride_size;
+ /* Check if WQE buffer size is supported by hardware. */
+ if (log_stride_wqe_size < dev_cap->mprq.log_min_stride_wqe_size) {
+ *actual_log_stride_num = log_def_stride_num;
+ *actual_log_stride_size = log_def_stride_size;
+ DRV_LOG(WARNING,
+ "Port %u Rx queue %u size of WQE buffer for Multi-Packet RQ is too small, setting default values (stride_num_n=%u, stride_size_n=%u)",
+ dev->data->port_id, idx, RTE_BIT32(log_def_stride_num),
+ RTE_BIT32(log_def_stride_size));
+ log_stride_wqe_size = log_def_stride_num + log_def_stride_size;
+ }
+ MLX5_ASSERT(log_stride_wqe_size >=
+ dev_cap->mprq.log_min_stride_wqe_size);
+ if (desc <= RTE_BIT32(*actual_log_stride_num))
+ goto unsupport;
+ if (min_mbuf_size > RTE_BIT32(log_stride_wqe_size)) {
+ DRV_LOG(WARNING, "Port %u Rx queue %u "
+ "Multi-Packet RQ is unsupported, WQE buffer size (%u) "
+ "is smaller than min mbuf size (%u)",
+ dev->data->port_id, idx, RTE_BIT32(log_stride_wqe_size),
+ min_mbuf_size);
+ goto unsupport;
+ }
+ DRV_LOG(DEBUG, "Port %u Rx queue %u "
+ "Multi-Packet RQ is enabled strd_num_n = %u, strd_sz_n = %u",
+ dev->data->port_id, idx, RTE_BIT32(*actual_log_stride_num),
+ RTE_BIT32(*actual_log_stride_size));
+ return 0;
+unsupport:
+ if (config->mprq.enabled)
+ DRV_LOG(WARNING,
+ "Port %u MPRQ is requested but cannot be enabled\n"
+ " (requested: pkt_sz = %u, desc_num = %u,"
+ " rxq_num = %u, stride_sz = %u, stride_num = %u\n"
+ " supported: min_rxqs_num = %u, min_buf_wqe_sz = %u"
+ " min_stride_sz = %u, max_stride_sz = %u).\n"
+ "Rx segment is %senable.",
+ dev->data->port_id, min_mbuf_size, desc, priv->rxqs_n,
+ RTE_BIT32(config->mprq.log_stride_size),
+ RTE_BIT32(config->mprq.log_stride_num),
+ config->mprq.min_rxqs_num,
+ RTE_BIT32(dev_cap->mprq.log_min_stride_wqe_size),
+ RTE_BIT32(dev_cap->mprq.log_min_stride_size),
+ RTE_BIT32(dev_cap->mprq.log_max_stride_size),
+ rx_seg_en ? "" : "not ");
+ return -1;
+}
+