xref: /openbmc/linux/drivers/net/ethernet/amazon/ena/ena_eth_com.c (revision b181f7029bd71238ac2754ce7052dffd69432085)
12246cbc2SShay Agroskin // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
21738cd3eSNetanel Belgazal /*
32246cbc2SShay Agroskin  * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
41738cd3eSNetanel Belgazal  */
51738cd3eSNetanel Belgazal 
61738cd3eSNetanel Belgazal #include "ena_eth_com.h"
71738cd3eSNetanel Belgazal 
ena_com_get_next_rx_cdesc(struct ena_com_io_cq * io_cq)8c2b54204SSameeh Jubran static struct ena_eth_io_rx_cdesc_base *ena_com_get_next_rx_cdesc(
91738cd3eSNetanel Belgazal 	struct ena_com_io_cq *io_cq)
101738cd3eSNetanel Belgazal {
111738cd3eSNetanel Belgazal 	struct ena_eth_io_rx_cdesc_base *cdesc;
121738cd3eSNetanel Belgazal 	u16 expected_phase, head_masked;
131738cd3eSNetanel Belgazal 	u16 desc_phase;
141738cd3eSNetanel Belgazal 
151738cd3eSNetanel Belgazal 	head_masked = io_cq->head & (io_cq->q_depth - 1);
161738cd3eSNetanel Belgazal 	expected_phase = io_cq->phase;
171738cd3eSNetanel Belgazal 
181738cd3eSNetanel Belgazal 	cdesc = (struct ena_eth_io_rx_cdesc_base *)(io_cq->cdesc_addr.virt_addr
191738cd3eSNetanel Belgazal 			+ (head_masked * io_cq->cdesc_entry_size_in_bytes));
201738cd3eSNetanel Belgazal 
21*26668c2dSDavid Arinzon 	desc_phase = (READ_ONCE(cdesc->status) & ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK) >>
221738cd3eSNetanel Belgazal 		     ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT;
231738cd3eSNetanel Belgazal 
241738cd3eSNetanel Belgazal 	if (desc_phase != expected_phase)
251738cd3eSNetanel Belgazal 		return NULL;
261738cd3eSNetanel Belgazal 
2737dff155SNetanel Belgazal 	/* Make sure we read the rest of the descriptor after the phase bit
2837dff155SNetanel Belgazal 	 * has been read
2937dff155SNetanel Belgazal 	 */
3037dff155SNetanel Belgazal 	dma_rmb();
3137dff155SNetanel Belgazal 
321738cd3eSNetanel Belgazal 	return cdesc;
331738cd3eSNetanel Belgazal }
341738cd3eSNetanel Belgazal 
get_sq_desc_regular_queue(struct ena_com_io_sq * io_sq)35c2b54204SSameeh Jubran static void *get_sq_desc_regular_queue(struct ena_com_io_sq *io_sq)
361738cd3eSNetanel Belgazal {
371738cd3eSNetanel Belgazal 	u16 tail_masked;
381738cd3eSNetanel Belgazal 	u32 offset;
391738cd3eSNetanel Belgazal 
401738cd3eSNetanel Belgazal 	tail_masked = io_sq->tail & (io_sq->q_depth - 1);
411738cd3eSNetanel Belgazal 
421738cd3eSNetanel Belgazal 	offset = tail_masked * io_sq->desc_entry_size;
431738cd3eSNetanel Belgazal 
441738cd3eSNetanel Belgazal 	return (void *)((uintptr_t)io_sq->desc_addr.virt_addr + offset);
451738cd3eSNetanel Belgazal }
461738cd3eSNetanel Belgazal 
ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq * io_sq,u8 * bounce_buffer)47c2b54204SSameeh Jubran static int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq,
48689b2bdaSArthur Kiyanovski 						     u8 *bounce_buffer)
491738cd3eSNetanel Belgazal {
50689b2bdaSArthur Kiyanovski 	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
511738cd3eSNetanel Belgazal 
52689b2bdaSArthur Kiyanovski 	u16 dst_tail_mask;
53689b2bdaSArthur Kiyanovski 	u32 dst_offset;
541738cd3eSNetanel Belgazal 
55689b2bdaSArthur Kiyanovski 	dst_tail_mask = io_sq->tail & (io_sq->q_depth - 1);
56689b2bdaSArthur Kiyanovski 	dst_offset = dst_tail_mask * llq_info->desc_list_entry_size;
571738cd3eSNetanel Belgazal 
5805d62ca2SSameeh Jubran 	if (is_llq_max_tx_burst_exists(io_sq)) {
5905d62ca2SSameeh Jubran 		if (unlikely(!io_sq->entries_in_tx_burst_left)) {
60da580ca8SShay Agroskin 			netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
61da580ca8SShay Agroskin 				   "Error: trying to send more packets than tx burst allows\n");
6205d62ca2SSameeh Jubran 			return -ENOSPC;
6305d62ca2SSameeh Jubran 		}
6405d62ca2SSameeh Jubran 
6505d62ca2SSameeh Jubran 		io_sq->entries_in_tx_burst_left--;
66da580ca8SShay Agroskin 		netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
67*26668c2dSDavid Arinzon 			   "Decreasing entries_in_tx_burst_left of queue %d to %d\n", io_sq->qid,
68*26668c2dSDavid Arinzon 			   io_sq->entries_in_tx_burst_left);
6905d62ca2SSameeh Jubran 	}
7005d62ca2SSameeh Jubran 
71689b2bdaSArthur Kiyanovski 	/* Make sure everything was written into the bounce buffer before
72689b2bdaSArthur Kiyanovski 	 * writing the bounce buffer to the device
73689b2bdaSArthur Kiyanovski 	 */
74689b2bdaSArthur Kiyanovski 	wmb();
75689b2bdaSArthur Kiyanovski 
76689b2bdaSArthur Kiyanovski 	/* The line is completed. Copy it to dev */
77*26668c2dSDavid Arinzon 	__iowrite64_copy(io_sq->desc_addr.pbuf_dev_addr + dst_offset, bounce_buffer,
78*26668c2dSDavid Arinzon 			 (llq_info->desc_list_entry_size) / 8);
79689b2bdaSArthur Kiyanovski 
801738cd3eSNetanel Belgazal 	io_sq->tail++;
811738cd3eSNetanel Belgazal 
821738cd3eSNetanel Belgazal 	/* Switch phase bit in case of wrap around */
831738cd3eSNetanel Belgazal 	if (unlikely((io_sq->tail & (io_sq->q_depth - 1)) == 0))
841738cd3eSNetanel Belgazal 		io_sq->phase ^= 1;
85689b2bdaSArthur Kiyanovski 
86689b2bdaSArthur Kiyanovski 	return 0;
871738cd3eSNetanel Belgazal }
881738cd3eSNetanel Belgazal 
ena_com_write_header_to_bounce(struct ena_com_io_sq * io_sq,u8 * header_src,u16 header_len)89c2b54204SSameeh Jubran static int ena_com_write_header_to_bounce(struct ena_com_io_sq *io_sq,
90689b2bdaSArthur Kiyanovski 						 u8 *header_src,
91689b2bdaSArthur Kiyanovski 						 u16 header_len)
921738cd3eSNetanel Belgazal {
93689b2bdaSArthur Kiyanovski 	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
94689b2bdaSArthur Kiyanovski 	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
95689b2bdaSArthur Kiyanovski 	u8 *bounce_buffer = pkt_ctrl->curr_bounce_buf;
96689b2bdaSArthur Kiyanovski 	u16 header_offset;
971738cd3eSNetanel Belgazal 
98689b2bdaSArthur Kiyanovski 	if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST))
991738cd3eSNetanel Belgazal 		return 0;
1001738cd3eSNetanel Belgazal 
101689b2bdaSArthur Kiyanovski 	header_offset =
102689b2bdaSArthur Kiyanovski 		llq_info->descs_num_before_header * io_sq->desc_entry_size;
103689b2bdaSArthur Kiyanovski 
104*26668c2dSDavid Arinzon 	if (unlikely((header_offset + header_len) > llq_info->desc_list_entry_size)) {
105da580ca8SShay Agroskin 		netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
106da580ca8SShay Agroskin 			   "Trying to write header larger than llq entry can accommodate\n");
107689b2bdaSArthur Kiyanovski 		return -EFAULT;
1081738cd3eSNetanel Belgazal 	}
1091738cd3eSNetanel Belgazal 
110689b2bdaSArthur Kiyanovski 	if (unlikely(!bounce_buffer)) {
111*26668c2dSDavid Arinzon 		netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, "Bounce buffer is NULL\n");
112689b2bdaSArthur Kiyanovski 		return -EFAULT;
113689b2bdaSArthur Kiyanovski 	}
114689b2bdaSArthur Kiyanovski 
115689b2bdaSArthur Kiyanovski 	memcpy(bounce_buffer + header_offset, header_src, header_len);
116689b2bdaSArthur Kiyanovski 
117689b2bdaSArthur Kiyanovski 	return 0;
118689b2bdaSArthur Kiyanovski }
119689b2bdaSArthur Kiyanovski 
get_sq_desc_llq(struct ena_com_io_sq * io_sq)120c2b54204SSameeh Jubran static void *get_sq_desc_llq(struct ena_com_io_sq *io_sq)
121689b2bdaSArthur Kiyanovski {
122689b2bdaSArthur Kiyanovski 	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
123689b2bdaSArthur Kiyanovski 	u8 *bounce_buffer;
124689b2bdaSArthur Kiyanovski 	void *sq_desc;
125689b2bdaSArthur Kiyanovski 
126689b2bdaSArthur Kiyanovski 	bounce_buffer = pkt_ctrl->curr_bounce_buf;
127689b2bdaSArthur Kiyanovski 
128689b2bdaSArthur Kiyanovski 	if (unlikely(!bounce_buffer)) {
129*26668c2dSDavid Arinzon 		netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, "Bounce buffer is NULL\n");
130689b2bdaSArthur Kiyanovski 		return NULL;
131689b2bdaSArthur Kiyanovski 	}
132689b2bdaSArthur Kiyanovski 
133689b2bdaSArthur Kiyanovski 	sq_desc = bounce_buffer + pkt_ctrl->idx * io_sq->desc_entry_size;
134689b2bdaSArthur Kiyanovski 	pkt_ctrl->idx++;
135689b2bdaSArthur Kiyanovski 	pkt_ctrl->descs_left_in_line--;
136689b2bdaSArthur Kiyanovski 
137689b2bdaSArthur Kiyanovski 	return sq_desc;
138689b2bdaSArthur Kiyanovski }
139689b2bdaSArthur Kiyanovski 
ena_com_close_bounce_buffer(struct ena_com_io_sq * io_sq)140c2b54204SSameeh Jubran static int ena_com_close_bounce_buffer(struct ena_com_io_sq *io_sq)
141689b2bdaSArthur Kiyanovski {
142689b2bdaSArthur Kiyanovski 	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
143689b2bdaSArthur Kiyanovski 	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
144689b2bdaSArthur Kiyanovski 	int rc;
145689b2bdaSArthur Kiyanovski 
146689b2bdaSArthur Kiyanovski 	if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST))
147689b2bdaSArthur Kiyanovski 		return 0;
148689b2bdaSArthur Kiyanovski 
149689b2bdaSArthur Kiyanovski 	/* bounce buffer was used, so write it and get a new one */
150e4ac382eSShay Agroskin 	if (likely(pkt_ctrl->idx)) {
151689b2bdaSArthur Kiyanovski 		rc = ena_com_write_bounce_buffer_to_dev(io_sq,
152689b2bdaSArthur Kiyanovski 							pkt_ctrl->curr_bounce_buf);
153091d0e85SShay Agroskin 		if (unlikely(rc)) {
154091d0e85SShay Agroskin 			netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
155091d0e85SShay Agroskin 				   "Failed to write bounce buffer to device\n");
156689b2bdaSArthur Kiyanovski 			return rc;
157091d0e85SShay Agroskin 		}
158689b2bdaSArthur Kiyanovski 
159689b2bdaSArthur Kiyanovski 		pkt_ctrl->curr_bounce_buf =
160689b2bdaSArthur Kiyanovski 			ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
161689b2bdaSArthur Kiyanovski 		memset(io_sq->llq_buf_ctrl.curr_bounce_buf,
162689b2bdaSArthur Kiyanovski 		       0x0, llq_info->desc_list_entry_size);
163689b2bdaSArthur Kiyanovski 	}
164689b2bdaSArthur Kiyanovski 
165689b2bdaSArthur Kiyanovski 	pkt_ctrl->idx = 0;
166689b2bdaSArthur Kiyanovski 	pkt_ctrl->descs_left_in_line = llq_info->descs_num_before_header;
167689b2bdaSArthur Kiyanovski 	return 0;
168689b2bdaSArthur Kiyanovski }
169689b2bdaSArthur Kiyanovski 
get_sq_desc(struct ena_com_io_sq * io_sq)170c2b54204SSameeh Jubran static void *get_sq_desc(struct ena_com_io_sq *io_sq)
171689b2bdaSArthur Kiyanovski {
172689b2bdaSArthur Kiyanovski 	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
173689b2bdaSArthur Kiyanovski 		return get_sq_desc_llq(io_sq);
174689b2bdaSArthur Kiyanovski 
175689b2bdaSArthur Kiyanovski 	return get_sq_desc_regular_queue(io_sq);
176689b2bdaSArthur Kiyanovski }
177689b2bdaSArthur Kiyanovski 
ena_com_sq_update_llq_tail(struct ena_com_io_sq * io_sq)178c2b54204SSameeh Jubran static int ena_com_sq_update_llq_tail(struct ena_com_io_sq *io_sq)
179689b2bdaSArthur Kiyanovski {
180689b2bdaSArthur Kiyanovski 	struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
181689b2bdaSArthur Kiyanovski 	struct ena_com_llq_info *llq_info = &io_sq->llq_info;
182689b2bdaSArthur Kiyanovski 	int rc;
183689b2bdaSArthur Kiyanovski 
184689b2bdaSArthur Kiyanovski 	if (!pkt_ctrl->descs_left_in_line) {
185689b2bdaSArthur Kiyanovski 		rc = ena_com_write_bounce_buffer_to_dev(io_sq,
186689b2bdaSArthur Kiyanovski 							pkt_ctrl->curr_bounce_buf);
187091d0e85SShay Agroskin 		if (unlikely(rc)) {
188091d0e85SShay Agroskin 			netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
189091d0e85SShay Agroskin 				   "Failed to write bounce buffer to device\n");
190689b2bdaSArthur Kiyanovski 			return rc;
191091d0e85SShay Agroskin 		}
192689b2bdaSArthur Kiyanovski 
193689b2bdaSArthur Kiyanovski 		pkt_ctrl->curr_bounce_buf =
194689b2bdaSArthur Kiyanovski 			ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
195689b2bdaSArthur Kiyanovski 		memset(io_sq->llq_buf_ctrl.curr_bounce_buf,
196689b2bdaSArthur Kiyanovski 		       0x0, llq_info->desc_list_entry_size);
197689b2bdaSArthur Kiyanovski 
198689b2bdaSArthur Kiyanovski 		pkt_ctrl->idx = 0;
199689b2bdaSArthur Kiyanovski 		if (unlikely(llq_info->desc_stride_ctrl == ENA_ADMIN_SINGLE_DESC_PER_ENTRY))
200689b2bdaSArthur Kiyanovski 			pkt_ctrl->descs_left_in_line = 1;
201689b2bdaSArthur Kiyanovski 		else
202689b2bdaSArthur Kiyanovski 			pkt_ctrl->descs_left_in_line =
203689b2bdaSArthur Kiyanovski 			llq_info->desc_list_entry_size / io_sq->desc_entry_size;
204689b2bdaSArthur Kiyanovski 	}
205689b2bdaSArthur Kiyanovski 
206689b2bdaSArthur Kiyanovski 	return 0;
207689b2bdaSArthur Kiyanovski }
208689b2bdaSArthur Kiyanovski 
ena_com_sq_update_tail(struct ena_com_io_sq * io_sq)209c2b54204SSameeh Jubran static int ena_com_sq_update_tail(struct ena_com_io_sq *io_sq)
210689b2bdaSArthur Kiyanovski {
211689b2bdaSArthur Kiyanovski 	if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
212689b2bdaSArthur Kiyanovski 		return ena_com_sq_update_llq_tail(io_sq);
213689b2bdaSArthur Kiyanovski 
214689b2bdaSArthur Kiyanovski 	io_sq->tail++;
215689b2bdaSArthur Kiyanovski 
216689b2bdaSArthur Kiyanovski 	/* Switch phase bit in case of wrap around */
217689b2bdaSArthur Kiyanovski 	if (unlikely((io_sq->tail & (io_sq->q_depth - 1)) == 0))
218689b2bdaSArthur Kiyanovski 		io_sq->phase ^= 1;
2191738cd3eSNetanel Belgazal 
2201738cd3eSNetanel Belgazal 	return 0;
2211738cd3eSNetanel Belgazal }
2221738cd3eSNetanel Belgazal 
223c2b54204SSameeh Jubran static struct ena_eth_io_rx_cdesc_base *
ena_com_rx_cdesc_idx_to_ptr(struct ena_com_io_cq * io_cq,u16 idx)2241738cd3eSNetanel Belgazal 	ena_com_rx_cdesc_idx_to_ptr(struct ena_com_io_cq *io_cq, u16 idx)
2251738cd3eSNetanel Belgazal {
2261738cd3eSNetanel Belgazal 	idx &= (io_cq->q_depth - 1);
2271738cd3eSNetanel Belgazal 	return (struct ena_eth_io_rx_cdesc_base *)
2281738cd3eSNetanel Belgazal 		((uintptr_t)io_cq->cdesc_addr.virt_addr +
2291738cd3eSNetanel Belgazal 		idx * io_cq->cdesc_entry_size_in_bytes);
2301738cd3eSNetanel Belgazal }
2311738cd3eSNetanel Belgazal 
ena_com_cdesc_rx_pkt_get(struct ena_com_io_cq * io_cq,u16 * first_cdesc_idx)232c2b54204SSameeh Jubran static u16 ena_com_cdesc_rx_pkt_get(struct ena_com_io_cq *io_cq,
2331738cd3eSNetanel Belgazal 					   u16 *first_cdesc_idx)
2341738cd3eSNetanel Belgazal {
2351738cd3eSNetanel Belgazal 	struct ena_eth_io_rx_cdesc_base *cdesc;
2361738cd3eSNetanel Belgazal 	u16 count = 0, head_masked;
2371738cd3eSNetanel Belgazal 	u32 last = 0;
2381738cd3eSNetanel Belgazal 
2391738cd3eSNetanel Belgazal 	do {
2401738cd3eSNetanel Belgazal 		cdesc = ena_com_get_next_rx_cdesc(io_cq);
2411738cd3eSNetanel Belgazal 		if (!cdesc)
2421738cd3eSNetanel Belgazal 			break;
2431738cd3eSNetanel Belgazal 
2441738cd3eSNetanel Belgazal 		ena_com_cq_inc_head(io_cq);
2451738cd3eSNetanel Belgazal 		count++;
246*26668c2dSDavid Arinzon 		last = (READ_ONCE(cdesc->status) & ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK) >>
2471738cd3eSNetanel Belgazal 		       ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT;
2481738cd3eSNetanel Belgazal 	} while (!last);
2491738cd3eSNetanel Belgazal 
2501738cd3eSNetanel Belgazal 	if (last) {
2511738cd3eSNetanel Belgazal 		*first_cdesc_idx = io_cq->cur_rx_pkt_cdesc_start_idx;
2521738cd3eSNetanel Belgazal 		count += io_cq->cur_rx_pkt_cdesc_count;
2531738cd3eSNetanel Belgazal 
2541738cd3eSNetanel Belgazal 		head_masked = io_cq->head & (io_cq->q_depth - 1);
2551738cd3eSNetanel Belgazal 
2561738cd3eSNetanel Belgazal 		io_cq->cur_rx_pkt_cdesc_count = 0;
2571738cd3eSNetanel Belgazal 		io_cq->cur_rx_pkt_cdesc_start_idx = head_masked;
2581738cd3eSNetanel Belgazal 
259da580ca8SShay Agroskin 		netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device,
260da580ca8SShay Agroskin 			   "ENA q_id: %d packets were completed. first desc idx %u descs# %d\n",
2611738cd3eSNetanel Belgazal 			   io_cq->qid, *first_cdesc_idx, count);
2621738cd3eSNetanel Belgazal 	} else {
2631738cd3eSNetanel Belgazal 		io_cq->cur_rx_pkt_cdesc_count += count;
2641738cd3eSNetanel Belgazal 		count = 0;
2651738cd3eSNetanel Belgazal 	}
2661738cd3eSNetanel Belgazal 
2671738cd3eSNetanel Belgazal 	return count;
2681738cd3eSNetanel Belgazal }
2691738cd3eSNetanel Belgazal 
ena_com_create_meta(struct ena_com_io_sq * io_sq,struct ena_com_tx_meta * ena_meta)2700e3a3f6dSArthur Kiyanovski static int ena_com_create_meta(struct ena_com_io_sq *io_sq,
2710e3a3f6dSArthur Kiyanovski 			       struct ena_com_tx_meta *ena_meta)
2721738cd3eSNetanel Belgazal {
2731738cd3eSNetanel Belgazal 	struct ena_eth_io_tx_meta_desc *meta_desc = NULL;
2741738cd3eSNetanel Belgazal 
2751738cd3eSNetanel Belgazal 	meta_desc = get_sq_desc(io_sq);
276f49ed500SShay Agroskin 	if (unlikely(!meta_desc))
277f49ed500SShay Agroskin 		return -EFAULT;
278f49ed500SShay Agroskin 
2791738cd3eSNetanel Belgazal 	memset(meta_desc, 0x0, sizeof(struct ena_eth_io_tx_meta_desc));
2801738cd3eSNetanel Belgazal 
2811738cd3eSNetanel Belgazal 	meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_META_DESC_MASK;
2821738cd3eSNetanel Belgazal 
2831738cd3eSNetanel Belgazal 	meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_EXT_VALID_MASK;
2841738cd3eSNetanel Belgazal 
2851738cd3eSNetanel Belgazal 	/* bits 0-9 of the mss */
286f49ed500SShay Agroskin 	meta_desc->word2 |= ((u32)ena_meta->mss <<
2871738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_META_DESC_MSS_LO_SHIFT) &
2881738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_META_DESC_MSS_LO_MASK;
2891738cd3eSNetanel Belgazal 	/* bits 10-13 of the mss */
2901738cd3eSNetanel Belgazal 	meta_desc->len_ctrl |= ((ena_meta->mss >> 10) <<
2911738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_META_DESC_MSS_HI_SHIFT) &
2921738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_META_DESC_MSS_HI_MASK;
2931738cd3eSNetanel Belgazal 
2941738cd3eSNetanel Belgazal 	/* Extended meta desc */
2951738cd3eSNetanel Belgazal 	meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_MASK;
296f49ed500SShay Agroskin 	meta_desc->len_ctrl |= ((u32)io_sq->phase <<
2971738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_META_DESC_PHASE_SHIFT) &
2981738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_META_DESC_PHASE_MASK;
2991738cd3eSNetanel Belgazal 
3001738cd3eSNetanel Belgazal 	meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_FIRST_MASK;
3010e3a3f6dSArthur Kiyanovski 	meta_desc->len_ctrl |= ENA_ETH_IO_TX_META_DESC_META_STORE_MASK;
3020e3a3f6dSArthur Kiyanovski 
3031738cd3eSNetanel Belgazal 	meta_desc->word2 |= ena_meta->l3_hdr_len &
3041738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_META_DESC_L3_HDR_LEN_MASK;
3051738cd3eSNetanel Belgazal 	meta_desc->word2 |= (ena_meta->l3_hdr_offset <<
3061738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_SHIFT) &
3071738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_MASK;
3081738cd3eSNetanel Belgazal 
309f49ed500SShay Agroskin 	meta_desc->word2 |= ((u32)ena_meta->l4_hdr_len <<
3101738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_SHIFT) &
3111738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_MASK;
3121738cd3eSNetanel Belgazal 
3130e3a3f6dSArthur Kiyanovski 	return ena_com_sq_update_tail(io_sq);
3140e3a3f6dSArthur Kiyanovski }
3151738cd3eSNetanel Belgazal 
ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq * io_sq,struct ena_com_tx_ctx * ena_tx_ctx,bool * have_meta)3160e3a3f6dSArthur Kiyanovski static int ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq,
3170e3a3f6dSArthur Kiyanovski 						 struct ena_com_tx_ctx *ena_tx_ctx,
3180e3a3f6dSArthur Kiyanovski 						 bool *have_meta)
3190e3a3f6dSArthur Kiyanovski {
3200e3a3f6dSArthur Kiyanovski 	struct ena_com_tx_meta *ena_meta = &ena_tx_ctx->ena_meta;
3210e3a3f6dSArthur Kiyanovski 
3220e3a3f6dSArthur Kiyanovski 	/* When disable meta caching is set, don't bother to save the meta and
3230e3a3f6dSArthur Kiyanovski 	 * compare it to the stored version, just create the meta
3240e3a3f6dSArthur Kiyanovski 	 */
3250e3a3f6dSArthur Kiyanovski 	if (io_sq->disable_meta_caching) {
3260e3a3f6dSArthur Kiyanovski 		*have_meta = true;
3270e3a3f6dSArthur Kiyanovski 		return ena_com_create_meta(io_sq, ena_meta);
3280e3a3f6dSArthur Kiyanovski 	}
3290e3a3f6dSArthur Kiyanovski 
3300e3a3f6dSArthur Kiyanovski 	if (ena_com_meta_desc_changed(io_sq, ena_tx_ctx)) {
3310e3a3f6dSArthur Kiyanovski 		*have_meta = true;
3320e3a3f6dSArthur Kiyanovski 		/* Cache the meta desc */
3331738cd3eSNetanel Belgazal 		memcpy(&io_sq->cached_tx_meta, ena_meta,
3341738cd3eSNetanel Belgazal 		       sizeof(struct ena_com_tx_meta));
3350e3a3f6dSArthur Kiyanovski 		return ena_com_create_meta(io_sq, ena_meta);
3360e3a3f6dSArthur Kiyanovski 	}
3371738cd3eSNetanel Belgazal 
3380e3a3f6dSArthur Kiyanovski 	*have_meta = false;
3390e3a3f6dSArthur Kiyanovski 	return 0;
3401738cd3eSNetanel Belgazal }
3411738cd3eSNetanel Belgazal 
ena_com_rx_set_flags(struct ena_com_io_cq * io_cq,struct ena_com_rx_ctx * ena_rx_ctx,struct ena_eth_io_rx_cdesc_base * cdesc)342da580ca8SShay Agroskin static void ena_com_rx_set_flags(struct ena_com_io_cq *io_cq,
343da580ca8SShay Agroskin 				 struct ena_com_rx_ctx *ena_rx_ctx,
3441738cd3eSNetanel Belgazal 				 struct ena_eth_io_rx_cdesc_base *cdesc)
3451738cd3eSNetanel Belgazal {
3461738cd3eSNetanel Belgazal 	ena_rx_ctx->l3_proto = cdesc->status &
3471738cd3eSNetanel Belgazal 		ENA_ETH_IO_RX_CDESC_BASE_L3_PROTO_IDX_MASK;
3481738cd3eSNetanel Belgazal 	ena_rx_ctx->l4_proto =
3491738cd3eSNetanel Belgazal 		(cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_MASK) >>
3501738cd3eSNetanel Belgazal 		ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_SHIFT;
3511738cd3eSNetanel Belgazal 	ena_rx_ctx->l3_csum_err =
352248ab773SArthur Kiyanovski 		!!((cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_MASK) >>
353248ab773SArthur Kiyanovski 		ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_SHIFT);
3541738cd3eSNetanel Belgazal 	ena_rx_ctx->l4_csum_err =
355248ab773SArthur Kiyanovski 		!!((cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK) >>
356248ab773SArthur Kiyanovski 		ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT);
357cb36bb36SArthur Kiyanovski 	ena_rx_ctx->l4_csum_checked =
358cb36bb36SArthur Kiyanovski 		!!((cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_MASK) >>
359cb36bb36SArthur Kiyanovski 		ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_SHIFT);
3601738cd3eSNetanel Belgazal 	ena_rx_ctx->hash = cdesc->hash;
3611738cd3eSNetanel Belgazal 	ena_rx_ctx->frag =
3621738cd3eSNetanel Belgazal 		(cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK) >>
3631738cd3eSNetanel Belgazal 		ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_SHIFT;
3641738cd3eSNetanel Belgazal 
365da580ca8SShay Agroskin 	netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device,
366da580ca8SShay Agroskin 		   "l3_proto %d l4_proto %d l3_csum_err %d l4_csum_err %d hash %d frag %d cdesc_status %x\n",
367*26668c2dSDavid Arinzon 		   ena_rx_ctx->l3_proto, ena_rx_ctx->l4_proto, ena_rx_ctx->l3_csum_err,
368*26668c2dSDavid Arinzon 		   ena_rx_ctx->l4_csum_err, ena_rx_ctx->hash, ena_rx_ctx->frag, cdesc->status);
3691738cd3eSNetanel Belgazal }
3701738cd3eSNetanel Belgazal 
3711738cd3eSNetanel Belgazal /*****************************************************************************/
3721738cd3eSNetanel Belgazal /*****************************     API      **********************************/
3731738cd3eSNetanel Belgazal /*****************************************************************************/
3741738cd3eSNetanel Belgazal 
ena_com_prepare_tx(struct ena_com_io_sq * io_sq,struct ena_com_tx_ctx * ena_tx_ctx,int * nb_hw_desc)3751738cd3eSNetanel Belgazal int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
3761738cd3eSNetanel Belgazal 		       struct ena_com_tx_ctx *ena_tx_ctx,
3771738cd3eSNetanel Belgazal 		       int *nb_hw_desc)
3781738cd3eSNetanel Belgazal {
3791738cd3eSNetanel Belgazal 	struct ena_eth_io_tx_desc *desc = NULL;
3801738cd3eSNetanel Belgazal 	struct ena_com_buf *ena_bufs = ena_tx_ctx->ena_bufs;
381689b2bdaSArthur Kiyanovski 	void *buffer_to_push = ena_tx_ctx->push_header;
3821738cd3eSNetanel Belgazal 	u16 header_len = ena_tx_ctx->header_len;
3831738cd3eSNetanel Belgazal 	u16 num_bufs = ena_tx_ctx->num_bufs;
384689b2bdaSArthur Kiyanovski 	u16 start_tail = io_sq->tail;
385689b2bdaSArthur Kiyanovski 	int i, rc;
3861738cd3eSNetanel Belgazal 	bool have_meta;
3871738cd3eSNetanel Belgazal 	u64 addr_hi;
3881738cd3eSNetanel Belgazal 
3891738cd3eSNetanel Belgazal 	WARN(io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_TX, "wrong Q type");
3901738cd3eSNetanel Belgazal 
3911738cd3eSNetanel Belgazal 	/* num_bufs +1 for potential meta desc */
392689b2bdaSArthur Kiyanovski 	if (unlikely(!ena_com_sq_have_enough_space(io_sq, num_bufs + 1))) {
393da580ca8SShay Agroskin 		netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
394da580ca8SShay Agroskin 			   "Not enough space in the tx queue\n");
3951738cd3eSNetanel Belgazal 		return -ENOMEM;
3961738cd3eSNetanel Belgazal 	}
3971738cd3eSNetanel Belgazal 
3981738cd3eSNetanel Belgazal 	if (unlikely(header_len > io_sq->tx_max_header_size)) {
399da580ca8SShay Agroskin 		netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
400*26668c2dSDavid Arinzon 			   "Header size is too large %d max header: %d\n", header_len,
401*26668c2dSDavid Arinzon 			   io_sq->tx_max_header_size);
4021738cd3eSNetanel Belgazal 		return -EINVAL;
4031738cd3eSNetanel Belgazal 	}
4041738cd3eSNetanel Belgazal 
405*26668c2dSDavid Arinzon 	if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV && !buffer_to_push)) {
406091d0e85SShay Agroskin 		netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
407091d0e85SShay Agroskin 			   "Push header wasn't provided in LLQ mode\n");
408689b2bdaSArthur Kiyanovski 		return -EINVAL;
409091d0e85SShay Agroskin 	}
410689b2bdaSArthur Kiyanovski 
411689b2bdaSArthur Kiyanovski 	rc = ena_com_write_header_to_bounce(io_sq, buffer_to_push, header_len);
4121738cd3eSNetanel Belgazal 	if (unlikely(rc))
4131738cd3eSNetanel Belgazal 		return rc;
4141738cd3eSNetanel Belgazal 
4150e3a3f6dSArthur Kiyanovski 	rc = ena_com_create_and_store_tx_meta_desc(io_sq, ena_tx_ctx, &have_meta);
4160e3a3f6dSArthur Kiyanovski 	if (unlikely(rc)) {
417da580ca8SShay Agroskin 		netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
418da580ca8SShay Agroskin 			   "Failed to create and store tx meta desc\n");
419689b2bdaSArthur Kiyanovski 		return rc;
420689b2bdaSArthur Kiyanovski 	}
4211738cd3eSNetanel Belgazal 
422689b2bdaSArthur Kiyanovski 	/* If the caller doesn't want to send packets */
4231738cd3eSNetanel Belgazal 	if (unlikely(!num_bufs && !header_len)) {
424689b2bdaSArthur Kiyanovski 		rc = ena_com_close_bounce_buffer(io_sq);
425091d0e85SShay Agroskin 		if (rc)
426091d0e85SShay Agroskin 			netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
427091d0e85SShay Agroskin 				   "Failed to write buffers to LLQ\n");
428689b2bdaSArthur Kiyanovski 		*nb_hw_desc = io_sq->tail - start_tail;
429689b2bdaSArthur Kiyanovski 		return rc;
4301738cd3eSNetanel Belgazal 	}
4311738cd3eSNetanel Belgazal 
4321738cd3eSNetanel Belgazal 	desc = get_sq_desc(io_sq);
433689b2bdaSArthur Kiyanovski 	if (unlikely(!desc))
434689b2bdaSArthur Kiyanovski 		return -EFAULT;
4351738cd3eSNetanel Belgazal 	memset(desc, 0x0, sizeof(struct ena_eth_io_tx_desc));
4361738cd3eSNetanel Belgazal 
4371738cd3eSNetanel Belgazal 	/* Set first desc when we don't have meta descriptor */
4381738cd3eSNetanel Belgazal 	if (!have_meta)
4391738cd3eSNetanel Belgazal 		desc->len_ctrl |= ENA_ETH_IO_TX_DESC_FIRST_MASK;
4401738cd3eSNetanel Belgazal 
441f49ed500SShay Agroskin 	desc->buff_addr_hi_hdr_sz |= ((u32)header_len <<
4421738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_DESC_HEADER_LENGTH_SHIFT) &
4431738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_DESC_HEADER_LENGTH_MASK;
444f49ed500SShay Agroskin 	desc->len_ctrl |= ((u32)io_sq->phase << ENA_ETH_IO_TX_DESC_PHASE_SHIFT) &
4451738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_DESC_PHASE_MASK;
4461738cd3eSNetanel Belgazal 
4471738cd3eSNetanel Belgazal 	desc->len_ctrl |= ENA_ETH_IO_TX_DESC_COMP_REQ_MASK;
4481738cd3eSNetanel Belgazal 
4491738cd3eSNetanel Belgazal 	/* Bits 0-9 */
450f49ed500SShay Agroskin 	desc->meta_ctrl |= ((u32)ena_tx_ctx->req_id <<
4511738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_DESC_REQ_ID_LO_SHIFT) &
4521738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_DESC_REQ_ID_LO_MASK;
4531738cd3eSNetanel Belgazal 
4541738cd3eSNetanel Belgazal 	desc->meta_ctrl |= (ena_tx_ctx->df <<
4551738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_DESC_DF_SHIFT) &
4561738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_DESC_DF_MASK;
4571738cd3eSNetanel Belgazal 
4581738cd3eSNetanel Belgazal 	/* Bits 10-15 */
4591738cd3eSNetanel Belgazal 	desc->len_ctrl |= ((ena_tx_ctx->req_id >> 10) <<
4601738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_DESC_REQ_ID_HI_SHIFT) &
4611738cd3eSNetanel Belgazal 		ENA_ETH_IO_TX_DESC_REQ_ID_HI_MASK;
4621738cd3eSNetanel Belgazal 
4631738cd3eSNetanel Belgazal 	if (ena_tx_ctx->meta_valid) {
4641738cd3eSNetanel Belgazal 		desc->meta_ctrl |= (ena_tx_ctx->tso_enable <<
4651738cd3eSNetanel Belgazal 			ENA_ETH_IO_TX_DESC_TSO_EN_SHIFT) &
4661738cd3eSNetanel Belgazal 			ENA_ETH_IO_TX_DESC_TSO_EN_MASK;
4671738cd3eSNetanel Belgazal 		desc->meta_ctrl |= ena_tx_ctx->l3_proto &
4681738cd3eSNetanel Belgazal 			ENA_ETH_IO_TX_DESC_L3_PROTO_IDX_MASK;
4691738cd3eSNetanel Belgazal 		desc->meta_ctrl |= (ena_tx_ctx->l4_proto <<
4701738cd3eSNetanel Belgazal 			ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_SHIFT) &
4711738cd3eSNetanel Belgazal 			ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_MASK;
4721738cd3eSNetanel Belgazal 		desc->meta_ctrl |= (ena_tx_ctx->l3_csum_enable <<
4731738cd3eSNetanel Belgazal 			ENA_ETH_IO_TX_DESC_L3_CSUM_EN_SHIFT) &
4741738cd3eSNetanel Belgazal 			ENA_ETH_IO_TX_DESC_L3_CSUM_EN_MASK;
4751738cd3eSNetanel Belgazal 		desc->meta_ctrl |= (ena_tx_ctx->l4_csum_enable <<
4761738cd3eSNetanel Belgazal 			ENA_ETH_IO_TX_DESC_L4_CSUM_EN_SHIFT) &
4771738cd3eSNetanel Belgazal 			ENA_ETH_IO_TX_DESC_L4_CSUM_EN_MASK;
4781738cd3eSNetanel Belgazal 		desc->meta_ctrl |= (ena_tx_ctx->l4_csum_partial <<
4791738cd3eSNetanel Belgazal 			ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_SHIFT) &
4801738cd3eSNetanel Belgazal 			ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_MASK;
4811738cd3eSNetanel Belgazal 	}
4821738cd3eSNetanel Belgazal 
4831738cd3eSNetanel Belgazal 	for (i = 0; i < num_bufs; i++) {
4841738cd3eSNetanel Belgazal 		/* The first desc share the same desc as the header */
4851738cd3eSNetanel Belgazal 		if (likely(i != 0)) {
486689b2bdaSArthur Kiyanovski 			rc = ena_com_sq_update_tail(io_sq);
487091d0e85SShay Agroskin 			if (unlikely(rc)) {
488091d0e85SShay Agroskin 				netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
489091d0e85SShay Agroskin 					   "Failed to update sq tail\n");
490689b2bdaSArthur Kiyanovski 				return rc;
491091d0e85SShay Agroskin 			}
4921738cd3eSNetanel Belgazal 
4931738cd3eSNetanel Belgazal 			desc = get_sq_desc(io_sq);
494689b2bdaSArthur Kiyanovski 			if (unlikely(!desc))
495689b2bdaSArthur Kiyanovski 				return -EFAULT;
496689b2bdaSArthur Kiyanovski 
4971738cd3eSNetanel Belgazal 			memset(desc, 0x0, sizeof(struct ena_eth_io_tx_desc));
4981738cd3eSNetanel Belgazal 
499f49ed500SShay Agroskin 			desc->len_ctrl |= ((u32)io_sq->phase <<
5001738cd3eSNetanel Belgazal 				ENA_ETH_IO_TX_DESC_PHASE_SHIFT) &
5011738cd3eSNetanel Belgazal 				ENA_ETH_IO_TX_DESC_PHASE_MASK;
5021738cd3eSNetanel Belgazal 		}
5031738cd3eSNetanel Belgazal 
5041738cd3eSNetanel Belgazal 		desc->len_ctrl |= ena_bufs->len &
5051738cd3eSNetanel Belgazal 			ENA_ETH_IO_TX_DESC_LENGTH_MASK;
5061738cd3eSNetanel Belgazal 
5071738cd3eSNetanel Belgazal 		addr_hi = ((ena_bufs->paddr &
5081738cd3eSNetanel Belgazal 			GENMASK_ULL(io_sq->dma_addr_bits - 1, 32)) >> 32);
5091738cd3eSNetanel Belgazal 
5101738cd3eSNetanel Belgazal 		desc->buff_addr_lo = (u32)ena_bufs->paddr;
5111738cd3eSNetanel Belgazal 		desc->buff_addr_hi_hdr_sz |= addr_hi &
5121738cd3eSNetanel Belgazal 			ENA_ETH_IO_TX_DESC_ADDR_HI_MASK;
5131738cd3eSNetanel Belgazal 		ena_bufs++;
5141738cd3eSNetanel Belgazal 	}
5151738cd3eSNetanel Belgazal 
5161738cd3eSNetanel Belgazal 	/* set the last desc indicator */
5171738cd3eSNetanel Belgazal 	desc->len_ctrl |= ENA_ETH_IO_TX_DESC_LAST_MASK;
5181738cd3eSNetanel Belgazal 
519689b2bdaSArthur Kiyanovski 	rc = ena_com_sq_update_tail(io_sq);
520091d0e85SShay Agroskin 	if (unlikely(rc)) {
521091d0e85SShay Agroskin 		netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
522091d0e85SShay Agroskin 			   "Failed to update sq tail of the last descriptor\n");
523689b2bdaSArthur Kiyanovski 		return rc;
524091d0e85SShay Agroskin 	}
5251738cd3eSNetanel Belgazal 
526689b2bdaSArthur Kiyanovski 	rc = ena_com_close_bounce_buffer(io_sq);
5271738cd3eSNetanel Belgazal 
528689b2bdaSArthur Kiyanovski 	*nb_hw_desc = io_sq->tail - start_tail;
529689b2bdaSArthur Kiyanovski 	return rc;
5301738cd3eSNetanel Belgazal }
5311738cd3eSNetanel Belgazal 
ena_com_rx_pkt(struct ena_com_io_cq * io_cq,struct ena_com_io_sq * io_sq,struct ena_com_rx_ctx * ena_rx_ctx)5321738cd3eSNetanel Belgazal int ena_com_rx_pkt(struct ena_com_io_cq *io_cq,
5331738cd3eSNetanel Belgazal 		   struct ena_com_io_sq *io_sq,
5341738cd3eSNetanel Belgazal 		   struct ena_com_rx_ctx *ena_rx_ctx)
5351738cd3eSNetanel Belgazal {
5361738cd3eSNetanel Belgazal 	struct ena_com_rx_buf_info *ena_buf = &ena_rx_ctx->ena_bufs[0];
5371738cd3eSNetanel Belgazal 	struct ena_eth_io_rx_cdesc_base *cdesc = NULL;
5385b7022cfSShay Agroskin 	u16 q_depth = io_cq->q_depth;
5391738cd3eSNetanel Belgazal 	u16 cdesc_idx = 0;
5401738cd3eSNetanel Belgazal 	u16 nb_hw_desc;
54168f236dfSArthur Kiyanovski 	u16 i = 0;
5421738cd3eSNetanel Belgazal 
5431738cd3eSNetanel Belgazal 	WARN(io_cq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX, "wrong Q type");
5441738cd3eSNetanel Belgazal 
5451738cd3eSNetanel Belgazal 	nb_hw_desc = ena_com_cdesc_rx_pkt_get(io_cq, &cdesc_idx);
5461738cd3eSNetanel Belgazal 	if (nb_hw_desc == 0) {
5471738cd3eSNetanel Belgazal 		ena_rx_ctx->descs = nb_hw_desc;
5481738cd3eSNetanel Belgazal 		return 0;
5491738cd3eSNetanel Belgazal 	}
5501738cd3eSNetanel Belgazal 
551da580ca8SShay Agroskin 	netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device,
552*26668c2dSDavid Arinzon 		   "Fetch rx packet: queue %d completed desc: %d\n", io_cq->qid, nb_hw_desc);
5531738cd3eSNetanel Belgazal 
5541738cd3eSNetanel Belgazal 	if (unlikely(nb_hw_desc > ena_rx_ctx->max_bufs)) {
555da580ca8SShay Agroskin 		netdev_err(ena_com_io_cq_to_ena_dev(io_cq)->net_device,
556*26668c2dSDavid Arinzon 			   "Too many RX cdescs (%d) > MAX(%d)\n", nb_hw_desc, ena_rx_ctx->max_bufs);
5571738cd3eSNetanel Belgazal 		return -ENOSPC;
5581738cd3eSNetanel Belgazal 	}
5591738cd3eSNetanel Belgazal 
56068f236dfSArthur Kiyanovski 	cdesc = ena_com_rx_cdesc_idx_to_ptr(io_cq, cdesc_idx);
56168f236dfSArthur Kiyanovski 	ena_rx_ctx->pkt_offset = cdesc->offset;
56268f236dfSArthur Kiyanovski 
56368f236dfSArthur Kiyanovski 	do {
56468f236dfSArthur Kiyanovski 		ena_buf[i].len = cdesc->length;
56568f236dfSArthur Kiyanovski 		ena_buf[i].req_id = cdesc->req_id;
5665b7022cfSShay Agroskin 		if (unlikely(ena_buf[i].req_id >= q_depth))
5675b7022cfSShay Agroskin 			return -EIO;
56868f236dfSArthur Kiyanovski 
56968f236dfSArthur Kiyanovski 		if (++i >= nb_hw_desc)
57068f236dfSArthur Kiyanovski 			break;
57168f236dfSArthur Kiyanovski 
5721738cd3eSNetanel Belgazal 		cdesc = ena_com_rx_cdesc_idx_to_ptr(io_cq, cdesc_idx + i);
5731738cd3eSNetanel Belgazal 
57468f236dfSArthur Kiyanovski 	} while (1);
5751738cd3eSNetanel Belgazal 
5761738cd3eSNetanel Belgazal 	/* Update SQ head ptr */
5771738cd3eSNetanel Belgazal 	io_sq->next_to_comp += nb_hw_desc;
5781738cd3eSNetanel Belgazal 
579da580ca8SShay Agroskin 	netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device,
580*26668c2dSDavid Arinzon 		   "[%s][QID#%d] Updating SQ head to: %d\n", __func__, io_sq->qid,
581*26668c2dSDavid Arinzon 		   io_sq->next_to_comp);
5821738cd3eSNetanel Belgazal 
5831738cd3eSNetanel Belgazal 	/* Get rx flags from the last pkt */
584da580ca8SShay Agroskin 	ena_com_rx_set_flags(io_cq, ena_rx_ctx, cdesc);
5851738cd3eSNetanel Belgazal 
5861738cd3eSNetanel Belgazal 	ena_rx_ctx->descs = nb_hw_desc;
5871e584739SShay Agroskin 
5881738cd3eSNetanel Belgazal 	return 0;
5891738cd3eSNetanel Belgazal }
5901738cd3eSNetanel Belgazal 
ena_com_add_single_rx_desc(struct ena_com_io_sq * io_sq,struct ena_com_buf * ena_buf,u16 req_id)5911738cd3eSNetanel Belgazal int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq,
5921738cd3eSNetanel Belgazal 			       struct ena_com_buf *ena_buf,
5931738cd3eSNetanel Belgazal 			       u16 req_id)
5941738cd3eSNetanel Belgazal {
5951738cd3eSNetanel Belgazal 	struct ena_eth_io_rx_desc *desc;
5961738cd3eSNetanel Belgazal 
5971738cd3eSNetanel Belgazal 	WARN(io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX, "wrong Q type");
5981738cd3eSNetanel Belgazal 
599689b2bdaSArthur Kiyanovski 	if (unlikely(!ena_com_sq_have_enough_space(io_sq, 1)))
6001738cd3eSNetanel Belgazal 		return -ENOSPC;
6011738cd3eSNetanel Belgazal 
6021738cd3eSNetanel Belgazal 	desc = get_sq_desc(io_sq);
603689b2bdaSArthur Kiyanovski 	if (unlikely(!desc))
604689b2bdaSArthur Kiyanovski 		return -EFAULT;
605689b2bdaSArthur Kiyanovski 
6061738cd3eSNetanel Belgazal 	memset(desc, 0x0, sizeof(struct ena_eth_io_rx_desc));
6071738cd3eSNetanel Belgazal 
6081738cd3eSNetanel Belgazal 	desc->length = ena_buf->len;
6091738cd3eSNetanel Belgazal 
610b0ae3ac4SArthur Kiyanovski 	desc->ctrl = ENA_ETH_IO_RX_DESC_FIRST_MASK |
611b0ae3ac4SArthur Kiyanovski 		     ENA_ETH_IO_RX_DESC_LAST_MASK |
6121e584739SShay Agroskin 		     ENA_ETH_IO_RX_DESC_COMP_REQ_MASK |
6131e584739SShay Agroskin 		     (io_sq->phase & ENA_ETH_IO_RX_DESC_PHASE_MASK);
6141738cd3eSNetanel Belgazal 
6151738cd3eSNetanel Belgazal 	desc->req_id = req_id;
6161738cd3eSNetanel Belgazal 
617da580ca8SShay Agroskin 	netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
618*26668c2dSDavid Arinzon 		   "[%s] Adding single RX desc, Queue: %u, req_id: %u\n", __func__, io_sq->qid,
619*26668c2dSDavid Arinzon 		   req_id);
620da580ca8SShay Agroskin 
6211738cd3eSNetanel Belgazal 	desc->buff_addr_lo = (u32)ena_buf->paddr;
6221738cd3eSNetanel Belgazal 	desc->buff_addr_hi =
6231738cd3eSNetanel Belgazal 		((ena_buf->paddr & GENMASK_ULL(io_sq->dma_addr_bits - 1, 32)) >> 32);
6241738cd3eSNetanel Belgazal 
625689b2bdaSArthur Kiyanovski 	return ena_com_sq_update_tail(io_sq);
6261738cd3eSNetanel Belgazal }
6271738cd3eSNetanel Belgazal 
ena_com_cq_empty(struct ena_com_io_cq * io_cq)6288510e1a3SNetanel Belgazal bool ena_com_cq_empty(struct ena_com_io_cq *io_cq)
6298510e1a3SNetanel Belgazal {
6308510e1a3SNetanel Belgazal 	struct ena_eth_io_rx_cdesc_base *cdesc;
6318510e1a3SNetanel Belgazal 
6328510e1a3SNetanel Belgazal 	cdesc = ena_com_get_next_rx_cdesc(io_cq);
6338510e1a3SNetanel Belgazal 	if (cdesc)
6348510e1a3SNetanel Belgazal 		return false;
6358510e1a3SNetanel Belgazal 	else
6368510e1a3SNetanel Belgazal 		return true;
6378510e1a3SNetanel Belgazal }
638