xref: /freebsd/sys/contrib/alpine-hal/al_hal_udma.h (revision 273c26a3c3bea87a241d6879abd4f991db180bf0)
1 /*-
2 *******************************************************************************
3 Copyright (C) 2015 Annapurna Labs Ltd.
4 
5 This file may be licensed under the terms of the Annapurna Labs Commercial
6 License Agreement.
7 
8 Alternatively, this file can be distributed under the terms of the GNU General
9 Public License V2 as published by the Free Software Foundation and can be
10 found at http://www.gnu.org/licenses/gpl-2.0.html
11 
12 Alternatively, redistribution and use in source and binary forms, with or
13 without modification, are permitted provided that the following conditions are
14 met:
15 
16     *     Redistributions of source code must retain the above copyright notice,
17 this list of conditions and the following disclaimer.
18 
19     *     Redistributions in binary form must reproduce the above copyright
20 notice, this list of conditions and the following disclaimer in
21 the documentation and/or other materials provided with the
22 distribution.
23 
24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
28 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 
35 *******************************************************************************/
36 
37 /**
38  * @defgroup group_udma_api API
39  * @ingroup group_udma
40  * UDMA API
41  * @{
42  * @}
43  *
44  * @defgroup group_udma_main UDMA Main
45  * @ingroup group_udma_api
46  * UDMA main API
47  * @{
48  * @file   al_hal_udma.h
49  *
50  * @brief C Header file for the Universal DMA HAL driver
51  *
52  */
53 
54 #ifndef __AL_HAL_UDMA_H__
55 #define __AL_HAL_UDMA_H__
56 
57 #include "al_hal_common.h"
58 #include "al_hal_udma_regs.h"
59 
60 /* *INDENT-OFF* */
61 #ifdef __cplusplus
62 extern "C" {
63 #endif
64 /* *INDENT-ON* */
65 
66 #define DMA_MAX_Q 	4
67 #define AL_UDMA_MIN_Q_SIZE 	4
68 #define AL_UDMA_MAX_Q_SIZE 	(1 << 16) /* hw can do more, but we limit it */
69 
70 /* Default Max number of descriptors supported per action */
71 #define AL_UDMA_DEFAULT_MAX_ACTN_DESCS	16
72 
73 #define AL_UDMA_REV_ID_1	1
74 #define AL_UDMA_REV_ID_2	2
75 
76 #define DMA_RING_ID_MASK	0x3
77 /* New registers ?? */
78 /* Statistics - TBD */
79 
80 /** UDMA submission descriptor */
81 union al_udma_desc {
82 	/* TX */
83 	struct {
84 		uint32_t len_ctrl;
85 		uint32_t meta_ctrl;
86 		uint64_t buf_ptr;
87 	} tx;
88 	/* TX Meta, used by upper layer */
89 	struct {
90 		uint32_t len_ctrl;
91 		uint32_t meta_ctrl;
92 		uint32_t meta1;
93 		uint32_t meta2;
94 	} tx_meta;
95 	/* RX */
96 	struct {
97 		uint32_t len_ctrl;
98 		uint32_t buf2_ptr_lo;
99 		uint64_t buf1_ptr;
100 	} rx;
101 } __packed_a16;
102 
103 /* TX desc length and control fields */
104 
105 #define AL_M2S_DESC_CONCAT			AL_BIT(31)	/* concatenate */
106 #define AL_M2S_DESC_DMB				AL_BIT(30)
107 						/** Data Memory Barrier */
108 #define AL_M2S_DESC_NO_SNOOP_H			AL_BIT(29)
109 #define AL_M2S_DESC_INT_EN			AL_BIT(28)	/** enable interrupt */
110 #define AL_M2S_DESC_LAST			AL_BIT(27)
111 #define AL_M2S_DESC_FIRST			AL_BIT(26)
112 #define AL_M2S_DESC_RING_ID_SHIFT		24
113 #define AL_M2S_DESC_RING_ID_MASK		(0x3 << AL_M2S_DESC_RING_ID_SHIFT)
114 #define AL_M2S_DESC_META_DATA			AL_BIT(23)
115 #define AL_M2S_DESC_DUMMY			AL_BIT(22) /* for Metdata only */
116 #define AL_M2S_DESC_LEN_ADJ_SHIFT		20
117 #define AL_M2S_DESC_LEN_ADJ_MASK		(0x7 << AL_M2S_DESC_LEN_ADJ_SHIFT)
118 #define AL_M2S_DESC_LEN_SHIFT			0
119 #define AL_M2S_DESC_LEN_MASK			(0xfffff << AL_M2S_DESC_LEN_SHIFT)
120 
121 #define AL_S2M_DESC_DUAL_BUF			AL_BIT(31)
122 #define AL_S2M_DESC_NO_SNOOP_H			AL_BIT(29)
123 #define AL_S2M_DESC_INT_EN			AL_BIT(28)	/** enable interrupt */
124 #define AL_S2M_DESC_RING_ID_SHIFT		24
125 #define AL_S2M_DESC_RING_ID_MASK		(0x3 << AL_S2M_DESC_RING_ID_SHIFT)
126 #define AL_S2M_DESC_LEN_SHIFT			0
127 #define AL_S2M_DESC_LEN_MASK			(0xffff << AL_S2M_DESC_LEN_SHIFT)
128 #define AL_S2M_DESC_LEN2_SHIFT			16
129 #define AL_S2M_DESC_LEN2_MASK			(0x3fff << AL_S2M_DESC_LEN2_SHIFT)
130 #define AL_S2M_DESC_LEN2_GRANULARITY_SHIFT	6
131 
132 /* TX/RX descriptor Target-ID field (in the buffer address 64 bit field) */
133 #define AL_UDMA_DESC_TGTID_SHIFT		48
134 
135 /** UDMA completion descriptor */
136 union al_udma_cdesc {
137 	/* TX completion */
138 	struct {
139 		uint32_t ctrl_meta;
140 	} al_desc_comp_tx;
141 	/* RX completion */
142 	struct {
143 		/* TBD */
144 		uint32_t ctrl_meta;
145 	} al_desc_comp_rx;
146 } __packed_a4;
147 
148 /* TX/RX common completion desc ctrl_meta feilds */
149 #define AL_UDMA_CDESC_ERROR		AL_BIT(31)
150 #define AL_UDMA_CDESC_BUF1_USED		AL_BIT(30)
151 #define AL_UDMA_CDESC_DDP		AL_BIT(29)
152 #define AL_UDMA_CDESC_LAST		AL_BIT(27)
153 #define AL_UDMA_CDESC_FIRST		AL_BIT(26)
154 /* word 2 */
155 #define AL_UDMA_CDESC_BUF2_USED			AL_BIT(31)
156 #define AL_UDMA_CDESC_BUF2_LEN_SHIFT	16
157 #define AL_UDMA_CDESC_BUF2_LEN_MASK		AL_FIELD_MASK(29, 16)
158 /** Basic Buffer structure */
159 struct al_buf {
160 	al_phys_addr_t addr; /**< Buffer physical address */
161 	uint32_t len; /**< Buffer lenght in bytes */
162 };
163 
164 /** Block is a set of buffers that belong to same source or destination */
165 struct al_block {
166 	struct al_buf *bufs; /**< The buffers of the block */
167 	uint32_t num; /**< Number of buffers of the block */
168 
169 	/**<
170 	 * Target-ID to be assigned to the block descriptors
171 	 * Requires Target-ID in descriptor to be enabled for the specific UDMA
172 	 * queue.
173 	 */
174 	uint16_t tgtid;
175 };
176 
177 /** UDMA type */
178 enum al_udma_type {
179 	UDMA_TX,
180 	UDMA_RX
181 };
182 
183 /** UDMA state */
184 enum al_udma_state {
185 	UDMA_DISABLE = 0,
186 	UDMA_IDLE,
187 	UDMA_NORMAL,
188 	UDMA_ABORT,
189 	UDMA_RESET
190 };
191 
192 extern const char *const al_udma_states_name[];
193 
194 /** UDMA Q specific parameters from upper layer */
195 struct al_udma_q_params {
196 	uint32_t size;		/**< ring size (in descriptors), submission and
197 				 * completion rings must have same size
198 				 */
199 	union al_udma_desc *desc_base; /**< cpu address for submission ring
200 					 * descriptors
201 					 */
202 	al_phys_addr_t desc_phy_base;	/**< submission ring descriptors
203 					 * physical base address
204 					 */
205 #ifdef __FreeBSD__
206 	bus_dma_tag_t desc_phy_base_tag;
207 	bus_dmamap_t desc_phy_base_map;
208 #endif
209 	uint8_t *cdesc_base;	/**< completion descriptors pointer, NULL */
210 				/* means no completion update */
211 	al_phys_addr_t cdesc_phy_base;	/**< completion descriptors ring
212 					 * physical base address
213 					 */
214 #ifdef __FreeBSD__
215 	bus_dma_tag_t cdesc_phy_base_tag;
216 	bus_dmamap_t cdesc_phy_base_map;
217 #endif
218 	uint32_t cdesc_size;	/**< size (in bytes) of a single dma completion
219 					* descriptor
220 					*/
221 
222 	uint8_t adapter_rev_id; /**<PCI adapter revision ID */
223 };
224 
225 /** UDMA parameters from upper layer */
226 struct al_udma_params {
227 	struct unit_regs __iomem *udma_regs_base;
228 	enum al_udma_type type;	/**< Tx or Rx */
229 	uint8_t num_of_queues; /**< number of queues supported by the UDMA */
230 	const char *name; /**< the upper layer must keep the string area */
231 };
232 
233 /* Fordward decleration */
234 struct al_udma;
235 
236 /** SW status of a queue */
237 enum al_udma_queue_status {
238 	AL_QUEUE_NOT_INITIALIZED = 0,
239 	AL_QUEUE_DISABLED,
240 	AL_QUEUE_ENABLED,
241 	AL_QUEUE_ABORTED
242 };
243 
244 /** UDMA Queue private data structure */
245 struct __cache_aligned al_udma_q {
246 	uint16_t size_mask;		/**< mask used for pointers wrap around
247 					 * equals to size - 1
248 					 */
249 	union udma_q_regs __iomem *q_regs; /**< pointer to the per queue UDMA
250 					   * registers
251 					   */
252 	union al_udma_desc *desc_base_ptr; /**< base address submission ring
253 						* descriptors
254 						*/
255 	uint16_t next_desc_idx; /**< index to the next available submission
256 				      * descriptor
257 				      */
258 
259 	uint32_t desc_ring_id;	/**< current submission ring id */
260 
261 	uint8_t *cdesc_base_ptr;/**< completion descriptors pointer, NULL */
262 				/* means no completion */
263 	uint32_t cdesc_size;	/**< size (in bytes) of the udma completion ring
264 				 * descriptor
265 				 */
266 	uint16_t next_cdesc_idx; /**< index in descriptors for next completing
267 			      * ring descriptor
268 			      */
269 	uint8_t *end_cdesc_ptr;	/**< used for wrap around detection */
270 	uint16_t comp_head_idx; /**< completion ring head pointer register
271 				 *shadow
272 				 */
273 	volatile union al_udma_cdesc *comp_head_ptr; /**< when working in get_packet mode
274 				       * we maintain pointer instead of the
275 				       * above idx
276 				       */
277 
278 	uint32_t pkt_crnt_descs; /**< holds the number of processed descriptors
279 				  * of the current packet
280 				  */
281 	uint32_t comp_ring_id;	/**< current completion Ring Id */
282 
283 
284 	al_phys_addr_t desc_phy_base; /**< submission desc. physical base */
285 	al_phys_addr_t cdesc_phy_base; /**< completion desc. physical base */
286 
287 	uint32_t flags; /**< flags used for completion modes */
288 	uint32_t size;		/**< ring size in descriptors  */
289 	enum al_udma_queue_status status;
290 	struct al_udma *udma;	/**< pointer to parent UDMA */
291 	uint32_t qid;		/**< the index number of the queue */
292 
293 	/*
294 	 * The following fields are duplicated from the UDMA parent adapter
295 	 * due to performance considerations.
296 	 */
297 	uint8_t adapter_rev_id; /**<PCI adapter revision ID */
298 };
299 
300 /* UDMA */
301 struct al_udma {
302 	const char *name;
303 	enum al_udma_type type;	/* Tx or Rx */
304 	enum al_udma_state state;
305 	uint8_t num_of_queues; /* number of queues supported by the UDMA */
306 	union udma_regs __iomem *udma_regs; /* pointer to the UDMA registers */
307 	struct udma_gen_regs *gen_regs;		/* pointer to the Gen registers*/
308 	struct al_udma_q udma_q[DMA_MAX_Q];	/* Array of UDMA Qs pointers */
309 	unsigned int rev_id; /* UDMA revision ID */
310 };
311 
312 
313 /*
314  * Configurations
315  */
316 
317 /* Initializations functions */
318 /**
319  * Initialize the udma engine
320  *
321  * @param udma udma data structure
322  * @param udma_params udma parameters from upper layer
323  *
324  * @return 0 on success. -EINVAL otherwise.
325  */
326 int al_udma_init(struct al_udma *udma, struct al_udma_params *udma_params);
327 
328 /**
329  * Initialize the udma queue data structure
330  *
331  * @param udma
332  * @param qid
333  * @param q_params
334  *
335  * @return 0 if no error found.
336  *	   -EINVAL if the qid is out of range
337  *	   -EIO if queue was already initialized
338  */
339 
340 int al_udma_q_init(struct al_udma *udma, uint32_t qid,
341 		   struct al_udma_q_params *q_params);
342 
343 /**
344  * Reset a udma queue
345  *
346  * Prior to calling this function make sure:
347  * 1. Queue interrupts are masked
348  * 2. No additional descriptors are written to the descriptor ring of the queue
349  * 3. No completed descriptors are being fetched
350  *
351  * The queue can be initialized again using 'al_udma_q_init'
352  *
353  * @param udma_q
354  *
355  * @return 0 if no error found.
356  */
357 
358 int al_udma_q_reset(struct al_udma_q *udma_q);
359 
360 /**
361  * return (by reference) a pointer to a specific queue date structure.
362  * this pointer needed for calling functions (i.e. al_udma_desc_action_add) that
363  * require this pointer as input argument.
364  *
365  * @param udma udma data structure
366  * @param qid queue index
367  * @param q_handle pointer to the location where the queue structure pointer
368  * written to.
369  *
370  * @return  0 on success. -EINVAL otherwise.
371  */
372 int al_udma_q_handle_get(struct al_udma *udma, uint32_t qid,
373 		      struct al_udma_q **q_handle);
374 
375 /**
376  * Change the UDMA's state
377  *
378  * @param udma udma data structure
379  * @param state the target state
380  *
381  * @return 0
382  */
383 int al_udma_state_set(struct al_udma *udma, enum al_udma_state state);
384 
385 /**
386  * return the current UDMA hardware state
387  *
388  * @param udma udma handle
389  *
390  * @return the UDMA state as reported by the hardware.
391  */
392 enum al_udma_state al_udma_state_get(struct al_udma *udma);
393 
394 /*
395  * Action handling
396  */
397 
398 /**
399  * get number of descriptors that can be submitted to the udma.
400  * keep one free descriptor to simplify full/empty management
401  * @param udma_q queue handle
402  *
403  * @return num of free descriptors.
404  */
405 static INLINE uint32_t al_udma_available_get(struct al_udma_q *udma_q)
406 {
407 	uint16_t tmp = udma_q->next_cdesc_idx - (udma_q->next_desc_idx + 1);
408 	tmp &= udma_q->size_mask;
409 
410 	return (uint32_t) tmp;
411 }
412 
413 /**
414  * check if queue has pending descriptors
415  *
416  * @param udma_q queue handle
417  *
418  * @return AL_TRUE if descriptors are submitted to completion ring and still
419  * not completed (with ack). AL_FALSE otherwise.
420  */
421 static INLINE al_bool al_udma_is_empty(struct al_udma_q *udma_q)
422 {
423 	if (((udma_q->next_cdesc_idx - udma_q->next_desc_idx) &
424 	     udma_q->size_mask) == 0)
425 		return AL_TRUE;
426 
427 	return AL_FALSE;
428 }
429 
430 /**
431  * get next available descriptor
432  * @param udma_q queue handle
433  *
434  * @return pointer to the next available descriptor
435  */
436 static INLINE union al_udma_desc *al_udma_desc_get(struct al_udma_q *udma_q)
437 {
438 	union al_udma_desc *desc;
439 	uint16_t next_desc_idx;
440 
441 	al_assert(udma_q);
442 
443 	next_desc_idx = udma_q->next_desc_idx;
444 	desc = udma_q->desc_base_ptr + next_desc_idx;
445 
446 	next_desc_idx++;
447 
448 	/* if reached end of queue, wrap around */
449 	udma_q->next_desc_idx = next_desc_idx & udma_q->size_mask;
450 
451 	return desc;
452 }
453 
454 /**
455  * get ring id for the last allocated descriptor
456  * @param udma_q
457  *
458  * @return ring id for the last allocated descriptor
459  * this function must be called each time a new descriptor is allocated
460  * by the al_udma_desc_get(), unless ring id is ignored.
461  */
462 static INLINE uint32_t al_udma_ring_id_get(struct al_udma_q *udma_q)
463 {
464 	uint32_t ring_id;
465 
466 	al_assert(udma_q);
467 
468 	ring_id = udma_q->desc_ring_id;
469 
470 	/* calculate the ring id of the next desc */
471 	/* if next_desc points to first desc, then queue wrapped around */
472 	if (unlikely(udma_q->next_desc_idx) == 0)
473 		udma_q->desc_ring_id = (udma_q->desc_ring_id + 1) &
474 			DMA_RING_ID_MASK;
475 	return ring_id;
476 }
477 
478 /* add DMA action - trigger the engine */
479 /**
480  * add num descriptors to the submission queue.
481  *
482  * @param udma_q queue handle
483  * @param num number of descriptors to add to the queues ring.
484  *
485  * @return 0;
486  */
487 static INLINE int al_udma_desc_action_add(struct al_udma_q *udma_q,
488 					  uint32_t num)
489 {
490 	uint32_t *addr;
491 
492 	al_assert(udma_q);
493 	al_assert((num > 0) && (num <= udma_q->size));
494 
495 	addr = &udma_q->q_regs->rings.drtp_inc;
496 	/* make sure data written to the descriptors will be visible by the */
497 	/* DMA */
498 	al_local_data_memory_barrier();
499 
500 	/*
501 	 * As we explicitly invoke the synchronization function
502 	 * (al_data_memory_barrier()), then we can use the relaxed version.
503 	 */
504 	al_reg_write32_relaxed(addr, num);
505 
506 	return 0;
507 }
508 
509 #define cdesc_is_first(flags) ((flags) & AL_UDMA_CDESC_FIRST)
510 #define cdesc_is_last(flags) ((flags) & AL_UDMA_CDESC_LAST)
511 
512 /**
513  * return pointer to the cdesc + offset desciptors. wrap around when needed.
514  *
515  * @param udma_q queue handle
516  * @param cdesc pointer that set by this function
517  * @param offset offset desciptors
518  *
519  */
520 static INLINE volatile union al_udma_cdesc *al_cdesc_next(
521 	struct al_udma_q		*udma_q,
522 	volatile union al_udma_cdesc	*cdesc,
523 	uint32_t			offset)
524 {
525 	volatile uint8_t *tmp = (volatile uint8_t *) cdesc + offset * udma_q->cdesc_size;
526 	al_assert(udma_q);
527 	al_assert(cdesc);
528 
529 	/* if wrap around */
530 	if (unlikely((tmp > udma_q->end_cdesc_ptr)))
531 		return (union al_udma_cdesc *)
532 			(udma_q->cdesc_base_ptr +
533 			(tmp - udma_q->end_cdesc_ptr - udma_q->cdesc_size));
534 
535 	return (volatile union al_udma_cdesc *) tmp;
536 }
537 
538 /**
539  * check if the flags of the descriptor indicates that is new one
540  * the function uses the ring id from the descriptor flags to know whether it
541  * new one by comparing it with the curring ring id of the queue
542  *
543  * @param udma_q queue handle
544  * @param flags the flags of the completion descriptor
545  *
546  * @return AL_TRUE if the completion descriptor is new one.
547  * 	AL_FALSE if it old one.
548  */
549 static INLINE al_bool al_udma_new_cdesc(struct al_udma_q *udma_q,
550 								uint32_t flags)
551 {
552 	if (((flags & AL_M2S_DESC_RING_ID_MASK) >> AL_M2S_DESC_RING_ID_SHIFT)
553 	    == udma_q->comp_ring_id)
554 		return AL_TRUE;
555 	return AL_FALSE;
556 }
557 
558 /**
559  * get next completion descriptor
560  * this function will also increment the completion ring id when the ring wraps
561  * around
562  *
563  * @param udma_q queue handle
564  * @param cdesc current completion descriptor
565  *
566  * @return pointer to the completion descriptor that follows the one pointed by
567  * cdesc
568  */
569 static INLINE volatile union al_udma_cdesc *al_cdesc_next_update(
570 	struct al_udma_q		*udma_q,
571 	volatile union al_udma_cdesc	*cdesc)
572 {
573 	/* if last desc, wrap around */
574 	if (unlikely(((volatile uint8_t *) cdesc == udma_q->end_cdesc_ptr))) {
575 		udma_q->comp_ring_id =
576 		    (udma_q->comp_ring_id + 1) & DMA_RING_ID_MASK;
577 		return (union al_udma_cdesc *) udma_q->cdesc_base_ptr;
578 	}
579 	return (volatile union al_udma_cdesc *) ((volatile uint8_t *) cdesc + udma_q->cdesc_size);
580 }
581 
582 /**
583  * get next completed packet from completion ring of the queue
584  *
585  * @param udma_q udma queue handle
586  * @param desc pointer that set by this function to the first descriptor
587  * note: desc is valid only when return value is not zero
588  * @return number of descriptors that belong to the packet. 0 means no completed
589  * full packet was found.
590  * If the descriptors found in the completion queue don't form full packet (no
591  * desc with LAST flag), then this function will do the following:
592  * (1) save the number of processed descriptors.
593  * (2) save last processed descriptor, so next time it called, it will resume
594  *     from there.
595  * (3) return 0.
596  * note: the descriptors that belong to the completed packet will still be
597  * considered as used, that means the upper layer is safe to access those
598  * descriptors when this function returns. the al_udma_cdesc_ack() should be
599  * called to inform the udma driver that those descriptors are freed.
600  */
601 uint32_t al_udma_cdesc_packet_get(
602 	struct al_udma_q		*udma_q,
603 	volatile union al_udma_cdesc	**desc);
604 
605 /** get completion descriptor pointer from its index */
606 #define al_udma_cdesc_idx_to_ptr(udma_q, idx)				\
607 	((volatile union al_udma_cdesc *) ((udma_q)->cdesc_base_ptr +	\
608 				(idx) * (udma_q)->cdesc_size))
609 
610 
611 /**
612  * return number of all completed descriptors in the completion ring
613  *
614  * @param udma_q udma queue handle
615  * @param cdesc pointer that set by this function to the first descriptor
616  * note: desc is valid only when return value is not zero
617  * note: pass NULL if not interested
618  * @return number of descriptors. 0 means no completed descriptors were found.
619  * note: the descriptors that belong to the completed packet will still be
620  * considered as used, that means the upper layer is safe to access those
621  * descriptors when this function returns. the al_udma_cdesc_ack() should be
622  * called to inform the udma driver that those descriptors are freed.
623  */
624 static INLINE uint32_t al_udma_cdesc_get_all(
625 	struct al_udma_q		*udma_q,
626 	volatile union al_udma_cdesc	**cdesc)
627 {
628 	uint16_t count = 0;
629 
630 	al_assert(udma_q);
631 
632 	udma_q->comp_head_idx = (uint16_t)
633 				(al_reg_read32(&udma_q->q_regs->rings.crhp) &
634 						0xFFFF);
635 
636 	count = (udma_q->comp_head_idx - udma_q->next_cdesc_idx) &
637 		udma_q->size_mask;
638 
639 	if (cdesc)
640 		*cdesc = al_udma_cdesc_idx_to_ptr(udma_q, udma_q->next_cdesc_idx);
641 
642 	return (uint32_t)count;
643 }
644 
645 /**
646  * acknowledge the driver that the upper layer completed processing completion
647  * descriptors
648  *
649  * @param udma_q udma queue handle
650  * @param num number of descriptors to acknowledge
651  *
652  * @return 0
653  */
654 static INLINE int al_udma_cdesc_ack(struct al_udma_q *udma_q, uint32_t num)
655 {
656 	al_assert(udma_q);
657 
658 	udma_q->next_cdesc_idx += num;
659 	udma_q->next_cdesc_idx &= udma_q->size_mask;
660 
661 	return 0;
662 }
663 
664 /* *INDENT-OFF* */
665 #ifdef __cplusplus
666 }
667 #endif
668 /* *INDENT-ON* */
669 
670 #endif /* __AL_HAL_UDMA_H__ */
671 /** @} end of UDMA group */
672