xref: /dpdk/drivers/net/mana/gdma.c (revision 26c6bdf3d1169e6e9ab04691a1088937137a6d5c)
156dd45c0SLong Li /* SPDX-License-Identifier: BSD-3-Clause
256dd45c0SLong Li  * Copyright 2022 Microsoft Corporation
356dd45c0SLong Li  */
456dd45c0SLong Li 
556dd45c0SLong Li #include <ethdev_driver.h>
656dd45c0SLong Li #include <rte_io.h>
756dd45c0SLong Li 
856dd45c0SLong Li #include "mana.h"
956dd45c0SLong Li 
1056dd45c0SLong Li uint8_t *
gdma_get_wqe_pointer(struct mana_gdma_queue * queue)1156dd45c0SLong Li gdma_get_wqe_pointer(struct mana_gdma_queue *queue)
1256dd45c0SLong Li {
1356dd45c0SLong Li 	uint32_t offset_in_bytes =
1456dd45c0SLong Li 		(queue->head * GDMA_WQE_ALIGNMENT_UNIT_SIZE) &
1556dd45c0SLong Li 		(queue->size - 1);
1656dd45c0SLong Li 
17e2d3a3c0SLong Li 	DP_LOG(DEBUG, "txq sq_head %u sq_size %u offset_in_bytes %u",
1856dd45c0SLong Li 	       queue->head, queue->size, offset_in_bytes);
1956dd45c0SLong Li 
2056dd45c0SLong Li 	if (offset_in_bytes + GDMA_WQE_ALIGNMENT_UNIT_SIZE > queue->size)
21e2d3a3c0SLong Li 		DP_LOG(ERR, "fatal error: offset_in_bytes %u too big",
2256dd45c0SLong Li 		       offset_in_bytes);
2356dd45c0SLong Li 
2456dd45c0SLong Li 	return ((uint8_t *)queue->buffer) + offset_in_bytes;
2556dd45c0SLong Li }
2656dd45c0SLong Li 
2756dd45c0SLong Li static uint32_t
write_dma_client_oob(uint8_t * work_queue_buffer_pointer,const struct gdma_work_request * work_request,uint32_t client_oob_size)2856dd45c0SLong Li write_dma_client_oob(uint8_t *work_queue_buffer_pointer,
2956dd45c0SLong Li 		     const struct gdma_work_request *work_request,
3056dd45c0SLong Li 		     uint32_t client_oob_size)
3156dd45c0SLong Li {
3256dd45c0SLong Li 	uint8_t *p = work_queue_buffer_pointer;
3356dd45c0SLong Li 
3456dd45c0SLong Li 	struct gdma_wqe_dma_oob *header = (struct gdma_wqe_dma_oob *)p;
3556dd45c0SLong Li 
3656dd45c0SLong Li 	memset(header, 0, sizeof(struct gdma_wqe_dma_oob));
3756dd45c0SLong Li 	header->num_sgl_entries = work_request->num_sgl_elements;
3856dd45c0SLong Li 	header->inline_client_oob_size_in_dwords =
3956dd45c0SLong Li 		client_oob_size / sizeof(uint32_t);
4056dd45c0SLong Li 	header->client_data_unit = work_request->client_data_unit;
4156dd45c0SLong Li 
42e2d3a3c0SLong Li 	DP_LOG(DEBUG, "queue buf %p sgl %u oob_h %u du %u oob_buf %p oob_b %u",
4356dd45c0SLong Li 	       work_queue_buffer_pointer, header->num_sgl_entries,
4456dd45c0SLong Li 	       header->inline_client_oob_size_in_dwords,
4556dd45c0SLong Li 	       header->client_data_unit, work_request->inline_oob_data,
4656dd45c0SLong Li 	       work_request->inline_oob_size_in_bytes);
4756dd45c0SLong Li 
4856dd45c0SLong Li 	p += sizeof(struct gdma_wqe_dma_oob);
4956dd45c0SLong Li 	if (work_request->inline_oob_data &&
5056dd45c0SLong Li 	    work_request->inline_oob_size_in_bytes > 0) {
5156dd45c0SLong Li 		memcpy(p, work_request->inline_oob_data,
5256dd45c0SLong Li 		       work_request->inline_oob_size_in_bytes);
5356dd45c0SLong Li 		if (client_oob_size > work_request->inline_oob_size_in_bytes)
5456dd45c0SLong Li 			memset(p + work_request->inline_oob_size_in_bytes, 0,
5556dd45c0SLong Li 			       client_oob_size -
5656dd45c0SLong Li 			       work_request->inline_oob_size_in_bytes);
5756dd45c0SLong Li 	}
5856dd45c0SLong Li 
5956dd45c0SLong Li 	return sizeof(struct gdma_wqe_dma_oob) + client_oob_size;
6056dd45c0SLong Li }
6156dd45c0SLong Li 
6256dd45c0SLong Li static uint32_t
write_scatter_gather_list(uint8_t * work_queue_head_pointer,uint8_t * work_queue_end_pointer,uint8_t * work_queue_cur_pointer,struct gdma_work_request * work_request)6356dd45c0SLong Li write_scatter_gather_list(uint8_t *work_queue_head_pointer,
6456dd45c0SLong Li 			  uint8_t *work_queue_end_pointer,
6556dd45c0SLong Li 			  uint8_t *work_queue_cur_pointer,
6656dd45c0SLong Li 			  struct gdma_work_request *work_request)
6756dd45c0SLong Li {
6856dd45c0SLong Li 	struct gdma_sgl_element *sge_list;
6956dd45c0SLong Li 	struct gdma_sgl_element dummy_sgl[1];
7056dd45c0SLong Li 	uint8_t *address;
7156dd45c0SLong Li 	uint32_t size;
7256dd45c0SLong Li 	uint32_t num_sge;
7356dd45c0SLong Li 	uint32_t size_to_queue_end;
7456dd45c0SLong Li 	uint32_t sge_list_size;
7556dd45c0SLong Li 
76e2d3a3c0SLong Li 	DP_LOG(DEBUG, "work_queue_cur_pointer %p work_request->flags %x",
7756dd45c0SLong Li 	       work_queue_cur_pointer, work_request->flags);
7856dd45c0SLong Li 
7956dd45c0SLong Li 	num_sge = work_request->num_sgl_elements;
8056dd45c0SLong Li 	sge_list = work_request->sgl;
8156dd45c0SLong Li 	size_to_queue_end = (uint32_t)(work_queue_end_pointer -
8256dd45c0SLong Li 				       work_queue_cur_pointer);
8356dd45c0SLong Li 
8456dd45c0SLong Li 	if (num_sge == 0) {
8556dd45c0SLong Li 		/* Per spec, the case of an empty SGL should be handled as
8656dd45c0SLong Li 		 * follows to avoid corrupted WQE errors:
8756dd45c0SLong Li 		 * Write one dummy SGL entry
8856dd45c0SLong Li 		 * Set the address to 1, leave the rest as 0
8956dd45c0SLong Li 		 */
9056dd45c0SLong Li 		dummy_sgl[num_sge].address = 1;
9156dd45c0SLong Li 		dummy_sgl[num_sge].size = 0;
9256dd45c0SLong Li 		dummy_sgl[num_sge].memory_key = 0;
9356dd45c0SLong Li 		num_sge++;
9456dd45c0SLong Li 		sge_list = dummy_sgl;
9556dd45c0SLong Li 	}
9656dd45c0SLong Li 
9756dd45c0SLong Li 	sge_list_size = 0;
9856dd45c0SLong Li 	{
9956dd45c0SLong Li 		address = (uint8_t *)sge_list;
10056dd45c0SLong Li 		size = sizeof(struct gdma_sgl_element) * num_sge;
10156dd45c0SLong Li 		if (size_to_queue_end < size) {
10256dd45c0SLong Li 			memcpy(work_queue_cur_pointer, address,
10356dd45c0SLong Li 			       size_to_queue_end);
10456dd45c0SLong Li 			work_queue_cur_pointer = work_queue_head_pointer;
10556dd45c0SLong Li 			address += size_to_queue_end;
10656dd45c0SLong Li 			size -= size_to_queue_end;
10756dd45c0SLong Li 		}
10856dd45c0SLong Li 
10956dd45c0SLong Li 		memcpy(work_queue_cur_pointer, address, size);
11056dd45c0SLong Li 		sge_list_size = size;
11156dd45c0SLong Li 	}
11256dd45c0SLong Li 
113e2d3a3c0SLong Li 	DP_LOG(DEBUG, "sge %u address 0x%" PRIx64 " size %u key %u list_s %u",
11456dd45c0SLong Li 	       num_sge, sge_list->address, sge_list->size,
11556dd45c0SLong Li 	       sge_list->memory_key, sge_list_size);
11656dd45c0SLong Li 
11756dd45c0SLong Li 	return sge_list_size;
11856dd45c0SLong Li }
11956dd45c0SLong Li 
12056dd45c0SLong Li /*
12156dd45c0SLong Li  * Post a work request to queue.
12256dd45c0SLong Li  */
12356dd45c0SLong Li int
gdma_post_work_request(struct mana_gdma_queue * queue,struct gdma_work_request * work_req,uint32_t * wqe_size_in_bu)12456dd45c0SLong Li gdma_post_work_request(struct mana_gdma_queue *queue,
12556dd45c0SLong Li 		       struct gdma_work_request *work_req,
126b5dfcaecSLong Li 		       uint32_t *wqe_size_in_bu)
12756dd45c0SLong Li {
12856dd45c0SLong Li 	uint32_t client_oob_size =
12956dd45c0SLong Li 		work_req->inline_oob_size_in_bytes >
13056dd45c0SLong Li 				INLINE_OOB_SMALL_SIZE_IN_BYTES ?
13156dd45c0SLong Li 			INLINE_OOB_LARGE_SIZE_IN_BYTES :
13256dd45c0SLong Li 			INLINE_OOB_SMALL_SIZE_IN_BYTES;
13356dd45c0SLong Li 
13456dd45c0SLong Li 	uint32_t sgl_data_size = sizeof(struct gdma_sgl_element) *
13556dd45c0SLong Li 			RTE_MAX((uint32_t)1, work_req->num_sgl_elements);
13656dd45c0SLong Li 	uint32_t wqe_size =
13756dd45c0SLong Li 		RTE_ALIGN(sizeof(struct gdma_wqe_dma_oob) +
13856dd45c0SLong Li 				client_oob_size + sgl_data_size,
13956dd45c0SLong Li 			  GDMA_WQE_ALIGNMENT_UNIT_SIZE);
14056dd45c0SLong Li 	uint8_t *wq_buffer_pointer;
14156dd45c0SLong Li 	uint32_t queue_free_units = queue->count - (queue->head - queue->tail);
14256dd45c0SLong Li 
14356dd45c0SLong Li 	if (wqe_size / GDMA_WQE_ALIGNMENT_UNIT_SIZE > queue_free_units) {
144e2d3a3c0SLong Li 		DP_LOG(DEBUG, "WQE size %u queue count %u head %u tail %u",
14556dd45c0SLong Li 		       wqe_size, queue->count, queue->head, queue->tail);
14656dd45c0SLong Li 		return -EBUSY;
14756dd45c0SLong Li 	}
14856dd45c0SLong Li 
149e2d3a3c0SLong Li 	DP_LOG(DEBUG, "client_oob_size %u sgl_data_size %u wqe_size %u",
15056dd45c0SLong Li 	       client_oob_size, sgl_data_size, wqe_size);
15156dd45c0SLong Li 
152b5dfcaecSLong Li 	*wqe_size_in_bu = wqe_size / GDMA_WQE_ALIGNMENT_UNIT_SIZE;
15356dd45c0SLong Li 
15456dd45c0SLong Li 	wq_buffer_pointer = gdma_get_wqe_pointer(queue);
15556dd45c0SLong Li 	wq_buffer_pointer += write_dma_client_oob(wq_buffer_pointer, work_req,
15656dd45c0SLong Li 						  client_oob_size);
15756dd45c0SLong Li 	if (wq_buffer_pointer >= ((uint8_t *)queue->buffer) + queue->size)
15856dd45c0SLong Li 		wq_buffer_pointer -= queue->size;
15956dd45c0SLong Li 
16056dd45c0SLong Li 	write_scatter_gather_list((uint8_t *)queue->buffer,
16156dd45c0SLong Li 				  (uint8_t *)queue->buffer + queue->size,
16256dd45c0SLong Li 				  wq_buffer_pointer, work_req);
16356dd45c0SLong Li 
16456dd45c0SLong Li 	queue->head += wqe_size / GDMA_WQE_ALIGNMENT_UNIT_SIZE;
16556dd45c0SLong Li 
16656dd45c0SLong Li 	return 0;
16756dd45c0SLong Li }
16856dd45c0SLong Li 
169*26c6bdf3SWei Hu #ifdef RTE_ARCH_32
170*26c6bdf3SWei Hu union gdma_short_doorbell_entry {
171*26c6bdf3SWei Hu 	uint32_t     as_uint32;
172*26c6bdf3SWei Hu 
173*26c6bdf3SWei Hu 	struct {
174*26c6bdf3SWei Hu 		uint32_t tail_ptr_incr	: 16; /* Number of CQEs */
175*26c6bdf3SWei Hu 		uint32_t id		: 12;
176*26c6bdf3SWei Hu 		uint32_t reserved	: 3;
177*26c6bdf3SWei Hu 		uint32_t arm		: 1;
178*26c6bdf3SWei Hu 	} cq;
179*26c6bdf3SWei Hu 
180*26c6bdf3SWei Hu 	struct {
181*26c6bdf3SWei Hu 		uint32_t tail_ptr_incr	: 16; /* In number of bytes */
182*26c6bdf3SWei Hu 		uint32_t id		: 12;
183*26c6bdf3SWei Hu 		uint32_t reserved	: 4;
184*26c6bdf3SWei Hu 	} rq;
185*26c6bdf3SWei Hu 
186*26c6bdf3SWei Hu 	struct {
187*26c6bdf3SWei Hu 		uint32_t tail_ptr_incr	: 16; /* In number of bytes */
188*26c6bdf3SWei Hu 		uint32_t id		: 12;
189*26c6bdf3SWei Hu 		uint32_t reserved	: 4;
190*26c6bdf3SWei Hu 	} sq;
191*26c6bdf3SWei Hu 
192*26c6bdf3SWei Hu 	struct {
193*26c6bdf3SWei Hu 		uint32_t tail_ptr_incr	: 16; /* Number of EQEs */
194*26c6bdf3SWei Hu 		uint32_t id		: 12;
195*26c6bdf3SWei Hu 		uint32_t reserved	: 3;
196*26c6bdf3SWei Hu 		uint32_t arm		: 1;
197*26c6bdf3SWei Hu 	} eq;
198*26c6bdf3SWei Hu }; /* HW DATA */
199*26c6bdf3SWei Hu 
200*26c6bdf3SWei Hu enum {
201*26c6bdf3SWei Hu 	DOORBELL_SHORT_OFFSET_SQ = 0x10,
202*26c6bdf3SWei Hu 	DOORBELL_SHORT_OFFSET_RQ = 0x410,
203*26c6bdf3SWei Hu 	DOORBELL_SHORT_OFFSET_CQ = 0x810,
204*26c6bdf3SWei Hu 	DOORBELL_SHORT_OFFSET_EQ = 0xFF0,
205*26c6bdf3SWei Hu };
206*26c6bdf3SWei Hu 
207*26c6bdf3SWei Hu /*
208*26c6bdf3SWei Hu  * Write to hardware doorbell to notify new activity.
209*26c6bdf3SWei Hu  */
210*26c6bdf3SWei Hu int
mana_ring_short_doorbell(void * db_page,enum gdma_queue_types queue_type,uint32_t queue_id,uint32_t tail_incr,uint8_t arm)211*26c6bdf3SWei Hu mana_ring_short_doorbell(void *db_page, enum gdma_queue_types queue_type,
212*26c6bdf3SWei Hu 			 uint32_t queue_id, uint32_t tail_incr, uint8_t arm)
213*26c6bdf3SWei Hu {
214*26c6bdf3SWei Hu 	uint8_t *addr = db_page;
215*26c6bdf3SWei Hu 	union gdma_short_doorbell_entry e = {};
216*26c6bdf3SWei Hu 
217*26c6bdf3SWei Hu 	if ((queue_id & ~GDMA_SHORT_DB_QID_MASK) ||
218*26c6bdf3SWei Hu 	    (tail_incr & ~GDMA_SHORT_DB_INC_MASK)) {
219*26c6bdf3SWei Hu 		DP_LOG(ERR, "%s: queue_id %u or "
220*26c6bdf3SWei Hu 		       "tail_incr %u overflowed, queue type %d",
221*26c6bdf3SWei Hu 		       __func__, queue_id, tail_incr, queue_type);
222*26c6bdf3SWei Hu 		return -EINVAL;
223*26c6bdf3SWei Hu 	}
224*26c6bdf3SWei Hu 
225*26c6bdf3SWei Hu 	switch (queue_type) {
226*26c6bdf3SWei Hu 	case GDMA_QUEUE_SEND:
227*26c6bdf3SWei Hu 		e.sq.id = queue_id;
228*26c6bdf3SWei Hu 		e.sq.tail_ptr_incr = tail_incr;
229*26c6bdf3SWei Hu 		addr += DOORBELL_SHORT_OFFSET_SQ;
230*26c6bdf3SWei Hu 		break;
231*26c6bdf3SWei Hu 
232*26c6bdf3SWei Hu 	case GDMA_QUEUE_RECEIVE:
233*26c6bdf3SWei Hu 		e.rq.id = queue_id;
234*26c6bdf3SWei Hu 		e.rq.tail_ptr_incr = tail_incr;
235*26c6bdf3SWei Hu 		addr += DOORBELL_SHORT_OFFSET_RQ;
236*26c6bdf3SWei Hu 		break;
237*26c6bdf3SWei Hu 
238*26c6bdf3SWei Hu 	case GDMA_QUEUE_COMPLETION:
239*26c6bdf3SWei Hu 		e.cq.id = queue_id;
240*26c6bdf3SWei Hu 		e.cq.tail_ptr_incr = tail_incr;
241*26c6bdf3SWei Hu 		e.cq.arm = arm;
242*26c6bdf3SWei Hu 		addr += DOORBELL_SHORT_OFFSET_CQ;
243*26c6bdf3SWei Hu 		break;
244*26c6bdf3SWei Hu 
245*26c6bdf3SWei Hu 	default:
246*26c6bdf3SWei Hu 		DP_LOG(ERR, "Unsupported queue type %d", queue_type);
247*26c6bdf3SWei Hu 		return -1;
248*26c6bdf3SWei Hu 	}
249*26c6bdf3SWei Hu 
250*26c6bdf3SWei Hu 	/* Ensure all writes are done before ringing doorbell */
251*26c6bdf3SWei Hu 	rte_wmb();
252*26c6bdf3SWei Hu 
253*26c6bdf3SWei Hu 	DP_LOG(DEBUG, "db_page %p addr %p queue_id %u type %u tail %u arm %u",
254*26c6bdf3SWei Hu 	       db_page, addr, queue_id, queue_type, tail_incr, arm);
255*26c6bdf3SWei Hu 
256*26c6bdf3SWei Hu 	rte_write32(e.as_uint32, addr);
257*26c6bdf3SWei Hu 	return 0;
258*26c6bdf3SWei Hu }
259*26c6bdf3SWei Hu #else
26056dd45c0SLong Li union gdma_doorbell_entry {
26156dd45c0SLong Li 	uint64_t     as_uint64;
26256dd45c0SLong Li 
26356dd45c0SLong Li 	struct {
26456dd45c0SLong Li 		uint64_t id	  : 24;
26556dd45c0SLong Li 		uint64_t reserved    : 8;
26656dd45c0SLong Li 		uint64_t tail_ptr    : 31;
26756dd45c0SLong Li 		uint64_t arm	 : 1;
26856dd45c0SLong Li 	} cq;
26956dd45c0SLong Li 
27056dd45c0SLong Li 	struct {
27156dd45c0SLong Li 		uint64_t id	  : 24;
27256dd45c0SLong Li 		uint64_t wqe_cnt     : 8;
27356dd45c0SLong Li 		uint64_t tail_ptr    : 32;
27456dd45c0SLong Li 	} rq;
27556dd45c0SLong Li 
27656dd45c0SLong Li 	struct {
27756dd45c0SLong Li 		uint64_t id	  : 24;
27856dd45c0SLong Li 		uint64_t reserved    : 8;
27956dd45c0SLong Li 		uint64_t tail_ptr    : 32;
28056dd45c0SLong Li 	} sq;
28156dd45c0SLong Li 
28256dd45c0SLong Li 	struct {
28356dd45c0SLong Li 		uint64_t id	  : 16;
28456dd45c0SLong Li 		uint64_t reserved    : 16;
28556dd45c0SLong Li 		uint64_t tail_ptr    : 31;
28656dd45c0SLong Li 		uint64_t arm	 : 1;
28756dd45c0SLong Li 	} eq;
28856dd45c0SLong Li }; /* HW DATA */
28956dd45c0SLong Li 
29056dd45c0SLong Li enum {
29156dd45c0SLong Li 	DOORBELL_OFFSET_SQ = 0x0,
29256dd45c0SLong Li 	DOORBELL_OFFSET_RQ = 0x400,
29356dd45c0SLong Li 	DOORBELL_OFFSET_CQ = 0x800,
29456dd45c0SLong Li 	DOORBELL_OFFSET_EQ = 0xFF8,
29556dd45c0SLong Li };
29656dd45c0SLong Li 
29756dd45c0SLong Li /*
29856dd45c0SLong Li  * Write to hardware doorbell to notify new activity.
29956dd45c0SLong Li  */
30056dd45c0SLong Li int
mana_ring_doorbell(void * db_page,enum gdma_queue_types queue_type,uint32_t queue_id,uint32_t tail,uint8_t arm)30156dd45c0SLong Li mana_ring_doorbell(void *db_page, enum gdma_queue_types queue_type,
302afd5d170SLong Li 		   uint32_t queue_id, uint32_t tail, uint8_t arm)
30356dd45c0SLong Li {
30456dd45c0SLong Li 	uint8_t *addr = db_page;
30556dd45c0SLong Li 	union gdma_doorbell_entry e = {};
30656dd45c0SLong Li 
30756dd45c0SLong Li 	switch (queue_type) {
30856dd45c0SLong Li 	case GDMA_QUEUE_SEND:
30956dd45c0SLong Li 		e.sq.id = queue_id;
31056dd45c0SLong Li 		e.sq.tail_ptr = tail;
31156dd45c0SLong Li 		addr += DOORBELL_OFFSET_SQ;
31256dd45c0SLong Li 		break;
31356dd45c0SLong Li 
31456dd45c0SLong Li 	case GDMA_QUEUE_RECEIVE:
31556dd45c0SLong Li 		e.rq.id = queue_id;
31656dd45c0SLong Li 		e.rq.tail_ptr = tail;
317afd5d170SLong Li 		e.rq.wqe_cnt = arm;
31856dd45c0SLong Li 		addr += DOORBELL_OFFSET_RQ;
31956dd45c0SLong Li 		break;
32056dd45c0SLong Li 
32156dd45c0SLong Li 	case GDMA_QUEUE_COMPLETION:
32256dd45c0SLong Li 		e.cq.id = queue_id;
32356dd45c0SLong Li 		e.cq.tail_ptr = tail;
324afd5d170SLong Li 		e.cq.arm = arm;
32556dd45c0SLong Li 		addr += DOORBELL_OFFSET_CQ;
32656dd45c0SLong Li 		break;
32756dd45c0SLong Li 
32856dd45c0SLong Li 	default:
329e2d3a3c0SLong Li 		DP_LOG(ERR, "Unsupported queue type %d", queue_type);
33056dd45c0SLong Li 		return -1;
33156dd45c0SLong Li 	}
33256dd45c0SLong Li 
33356dd45c0SLong Li 	/* Ensure all writes are done before ringing doorbell */
33456dd45c0SLong Li 	rte_wmb();
33556dd45c0SLong Li 
336e2d3a3c0SLong Li 	DP_LOG(DEBUG, "db_page %p addr %p queue_id %u type %u tail %u arm %u",
337afd5d170SLong Li 	       db_page, addr, queue_id, queue_type, tail, arm);
33856dd45c0SLong Li 
33956dd45c0SLong Li 	rte_write64(e.as_uint64, addr);
34056dd45c0SLong Li 	return 0;
34156dd45c0SLong Li }
342*26c6bdf3SWei Hu #endif
34356dd45c0SLong Li 
34456dd45c0SLong Li /*
34556dd45c0SLong Li  * Poll completion queue for completions.
34656dd45c0SLong Li  */
34731124619SLong Li uint32_t
gdma_poll_completion_queue(struct mana_gdma_queue * cq,struct gdma_comp * gdma_comp,uint32_t max_comp)34831124619SLong Li gdma_poll_completion_queue(struct mana_gdma_queue *cq,
34931124619SLong Li 			   struct gdma_comp *gdma_comp, uint32_t max_comp)
35056dd45c0SLong Li {
35156dd45c0SLong Li 	struct gdma_hardware_completion_entry *cqe;
35256dd45c0SLong Li 	uint32_t new_owner_bits, old_owner_bits;
35356dd45c0SLong Li 	uint32_t cqe_owner_bits;
35431124619SLong Li 	uint32_t num_comp = 0;
35556dd45c0SLong Li 	struct gdma_hardware_completion_entry *buffer = cq->buffer;
35656dd45c0SLong Li 
35731124619SLong Li 	while (num_comp < max_comp) {
35831124619SLong Li 		cqe = &buffer[cq->head % cq->count];
35931124619SLong Li 		new_owner_bits = (cq->head / cq->count) &
36031124619SLong Li 					COMPLETION_QUEUE_OWNER_MASK;
36156dd45c0SLong Li 		old_owner_bits = (cq->head / cq->count - 1) &
36256dd45c0SLong Li 					COMPLETION_QUEUE_OWNER_MASK;
36356dd45c0SLong Li 		cqe_owner_bits = cqe->owner_bits;
36456dd45c0SLong Li 
365e2d3a3c0SLong Li 		DP_LOG(DEBUG, "comp cqe bits 0x%x owner bits 0x%x",
36656dd45c0SLong Li 			cqe_owner_bits, old_owner_bits);
36756dd45c0SLong Li 
36831124619SLong Li 		/* No new entry */
36956dd45c0SLong Li 		if (cqe_owner_bits == old_owner_bits)
37031124619SLong Li 			break;
37156dd45c0SLong Li 
37256dd45c0SLong Li 		if (cqe_owner_bits != new_owner_bits) {
37331124619SLong Li 			DRV_LOG(ERR, "CQ overflowed, ID %u cqe 0x%x new 0x%x",
37456dd45c0SLong Li 				cq->id, cqe_owner_bits, new_owner_bits);
37531124619SLong Li 			break;
37656dd45c0SLong Li 		}
37756dd45c0SLong Li 
37831124619SLong Li 		gdma_comp[num_comp].cqe_data = cqe->dma_client_data;
37931124619SLong Li 		num_comp++;
38056dd45c0SLong Li 
38156dd45c0SLong Li 		cq->head++;
38256dd45c0SLong Li 
383e2d3a3c0SLong Li 		DP_LOG(DEBUG, "comp new 0x%x old 0x%x cqe 0x%x wq %u sq %u head %u",
38456dd45c0SLong Li 		       new_owner_bits, old_owner_bits, cqe_owner_bits,
38531124619SLong Li 		       cqe->wq_num, cqe->is_sq, cq->head);
38631124619SLong Li 	}
38731124619SLong Li 
38831124619SLong Li 	/* Make sure the CQE owner bits are checked before we access the data
38931124619SLong Li 	 * in CQE
39031124619SLong Li 	 */
39131124619SLong Li 	rte_rmb();
39231124619SLong Li 
39331124619SLong Li 	return num_comp;
39456dd45c0SLong Li }
395