Commit 1f41dc5e authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'ena-next'



Arthur Kiyanovski says:

====================
Improving performance and reducing latencies, by using latest capabilities exposed in ENA device

This patchset introduces the following:
1. A new placement policy of Tx headers and descriptors, which takes
advantage of an option to place headers + descriptors in device memory
space. This is sometimes referred to as LLQ - low latency queue.
The patch set defines the admin capability, maps the device memory as
write-combined, and adds a mode in transmit datapath to do header +
descriptor placement on the device.
2. Support for RX checksum offloading
3. Miscelaneous small improvements and code cleanups

Note: V1 of this patchset was created as if patches e2a322a0 248ab773
from net were applied to net-next before applying the patchset. This V2
version does not assume this, and should be applyed directly on net-next
without the aformentioned patches.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7b68b836 be26667c
Loading
Loading
Loading
Loading
+235 −190
Original line number Diff line number Diff line
@@ -32,71 +32,49 @@
#ifndef _ENA_ADMIN_H_
#define _ENA_ADMIN_H_


enum ena_admin_aq_opcode {
	ENA_ADMIN_CREATE_SQ                         = 1,

	ENA_ADMIN_DESTROY_SQ                        = 2,

	ENA_ADMIN_CREATE_CQ                         = 3,

	ENA_ADMIN_DESTROY_CQ                        = 4,

	ENA_ADMIN_GET_FEATURE                       = 8,

	ENA_ADMIN_SET_FEATURE                       = 9,

	ENA_ADMIN_GET_STATS                         = 11,
};

enum ena_admin_aq_completion_status {
	ENA_ADMIN_SUCCESS                           = 0,

	ENA_ADMIN_RESOURCE_ALLOCATION_FAILURE       = 1,

	ENA_ADMIN_BAD_OPCODE                        = 2,

	ENA_ADMIN_UNSUPPORTED_OPCODE                = 3,

	ENA_ADMIN_MALFORMED_REQUEST                 = 4,

	/* Additional status is provided in ACQ entry extended_status */
	ENA_ADMIN_ILLEGAL_PARAMETER                 = 5,

	ENA_ADMIN_UNKNOWN_ERROR                     = 6,
	ENA_ADMIN_RESOURCE_BUSY                     = 7,
};

enum ena_admin_aq_feature_id {
	ENA_ADMIN_DEVICE_ATTRIBUTES                 = 1,

	ENA_ADMIN_MAX_QUEUES_NUM                    = 2,

	ENA_ADMIN_HW_HINTS                          = 3,

	ENA_ADMIN_LLQ                               = 4,
	ENA_ADMIN_RSS_HASH_FUNCTION                 = 10,

	ENA_ADMIN_STATELESS_OFFLOAD_CONFIG          = 11,

	ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG      = 12,

	ENA_ADMIN_MTU                               = 14,

	ENA_ADMIN_RSS_HASH_INPUT                    = 18,

	ENA_ADMIN_INTERRUPT_MODERATION              = 20,

	ENA_ADMIN_AENQ_CONFIG                       = 26,

	ENA_ADMIN_LINK_CONFIG                       = 27,

	ENA_ADMIN_HOST_ATTR_CONFIG                  = 28,

	ENA_ADMIN_FEATURES_OPCODE_NUM               = 32,
};

enum ena_admin_placement_policy_type {
	/* descriptors and headers are in host memory */
	ENA_ADMIN_PLACEMENT_POLICY_HOST             = 1,

	/* descriptors and headers are in device memory (a.k.a Low Latency
	 * Queue)
	 */
@@ -105,38 +83,26 @@ enum ena_admin_placement_policy_type {

enum ena_admin_link_types {
	ENA_ADMIN_LINK_SPEED_1G                     = 0x1,

	ENA_ADMIN_LINK_SPEED_2_HALF_G               = 0x2,

	ENA_ADMIN_LINK_SPEED_5G                     = 0x4,

	ENA_ADMIN_LINK_SPEED_10G                    = 0x8,

	ENA_ADMIN_LINK_SPEED_25G                    = 0x10,

	ENA_ADMIN_LINK_SPEED_40G                    = 0x20,

	ENA_ADMIN_LINK_SPEED_50G                    = 0x40,

	ENA_ADMIN_LINK_SPEED_100G                   = 0x80,

	ENA_ADMIN_LINK_SPEED_200G                   = 0x100,

	ENA_ADMIN_LINK_SPEED_400G                   = 0x200,
};

enum ena_admin_completion_policy_type {
	/* completion queue entry for each sq descriptor */
	ENA_ADMIN_COMPLETION_POLICY_DESC            = 0,

	/* completion queue entry upon request in sq descriptor */
	ENA_ADMIN_COMPLETION_POLICY_DESC_ON_DEMAND  = 1,

	/* current queue head pointer is updated in OS memory upon sq
	 * descriptor request
	 */
	ENA_ADMIN_COMPLETION_POLICY_HEAD_ON_DEMAND  = 2,

	/* current queue head pointer is updated in OS memory for each sq
	 * descriptor
	 */
@@ -149,13 +115,11 @@ enum ena_admin_completion_policy_type {
 */
enum ena_admin_get_stats_type {
	ENA_ADMIN_GET_STATS_TYPE_BASIC              = 0,

	ENA_ADMIN_GET_STATS_TYPE_EXTENDED           = 1,
};

enum ena_admin_get_stats_scope {
	ENA_ADMIN_SPECIFIC_QUEUE                    = 0,

	ENA_ADMIN_ETH_TRAFFIC                       = 1,
};

@@ -227,7 +191,9 @@ struct ena_admin_acq_common_desc {

	u16 extended_status;

	/* serves as a hint what AQ entries can be revoked */
	/* indicates to the driver which AQ entry has been consumed by the
	 *    device and could be reused
	 */
	u16 sq_head_indx;
};

@@ -297,7 +263,6 @@ struct ena_admin_aq_create_sq_cmd {

enum ena_admin_sq_direction {
	ENA_ADMIN_SQ_DIRECTION_TX                   = 1,

	ENA_ADMIN_SQ_DIRECTION_RX                   = 2,
};

@@ -483,8 +448,85 @@ struct ena_admin_device_attr_feature_desc {
	u32 max_mtu;
};

enum ena_admin_llq_header_location {
	/* header is in descriptor list */
	ENA_ADMIN_INLINE_HEADER                     = 1,
	/* header in a separate ring, implies 16B descriptor list entry */
	ENA_ADMIN_HEADER_RING                       = 2,
};

enum ena_admin_llq_ring_entry_size {
	ENA_ADMIN_LIST_ENTRY_SIZE_128B              = 1,
	ENA_ADMIN_LIST_ENTRY_SIZE_192B              = 2,
	ENA_ADMIN_LIST_ENTRY_SIZE_256B              = 4,
};

enum ena_admin_llq_num_descs_before_header {
	ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_0     = 0,
	ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1     = 1,
	ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2     = 2,
	ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4     = 4,
	ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8     = 8,
};

/* packet descriptor list entry always starts with one or more descriptors,
 * followed by a header. The rest of the descriptors are located in the
 * beginning of the subsequent entry. Stride refers to how the rest of the
 * descriptors are placed. This field is relevant only for inline header
 * mode
 */
enum ena_admin_llq_stride_ctrl {
	ENA_ADMIN_SINGLE_DESC_PER_ENTRY             = 1,
	ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY          = 2,
};

struct ena_admin_feature_llq_desc {
	u32 max_llq_num;

	u32 max_llq_depth;

	/*  specify the header locations the device supports. bitfield of
	 *    enum ena_admin_llq_header_location.
	 */
	u16 header_location_ctrl_supported;

	/* the header location the driver selected to use. */
	u16 header_location_ctrl_enabled;

	/* if inline header is specified - this is the size of descriptor
	 *    list entry. If header in a separate ring is specified - this is
	 *    the size of header ring entry. bitfield of enum
	 *    ena_admin_llq_ring_entry_size. specify the entry sizes the device
	 *    supports
	 */
	u16 entry_size_ctrl_supported;

	/* the entry size the driver selected to use. */
	u16 entry_size_ctrl_enabled;

	/* valid only if inline header is specified. First entry associated
	 *    with the packet includes descriptors and header. Rest of the
	 *    entries occupied by descriptors. This parameter defines the max
	 *    number of descriptors precedding the header in the first entry.
	 *    The field is bitfield of enum
	 *    ena_admin_llq_num_descs_before_header and specify the values the
	 *    device supports
	 */
	u16 desc_num_before_header_supported;

	/* the desire field the driver selected to use */
	u16 desc_num_before_header_enabled;

	/* valid only if inline was chosen. bitfield of enum
	 *    ena_admin_llq_stride_ctrl
	 */
	u16 descriptors_stride_ctrl_supported;

	/* the stride control the driver selected to use */
	u16 descriptors_stride_ctrl_enabled;
};

struct ena_admin_queue_feature_desc {
	/* including LLQs */
	u32 max_sq_num;

	u32 max_sq_depth;
@@ -493,9 +535,9 @@ struct ena_admin_queue_feature_desc {

	u32 max_cq_depth;

	u32 max_llq_num;
	u32 max_legacy_llq_num;

	u32 max_llq_depth;
	u32 max_legacy_llq_depth;

	u32 max_header_size;

@@ -584,7 +626,6 @@ struct ena_admin_feature_offload_desc {

enum ena_admin_hash_functions {
	ENA_ADMIN_TOEPLITZ                          = 1,

	ENA_ADMIN_CRC32                             = 2,
};

@@ -612,27 +653,17 @@ struct ena_admin_feature_rss_flow_hash_function {
/* RSS flow hash protocols */
enum ena_admin_flow_hash_proto {
	ENA_ADMIN_RSS_TCP4                          = 0,

	ENA_ADMIN_RSS_UDP4                          = 1,

	ENA_ADMIN_RSS_TCP6                          = 2,

	ENA_ADMIN_RSS_UDP6                          = 3,

	ENA_ADMIN_RSS_IP4                           = 4,

	ENA_ADMIN_RSS_IP6                           = 5,

	ENA_ADMIN_RSS_IP4_FRAG                      = 6,

	ENA_ADMIN_RSS_NOT_IP                        = 7,

	/* TCPv6 with extension header */
	ENA_ADMIN_RSS_TCP6_EX                       = 8,

	/* IPv6 with extension header */
	ENA_ADMIN_RSS_IP6_EX                        = 9,

	ENA_ADMIN_RSS_PROTO_NUM                     = 16,
};

@@ -640,19 +671,14 @@ enum ena_admin_flow_hash_proto {
enum ena_admin_flow_hash_fields {
	/* Ethernet Dest Addr */
	ENA_ADMIN_RSS_L2_DA                         = BIT(0),

	/* Ethernet Src Addr */
	ENA_ADMIN_RSS_L2_SA                         = BIT(1),

	/* ipv4/6 Dest Addr */
	ENA_ADMIN_RSS_L3_DA                         = BIT(2),

	/* ipv4/6 Src Addr */
	ENA_ADMIN_RSS_L3_SA                         = BIT(3),

	/* tcp/udp Dest Port */
	ENA_ADMIN_RSS_L4_DP                         = BIT(4),

	/* tcp/udp Src Port */
	ENA_ADMIN_RSS_L4_SP                         = BIT(5),
};
@@ -694,14 +720,12 @@ struct ena_admin_feature_rss_flow_hash_input {

enum ena_admin_os_type {
	ENA_ADMIN_OS_LINUX                          = 1,

	ENA_ADMIN_OS_WIN                            = 2,

	ENA_ADMIN_OS_DPDK                           = 3,

	ENA_ADMIN_OS_FREEBSD                        = 4,

	ENA_ADMIN_OS_IPXE                           = 5,
	ENA_ADMIN_OS_ESXI			    = 6,
	ENA_ADMIN_OS_GROUPS_NUM			    = 6,
};

struct ena_admin_host_info {
@@ -723,11 +747,27 @@ struct ena_admin_host_info {
	/* 7:0 : major
	 * 15:8 : minor
	 * 23:16 : sub_minor
	 * 31:24 : module_type
	 */
	u32 driver_version;

	/* features bitmap */
	u32 supported_network_features[4];
	u32 supported_network_features[2];

	/* ENA spec version of driver */
	u16 ena_spec_version;

	/* ENA device's Bus, Device and Function
	 * 2:0 : function
	 * 7:3 : device
	 * 15:8 : bus
	 */
	u16 bdf;

	/* Number of CPUs */
	u16 num_cpus;

	u16 reserved;
};

struct ena_admin_rss_ind_table_entry {
@@ -800,6 +840,8 @@ struct ena_admin_get_feat_resp {

		struct ena_admin_device_attr_feature_desc dev_attr;

		struct ena_admin_feature_llq_desc llq;

		struct ena_admin_queue_feature_desc max_queue;

		struct ena_admin_feature_aenq_desc aenq;
@@ -847,6 +889,9 @@ struct ena_admin_set_feat_cmd {

		/* rss indirection table */
		struct ena_admin_feature_rss_ind_table ind_table;

		/* LLQ configuration */
		struct ena_admin_feature_llq_desc llq;
	} u;
};

@@ -876,23 +921,16 @@ struct ena_admin_aenq_common_desc {
/* asynchronous event notification groups */
enum ena_admin_aenq_group {
	ENA_ADMIN_LINK_CHANGE                       = 0,

	ENA_ADMIN_FATAL_ERROR                       = 1,

	ENA_ADMIN_WARNING                           = 2,

	ENA_ADMIN_NOTIFICATION                      = 3,

	ENA_ADMIN_KEEP_ALIVE                        = 4,

	ENA_ADMIN_AENQ_GROUPS_NUM                   = 5,
};

enum ena_admin_aenq_notification_syndrom {
	ENA_ADMIN_SUSPEND                           = 0,

	ENA_ADMIN_RESUME                            = 1,

	ENA_ADMIN_UPDATE_HINTS                      = 2,
};

@@ -1008,6 +1046,13 @@ struct ena_admin_ena_mmio_req_read_less_resp {
#define ENA_ADMIN_HOST_INFO_MINOR_MASK                      GENMASK(15, 8)
#define ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT                 16
#define ENA_ADMIN_HOST_INFO_SUB_MINOR_MASK                  GENMASK(23, 16)
#define ENA_ADMIN_HOST_INFO_MODULE_TYPE_SHIFT               24
#define ENA_ADMIN_HOST_INFO_MODULE_TYPE_MASK                GENMASK(31, 24)
#define ENA_ADMIN_HOST_INFO_FUNCTION_MASK                   GENMASK(2, 0)
#define ENA_ADMIN_HOST_INFO_DEVICE_SHIFT                    3
#define ENA_ADMIN_HOST_INFO_DEVICE_MASK                     GENMASK(7, 3)
#define ENA_ADMIN_HOST_INFO_BUS_SHIFT                       8
#define ENA_ADMIN_HOST_INFO_BUS_MASK                        GENMASK(15, 8)

/* aenq_common_desc */
#define ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK               BIT(0)
+262 −40

File changed.

Preview size limit exceeded, changes collapsed.

+67 −4
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/gfp.h>
#include <linux/io.h>
#include <linux/sched.h>
#include <linux/sizes.h>
#include <linux/spinlock.h>
@@ -108,6 +109,14 @@ enum ena_intr_moder_level {
	ENA_INTR_MAX_NUM_OF_LEVELS,
};

struct ena_llq_configurations {
	enum ena_admin_llq_header_location llq_header_location;
	enum ena_admin_llq_ring_entry_size llq_ring_entry_size;
	enum ena_admin_llq_stride_ctrl  llq_stride_ctrl;
	enum ena_admin_llq_num_descs_before_header llq_num_decs_before_header;
	u16 llq_ring_entry_size_value;
};

struct ena_intr_moder_entry {
	unsigned int intr_moder_interval;
	unsigned int pkts_per_interval;
@@ -142,6 +151,15 @@ struct ena_com_tx_meta {
	u16 l4_hdr_len; /* In words */
};

struct ena_com_llq_info {
	u16 header_location_ctrl;
	u16 desc_stride_ctrl;
	u16 desc_list_entry_size_ctrl;
	u16 desc_list_entry_size;
	u16 descs_num_before_header;
	u16 descs_per_entry;
};

struct ena_com_io_cq {
	struct ena_com_io_desc_addr cdesc_addr;

@@ -179,6 +197,20 @@ struct ena_com_io_cq {

} ____cacheline_aligned;

struct ena_com_io_bounce_buffer_control {
	u8 *base_buffer;
	u16 next_to_use;
	u16 buffer_size;
	u16 buffers_num;  /* Must be a power of 2 */
};

/* This struct is to keep tracking the current location of the next llq entry */
struct ena_com_llq_pkt_ctrl {
	u8 *curr_bounce_buf;
	u16 idx;
	u16 descs_left_in_line;
};

struct ena_com_io_sq {
	struct ena_com_io_desc_addr desc_addr;

@@ -190,6 +222,9 @@ struct ena_com_io_sq {

	u32 msix_vector;
	struct ena_com_tx_meta cached_tx_meta;
	struct ena_com_llq_info llq_info;
	struct ena_com_llq_pkt_ctrl llq_buf_ctrl;
	struct ena_com_io_bounce_buffer_control bounce_buf_ctrl;

	u16 q_depth;
	u16 qid;
@@ -197,6 +232,7 @@ struct ena_com_io_sq {
	u16 idx;
	u16 tail;
	u16 next_to_comp;
	u16 llq_last_copy_tail;
	u32 tx_max_header_size;
	u8 phase;
	u8 desc_entry_size;
@@ -334,6 +370,8 @@ struct ena_com_dev {
	u16 intr_delay_resolution;
	u32 intr_moder_tx_interval;
	struct ena_intr_moder_entry *intr_moder_tbl;

	struct ena_com_llq_info llq_info;
};

struct ena_com_dev_get_features_ctx {
@@ -342,6 +380,7 @@ struct ena_com_dev_get_features_ctx {
	struct ena_admin_feature_aenq_desc aenq;
	struct ena_admin_feature_offload_desc offload;
	struct ena_admin_ena_hw_hints hw_hints;
	struct ena_admin_feature_llq_desc llq;
};

struct ena_com_create_io_ctx {
@@ -397,8 +436,6 @@ void ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev);
/* ena_com_admin_init - Init the admin and the async queues
 * @ena_dev: ENA communication layer struct
 * @aenq_handlers: Those handlers to be called upon event.
 * @init_spinlock: Indicate if this method should init the admin spinlock or
 * the spinlock was init before (for example, in a case of FLR).
 *
 * Initialize the admin submission and completion queues.
 * Initialize the asynchronous events notification queues.
@@ -406,8 +443,7 @@ void ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev);
 * @return - 0 on success, negative value on failure.
 */
int ena_com_admin_init(struct ena_com_dev *ena_dev,
		       struct ena_aenq_handlers *aenq_handlers,
		       bool init_spinlock);
		       struct ena_aenq_handlers *aenq_handlers);

/* ena_com_admin_destroy - Destroy the admin and the async events queues.
 * @ena_dev: ENA communication layer struct
@@ -935,6 +971,16 @@ void ena_com_get_intr_moderation_entry(struct ena_com_dev *ena_dev,
				       enum ena_intr_moder_level level,
				       struct ena_intr_moder_entry *entry);

/* ena_com_config_dev_mode - Configure the placement policy of the device.
 * @ena_dev: ENA communication layer struct
 * @llq_features: LLQ feature descriptor, retrieve via
 *                ena_com_get_dev_attr_feat.
 * @ena_llq_config: The default driver LLQ parameters configurations
 */
int ena_com_config_dev_mode(struct ena_com_dev *ena_dev,
			    struct ena_admin_feature_llq_desc *llq_features,
			    struct ena_llq_configurations *llq_default_config);

static inline bool ena_com_get_adaptive_moderation_enabled(struct ena_com_dev *ena_dev)
{
	return ena_dev->adaptive_coalescing;
@@ -1044,4 +1090,21 @@ static inline void ena_com_update_intr_reg(struct ena_eth_io_intr_reg *intr_reg,
		intr_reg->intr_control |= ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK;
}

static inline u8 *ena_com_get_next_bounce_buffer(struct ena_com_io_bounce_buffer_control *bounce_buf_ctrl)
{
	u16 size, buffers_num;
	u8 *buf;

	size = bounce_buf_ctrl->buffer_size;
	buffers_num = bounce_buf_ctrl->buffers_num;

	buf = bounce_buf_ctrl->base_buffer +
		(bounce_buf_ctrl->next_to_use++ & (buffers_num - 1)) * size;

	prefetchw(bounce_buf_ctrl->base_buffer +
		(bounce_buf_ctrl->next_to_use & (buffers_num - 1)) * size);

	return buf;
}

#endif /* !(ENA_COM) */
+2 −2
Original line number Diff line number Diff line
@@ -32,8 +32,8 @@
#ifndef _ENA_COMMON_H_
#define _ENA_COMMON_H_

#define ENA_COMMON_SPEC_VERSION_MAJOR	0 /*  */
#define ENA_COMMON_SPEC_VERSION_MINOR	10 /*  */
#define ENA_COMMON_SPEC_VERSION_MAJOR        2
#define ENA_COMMON_SPEC_VERSION_MINOR        0

/* ENA operates with 48-bit memory addresses. ena_mem_addr_t */
struct ena_common_mem_addr {
+182 −95
Original line number Diff line number Diff line
@@ -59,16 +59,7 @@ static inline struct ena_eth_io_rx_cdesc_base *ena_com_get_next_rx_cdesc(
	return cdesc;
}

static inline void ena_com_cq_inc_head(struct ena_com_io_cq *io_cq)
{
	io_cq->head++;

	/* Switch phase bit in case of wrap around */
	if (unlikely((io_cq->head & (io_cq->q_depth - 1)) == 0))
		io_cq->phase ^= 1;
}

static inline void *get_sq_desc(struct ena_com_io_sq *io_sq)
static inline void *get_sq_desc_regular_queue(struct ena_com_io_sq *io_sq)
{
	u16 tail_masked;
	u32 offset;
@@ -80,45 +71,159 @@ static inline void *get_sq_desc(struct ena_com_io_sq *io_sq)
	return (void *)((uintptr_t)io_sq->desc_addr.virt_addr + offset);
}

static inline void ena_com_copy_curr_sq_desc_to_dev(struct ena_com_io_sq *io_sq)
static inline int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq,
						     u8 *bounce_buffer)
{
	u16 tail_masked = io_sq->tail & (io_sq->q_depth - 1);
	u32 offset = tail_masked * io_sq->desc_entry_size;
	struct ena_com_llq_info *llq_info = &io_sq->llq_info;

	/* In case this queue isn't a LLQ */
	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)
		return;
	u16 dst_tail_mask;
	u32 dst_offset;

	memcpy_toio(io_sq->desc_addr.pbuf_dev_addr + offset,
		    io_sq->desc_addr.virt_addr + offset,
		    io_sq->desc_entry_size);
}
	dst_tail_mask = io_sq->tail & (io_sq->q_depth - 1);
	dst_offset = dst_tail_mask * llq_info->desc_list_entry_size;

	/* Make sure everything was written into the bounce buffer before
	 * writing the bounce buffer to the device
	 */
	wmb();

	/* The line is completed. Copy it to dev */
	__iowrite64_copy(io_sq->desc_addr.pbuf_dev_addr + dst_offset,
			 bounce_buffer, (llq_info->desc_list_entry_size) / 8);

static inline void ena_com_sq_update_tail(struct ena_com_io_sq *io_sq)
{
	io_sq->tail++;

	/* Switch phase bit in case of wrap around */
	if (unlikely((io_sq->tail & (io_sq->q_depth - 1)) == 0))
		io_sq->phase ^= 1;

	return 0;
}

static inline int ena_com_write_header(struct ena_com_io_sq *io_sq,
				       u8 *head_src, u16 header_len)
static inline int ena_com_write_header_to_bounce(struct ena_com_io_sq *io_sq,
						 u8 *header_src,
						 u16 header_len)
{
	u16 tail_masked = io_sq->tail & (io_sq->q_depth - 1);
	u8 __iomem *dev_head_addr =
		io_sq->header_addr + (tail_masked * io_sq->tx_max_header_size);
	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
	u8 *bounce_buffer = pkt_ctrl->curr_bounce_buf;
	u16 header_offset;

	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)
	if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST))
		return 0;

	if (unlikely(!io_sq->header_addr)) {
		pr_err("Push buffer header ptr is NULL\n");
		return -EINVAL;
	header_offset =
		llq_info->descs_num_before_header * io_sq->desc_entry_size;

	if (unlikely((header_offset + header_len) >
		     llq_info->desc_list_entry_size)) {
		pr_err("trying to write header larger than llq entry can accommodate\n");
		return -EFAULT;
	}

	if (unlikely(!bounce_buffer)) {
		pr_err("bounce buffer is NULL\n");
		return -EFAULT;
	}

	memcpy(bounce_buffer + header_offset, header_src, header_len);

	return 0;
}

static inline void *get_sq_desc_llq(struct ena_com_io_sq *io_sq)
{
	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
	u8 *bounce_buffer;
	void *sq_desc;

	bounce_buffer = pkt_ctrl->curr_bounce_buf;

	if (unlikely(!bounce_buffer)) {
		pr_err("bounce buffer is NULL\n");
		return NULL;
	}

	sq_desc = bounce_buffer + pkt_ctrl->idx * io_sq->desc_entry_size;
	pkt_ctrl->idx++;
	pkt_ctrl->descs_left_in_line--;

	return sq_desc;
}

static inline int ena_com_close_bounce_buffer(struct ena_com_io_sq *io_sq)
{
	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
	int rc;

	if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST))
		return 0;

	/* bounce buffer was used, so write it and get a new one */
	if (pkt_ctrl->idx) {
		rc = ena_com_write_bounce_buffer_to_dev(io_sq,
							pkt_ctrl->curr_bounce_buf);
		if (unlikely(rc))
			return rc;

		pkt_ctrl->curr_bounce_buf =
			ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
		memset(io_sq->llq_buf_ctrl.curr_bounce_buf,
		       0x0, llq_info->desc_list_entry_size);
	}

	pkt_ctrl->idx = 0;
	pkt_ctrl->descs_left_in_line = llq_info->descs_num_before_header;
	return 0;
}

static inline void *get_sq_desc(struct ena_com_io_sq *io_sq)
{
	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
		return get_sq_desc_llq(io_sq);

	return get_sq_desc_regular_queue(io_sq);
}

static inline int ena_com_sq_update_llq_tail(struct ena_com_io_sq *io_sq)
{
	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
	int rc;

	if (!pkt_ctrl->descs_left_in_line) {
		rc = ena_com_write_bounce_buffer_to_dev(io_sq,
							pkt_ctrl->curr_bounce_buf);
		if (unlikely(rc))
			return rc;

		pkt_ctrl->curr_bounce_buf =
			ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
			memset(io_sq->llq_buf_ctrl.curr_bounce_buf,
			       0x0, llq_info->desc_list_entry_size);

		pkt_ctrl->idx = 0;
		if (unlikely(llq_info->desc_stride_ctrl == ENA_ADMIN_SINGLE_DESC_PER_ENTRY))
			pkt_ctrl->descs_left_in_line = 1;
		else
			pkt_ctrl->descs_left_in_line =
			llq_info->desc_list_entry_size / io_sq->desc_entry_size;
	}

	memcpy_toio(dev_head_addr, head_src, header_len);
	return 0;
}

static inline int ena_com_sq_update_tail(struct ena_com_io_sq *io_sq)
{
	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
		return ena_com_sq_update_llq_tail(io_sq);

	io_sq->tail++;

	/* Switch phase bit in case of wrap around */
	if (unlikely((io_sq->tail & (io_sq->q_depth - 1)) == 0))
		io_sq->phase ^= 1;

	return 0;
}
@@ -186,7 +291,7 @@ static inline bool ena_com_meta_desc_changed(struct ena_com_io_sq *io_sq,
	return false;
}

static inline void ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq,
static inline int ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq,
							struct ena_com_tx_ctx *ena_tx_ctx)
{
	struct ena_eth_io_tx_meta_desc *meta_desc = NULL;
@@ -232,8 +337,7 @@ static inline void ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *i
	memcpy(&io_sq->cached_tx_meta, ena_meta,
	       sizeof(struct ena_com_tx_meta));

	ena_com_copy_curr_sq_desc_to_dev(io_sq);
	ena_com_sq_update_tail(io_sq);
	return ena_com_sq_update_tail(io_sq);
}

static inline void ena_com_rx_set_flags(struct ena_com_rx_ctx *ena_rx_ctx,
@@ -250,6 +354,9 @@ static inline void ena_com_rx_set_flags(struct ena_com_rx_ctx *ena_rx_ctx,
	ena_rx_ctx->l4_csum_err =
		(cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK) >>
		ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT;
	ena_rx_ctx->l4_csum_checked =
		!!((cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_MASK) >>
		ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_SHIFT);
	ena_rx_ctx->hash = cdesc->hash;
	ena_rx_ctx->frag =
		(cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK) >>
@@ -271,18 +378,19 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
{
	struct ena_eth_io_tx_desc *desc = NULL;
	struct ena_com_buf *ena_bufs = ena_tx_ctx->ena_bufs;
	void *push_header = ena_tx_ctx->push_header;
	void *buffer_to_push = ena_tx_ctx->push_header;
	u16 header_len = ena_tx_ctx->header_len;
	u16 num_bufs = ena_tx_ctx->num_bufs;
	int total_desc, i, rc;
	u16 start_tail = io_sq->tail;
	int i, rc;
	bool have_meta;
	u64 addr_hi;

	WARN(io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_TX, "wrong Q type");

	/* num_bufs +1 for potential meta desc */
	if (ena_com_sq_empty_space(io_sq) < (num_bufs + 1)) {
		pr_err("Not enough space in the tx queue\n");
	if (unlikely(!ena_com_sq_have_enough_space(io_sq, num_bufs + 1))) {
		pr_debug("Not enough space in the tx queue\n");
		return -ENOMEM;
	}

@@ -292,23 +400,32 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
		return -EINVAL;
	}

	/* start with pushing the header (if needed) */
	rc = ena_com_write_header(io_sq, push_header, header_len);
	if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV &&
		     !buffer_to_push))
		return -EINVAL;

	rc = ena_com_write_header_to_bounce(io_sq, buffer_to_push, header_len);
	if (unlikely(rc))
		return rc;

	have_meta = ena_tx_ctx->meta_valid && ena_com_meta_desc_changed(io_sq,
			ena_tx_ctx);
	if (have_meta)
		ena_com_create_and_store_tx_meta_desc(io_sq, ena_tx_ctx);
	if (have_meta) {
		rc = ena_com_create_and_store_tx_meta_desc(io_sq, ena_tx_ctx);
		if (unlikely(rc))
			return rc;
	}

	/* If the caller doesn't want send packets */
	/* If the caller doesn't want to send packets */
	if (unlikely(!num_bufs && !header_len)) {
		*nb_hw_desc = have_meta ? 0 : 1;
		return 0;
		rc = ena_com_close_bounce_buffer(io_sq);
		*nb_hw_desc = io_sq->tail - start_tail;
		return rc;
	}

	desc = get_sq_desc(io_sq);
	if (unlikely(!desc))
		return -EFAULT;
	memset(desc, 0x0, sizeof(struct ena_eth_io_tx_desc));

	/* Set first desc when we don't have meta descriptor */
@@ -360,10 +477,14 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
	for (i = 0; i < num_bufs; i++) {
		/* The first desc share the same desc as the header */
		if (likely(i != 0)) {
			ena_com_copy_curr_sq_desc_to_dev(io_sq);
			ena_com_sq_update_tail(io_sq);
			rc = ena_com_sq_update_tail(io_sq);
			if (unlikely(rc))
				return rc;

			desc = get_sq_desc(io_sq);
			if (unlikely(!desc))
				return -EFAULT;

			memset(desc, 0x0, sizeof(struct ena_eth_io_tx_desc));

			desc->len_ctrl |= (io_sq->phase <<
@@ -386,15 +507,14 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
	/* set the last desc indicator */
	desc->len_ctrl |= ENA_ETH_IO_TX_DESC_LAST_MASK;

	ena_com_copy_curr_sq_desc_to_dev(io_sq);

	ena_com_sq_update_tail(io_sq);
	rc = ena_com_sq_update_tail(io_sq);
	if (unlikely(rc))
		return rc;

	total_desc = max_t(u16, num_bufs, 1);
	total_desc += have_meta ? 1 : 0;
	rc = ena_com_close_bounce_buffer(io_sq);

	*nb_hw_desc = total_desc;
	return 0;
	*nb_hw_desc = io_sq->tail - start_tail;
	return rc;
}

int ena_com_rx_pkt(struct ena_com_io_cq *io_cq,
@@ -453,15 +573,18 @@ int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq,

	WARN(io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX, "wrong Q type");

	if (unlikely(ena_com_sq_empty_space(io_sq) == 0))
	if (unlikely(!ena_com_sq_have_enough_space(io_sq, 1)))
		return -ENOSPC;

	desc = get_sq_desc(io_sq);
	if (unlikely(!desc))
		return -EFAULT;

	memset(desc, 0x0, sizeof(struct ena_eth_io_rx_desc));

	desc->length = ena_buf->len;

	desc->ctrl |= ENA_ETH_IO_RX_DESC_FIRST_MASK;
	desc->ctrl = ENA_ETH_IO_RX_DESC_FIRST_MASK;
	desc->ctrl |= ENA_ETH_IO_RX_DESC_LAST_MASK;
	desc->ctrl |= io_sq->phase & ENA_ETH_IO_RX_DESC_PHASE_MASK;
	desc->ctrl |= ENA_ETH_IO_RX_DESC_COMP_REQ_MASK;
@@ -472,43 +595,7 @@ int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq,
	desc->buff_addr_hi =
		((ena_buf->paddr & GENMASK_ULL(io_sq->dma_addr_bits - 1, 32)) >> 32);

	ena_com_sq_update_tail(io_sq);

	return 0;
}

int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq, u16 *req_id)
{
	u8 expected_phase, cdesc_phase;
	struct ena_eth_io_tx_cdesc *cdesc;
	u16 masked_head;

	masked_head = io_cq->head & (io_cq->q_depth - 1);
	expected_phase = io_cq->phase;

	cdesc = (struct ena_eth_io_tx_cdesc *)
		((uintptr_t)io_cq->cdesc_addr.virt_addr +
		(masked_head * io_cq->cdesc_entry_size_in_bytes));

	/* When the current completion descriptor phase isn't the same as the
	 * expected, it mean that the device still didn't update
	 * this completion.
	 */
	cdesc_phase = READ_ONCE(cdesc->flags) & ENA_ETH_IO_TX_CDESC_PHASE_MASK;
	if (cdesc_phase != expected_phase)
		return -EAGAIN;

	dma_rmb();
	if (unlikely(cdesc->req_id >= io_cq->q_depth)) {
		pr_err("Invalid req id %d\n", cdesc->req_id);
		return -EINVAL;
	}

	ena_com_cq_inc_head(io_cq);

	*req_id = READ_ONCE(cdesc->req_id);

	return 0;
	return ena_com_sq_update_tail(io_sq);
}

bool ena_com_cq_empty(struct ena_com_io_cq *io_cq)
Loading