diff options
Diffstat (limited to 'firmware/target/arm/tms320dm320/sansa-connect/tnetv105_cppi.c')
-rw-r--r-- | firmware/target/arm/tms320dm320/sansa-connect/tnetv105_cppi.c | 1044 |
1 files changed, 1044 insertions, 0 deletions
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_cppi.c b/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_cppi.c new file mode 100644 index 0000000000..93477bed9e --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_cppi.c | |||
@@ -0,0 +1,1044 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2021 by Tomasz Moń | ||
11 | * Copied with minor modifications from Sansa Connect Linux driver | ||
12 | * Copyright (c) 2005,2006 Zermatt Systems, Inc. | ||
13 | * Written by: Ben Bostwick | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version 2 | ||
18 | * of the License, or (at your option) any later version. | ||
19 | * | ||
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
21 | * KIND, either express or implied. | ||
22 | * | ||
23 | ****************************************************************************/ | ||
24 | |||
25 | #include <string.h> | ||
26 | #include "config.h" | ||
27 | #include "system.h" | ||
28 | #include "kernel.h" | ||
29 | #include "panic.h" | ||
30 | #include "logf.h" | ||
31 | #include "tnetv105_usb_drv.h" | ||
32 | #include "tnetv105_cppi.h" | ||
33 | |||
34 | /* This file is pretty much directly copied from the Sansa Connect | ||
35 | * Linux kernel source code. This is because the functionality is | ||
36 | * nicely separated from actual kernel specific code and CPPI seems | ||
37 | * complex (atleast without access to the datasheet). | ||
38 | * | ||
39 | * The only non cosmetic change was changing the dynamic allocations | ||
40 | * to static allocations. | ||
41 | * | ||
42 | * It seems that the only way to get interrupt on non-control endpoint | ||
43 | * acticity is to use the CPPI. This sounds like a plausible explanation | ||
44 | * for the fake DMA buffers mentioned in CPPI code. | ||
45 | */ | ||
46 | |||
47 | /* Translate Linux consistent_sync() to Rockbox functions */ | ||
48 | #define DMA_TO_DEVICE commit_discard_dcache_range | ||
49 | #define DMA_FROM_DEVICE discard_dcache_range | ||
50 | #define consistent_sync(ptr, size, func) func(ptr, size) | ||
51 | /* Rockbox TMS320DM320 crt0.S maps everything to itself */ | ||
52 | #define __virt_to_phys(ptr) ptr | ||
53 | #define __phys_to_virt(ptr) ptr | ||
54 | |||
55 | // CPPI functions | ||
56 | #define CB_SOF_BIT (1<<31) | ||
57 | #define CB_EOF_BIT (1<<30) | ||
58 | #define CB_OWNERSHIP_BIT (1<<29) | ||
59 | #define CB_EOQ_BIT (1<<28) | ||
60 | #define CB_ZLP_GARBAGE (1<<23) | ||
61 | #define CB_SIZE_MASK 0x0000ffff | ||
62 | #define CB_OFFSET_MASK 0xffff0000 | ||
63 | #define TEARDOWN_VAL 0xfffffffc | ||
64 | |||
65 | #define MAX_BUF_SIZE 512 | ||
66 | |||
67 | #define CPPI_DMA_RX_BUF_SIZE (MAX_BUF_SIZE * CPPI_RX_NUM_BUFS) | ||
68 | |||
69 | static uint8_t *dma_recv_buf[CPPI_NUM_CHANNELS]; | ||
70 | static uint8_t ch0_rx_buf[CPPI_DMA_RX_BUF_SIZE]; | ||
71 | static uint8_t ch1_rx_buf[CPPI_DMA_RX_BUF_SIZE]; | ||
72 | |||
73 | #if USB_CPPI_LOGGING | ||
74 | #define cppi_log_event0(msg) usb_log_event(msg, LOG_EVENT_D0, 0, 0, 0, 0) | ||
75 | #define cppi_log_event1(msg, data0) usb_log_event(msg, LOG_EVENT_D1, data0, 0, 0, 0) | ||
76 | #define cppi_log_event2(msg, data0, data1) usb_log_event(msg, LOG_EVENT_D2, data0, data1, 0, 0) | ||
77 | #define cppi_log_event3(msg, data0, data1, data2) usb_log_event(msg, LOG_EVENT_D3, data0, data1, data2, 0) | ||
78 | #define cppi_log_event4(msg, data0, data1, data2, data3) usb_log_event(msg, LOG_EVENT_D4, data0, data1, data2, data3) | ||
79 | #else | ||
80 | #define cppi_log_event0(x) | ||
81 | #define cppi_log_event1(x, y) | ||
82 | #define cppi_log_event2(x, y, z) | ||
83 | #define cppi_log_event3(x, y, z, w) | ||
84 | #define cppi_log_event4(x, y, z, w, u) | ||
85 | #endif | ||
86 | |||
87 | /* | ||
88 | * This function processes transmit interrupts. It traverses the | ||
89 | * transmit buffer queue, detecting sent data buffers | ||
90 | * | ||
91 | * @return 0 if OK, non-zero otherwise. | ||
92 | */ | ||
93 | int tnetv_cppi_tx_int(struct cppi_info *cppi, int ch) | ||
94 | { | ||
95 | cppi_tcb *CurrentTcb,*LastTcbProcessed; | ||
96 | uint32_t TxFrameStatus; | ||
97 | cppi_txcntl *pTxCtl = &cppi->tx_ctl[ch]; | ||
98 | int bytes_sent = 0; | ||
99 | |||
100 | cppi_log_event1("[cppi]TxInt ch", ch); | ||
101 | |||
102 | CurrentTcb = pTxCtl->TxActQueueHead; | ||
103 | |||
104 | if (CurrentTcb == 0) | ||
105 | { | ||
106 | cppi_log_event0("[cppi] tx int: no current tcb"); | ||
107 | return -1; | ||
108 | } | ||
109 | |||
110 | // sync up the tcb from memory | ||
111 | consistent_sync(CurrentTcb, sizeof(*CurrentTcb), DMA_FROM_DEVICE); | ||
112 | |||
113 | TxFrameStatus = CurrentTcb->mode; | ||
114 | LastTcbProcessed = NULL; | ||
115 | |||
116 | cppi_log_event3("[cppi] int tcb status", (uint32_t) CurrentTcb, TxFrameStatus, CurrentTcb->Off_BLen); | ||
117 | |||
118 | while(CurrentTcb && (TxFrameStatus & CB_OWNERSHIP_BIT) == 0) | ||
119 | { | ||
120 | cppi_log_event3("[cppi] tx int: tcb (mode) (len)", (uint32_t) CurrentTcb, CurrentTcb->mode, CurrentTcb->Off_BLen); | ||
121 | |||
122 | // calculate the amount of bytes sent. | ||
123 | // don't count the fake ZLP byte | ||
124 | if (CurrentTcb->Off_BLen > 0x1) | ||
125 | { | ||
126 | bytes_sent += CurrentTcb->Off_BLen & 0xFFFF; | ||
127 | } | ||
128 | |||
129 | if (CurrentTcb->mode & CB_EOQ_BIT) | ||
130 | { | ||
131 | if (CurrentTcb->Next) | ||
132 | { | ||
133 | cppi_log_event0(" [cppi] misqueue!"); | ||
134 | |||
135 | // Misqueued packet | ||
136 | tnetv_usb_reg_write(TNETV_DMA_TX_STATE(ch, TNETV_CPPI_TX_WORD_HDP), CurrentTcb->HNext); | ||
137 | } | ||
138 | else | ||
139 | { | ||
140 | cppi_log_event0("[cppi] eoq"); | ||
141 | |||
142 | /* Tx End of Queue */ | ||
143 | pTxCtl->TxActive = 0; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | cppi_log_event1("[cppi]SendComplete: ", CurrentTcb->Off_BLen & 0xFFFF); | ||
148 | |||
149 | // Write the completion pointer | ||
150 | tnetv_usb_reg_write(TNETV_DMA_TX_CMPL(ch), __dma_to_vlynq_phys(CurrentTcb->dma_handle)); | ||
151 | |||
152 | |||
153 | LastTcbProcessed = CurrentTcb; | ||
154 | CurrentTcb = CurrentTcb->Next; | ||
155 | |||
156 | // clean up TCB fields | ||
157 | LastTcbProcessed->HNext = 0; | ||
158 | LastTcbProcessed->Next = 0; | ||
159 | LastTcbProcessed->BufPtr = 0; | ||
160 | LastTcbProcessed->Off_BLen = 0; | ||
161 | LastTcbProcessed->mode = 0; | ||
162 | LastTcbProcessed->Eop = 0; | ||
163 | |||
164 | /* Push Tcb(s) back onto the list */ | ||
165 | if (pTxCtl->TcbPool) | ||
166 | { | ||
167 | LastTcbProcessed->Next = pTxCtl->TcbPool->Next; | ||
168 | pTxCtl->TcbPool->Next = LastTcbProcessed; | ||
169 | } | ||
170 | else | ||
171 | { | ||
172 | pTxCtl->TcbPool = LastTcbProcessed; | ||
173 | } | ||
174 | |||
175 | consistent_sync(LastTcbProcessed, sizeof(*LastTcbProcessed), DMA_TO_DEVICE); | ||
176 | |||
177 | // get the status of the next packet | ||
178 | if (CurrentTcb) | ||
179 | { | ||
180 | // sync up the tcb from memory | ||
181 | consistent_sync(CurrentTcb, sizeof(*CurrentTcb), DMA_FROM_DEVICE); | ||
182 | |||
183 | TxFrameStatus = CurrentTcb->mode; | ||
184 | } | ||
185 | |||
186 | |||
187 | } | ||
188 | |||
189 | pTxCtl->TxActQueueHead = CurrentTcb; | ||
190 | |||
191 | if (!LastTcbProcessed) | ||
192 | { | ||
193 | cppi_log_event1(" [cppi]No Tx packets serviced on int! ch", ch); | ||
194 | return -1; | ||
195 | } | ||
196 | |||
197 | return bytes_sent; | ||
198 | } | ||
199 | |||
200 | int tnetv_cppi_flush_tx_queue(struct cppi_info *cppi, int ch) | ||
201 | { | ||
202 | cppi_txcntl *pTxCtl = &cppi->tx_ctl[ch]; | ||
203 | cppi_tcb *tcb, *next_tcb; | ||
204 | |||
205 | tcb = pTxCtl->TxActQueueHead; | ||
206 | |||
207 | cppi_log_event1("[cppi] flush TX ", (uint32_t) pTxCtl->TxActQueueHead); | ||
208 | |||
209 | while (tcb) | ||
210 | { | ||
211 | tcb->mode = 0; | ||
212 | tcb->BufPtr = 0; | ||
213 | tcb->Off_BLen = 0; | ||
214 | tcb->Eop = 0; | ||
215 | tcb->HNext = 0; | ||
216 | |||
217 | next_tcb = tcb->Next; | ||
218 | |||
219 | tcb->Next = pTxCtl->TcbPool; | ||
220 | pTxCtl->TcbPool = tcb; | ||
221 | |||
222 | tcb = next_tcb; | ||
223 | } | ||
224 | |||
225 | pTxCtl->TxActQueueHead = 0; | ||
226 | pTxCtl->TxActQueueTail = 0; | ||
227 | pTxCtl->TxActive = 0; | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | |||
233 | /** | ||
234 | * @ingroup CPHAL_Functions | ||
235 | * This function transmits the data in FragList using available transmit | ||
236 | * buffer descriptors. More information on the use of the Mode parameter | ||
237 | * is available in the module-specific appendices. Note: The OS should | ||
238 | * not call Send() for a channel that has been requested to be torndown. | ||
239 | * | ||
240 | */ | ||
241 | int tnetv_cppi_send(struct cppi_info *cppi, int ch, dma_addr_t buf, unsigned length, int send_zlp) | ||
242 | { | ||
243 | cppi_txcntl *pTxCtl; | ||
244 | cppi_tcb *first_tcb; | ||
245 | cppi_tcb *tcb; | ||
246 | int queued_len; | ||
247 | dma_addr_t buf_to_send; | ||
248 | dma_addr_t buf_ptr; | ||
249 | int total_len = length; | ||
250 | int pktlen; | ||
251 | |||
252 | pTxCtl = &cppi->tx_ctl[ch]; | ||
253 | |||
254 | if (length == 0) | ||
255 | { | ||
256 | cppi_log_event0("[cppi] len = 0, nothing to send"); | ||
257 | return -1; | ||
258 | } | ||
259 | |||
260 | // no send buffers.. try again later | ||
261 | if (!pTxCtl->TcbPool) | ||
262 | { | ||
263 | cppi_log_event0("[cppi] out of cppi buffers"); | ||
264 | return -1; | ||
265 | } | ||
266 | |||
267 | // only send 1 packet at a time | ||
268 | if (pTxCtl->TxActQueueHead || pTxCtl->TxActive) | ||
269 | { | ||
270 | cppi_log_event0("[cppi] already sending!"); | ||
271 | return -1; | ||
272 | } | ||
273 | |||
274 | buf_to_send = buf; | ||
275 | |||
276 | // usb_requests can have a 32 bit length, but CPPI DMA fragments | ||
277 | // have a (64k - 1) limit. Split the usb_request up into fragments here. | ||
278 | first_tcb = pTxCtl->TcbPool; | ||
279 | tcb = first_tcb; | ||
280 | |||
281 | cppi_log_event4("[cppi]cppi_send (buf) (len) (pool) (dma)", (uint32_t) buf_to_send, total_len, (uint32_t) first_tcb, first_tcb->dma_handle); | ||
282 | |||
283 | queued_len = 0; | ||
284 | |||
285 | do | ||
286 | { | ||
287 | buf_ptr = buf_to_send + queued_len; | ||
288 | tcb->BufPtr = __dma_to_vlynq_phys(buf_ptr); | ||
289 | tcb->HNext = 0; | ||
290 | |||
291 | // can't transfer more that 64k-1 bytes in 1 CPPI transfer | ||
292 | // need to queue up transfers if it's greater than that | ||
293 | pktlen = ((total_len - queued_len) > CPPI_MAX_FRAG) ? CPPI_MAX_FRAG : (total_len - queued_len); | ||
294 | tcb->Off_BLen = pktlen; | ||
295 | tcb->mode = (CB_OWNERSHIP_BIT | CB_SOF_BIT | CB_EOF_BIT | pktlen); | ||
296 | |||
297 | queued_len += pktlen; | ||
298 | |||
299 | if (queued_len < total_len) | ||
300 | { | ||
301 | tcb->HNext = __dma_to_vlynq_phys(((cppi_tcb *) tcb->Next)->dma_handle); | ||
302 | |||
303 | // write out the buffer to memory | ||
304 | consistent_sync(tcb, sizeof(*tcb), DMA_TO_DEVICE); | ||
305 | |||
306 | cppi_log_event4("[cppi] q tcb", (uint32_t) tcb, ((uint32_t *) tcb)[0], ((uint32_t *) tcb)[1], ((uint32_t *) tcb)[2]); | ||
307 | cppi_log_event4("[cppi] ", ((uint32_t *) tcb)[3], ((uint32_t *) tcb)[4], ((uint32_t *) tcb)[5], ((uint32_t *) tcb)[6]); | ||
308 | |||
309 | tcb = tcb->Next; | ||
310 | } | ||
311 | } while (queued_len < total_len); | ||
312 | |||
313 | /* In the Tx Interrupt handler, we will need to know which TCB is EOP, | ||
314 | so we can save that information in the SOP */ | ||
315 | first_tcb->Eop = tcb; | ||
316 | |||
317 | // set the secret ZLP bit if necessary, this will be a completely separate packet | ||
318 | if (send_zlp) | ||
319 | { | ||
320 | #if defined(AUTO_ZLP) && AUTO_ZLP | ||
321 | // add an extra buffer at the end to hold the ZLP | ||
322 | tcb->HNext = __dma_to_vlynq_phys(((cppi_tcb *) tcb->Next)->dma_handle); | ||
323 | |||
324 | // write out the buffer to memory | ||
325 | consistent_sync(tcb, sizeof(*tcb), DMA_TO_DEVICE); | ||
326 | |||
327 | tcb = tcb->Next; | ||
328 | |||
329 | /* In the Tx Interrupt handler, we will need to know which TCB is EOP, | ||
330 | so we can save that information in the SOP */ | ||
331 | first_tcb->Eop = tcb; | ||
332 | #endif | ||
333 | |||
334 | buf_ptr = buf_to_send + queued_len; | ||
335 | tcb->BufPtr = __dma_to_vlynq_phys(buf_ptr); // not used, but can't be zero | ||
336 | tcb->HNext = 0; | ||
337 | tcb->Off_BLen = 0x1; // device will send (((len - 1) / maxpacket) + 1) ZLPs | ||
338 | tcb->mode = (CB_SOF_BIT | CB_EOF_BIT | CB_OWNERSHIP_BIT | CB_ZLP_GARBAGE | 0x1); // send 1 ZLP | ||
339 | tcb->Eop = tcb; | ||
340 | |||
341 | cppi_log_event0("[cppi] Send ZLP!"); | ||
342 | } | ||
343 | |||
344 | pTxCtl->TcbPool = tcb->Next; | ||
345 | |||
346 | tcb->Next = 0; | ||
347 | tcb->HNext = 0; | ||
348 | |||
349 | // write out the buffer to memory | ||
350 | consistent_sync(tcb, sizeof(*tcb), DMA_TO_DEVICE); | ||
351 | |||
352 | cppi_log_event4("[cppi] q tcb", (uint32_t) tcb, ((uint32_t *) tcb)[0], ((uint32_t *) tcb)[1], ((uint32_t *) tcb)[2]); | ||
353 | cppi_log_event4("[cppi] ", ((uint32_t *) tcb)[3], ((uint32_t *) tcb)[4], ((uint32_t *) tcb)[5], ((uint32_t *) tcb)[6]); | ||
354 | |||
355 | cppi_log_event4("[cppi] send queued (ptr) (len) (ftcb, ltcb)", (uint32_t) tcb->BufPtr, tcb->Off_BLen, (uint32_t) first_tcb, (uint32_t) tcb); | ||
356 | |||
357 | /* put it on the queue */ | ||
358 | pTxCtl->TxActQueueHead = first_tcb; | ||
359 | pTxCtl->TxActQueueTail = tcb; | ||
360 | |||
361 | cppi_log_event3("[cppi] setting state (head) (virt) (next)", (uint32_t) first_tcb, __dma_to_vlynq_phys(first_tcb->dma_handle), (uint32_t) first_tcb->HNext); | ||
362 | |||
363 | /* write CPPI TX HDP - cache is cleaned above */ | ||
364 | tnetv_usb_reg_write(TNETV_DMA_TX_STATE(ch, TNETV_CPPI_TX_WORD_HDP), __dma_to_vlynq_phys(first_tcb->dma_handle)); | ||
365 | |||
366 | pTxCtl->TxActive = 1; | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | * This function allocates transmit buffer descriptors (internal CPHAL function). | ||
373 | * It creates a high priority transmit queue by default for a single Tx | ||
374 | * channel. If QoS is enabled for the given CPHAL device, this function | ||
375 | * will also allocate a low priority transmit queue. | ||
376 | * | ||
377 | * @return 0 OK, Non-Zero Not OK | ||
378 | */ | ||
379 | int tnetv_cppi_init_tcb(struct cppi_info *cppi, int ch) | ||
380 | { | ||
381 | int i, num; | ||
382 | cppi_tcb *pTcb = 0; | ||
383 | char *AllTcb; | ||
384 | int tcbSize; | ||
385 | cppi_txcntl *pTxCtl = &cppi->tx_ctl[ch]; | ||
386 | |||
387 | num = pTxCtl->TxNumBuffers; | ||
388 | tcbSize = (sizeof(cppi_tcb) + 0xf) & ~0xf; | ||
389 | |||
390 | cppi_log_event4("[cppi] init_tcb (ch) (num) (dma) (tcbsz)", ch, num, pTxCtl->tcb_start_dma_addr, tcbSize); | ||
391 | |||
392 | if (pTxCtl->TxNumBuffers == 0) | ||
393 | { | ||
394 | return -1; | ||
395 | } | ||
396 | |||
397 | /* if the memory has already been allocated, simply reuse it! */ | ||
398 | AllTcb = pTxCtl->TcbStart; | ||
399 | |||
400 | // now reinitialize the TCB pool | ||
401 | pTxCtl->TcbPool = 0; | ||
402 | for (i = 0; i < num; i++) | ||
403 | { | ||
404 | pTcb = (cppi_tcb *)(AllTcb + (i * tcbSize)); | ||
405 | pTcb->dma_handle = pTxCtl->tcb_start_dma_addr + (i * tcbSize); | ||
406 | |||
407 | pTcb->BufPtr = 0; | ||
408 | pTcb->mode = 0; | ||
409 | pTcb->HNext = 0; | ||
410 | pTcb->Off_BLen = 0; | ||
411 | pTcb->Eop = 0; | ||
412 | |||
413 | pTcb->Next = (void *) pTxCtl->TcbPool; | ||
414 | |||
415 | pTxCtl->TcbPool = pTcb; | ||
416 | } | ||
417 | |||
418 | cppi_log_event2(" [cppi]TcbPool", (uint32_t) pTxCtl->TcbPool, pTxCtl->TcbPool->dma_handle); | ||
419 | |||
420 | #if USB_CPPI_LOGGING | ||
421 | { | ||
422 | // BEN DEBUG | ||
423 | cppi_tcb *first_tcb = pTxCtl->TcbPool; | ||
424 | cppi_log_event4("[cppi] init tcb", (uint32_t) first_tcb, ((uint32_t *) first_tcb)[0], ((uint32_t *) first_tcb)[1], ((uint32_t *) first_tcb)[2]); | ||
425 | cppi_log_event4("[cppi] ", ((uint32_t *) first_tcb)[3], ((uint32_t *) first_tcb)[4], ((uint32_t *) first_tcb)[5], ((uint32_t *) first_tcb)[6]); | ||
426 | } | ||
427 | #endif | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | // BEN DEBUG | ||
433 | void tnetv_cppi_dump_info(struct cppi_info *cppi) | ||
434 | { | ||
435 | int ch; | ||
436 | cppi_rxcntl *pRxCtl; | ||
437 | cppi_txcntl *pTxCtl; | ||
438 | cppi_tcb *tcb; | ||
439 | cppi_rcb *rcb; | ||
440 | |||
441 | logf("CPPI struct:\n"); | ||
442 | logf("Buf mem: %x Buf size: %d int: %x %x\n\n", (uint32_t) cppi->dma_mem, cppi->dma_size, tnetv_usb_reg_read(TNETV_USB_RX_INT_STATUS), tnetv_usb_reg_read(DM320_VLYNQ_INTST)); | ||
443 | |||
444 | for (ch = 0; ch < CPPI_NUM_CHANNELS; ch++) | ||
445 | { | ||
446 | pRxCtl = &cppi->rx_ctl[ch]; | ||
447 | pTxCtl = &cppi->tx_ctl[ch]; | ||
448 | |||
449 | logf("ch: %d\n", ch); | ||
450 | logf(" rx_numbufs: %d active %d free_buf_cnt %d\n", pRxCtl->RxNumBuffers, pRxCtl->RxActive, tnetv_usb_reg_read(TNETV_USB_RX_FREE_BUF_CNT(ch))); | ||
451 | logf(" q_cnt %d head %x tail %x\n", pRxCtl->RxActQueueCount, (uint32_t) pRxCtl->RxActQueueHead, (uint32_t) pRxCtl->RxActQueueTail); | ||
452 | logf(" fake_head: %x fake_tail: %x\n", (uint32_t) pRxCtl->RxFakeRcvHead, (uint32_t) pRxCtl->RxFakeRcvTail); | ||
453 | |||
454 | rcb = (cppi_rcb *) pRxCtl->RcbStart; | ||
455 | do | ||
456 | { | ||
457 | if (!rcb) | ||
458 | break; | ||
459 | |||
460 | logf(" Rcb: %x\n", (uint32_t) rcb); | ||
461 | logf(" HNext %x BufPtr %x Off_BLen %x mode %x\n", rcb->HNext, rcb->BufPtr, rcb->Off_BLen, rcb->mode); | ||
462 | logf(" Next %x Eop %x dma_handle %x fake_bytes %x\n", (uint32_t) rcb->Next, (uint32_t) rcb->Eop, rcb->dma_handle, rcb->fake_bytes); | ||
463 | rcb = rcb->Next; | ||
464 | |||
465 | } while (rcb && rcb != (cppi_rcb *) pRxCtl->RcbStart); | ||
466 | |||
467 | logf("\n"); | ||
468 | logf(" tx_numbufs: %d active %d\n", pTxCtl->TxNumBuffers, pTxCtl->TxActive); | ||
469 | logf(" q_cnt %d head %x tail %x\n", pTxCtl->TxActQueueCount, (uint32_t) pTxCtl->TxActQueueHead, (uint32_t) pTxCtl->TxActQueueTail); | ||
470 | |||
471 | tcb = (cppi_tcb *) pTxCtl->TcbPool; | ||
472 | do | ||
473 | { | ||
474 | if (!tcb) | ||
475 | break; | ||
476 | |||
477 | logf(" Tcb (pool): %x\n", (uint32_t) tcb); | ||
478 | logf(" HNext %x BufPtr %x Off_BLen %x mode %x\n", tcb->HNext, tcb->BufPtr, tcb->Off_BLen, tcb->mode); | ||
479 | logf(" Next %x Eop %x dma_handle %x\n", (uint32_t) tcb->Next, (uint32_t) tcb->Eop, tcb->dma_handle); | ||
480 | tcb = tcb->Next; | ||
481 | |||
482 | } while (tcb && tcb != (cppi_tcb *) pTxCtl->TcbPool); | ||
483 | |||
484 | tcb = (cppi_tcb *) pTxCtl->TxActQueueHead; | ||
485 | do | ||
486 | { | ||
487 | if (!tcb) | ||
488 | break; | ||
489 | |||
490 | logf(" Tcb (act): %x\n", (uint32_t) tcb); | ||
491 | logf(" HNext %x BufPtr %x Off_BLen %x mode %x\n", tcb->HNext, tcb->BufPtr, tcb->Off_BLen, tcb->mode); | ||
492 | logf(" Next %x Eop %x dma_handle %x\n", (uint32_t) tcb->Next, (uint32_t) tcb->Eop, tcb->dma_handle); | ||
493 | tcb = tcb->Next; | ||
494 | |||
495 | } while (tcb && tcb != (cppi_tcb *) pTxCtl->TxActQueueTail); | ||
496 | |||
497 | } | ||
498 | } | ||
499 | |||
500 | /** | ||
501 | * | ||
502 | * This function is called to indicate to the CPHAL that the upper layer | ||
503 | * software has finished processing the receive data (given to it by | ||
504 | * osReceive()). The CPHAL will then return the appropriate receive buffers | ||
505 | * and buffer descriptors to the available pool. | ||
506 | * | ||
507 | */ | ||
508 | int tnetv_cppi_rx_return(struct cppi_info *cppi, int ch, cppi_rcb *done_rcb) | ||
509 | { | ||
510 | cppi_rxcntl *pRxCtl = &cppi->rx_ctl[ch]; | ||
511 | cppi_rcb *curRcb, *lastRcb, *endRcb; | ||
512 | int num_bufs = 0; | ||
513 | |||
514 | if (!done_rcb) | ||
515 | return -1; | ||
516 | |||
517 | //cppi_log_event3("[cppi] rx_return (last) (first) bufinq", (uint32_t) done_rcb, (uint32_t) done_rcb->Eop, tnetv_usb_reg_read(TNETV_USB_RX_FREE_BUF_CNT(ch))); | ||
518 | |||
519 | curRcb = done_rcb; | ||
520 | endRcb = done_rcb->Eop; | ||
521 | do | ||
522 | { | ||
523 | curRcb->mode = CB_OWNERSHIP_BIT; | ||
524 | curRcb->Off_BLen = MAX_BUF_SIZE; | ||
525 | curRcb->Eop = 0; | ||
526 | |||
527 | pRxCtl->RxActQueueCount++; | ||
528 | num_bufs++; | ||
529 | |||
530 | lastRcb = curRcb; | ||
531 | curRcb = lastRcb->Next; | ||
532 | |||
533 | consistent_sync(lastRcb, sizeof(*lastRcb), DMA_TO_DEVICE); | ||
534 | |||
535 | } while (lastRcb != endRcb); | ||
536 | |||
537 | cppi_log_event1("[cppi] rx_return done", num_bufs); | ||
538 | |||
539 | // let the hardware know about the buffer(s) | ||
540 | tnetv_usb_reg_write(TNETV_USB_RX_FREE_BUF_CNT(ch), num_bufs); | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | int tnetv_cppi_rx_int_recv(struct cppi_info *cppi, int ch, int *buf_size, void *buf, int maxpacket) | ||
546 | { | ||
547 | cppi_rxcntl *pRxCtl = &cppi->rx_ctl[ch]; | ||
548 | cppi_rcb *CurrentRcb, *LastRcb = 0, *SopRcb; | ||
549 | uint8_t *cur_buf_data_addr; | ||
550 | int cur_buf_bytes; | ||
551 | int copy_buf_size = *buf_size; | ||
552 | int ret = -EAGAIN; | ||
553 | |||
554 | *buf_size = 0; | ||
555 | |||
556 | CurrentRcb = pRxCtl->RxFakeRcvHead; | ||
557 | if (!CurrentRcb) | ||
558 | { | ||
559 | cppi_log_event2("[cppi] rx_int recv: nothing in q", tnetv_usb_reg_read(TNETV_USB_RX_INT_STATUS), tnetv_usb_reg_read(DM320_VLYNQ_INTST)); | ||
560 | return -1; | ||
561 | } | ||
562 | |||
563 | cppi_log_event1("[cppi] rx_int recv (ch)", ch); | ||
564 | cppi_log_event4(" [cppi] recv - Processing SOP descriptor fb hd tl", (uint32_t) CurrentRcb, CurrentRcb->fake_bytes, (uint32_t) pRxCtl->RxFakeRcvHead, (uint32_t) pRxCtl->RxFakeRcvTail); | ||
565 | |||
566 | SopRcb = CurrentRcb; | ||
567 | LastRcb = 0; | ||
568 | |||
569 | do | ||
570 | { | ||
571 | // convert from vlynq phys to virt | ||
572 | cur_buf_data_addr = (uint8_t *) __vlynq_phys_to_dma(CurrentRcb->BufPtr); | ||
573 | cur_buf_data_addr = (uint8_t *) __phys_to_virt(cur_buf_data_addr); | ||
574 | cur_buf_bytes = (CurrentRcb->mode) & CB_SIZE_MASK; | ||
575 | |||
576 | // make sure we don't overflow the buffer. | ||
577 | if (cur_buf_bytes > copy_buf_size) | ||
578 | { | ||
579 | ret = 0; | ||
580 | break; | ||
581 | } | ||
582 | |||
583 | // BEN - packet can be ZLP | ||
584 | if (cur_buf_bytes) | ||
585 | { | ||
586 | consistent_sync(cur_buf_data_addr, MAX_BUF_SIZE, DMA_FROM_DEVICE); | ||
587 | |||
588 | memcpy((buf + *buf_size), cur_buf_data_addr, cur_buf_bytes); | ||
589 | |||
590 | copy_buf_size -= cur_buf_bytes; | ||
591 | *buf_size += cur_buf_bytes; | ||
592 | CurrentRcb->fake_bytes -= cur_buf_bytes; | ||
593 | } | ||
594 | else | ||
595 | { | ||
596 | CurrentRcb->fake_bytes = 0; | ||
597 | } | ||
598 | |||
599 | cppi_log_event4(" [cppi] bytes totrcvd amtleft fake", cur_buf_bytes, *buf_size, copy_buf_size, CurrentRcb->fake_bytes); | ||
600 | |||
601 | LastRcb = CurrentRcb; | ||
602 | CurrentRcb = LastRcb->Next; | ||
603 | |||
604 | // sync out fake bytes info | ||
605 | consistent_sync(LastRcb, sizeof(*LastRcb), DMA_TO_DEVICE); | ||
606 | |||
607 | // make sure each packet processed individually | ||
608 | if (cur_buf_bytes < maxpacket) | ||
609 | { | ||
610 | ret = 0; | ||
611 | break; | ||
612 | } | ||
613 | |||
614 | } while (LastRcb != pRxCtl->RxFakeRcvTail && CurrentRcb->fake_bytes && copy_buf_size > 0); | ||
615 | |||
616 | // make sure that the CurrentRcb isn't in the cache | ||
617 | consistent_sync(CurrentRcb, sizeof(*CurrentRcb), DMA_FROM_DEVICE); | ||
618 | |||
619 | if (copy_buf_size == 0) | ||
620 | { | ||
621 | ret = 0; | ||
622 | } | ||
623 | |||
624 | if (LastRcb) | ||
625 | { | ||
626 | SopRcb->Eop = LastRcb; | ||
627 | |||
628 | cppi_log_event3(" [cppi] rcv end", *buf_size, (uint32_t) CurrentRcb, (uint32_t) SopRcb->Eop); | ||
629 | |||
630 | if (LastRcb == pRxCtl->RxFakeRcvTail) | ||
631 | { | ||
632 | pRxCtl->RxFakeRcvHead = 0; | ||
633 | pRxCtl->RxFakeRcvTail = 0; | ||
634 | } | ||
635 | else | ||
636 | { | ||
637 | pRxCtl->RxFakeRcvHead = CurrentRcb; | ||
638 | } | ||
639 | |||
640 | cppi_log_event1(" [cppi] st rx return", ch); | ||
641 | cppi_log_event2(" rcv fake hd tl", (uint32_t) pRxCtl->RxFakeRcvHead, (uint32_t) pRxCtl->RxFakeRcvTail); | ||
642 | |||
643 | // all done, clean up the RCBs | ||
644 | tnetv_cppi_rx_return(cppi, ch, SopRcb); | ||
645 | } | ||
646 | |||
647 | return ret; | ||
648 | } | ||
649 | |||
650 | /* | ||
651 | * This function processes receive interrupts. It traverses the receive | ||
652 | * buffer queue, extracting the data and passing it to the upper layer software via | ||
653 | * osReceive(). It handles all error conditions and fragments without valid data by | ||
654 | * immediately returning the RCB's to the RCB pool. | ||
655 | */ | ||
656 | int tnetv_cppi_rx_int(struct cppi_info *cppi, int ch) | ||
657 | { | ||
658 | cppi_rxcntl *pRxCtl = &cppi->rx_ctl[ch]; | ||
659 | cppi_rcb *CurrentRcb, *LastRcb = 0, *SopRcb; | ||
660 | uint32_t RxBufStatus,PacketsServiced; | ||
661 | int TotalFrags; | ||
662 | |||
663 | cppi_log_event1("[cppi] rx_int (ch)", ch); | ||
664 | |||
665 | CurrentRcb = pRxCtl->RxActQueueHead; | ||
666 | |||
667 | if (!CurrentRcb) | ||
668 | { | ||
669 | cppi_log_event1("[cppi] rx_int no bufs!", (uint32_t) CurrentRcb); | ||
670 | return -1; | ||
671 | } | ||
672 | |||
673 | // make sure that all of the buffers get an invalidated cache | ||
674 | consistent_sync(pRxCtl->RcbStart, sizeof(cppi_rcb) * CPPI_RX_NUM_BUFS, DMA_FROM_DEVICE); | ||
675 | |||
676 | RxBufStatus = CurrentRcb->mode; | ||
677 | PacketsServiced = 0; | ||
678 | |||
679 | cppi_log_event4("[cppi] currentrcb, mode numleft fake", (uint32_t) CurrentRcb, CurrentRcb->mode, pRxCtl->RxActQueueCount, CurrentRcb->fake_bytes); | ||
680 | cppi_log_event4("[cppi]", ((uint32_t *) CurrentRcb)[0], ((uint32_t *) CurrentRcb)[1], ((uint32_t *) CurrentRcb)[2], ((uint32_t *) CurrentRcb)[3]); | ||
681 | |||
682 | while(((RxBufStatus & CB_OWNERSHIP_BIT) == 0) && (pRxCtl->RxActQueueCount > 0)) | ||
683 | { | ||
684 | cppi_log_event2(" [cppi]Processing SOP descriptor st", (uint32_t) CurrentRcb, RxBufStatus); | ||
685 | |||
686 | SopRcb = CurrentRcb; | ||
687 | |||
688 | TotalFrags = 0; | ||
689 | |||
690 | do | ||
691 | { | ||
692 | TotalFrags++; | ||
693 | PacketsServiced++; | ||
694 | |||
695 | // Write the completion pointer | ||
696 | tnetv_usb_reg_write(TNETV_DMA_RX_CMPL(ch), __dma_to_vlynq_phys(CurrentRcb->dma_handle)); | ||
697 | |||
698 | CurrentRcb->fake_bytes = (CurrentRcb->mode) & 0xFFFF; | ||
699 | |||
700 | // BEN - make sure this gets marked! | ||
701 | if (!CurrentRcb->fake_bytes || (CurrentRcb->mode & CB_ZLP_GARBAGE)) | ||
702 | { | ||
703 | CurrentRcb->mode &= 0xFFFF0000; | ||
704 | CurrentRcb->fake_bytes = 0x10000; | ||
705 | } | ||
706 | |||
707 | cppi_log_event1(" fake_bytes:", CurrentRcb->fake_bytes); | ||
708 | |||
709 | RxBufStatus = CurrentRcb->mode; | ||
710 | LastRcb = CurrentRcb; | ||
711 | CurrentRcb = LastRcb->Next; | ||
712 | |||
713 | // sync the fake_bytes value back to mem | ||
714 | consistent_sync(LastRcb, sizeof(*LastRcb), DMA_TO_DEVICE); | ||
715 | |||
716 | } while (((CurrentRcb->mode & CB_OWNERSHIP_BIT) == 0) && ((RxBufStatus & CB_EOF_BIT) == 0)); | ||
717 | |||
718 | SopRcb->Eop = LastRcb; | ||
719 | |||
720 | pRxCtl->RxActQueueHead = CurrentRcb; | ||
721 | pRxCtl->RxActQueueCount -= TotalFrags; | ||
722 | |||
723 | if (LastRcb->mode & CB_EOQ_BIT) | ||
724 | { | ||
725 | if (CurrentRcb) | ||
726 | { | ||
727 | cppi_log_event1(" [cppi] rcv done q next", LastRcb->HNext); | ||
728 | tnetv_usb_reg_write(TNETV_DMA_RX_STATE(ch, TNETV_CPPI_RX_WORD_HDP), LastRcb->HNext); | ||
729 | } | ||
730 | else | ||
731 | { | ||
732 | cppi_log_event0(" [cppi] rcv done"); | ||
733 | |||
734 | pRxCtl->RxActive = 0; | ||
735 | } | ||
736 | } | ||
737 | |||
738 | // BEN - add to the list of buffers we need to deal with | ||
739 | if (!pRxCtl->RxFakeRcvHead) | ||
740 | { | ||
741 | pRxCtl->RxFakeRcvHead = SopRcb; | ||
742 | pRxCtl->RxFakeRcvTail = SopRcb->Eop; | ||
743 | } | ||
744 | else | ||
745 | { | ||
746 | pRxCtl->RxFakeRcvTail = SopRcb->Eop; | ||
747 | } | ||
748 | |||
749 | // make sure we have enough buffers | ||
750 | cppi_log_event1(" nextrcb", CurrentRcb->mode); | ||
751 | |||
752 | if (CurrentRcb) | ||
753 | { | ||
754 | // continue the loop | ||
755 | RxBufStatus = CurrentRcb->mode; | ||
756 | } | ||
757 | |||
758 | } /* while */ | ||
759 | |||
760 | cppi_log_event2("[cppi] fake hd tl", (uint32_t) pRxCtl->RxFakeRcvHead, (uint32_t) pRxCtl->RxFakeRcvTail); | ||
761 | |||
762 | // sync out all buffers before leaving | ||
763 | consistent_sync(pRxCtl->RcbStart, (CPPI_RX_NUM_BUFS * sizeof(cppi_rcb)), DMA_FROM_DEVICE); | ||
764 | |||
765 | return PacketsServiced; | ||
766 | } | ||
767 | |||
768 | static void tnetv_cppi_rx_queue_init(struct cppi_info *cppi, int ch, dma_addr_t buf, unsigned length) | ||
769 | { | ||
770 | cppi_rxcntl *pRxCtl = &cppi->rx_ctl[ch]; | ||
771 | cppi_rcb *rcb, *first_rcb; | ||
772 | unsigned int queued_len = 0; | ||
773 | int rcblen; | ||
774 | int num_frags = 0; | ||
775 | dma_addr_t buf_ptr; | ||
776 | |||
777 | if (length == 0) | ||
778 | { | ||
779 | cppi_log_event0("[cppi] len = 0, nothing to recv"); | ||
780 | return; | ||
781 | } | ||
782 | |||
783 | // usb_requests can have a 32 bit length, but CPPI DMA fragments | ||
784 | // have a 64k limit. Split the usb_request up into fragments here. | ||
785 | first_rcb = pRxCtl->RcbPool; | ||
786 | rcb = first_rcb; | ||
787 | |||
788 | cppi_log_event2("[cppi] Rx queue add: head len", (uint32_t) first_rcb, length); | ||
789 | |||
790 | while (queued_len < length) | ||
791 | { | ||
792 | buf_ptr = buf + queued_len; | ||
793 | rcb->BufPtr = __dma_to_vlynq_phys(buf_ptr); | ||
794 | |||
795 | rcb->HNext = 0; | ||
796 | rcb->mode = CB_OWNERSHIP_BIT; | ||
797 | |||
798 | rcblen = ((length - queued_len) > MAX_BUF_SIZE) ? MAX_BUF_SIZE : (length - queued_len); | ||
799 | rcb->Off_BLen = rcblen; | ||
800 | |||
801 | queued_len += rcblen; | ||
802 | if (queued_len < length) | ||
803 | { | ||
804 | rcb->HNext = __dma_to_vlynq_phys(((cppi_rcb *) (rcb->Next))->dma_handle); | ||
805 | rcb = rcb->Next; | ||
806 | } | ||
807 | |||
808 | num_frags++; | ||
809 | } | ||
810 | |||
811 | pRxCtl->RcbPool = rcb->Next; | ||
812 | rcb->Next = 0; | ||
813 | |||
814 | cppi_log_event4("[cppi] Adding Rcb (dma) (paddr) (buf)", (uint32_t) rcb, rcb->dma_handle, __dma_to_vlynq_phys(rcb->dma_handle), (uint32_t) rcb->BufPtr); | ||
815 | cppi_log_event4("[cppi] Next HNext (len) of (total)", (uint32_t) rcb->Next, rcb->HNext, queued_len, length); | ||
816 | |||
817 | pRxCtl->RxActQueueCount += num_frags; | ||
818 | |||
819 | cppi_log_event4("[cppi] rx queued (ptr) (len) (ftcb, ltcb)", (uint32_t) rcb->BufPtr, rcb->Off_BLen, (uint32_t) first_rcb, (uint32_t) rcb); | ||
820 | cppi_log_event2(" [cppi] mode num_frags", rcb->mode, num_frags); | ||
821 | |||
822 | pRxCtl->RxActQueueHead = first_rcb; | ||
823 | pRxCtl->RxActQueueTail = rcb; | ||
824 | |||
825 | cppi_log_event2("[cppi] setting rx (head) (virt)", (uint32_t) first_rcb, __dma_to_vlynq_phys(first_rcb->dma_handle)); | ||
826 | cppi_log_event4("[cppi] ", ((uint32_t *) first_rcb)[0], ((uint32_t *) first_rcb)[1], ((uint32_t *) first_rcb)[2], ((uint32_t *) first_rcb)[3]); | ||
827 | |||
828 | // make this into a circular buffer so we never get caught with | ||
829 | // no free buffers left | ||
830 | rcb->Next = pRxCtl->RxActQueueHead; | ||
831 | rcb->HNext = (uint32_t) (__dma_to_vlynq_phys(pRxCtl->RxActQueueHead->dma_handle)); | ||
832 | } | ||
833 | |||
834 | int tnetv_cppi_rx_queue_add(struct cppi_info *cppi, int ch, dma_addr_t buf, unsigned length) | ||
835 | { | ||
836 | (void)buf; | ||
837 | (void)length; | ||
838 | cppi_rxcntl *pRxCtl = &cppi->rx_ctl[ch]; | ||
839 | unsigned int cur_bufs; | ||
840 | |||
841 | cur_bufs = tnetv_usb_reg_read(TNETV_USB_RX_FREE_BUF_CNT(ch)); | ||
842 | |||
843 | if (!pRxCtl->RxActive) | ||
844 | { | ||
845 | cppi_log_event0("[cppi] queue add - not active"); | ||
846 | |||
847 | pRxCtl->RcbPool = (cppi_rcb *) pRxCtl->RcbStart; | ||
848 | |||
849 | // add all the buffers to the active (circular) queue | ||
850 | tnetv_cppi_rx_queue_init(cppi, ch, (dma_addr_t) __virt_to_phys(dma_recv_buf[ch]), (MAX_BUF_SIZE * pRxCtl->RxNumBuffers)); | ||
851 | |||
852 | /* write Rx Queue Head Descriptor Pointer */ | ||
853 | tnetv_usb_reg_write(TNETV_DMA_RX_STATE(ch, TNETV_CPPI_RX_WORD_HDP), __dma_to_vlynq_phys(pRxCtl->RxActQueueHead->dma_handle)); | ||
854 | |||
855 | pRxCtl->RxActive = 1; | ||
856 | |||
857 | // sync out all buffers before starting | ||
858 | consistent_sync(pRxCtl->RcbStart, (CPPI_RX_NUM_BUFS * sizeof(cppi_rcb)), DMA_TO_DEVICE); | ||
859 | |||
860 | // sync out temp rx buffer | ||
861 | consistent_sync(dma_recv_buf[ch], CPPI_DMA_RX_BUF_SIZE, DMA_FROM_DEVICE); | ||
862 | |||
863 | if (cur_bufs < pRxCtl->RxActQueueCount) | ||
864 | { | ||
865 | // let the hardware know about the buffer(s) | ||
866 | tnetv_usb_reg_write(TNETV_USB_RX_FREE_BUF_CNT(ch), pRxCtl->RxActQueueCount - cur_bufs); | ||
867 | } | ||
868 | } | ||
869 | |||
870 | cppi_log_event3("[cppi] rx add: (cur_bufs) (avail_bufs) (now)", cur_bufs, pRxCtl->RxActQueueCount, tnetv_usb_reg_read(TNETV_USB_RX_FREE_BUF_CNT(ch))); | ||
871 | |||
872 | return 0; | ||
873 | } | ||
874 | |||
875 | int tnetv_cppi_flush_rx_queue(struct cppi_info *cppi, int ch) | ||
876 | { | ||
877 | cppi_rxcntl *pRxCtl = &cppi->rx_ctl[ch]; | ||
878 | cppi_rcb *rcb; | ||
879 | int num_bufs; | ||
880 | |||
881 | cppi_log_event1("[cppi] flush RX ", (uint32_t) pRxCtl->RxActQueueHead); | ||
882 | |||
883 | // flush out any pending receives | ||
884 | tnetv_cppi_rx_int(cppi, ch); | ||
885 | |||
886 | // now discard all received data | ||
887 | rcb = pRxCtl->RxFakeRcvHead; | ||
888 | |||
889 | if (rcb) | ||
890 | { | ||
891 | rcb->Eop = pRxCtl->RxFakeRcvTail; | ||
892 | |||
893 | // clean up any unreceived RCBs | ||
894 | tnetv_cppi_rx_return(cppi, ch, rcb); | ||
895 | } | ||
896 | |||
897 | pRxCtl->RxFakeRcvHead = 0; | ||
898 | pRxCtl->RxFakeRcvTail = 0; | ||
899 | |||
900 | pRxCtl->RxActive = 0; | ||
901 | |||
902 | // drain the HW free buffer count | ||
903 | num_bufs = tnetv_usb_reg_read(TNETV_USB_RX_FREE_BUF_CNT(ch)); | ||
904 | tnetv_usb_reg_write(TNETV_USB_RX_FREE_BUF_CNT(ch), -num_bufs); | ||
905 | |||
906 | cppi_log_event2("[cppi] flush RX queue done (freed) act: ", num_bufs, (uint32_t) pRxCtl->RxActQueueCount); | ||
907 | |||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | |||
912 | /* | ||
913 | * This function allocates receive buffer descriptors (internal CPHAL function). | ||
914 | * After allocation, the function 'queues' (gives to the hardware) the newly | ||
915 | * created receive buffers to enable packet reception. | ||
916 | * | ||
917 | * @param ch Channel number. | ||
918 | * | ||
919 | * @return 0 OK, Non-Zero Not OK | ||
920 | */ | ||
921 | int tnetv_cppi_init_rcb(struct cppi_info *cppi, int ch) | ||
922 | { | ||
923 | int i, num; | ||
924 | cppi_rcb *pRcb; | ||
925 | char *AllRcb; | ||
926 | int rcbSize; | ||
927 | cppi_rxcntl *pRxCtl = &cppi->rx_ctl[ch]; | ||
928 | |||
929 | num = pRxCtl->RxNumBuffers; | ||
930 | rcbSize = (sizeof(cppi_rcb) + 0xf) & ~0xf; | ||
931 | |||
932 | cppi_log_event2("[cppi] init_rcb ch num", ch, num); | ||
933 | |||
934 | if (pRxCtl->RxNumBuffers == 0) | ||
935 | { | ||
936 | return -1; | ||
937 | } | ||
938 | |||
939 | /* if the memory has already been allocated, simply reuse it! */ | ||
940 | AllRcb = pRxCtl->RcbStart; | ||
941 | |||
942 | // now reinitialize the RCB pool | ||
943 | pRxCtl->RcbPool = 0; | ||
944 | for (i = (num - 1); i >= 0; i--) | ||
945 | { | ||
946 | pRcb = (cppi_rcb *)(AllRcb + (i * rcbSize)); | ||
947 | |||
948 | pRcb->dma_handle = pRxCtl->rcb_start_dma_addr + (i * rcbSize); | ||
949 | |||
950 | pRcb->BufPtr = 0; | ||
951 | pRcb->mode = 0; | ||
952 | pRcb->HNext = 0; | ||
953 | pRcb->Next = (void *) pRxCtl->RcbPool; | ||
954 | pRcb->Off_BLen = 0; | ||
955 | pRcb->Eop = 0; | ||
956 | pRcb->fake_bytes = 0; | ||
957 | |||
958 | pRxCtl->RcbPool = pRcb; | ||
959 | } | ||
960 | |||
961 | cppi_log_event2(" [cppi]RcbPool (dma)", (uint32_t) pRxCtl->RcbPool, pRxCtl->RcbPool->dma_handle); | ||
962 | |||
963 | pRxCtl->RxActQueueCount = 0; | ||
964 | pRxCtl->RxActQueueHead = 0; | ||
965 | pRxCtl->RxActive = 0; | ||
966 | |||
967 | pRxCtl->RxFakeRcvHead = 0; | ||
968 | pRxCtl->RxFakeRcvTail = 0; | ||
969 | |||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | static uint8_t ch_buf_cnt[][2] = { | ||
974 | {CPPI_RX_NUM_BUFS, 2}, // ch0: bulk out/in | ||
975 | {CPPI_RX_NUM_BUFS, 2}, // ch1: bulk out/in | ||
976 | {0, 2}, // ch2: interrupt | ||
977 | {0, 2} // ch3: interrupt | ||
978 | }; | ||
979 | |||
980 | void tnetv_cppi_init(struct cppi_info *cppi) | ||
981 | { | ||
982 | int ch; | ||
983 | uint8_t *alloc_ptr; | ||
984 | int ch_mem_size[CPPI_NUM_CHANNELS]; | ||
985 | |||
986 | // wipe cppi memory | ||
987 | memset(cppi, 0, sizeof(*cppi)); | ||
988 | |||
989 | // find out how much memory we need to allocate | ||
990 | cppi->dma_size = 0; | ||
991 | for (ch = 0; ch < CPPI_NUM_CHANNELS; ch++) | ||
992 | { | ||
993 | ch_mem_size[ch] = (ch_buf_cnt[ch][0] * sizeof(cppi_rcb)) + (ch_buf_cnt[ch][1] * sizeof(cppi_tcb)); | ||
994 | cppi->dma_size += ch_mem_size[ch]; | ||
995 | } | ||
996 | |||
997 | // allocate DMA-able memory | ||
998 | if (cppi->dma_size != CPPI_INFO_MEM_SIZE) | ||
999 | { | ||
1000 | panicf("Invalid dma size expected %d got %d", cppi->dma_size, CPPI_INFO_MEM_SIZE); | ||
1001 | } | ||
1002 | cppi->dma_handle = (dma_addr_t) __virt_to_phys(cppi->dma_mem); | ||
1003 | |||
1004 | memset(cppi->dma_mem, 0, cppi->dma_size); | ||
1005 | |||
1006 | cppi_log_event2("[cppi] all CBs sz mem", cppi->dma_size, (uint32_t) cppi->dma_mem); | ||
1007 | |||
1008 | // now set up the pointers | ||
1009 | alloc_ptr = cppi->dma_mem; | ||
1010 | for (ch = 0; ch < CPPI_NUM_CHANNELS; ch++) | ||
1011 | { | ||
1012 | cppi->rx_ctl[ch].RxNumBuffers = ch_buf_cnt[ch][0]; | ||
1013 | cppi->rx_ctl[ch].RcbStart = alloc_ptr; | ||
1014 | cppi->rx_ctl[ch].rcb_start_dma_addr = (dma_addr_t) __virt_to_phys(alloc_ptr); | ||
1015 | alloc_ptr += (ch_buf_cnt[ch][0] * sizeof(cppi_rcb)); | ||
1016 | |||
1017 | cppi->tx_ctl[ch].TxNumBuffers = ch_buf_cnt[ch][1]; | ||
1018 | cppi->tx_ctl[ch].TcbStart = alloc_ptr; | ||
1019 | cppi->tx_ctl[ch].tcb_start_dma_addr = (dma_addr_t) __virt_to_phys(alloc_ptr); | ||
1020 | alloc_ptr += (ch_buf_cnt[ch][1] * sizeof(cppi_tcb)); | ||
1021 | |||
1022 | cppi_log_event3("[cppi] alloc bufs: ch dmarcb dmatcb", ch, cppi->rx_ctl[ch].rcb_start_dma_addr, cppi->tx_ctl[ch].tcb_start_dma_addr); | ||
1023 | |||
1024 | // set up receive buffer | ||
1025 | if (ch_buf_cnt[ch][0]) | ||
1026 | { | ||
1027 | dma_recv_buf[ch] = (ch == 0) ? ch0_rx_buf : ((ch == 1) ? ch1_rx_buf : 0); | ||
1028 | cppi_log_event3("[cppi] Alloc fake DMA buf ch", ch, (uint32_t) dma_recv_buf[ch], (uint32_t) __virt_to_phys(dma_recv_buf[ch])); | ||
1029 | } | ||
1030 | else | ||
1031 | { | ||
1032 | dma_recv_buf[ch] = 0; | ||
1033 | } | ||
1034 | } | ||
1035 | |||
1036 | } | ||
1037 | |||
1038 | void tnetv_cppi_cleanup(struct cppi_info *cppi) | ||
1039 | { | ||
1040 | cppi_log_event0("wipe cppi mem"); | ||
1041 | |||
1042 | // wipe cppi memory | ||
1043 | memset(cppi, 0, sizeof(*cppi)); | ||
1044 | } | ||