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 * @{
39 * @file al_hal_udma_main.c
40 *
41 * @brief Universal DMA HAL driver for main functions (initialization, data path)
42 *
43 */
44
45 #include <al_hal_udma.h>
46 #include <al_hal_udma_config.h>
47
48 #define AL_UDMA_Q_RST_TOUT 10000 /* Queue reset timeout [uSecs] */
49
50 #define UDMA_STATE_IDLE 0x0
51 #define UDMA_STATE_NORMAL 0x1
52 #define UDMA_STATE_ABORT 0x2
53 #define UDMA_STATE_RESERVED 0x3
54
55 const char *const al_udma_states_name[] = {
56 "Disable",
57 "Idle",
58 "Normal",
59 "Abort",
60 "Reset"
61 };
62
63 #define AL_UDMA_INITIAL_RING_ID 1
64
65 /* dma_q flags */
66 #define AL_UDMA_Q_FLAGS_IGNORE_RING_ID AL_BIT(0)
67 #define AL_UDMA_Q_FLAGS_NO_COMP_UPDATE AL_BIT(1)
68 #define AL_UDMA_Q_FLAGS_EN_COMP_COAL AL_BIT(2)
69
70
al_udma_set_defaults(struct al_udma * udma)71 static void al_udma_set_defaults(struct al_udma *udma)
72 {
73 uint8_t rev_id = udma->rev_id;
74
75 if (udma->type == UDMA_TX) {
76 struct unit_regs* tmp_unit_regs =
77 (struct unit_regs*)udma->udma_regs;
78
79 /* Setting the data fifo depth to 4K (256 strips of 16B)
80 * This allows the UDMA to have 16 outstanding writes */
81 if (rev_id >= AL_UDMA_REV_ID_2) {
82 al_reg_write32_masked(&tmp_unit_regs->m2s.m2s_rd.data_cfg,
83 UDMA_M2S_RD_DATA_CFG_DATA_FIFO_DEPTH_MASK,
84 256 << UDMA_M2S_RD_DATA_CFG_DATA_FIFO_DEPTH_SHIFT);
85 }
86
87 /* set AXI timeout to 1M (~2.6 ms) */
88 al_reg_write32(&tmp_unit_regs->gen.axi.cfg_1, 1000000);
89
90 al_reg_write32(&tmp_unit_regs->m2s.m2s_comp.cfg_application_ack
91 , 0); /* Ack time out */
92 }
93 if (udma->type == UDMA_RX) {
94 al_reg_write32(
95 &udma->udma_regs->s2m.s2m_comp.cfg_application_ack, 0);
96 /* Ack time out */
97
98 }
99 }
100 /**
101 * misc queue configurations
102 *
103 * @param udma_q udma queue data structure
104 *
105 * @return 0
106 */
al_udma_q_config(struct al_udma_q * udma_q)107 static int al_udma_q_config(struct al_udma_q *udma_q)
108 {
109 uint32_t *reg_addr;
110 uint32_t val;
111
112 if (udma_q->udma->type == UDMA_TX) {
113 reg_addr = &udma_q->q_regs->m2s_q.rlimit.mask;
114
115 val = al_reg_read32(reg_addr);
116 // enable DMB
117 val &= ~UDMA_M2S_Q_RATE_LIMIT_MASK_INTERNAL_PAUSE_DMB;
118 al_reg_write32(reg_addr, val);
119 }
120 return 0;
121 }
122
123 /**
124 * set the queue's completion configuration register
125 *
126 * @param udma_q udma queue data structure
127 *
128 * @return 0
129 */
al_udma_q_config_compl(struct al_udma_q * udma_q)130 static int al_udma_q_config_compl(struct al_udma_q *udma_q)
131 {
132 uint32_t *reg_addr;
133 uint32_t val;
134
135 if (udma_q->udma->type == UDMA_TX)
136 reg_addr = &udma_q->q_regs->m2s_q.comp_cfg;
137 else
138 reg_addr = &udma_q->q_regs->s2m_q.comp_cfg;
139
140 val = al_reg_read32(reg_addr);
141
142 if (udma_q->flags & AL_UDMA_Q_FLAGS_NO_COMP_UPDATE)
143 val &= ~UDMA_M2S_Q_COMP_CFG_EN_COMP_RING_UPDATE;
144 else
145 val |= UDMA_M2S_Q_COMP_CFG_EN_COMP_RING_UPDATE;
146
147 if (udma_q->flags & AL_UDMA_Q_FLAGS_EN_COMP_COAL)
148 val &= ~UDMA_M2S_Q_COMP_CFG_DIS_COMP_COAL;
149 else
150 val |= UDMA_M2S_Q_COMP_CFG_DIS_COMP_COAL;
151
152 al_reg_write32(reg_addr, val);
153
154 /* set the completion queue size */
155 if (udma_q->udma->type == UDMA_RX) {
156 val = al_reg_read32(
157 &udma_q->udma->udma_regs->s2m.s2m_comp.cfg_1c);
158 val &= ~UDMA_S2M_COMP_CFG_1C_DESC_SIZE_MASK;
159 /* the register expects it to be in words */
160 val |= (udma_q->cdesc_size >> 2)
161 & UDMA_S2M_COMP_CFG_1C_DESC_SIZE_MASK;
162 al_reg_write32(&udma_q->udma->udma_regs->s2m.s2m_comp.cfg_1c
163 , val);
164 }
165 return 0;
166 }
167
168 /**
169 * reset the queues pointers (Head, Tail, etc) and set the base addresses
170 *
171 * @param udma_q udma queue data structure
172 */
al_udma_q_set_pointers(struct al_udma_q * udma_q)173 static int al_udma_q_set_pointers(struct al_udma_q *udma_q)
174 {
175 /* reset the descriptors ring pointers */
176 /* assert descriptor base address aligned. */
177 al_assert((AL_ADDR_LOW(udma_q->desc_phy_base) &
178 ~UDMA_M2S_Q_TDRBP_LOW_ADDR_MASK) == 0);
179 al_reg_write32(&udma_q->q_regs->rings.drbp_low,
180 AL_ADDR_LOW(udma_q->desc_phy_base));
181 al_reg_write32(&udma_q->q_regs->rings.drbp_high,
182 AL_ADDR_HIGH(udma_q->desc_phy_base));
183
184 al_reg_write32(&udma_q->q_regs->rings.drl, udma_q->size);
185
186 /* if completion ring update disabled */
187 if (udma_q->cdesc_base_ptr == NULL) {
188 udma_q->flags |= AL_UDMA_Q_FLAGS_NO_COMP_UPDATE;
189 } else {
190 /* reset the completion descriptors ring pointers */
191 /* assert completion base address aligned. */
192 al_assert((AL_ADDR_LOW(udma_q->cdesc_phy_base) &
193 ~UDMA_M2S_Q_TCRBP_LOW_ADDR_MASK) == 0);
194 al_reg_write32(&udma_q->q_regs->rings.crbp_low,
195 AL_ADDR_LOW(udma_q->cdesc_phy_base));
196 al_reg_write32(&udma_q->q_regs->rings.crbp_high,
197 AL_ADDR_HIGH(udma_q->cdesc_phy_base));
198 }
199 al_udma_q_config_compl(udma_q);
200 return 0;
201 }
202
203 /**
204 * enable/disable udma queue
205 *
206 * @param udma_q udma queue data structure
207 * @param enable none zero value enables the queue, zero means disable
208 *
209 * @return 0
210 */
al_udma_q_enable(struct al_udma_q * udma_q,int enable)211 static int al_udma_q_enable(struct al_udma_q *udma_q, int enable)
212 {
213 uint32_t reg = al_reg_read32(&udma_q->q_regs->rings.cfg);
214
215 if (enable) {
216 reg |= (UDMA_M2S_Q_CFG_EN_PREF | UDMA_M2S_Q_CFG_EN_SCHEDULING);
217 udma_q->status = AL_QUEUE_ENABLED;
218 } else {
219 reg &= ~(UDMA_M2S_Q_CFG_EN_PREF | UDMA_M2S_Q_CFG_EN_SCHEDULING);
220 udma_q->status = AL_QUEUE_DISABLED;
221 }
222 al_reg_write32(&udma_q->q_regs->rings.cfg, reg);
223 return 0;
224 }
225
226
227 /************************ API functions ***************************************/
228
229 /* Initializations functions */
230 /*
231 * Initialize the udma engine
232 */
al_udma_init(struct al_udma * udma,struct al_udma_params * udma_params)233 int al_udma_init(struct al_udma *udma, struct al_udma_params *udma_params)
234 {
235 int i;
236
237 al_assert(udma);
238
239 if (udma_params->num_of_queues > DMA_MAX_Q) {
240 al_err("udma: invalid num_of_queues parameter\n");
241 return -EINVAL;
242 }
243
244 udma->type = udma_params->type;
245 udma->num_of_queues = udma_params->num_of_queues;
246 udma->gen_regs = &udma_params->udma_regs_base->gen;
247
248 if (udma->type == UDMA_TX)
249 udma->udma_regs = (union udma_regs *)&udma_params->udma_regs_base->m2s;
250 else
251 udma->udma_regs = (union udma_regs *)&udma_params->udma_regs_base->s2m;
252
253 udma->rev_id = al_udma_get_revision(udma_params->udma_regs_base);
254
255 if (udma_params->name == NULL)
256 udma->name = "";
257 else
258 udma->name = udma_params->name;
259
260 udma->state = UDMA_DISABLE;
261 for (i = 0; i < DMA_MAX_Q; i++) {
262 udma->udma_q[i].status = AL_QUEUE_NOT_INITIALIZED;
263 }
264 /* initialize configuration registers to correct values */
265 al_udma_set_defaults(udma);
266 al_dbg("udma [%s] initialized. base %p\n", udma->name,
267 udma->udma_regs);
268 return 0;
269 }
270
271 /*
272 * Initialize the udma queue data structure
273 */
al_udma_q_init(struct al_udma * udma,uint32_t qid,struct al_udma_q_params * q_params)274 int al_udma_q_init(struct al_udma *udma, uint32_t qid,
275 struct al_udma_q_params *q_params)
276 {
277 struct al_udma_q *udma_q;
278
279 al_assert(udma);
280 al_assert(q_params);
281
282 if (qid >= udma->num_of_queues) {
283 al_err("udma: invalid queue id (%d)\n", qid);
284 return -EINVAL;
285 }
286
287 if (udma->udma_q[qid].status == AL_QUEUE_ENABLED) {
288 al_err("udma: queue (%d) already enabled!\n", qid);
289 return -EIO;
290 }
291
292 if (q_params->size < AL_UDMA_MIN_Q_SIZE) {
293 al_err("udma: queue (%d) size too small\n", qid);
294 return -EINVAL;
295 }
296
297 if (q_params->size > AL_UDMA_MAX_Q_SIZE) {
298 al_err("udma: queue (%d) size too large\n", qid);
299 return -EINVAL;
300 }
301
302 if (q_params->size & (q_params->size - 1)) {
303 al_err("udma: queue (%d) size (%d) must be power of 2\n",
304 q_params->size, qid);
305 return -EINVAL;
306 }
307
308 udma_q = &udma->udma_q[qid];
309 /* set the queue's regs base address */
310 if (udma->type == UDMA_TX)
311 udma_q->q_regs = (union udma_q_regs __iomem *)
312 &udma->udma_regs->m2s.m2s_q[qid];
313 else
314 udma_q->q_regs = (union udma_q_regs __iomem *)
315 &udma->udma_regs->s2m.s2m_q[qid];
316
317 udma_q->adapter_rev_id = q_params->adapter_rev_id;
318 udma_q->size = q_params->size;
319 udma_q->size_mask = q_params->size - 1;
320 udma_q->desc_base_ptr = q_params->desc_base;
321 udma_q->desc_phy_base = q_params->desc_phy_base;
322 udma_q->cdesc_base_ptr = q_params->cdesc_base;
323 udma_q->cdesc_phy_base = q_params->cdesc_phy_base;
324 udma_q->cdesc_size = q_params->cdesc_size;
325
326 udma_q->next_desc_idx = 0;
327 udma_q->next_cdesc_idx = 0;
328 udma_q->end_cdesc_ptr = (uint8_t *) udma_q->cdesc_base_ptr +
329 (udma_q->size - 1) * udma_q->cdesc_size;
330 udma_q->comp_head_idx = 0;
331 udma_q->comp_head_ptr = (union al_udma_cdesc *)udma_q->cdesc_base_ptr;
332 udma_q->desc_ring_id = AL_UDMA_INITIAL_RING_ID;
333 udma_q->comp_ring_id = AL_UDMA_INITIAL_RING_ID;
334 #if 0
335 udma_q->desc_ctrl_bits = AL_UDMA_INITIAL_RING_ID <<
336 AL_M2S_DESC_RING_ID_SHIFT;
337 #endif
338 udma_q->pkt_crnt_descs = 0;
339 udma_q->flags = 0;
340 udma_q->status = AL_QUEUE_DISABLED;
341 udma_q->udma = udma;
342 udma_q->qid = qid;
343
344 /* start hardware configuration: */
345 al_udma_q_config(udma_q);
346 /* reset the queue pointers */
347 al_udma_q_set_pointers(udma_q);
348
349 /* enable the q */
350 al_udma_q_enable(udma_q, 1);
351
352 al_dbg("udma [%s %d]: %s q init. size 0x%x\n"
353 " desc ring info: phys base 0x%llx virt base %p)",
354 udma_q->udma->name, udma_q->qid,
355 udma->type == UDMA_TX ? "Tx" : "Rx",
356 q_params->size,
357 (unsigned long long)q_params->desc_phy_base,
358 q_params->desc_base);
359 al_dbg(" cdesc ring info: phys base 0x%llx virt base %p entry size 0x%x",
360 (unsigned long long)q_params->cdesc_phy_base,
361 q_params->cdesc_base,
362 q_params->cdesc_size);
363
364 return 0;
365 }
366
367 /*
368 * Reset a udma queue
369 */
al_udma_q_reset(struct al_udma_q * udma_q)370 int al_udma_q_reset(struct al_udma_q *udma_q)
371 {
372 unsigned int remaining_time = AL_UDMA_Q_RST_TOUT;
373 uint32_t *status_reg;
374 uint32_t *dcp_reg;
375 uint32_t *crhp_reg;
376 uint32_t *q_sw_ctrl_reg;
377
378 al_assert(udma_q);
379
380 /* De-assert scheduling and prefetch */
381 al_udma_q_enable(udma_q, 0);
382
383 /* Wait for scheduling and prefetch to stop */
384 status_reg = &udma_q->q_regs->rings.status;
385
386 while (remaining_time) {
387 uint32_t status = al_reg_read32(status_reg);
388
389 if (!(status & (UDMA_M2S_Q_STATUS_PREFETCH |
390 UDMA_M2S_Q_STATUS_SCHEDULER)))
391 break;
392
393 remaining_time--;
394 al_udelay(1);
395 }
396
397 if (!remaining_time) {
398 al_err("udma [%s %d]: %s timeout waiting for prefetch and "
399 "scheduler disable\n", udma_q->udma->name, udma_q->qid,
400 __func__);
401 return -ETIMEDOUT;
402 }
403
404 /* Wait for the completion queue to reach to the same pointer as the
405 * prefetch stopped at ([TR]DCP == [TR]CRHP) */
406 dcp_reg = &udma_q->q_regs->rings.dcp;
407 crhp_reg = &udma_q->q_regs->rings.crhp;
408
409 while (remaining_time) {
410 uint32_t dcp = al_reg_read32(dcp_reg);
411 uint32_t crhp = al_reg_read32(crhp_reg);
412
413 if (dcp == crhp)
414 break;
415
416 remaining_time--;
417 al_udelay(1);
418 };
419
420 if (!remaining_time) {
421 al_err("udma [%s %d]: %s timeout waiting for dcp==crhp\n",
422 udma_q->udma->name, udma_q->qid, __func__);
423 return -ETIMEDOUT;
424 }
425
426 /* Assert the queue reset */
427 if (udma_q->udma->type == UDMA_TX)
428 q_sw_ctrl_reg = &udma_q->q_regs->m2s_q.q_sw_ctrl;
429 else
430 q_sw_ctrl_reg = &udma_q->q_regs->s2m_q.q_sw_ctrl;
431
432 al_reg_write32(q_sw_ctrl_reg, UDMA_M2S_Q_SW_CTRL_RST_Q);
433
434 return 0;
435 }
436
437 /*
438 * return (by reference) a pointer to a specific queue date structure.
439 */
al_udma_q_handle_get(struct al_udma * udma,uint32_t qid,struct al_udma_q ** q_handle)440 int al_udma_q_handle_get(struct al_udma *udma, uint32_t qid,
441 struct al_udma_q **q_handle)
442 {
443
444 al_assert(udma);
445 al_assert(q_handle);
446
447 if (unlikely(qid >= udma->num_of_queues)) {
448 al_err("udma [%s]: invalid queue id (%d)\n", udma->name, qid);
449 return -EINVAL;
450 }
451 *q_handle = &udma->udma_q[qid];
452 return 0;
453 }
454
455 /*
456 * Change the UDMA's state
457 */
al_udma_state_set(struct al_udma * udma,enum al_udma_state state)458 int al_udma_state_set(struct al_udma *udma, enum al_udma_state state)
459 {
460 uint32_t reg;
461
462 al_assert(udma != NULL);
463 if (state == udma->state)
464 al_dbg("udma [%s]: requested state identical to "
465 "current state (%d)\n", udma->name, state);
466
467 al_dbg("udma [%s]: change state from (%s) to (%s)\n",
468 udma->name, al_udma_states_name[udma->state],
469 al_udma_states_name[state]);
470
471 reg = 0;
472 switch (state) {
473 case UDMA_DISABLE:
474 reg |= UDMA_M2S_CHANGE_STATE_DIS;
475 break;
476 case UDMA_NORMAL:
477 reg |= UDMA_M2S_CHANGE_STATE_NORMAL;
478 break;
479 case UDMA_ABORT:
480 reg |= UDMA_M2S_CHANGE_STATE_ABORT;
481 break;
482 default:
483 al_err("udma: invalid state (%d)\n", state);
484 return -EINVAL;
485 }
486
487 if (udma->type == UDMA_TX)
488 al_reg_write32(&udma->udma_regs->m2s.m2s.change_state, reg);
489 else
490 al_reg_write32(&udma->udma_regs->s2m.s2m.change_state, reg);
491
492 udma->state = state;
493 return 0;
494 }
495
496 /*
497 * return the current UDMA hardware state
498 */
al_udma_state_get(struct al_udma * udma)499 enum al_udma_state al_udma_state_get(struct al_udma *udma)
500 {
501 uint32_t state_reg;
502 uint32_t comp_ctrl;
503 uint32_t stream_if;
504 uint32_t data_rd;
505 uint32_t desc_pref;
506
507 if (udma->type == UDMA_TX)
508 state_reg = al_reg_read32(&udma->udma_regs->m2s.m2s.state);
509 else
510 state_reg = al_reg_read32(&udma->udma_regs->s2m.s2m.state);
511
512 comp_ctrl = AL_REG_FIELD_GET(state_reg,
513 UDMA_M2S_STATE_COMP_CTRL_MASK,
514 UDMA_M2S_STATE_COMP_CTRL_SHIFT);
515 stream_if = AL_REG_FIELD_GET(state_reg,
516 UDMA_M2S_STATE_STREAM_IF_MASK,
517 UDMA_M2S_STATE_STREAM_IF_SHIFT);
518 data_rd = AL_REG_FIELD_GET(state_reg,
519 UDMA_M2S_STATE_DATA_RD_CTRL_MASK,
520 UDMA_M2S_STATE_DATA_RD_CTRL_SHIFT);
521 desc_pref = AL_REG_FIELD_GET(state_reg,
522 UDMA_M2S_STATE_DESC_PREF_MASK,
523 UDMA_M2S_STATE_DESC_PREF_SHIFT);
524
525 al_assert(comp_ctrl != UDMA_STATE_RESERVED);
526 al_assert(stream_if != UDMA_STATE_RESERVED);
527 al_assert(data_rd != UDMA_STATE_RESERVED);
528 al_assert(desc_pref != UDMA_STATE_RESERVED);
529
530 /* if any of the states is abort then return abort */
531 if ((comp_ctrl == UDMA_STATE_ABORT) || (stream_if == UDMA_STATE_ABORT)
532 || (data_rd == UDMA_STATE_ABORT)
533 || (desc_pref == UDMA_STATE_ABORT))
534 return UDMA_ABORT;
535
536 /* if any of the states is normal then return normal */
537 if ((comp_ctrl == UDMA_STATE_NORMAL)
538 || (stream_if == UDMA_STATE_NORMAL)
539 || (data_rd == UDMA_STATE_NORMAL)
540 || (desc_pref == UDMA_STATE_NORMAL))
541 return UDMA_NORMAL;
542
543 return UDMA_IDLE;
544 }
545
546 /*
547 * Action handling
548 */
549
550 /*
551 * get next completed packet from completion ring of the queue
552 */
al_udma_cdesc_packet_get(struct al_udma_q * udma_q,volatile union al_udma_cdesc ** cdesc)553 uint32_t al_udma_cdesc_packet_get(
554 struct al_udma_q *udma_q,
555 volatile union al_udma_cdesc **cdesc)
556 {
557 uint32_t count;
558 volatile union al_udma_cdesc *curr;
559 uint32_t comp_flags;
560
561 /* this function requires the completion ring update */
562 al_assert(!(udma_q->flags & AL_UDMA_Q_FLAGS_NO_COMP_UPDATE));
563
564 /* comp_head points to the last comp desc that was processed */
565 curr = udma_q->comp_head_ptr;
566 comp_flags = swap32_from_le(curr->al_desc_comp_tx.ctrl_meta);
567
568 /* check if the completion descriptor is new */
569 if (unlikely(al_udma_new_cdesc(udma_q, comp_flags) == AL_FALSE))
570 return 0;
571 /* if new desc found, increment the current packets descriptors */
572 count = udma_q->pkt_crnt_descs + 1;
573 while (!cdesc_is_last(comp_flags)) {
574 curr = al_cdesc_next_update(udma_q, curr);
575 comp_flags = swap32_from_le(curr->al_desc_comp_tx.ctrl_meta);
576 if (unlikely(al_udma_new_cdesc(udma_q, comp_flags)
577 == AL_FALSE)) {
578 /* the current packet here doesn't have all */
579 /* descriptors completed. log the current desc */
580 /* location and number of completed descriptors so */
581 /* far. then return */
582 udma_q->pkt_crnt_descs = count;
583 udma_q->comp_head_ptr = curr;
584 return 0;
585 }
586 count++;
587 /* check against max descs per packet. */
588 al_assert(count <= udma_q->size);
589 }
590 /* return back the first descriptor of the packet */
591 *cdesc = al_udma_cdesc_idx_to_ptr(udma_q, udma_q->next_cdesc_idx);
592 udma_q->pkt_crnt_descs = 0;
593 udma_q->comp_head_ptr = al_cdesc_next_update(udma_q, curr);
594
595 al_dbg("udma [%s %d]: packet completed. first desc %p (ixd 0x%x)"
596 " descs %d\n", udma_q->udma->name, udma_q->qid, *cdesc,
597 udma_q->next_cdesc_idx, count);
598
599 return count;
600 }
601
602 /** @} end of UDMA group */
603