1  /**********************************************************************
2  * Copyright (C) 2014-2015 Cadence Design Systems, Inc.- http://www.cadence.com
3  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  ******************************************************************************
17  * edd_tx.c
18  * Ethernet DMA MAC Driver
19  *
20  * Tx-related functions source file
21  *****************************************************************************/
22 /****************************************************************************
23 * Modification by Infineon: To make this file compile with ModusToolbox
24 * toolchain
25 *****************************************************************************/
26 
27 #include "cy_device.h"
28 
29 #if defined (CY_IP_MXETH)
30 
31 #include "cdn_stdint.h"
32 #include "cdn_errno.h"
33 #include "log.h"
34 #include "cps_v2.h"
35 #include "emac_regs.h"
36 #include "cedi.h"
37 #include "edd_int.h"
38 
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42 /******************************************************************************
43  * Private Driver functions
44  *****************************************************************************/
45 
46 /* move descriptor pointer bd and virtual address pointer vp on to next in ring.
47  * stat should be the status (word 1) of current descriptor */
inc_txbd(void * pD,uint32_t stat,txDesc ** bd,uintptr_t ** vp,txQueue_t * txQ)48 static void inc_txbd(void *pD, uint32_t stat, txDesc **bd, uintptr_t **vp,
49                         txQueue_t *txQ) {
50     if (stat & CEDI_TXD_WRAP) {
51         *bd = txQ->bdBase;
52         *vp = txQ->vAddrList;
53     } else {
54         *bd = (txDesc *) (((uintptr_t)(*bd))+(CEDI_PdVar(txDescriptorSize)));
55         ++(*vp);
56     }
57 }
58 
59 /* move descriptor and virtual address pointers back to previous in ring */
dec_txbd(void * pD,txDesc ** bd,uintptr_t ** vp,txQueue_t * txQ)60 static void dec_txbd(void *pD, txDesc **bd, uintptr_t **vp, txQueue_t *txQ) {
61     if (*bd==txQ->bdBase) {
62         *bd = (txDesc *)(((uintptr_t)(*bd))+
63                             (txQ->descMax-1)*(CEDI_PdVar(txDescriptorSize)));
64         *vp += (txQ->descMax-1);
65     } else {
66         *bd = (txDesc *)(((uintptr_t)(*bd))-(CEDI_PdVar(txDescriptorSize)));
67         --(*vp);
68     }
69 }
70 
71 /******************************************************************************
72  * Driver API functions
73  *****************************************************************************/
74 
75 /**
76  * Identify max Tx pkt size for queues. When using full store & forward packet
77  * buffering, this is based on the sram size for each queue, otherwise it is
78  * limited by an internal counter to 16kB.
79  * @param pD - driver private state info specific to this instance
80  * @param maxTxSize - pointer for returning array of sizes for queues
81  * @return 0 if successful
82  * @return EINVAL if any parameter =NULL
83  */
emacCalcMaxTxFrameSize(void * pD,CEDI_FrameSize * maxTxSize)84 uint32_t emacCalcMaxTxFrameSize(void *pD, CEDI_FrameSize *maxTxSize) {
85     uint32_t i, watermark;
86     uint16_t ram_word_size, ram_addr_bits, burst_len;
87     uint16_t ram_size, num_segments, size_per_segment, tx_overhead;
88     uint16_t num_segments_q[CEDI_MAX_TX_QUEUES];
89     uint8_t enabled = 0;
90     uint32_t ret;
91 
92     if ((pD==NULL) || (maxTxSize==NULL)) return EINVAL;
93 
94     if (0!=(ret = emacGetTxPartialStFwd(pD, &watermark, &enabled)))
95         return ret;
96 
97     if (!(enabled) && CEDI_PdVar(hwCfg).tx_pkt_buffer)
98     {
99         // What is word size of SRAM in bytes
100         ram_word_size = (CEDI_PdVar(hwCfg).tx_pbuf_data >> 1)+1;
101         //vDbgMsg(DBG_GEN_MSG, 10, "RAM word size = %u (x32 bits)\n", CEDI_PdVar(hwCfg).tx_pbuf_data);
102         ram_addr_bits = CEDI_PdVar(hwCfg).tx_pbuf_addr;
103         //vDbgMsg(DBG_GEN_MSG, 10, "RAM Tx addr bits = %u\n", ram_addr_bits);
104 
105         ram_size = ram_addr_bits + ram_word_size + 1;
106         vDbgMsg(DBG_GEN_MSG, 10, "RAM size = %u\n", 1<<ram_size);
107 
108         // how many segments are there ?
109         num_segments = CEDI_PdVar(hwCfg).tx_pbuf_queue_segment_size;
110         /* this is number of address lines used for segment selection,
111          * e.g. if =3, there are 2^3 = 8 segments */
112         vDbgMsg(DBG_GEN_MSG, 10, "Num segments = %u\n", 1<<num_segments);
113 
114         size_per_segment  = (ram_size - num_segments);
115                                                   /* again, as a power of 2 */
116         vDbgMsg(DBG_GEN_MSG, 10, "RAM Size per segment = %u\n",
117                 1<<size_per_segment);
118 
119         num_segments_q[0] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q0;
120         num_segments_q[1] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q1;
121         num_segments_q[2] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q2;
122         num_segments_q[3] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q3;
123         num_segments_q[4] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q4;
124         num_segments_q[5] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q5;
125         num_segments_q[6] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q6;
126         num_segments_q[7] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q7;
127         num_segments_q[8] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q8;
128         num_segments_q[9] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q9;
129         num_segments_q[10] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q10;
130         num_segments_q[11] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q11;
131         num_segments_q[12] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q12;
132         num_segments_q[13] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q13;
133         num_segments_q[14] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q14;
134         num_segments_q[15] = CEDI_PdVar(hwCfg).tx_pbuf_num_segments_q15;
135         vDbgMsg(DBG_GEN_MSG, 10,
136                 "number segments  Q0 = %u, Q1 = %u, Q2 = %u, Q3 = %u,\n",
137                 num_segments_q[0], num_segments_q[1], num_segments_q[2],
138                 num_segments_q[3]);
139         vDbgMsg(DBG_GEN_MSG, 10,
140                 "number segments  Q4 = %u, Q5 = %u, Q6 = %u, Q7 = %u,\n",
141                 num_segments_q[4], num_segments_q[5], num_segments_q[6],
142                 num_segments_q[7]);
143 
144         burst_len = EMAC_REGS__DMA_CONFIG__AMBA_BURST_LENGTH__READ(
145                         CPS_UncachedRead32(CEDI_RegAddr(dma_config)));
146         switch (burst_len) {
147          case CEDI_AMBD_BURST_LEN_8:
148                  tx_overhead = ((CEDI_PdVar(hwCfg).tx_pbuf_data << 5)/8)*26;
149                  break;
150          case CEDI_AMBD_BURST_LEN_16:
151                  tx_overhead = ((CEDI_PdVar(hwCfg).tx_pbuf_data << 5)/8)*46;
152                  break;
153          case CEDI_AMBD_BURST_LEN_1:
154          case CEDI_AMBD_BURST_LEN_4:
155          default:
156                  tx_overhead = ((CEDI_PdVar(hwCfg).tx_pbuf_data << 5)/8)*16;
157         }
158 
159         for (i=0; i<CEDI_MAX_TX_QUEUES; i++) {
160             if (i<CEDI_PdVar(cfg).txQs) {
161                 maxTxSize->FrameSize[i] =
162                    (1 << (num_segments_q[i] + size_per_segment)) - tx_overhead;
163                 /* add in some extra overhead */
164                 maxTxSize->FrameSize[i] = (maxTxSize->FrameSize[i]*9)/10;
165             }
166             else
167                 maxTxSize->FrameSize[i] = 0;
168         }
169     }
170     else
171         for (i=0; i<CEDI_MAX_TX_QUEUES; i++)
172             if (i<CEDI_PdVar(cfg).txQs)
173                 maxTxSize->FrameSize[i] = CEDI_TXD_LMASK;
174             else
175                 maxTxSize->FrameSize[i] = 0;
176 
177     vDbgMsg(DBG_GEN_MSG, 10,
178             "max_frm_size_Q0 = %u, Q1 = %u, Q2 = %u, Q3 = %u,\n",
179             maxTxSize->FrameSize[0], maxTxSize->FrameSize[1],
180             maxTxSize->FrameSize[2], maxTxSize->FrameSize[3]);
181     vDbgMsg(DBG_GEN_MSG, 10,
182             "max_frm_size_Q4 = %u, Q5 = %u, Q6 = %u, Q7 = %u,\n",
183             maxTxSize->FrameSize[4], maxTxSize->FrameSize[5],
184             maxTxSize->FrameSize[6], maxTxSize->FrameSize[7]);
185     return 0;
186 }
187 
188 
189 /* Add a buffer containing Tx data to the end of the transmit queue.
190  * Use repeated calls for multi-buffer frames, setting lastBuffer on the
191  * last call, to indicate the end of the frame.
192  * @param pD - driver private state info specific to this instance
193  * @param queueNum - number of Tx queue
194  * @param bufAdd - pointer to struct for virtual and physical addresses of
195  *              start of data buffer
196  * @param length - length of data in buffer
197  * @param flags - bit-flags specifying last buffer/auto CRC/auto-start
198  * @return 0 if successful
199  * @return EINVAL if invalid queueNum, length or buffer alignment, NULL
200  *      pointers or buffer addresses
201  * @return ENOENT if no available descriptors
202  */
emacQueueTxBuf(void * pD,uint8_t queueNum,CEDI_BuffAddr * bufAdd,uint32_t length,uint8_t flags)203 uint32_t emacQueueTxBuf(void *pD, uint8_t queueNum, CEDI_BuffAddr *bufAdd,
204         uint32_t length, uint8_t flags)
205 {
206     txQueue_t *txQ;
207     txDesc *freeDesc;
208     txDesc *bd1stBuf;
209     uint32_t stat, ncr;
210     uint16_t nFree;
211 
212     if ((pD==NULL) || (queueNum>=CEDI_PdVar(cfg).txQs) || (bufAdd==NULL)
213             || (bufAdd->pAddr==0))
214         return EINVAL;
215 
216 //    vDbgMsg(DBG_GEN_MSG, 10, "%s entered\n", __func__);
217 
218     txQ = &CEDI_PdVar(txQueue)[queueNum];
219     freeDesc = txQ->bdHead;
220     bd1stBuf = txQ->bd1stBuf;
221 
222     if (!length || (length > CEDI_TXD_LMASK)) {
223         vDbgMsg(DBG_GEN_MSG, 5, "Error: bad length specified: %u\n", length);
224         return EINVAL;
225     }
226 
227     if (emacTxDescFree(pD, queueNum, &nFree)) return EINVAL;
228     if (!nFree) {
229         vDbgMsg(DBG_GEN_MSG, 5, "%s\n", "Error: insufficient buffer descriptors");
230         return ENOENT;
231     }
232 
233     /* preserve wrap bit if present in status word */
234     stat = CPS_UncachedRead32(&freeDesc->word[1]) & CEDI_TXD_WRAP;
235     stat |= ((flags & CEDI_TXB_LAST_BUFF)?CEDI_TXD_LAST_BUF:0)
236             | ((flags & CEDI_TXB_NO_AUTO_CRC)?CEDI_TXD_NO_AUTO_CRC:0) | length;
237 
238     /* Handle a multi-buffer frame */
239     if (!(flags & CEDI_TXB_LAST_BUFF) && (NULL == bd1stBuf)) {
240         /* This is the 1st buf of several; prevent it from going and remember its BD. */
241         stat |= (uint32_t)CEDI_TXD_USED;
242         txQ->bd1stBuf = freeDesc;
243     }
244 
245     *txQ->vHead = bufAdd->vAddr;
246     CPS_UncachedWrite32(&freeDesc->word[0], bufAdd->pAddr & 0xFFFFFFFF);
247     /* upper 32 bits if 64 bit addressing */
248     if (CEDI_PdVar(cfg).dmaAddrBusWidth) {
249 #ifdef CEDI_64B_COMPILE
250         /* 64-bit addressing */
251         CPS_UncachedWrite32(&freeDesc->word[2],
252                              (bufAdd->pAddr & 0xFFFFFFFF00000000)>>32);
253 #else
254         /* 32-bit addressing */
255 #endif
256     }
257     CPS_UncachedWrite32(&freeDesc->word[1], stat);
258 
259     if ((flags & CEDI_TXB_LAST_BUFF) && (NULL != bd1stBuf)) {
260         /* Last buffer of a multibuffer frame is in place, 1st buffer can go. */
261         CPS_UncachedWrite32(&bd1stBuf->word[1],
262             CPS_UncachedRead32(&bd1stBuf->word[1]) & ~CEDI_TXD_USED);
263         txQ->bd1stBuf = NULL;
264     }
265 
266     --txQ->descFree;
267     if (emacTxDescFree(pD, queueNum, &nFree)) return EINVAL;
268     vDbgMsg(DBG_GEN_MSG, 15, "len=%u, queue=%u, txbdHead=%p, buffV=%p, buffP=%p, descFree=%u\n",
269             length, queueNum, freeDesc, (void *)bufAdd->vAddr, (void *)bufAdd->pAddr, nFree);
270     inc_txbd(pD, stat, &freeDesc, &txQ->vHead, txQ);
271     txQ->bdHead = freeDesc;
272 
273     /* set going if complete frame queued */
274     if ((flags & CEDI_TXB_LAST_BUFF) && !(flags & CEDI_TXB_NO_AUTO_START)) {
275         ncr = CPS_UncachedRead32(CEDI_RegAddr(network_control));
276         EMAC_REGS__NETWORK_CONTROL__TX_START_PCLK__SET(ncr);
277         CPS_UncachedWrite32(CEDI_RegAddr(network_control), ncr);
278     }
279 
280     return 0;
281 }
282 
283 /* Add a buffer containing Tx data to the end of the transmit queue.
284  * Use repeated calls for multi-buffer frames, setting lastBuffer on the
285  * last call, to indicate the end of the frame.
286  * @param pD - driver private state info specific to this instance
287  * @param prm - pointer to struct of parameters
288  * @return 0 if successful
289  * @return EINVAL if invalid queueNum, length or buffer alignment, NULL
290  *      pointers or buffer addresses, or prm->flags specifies
291  *      CEDI_TXB_LAST_BUFF as well as CEDI_TXB_TCP_ENCAP or CEDI_TXB_UDP_ENCAP
292  * @return ENOENT if no available descriptors
293  */
emacQTxBuf(void * pD,CEDI_qTxBufParams * prm)294 uint32_t emacQTxBuf(void *pD, CEDI_qTxBufParams *prm)
295 {
296     txQueue_t *txQ;
297     txDesc *freeDesc;
298     txDesc *bd1stBuf;
299     uint32_t stat, ncr;
300     uint16_t nFree;
301 
302     if ((pD==NULL) || (prm->queueNum>=CEDI_PdVar(cfg).txQs)
303             || (prm->bufAdd==NULL)
304             || (prm->bufAdd->pAddr==0))
305         return EINVAL;
306 
307 //    vDbgMsg(DBG_GEN_MSG, 10, "%s entered\n", __func__);
308 
309     txQ = &CEDI_PdVar(txQueue)[prm->queueNum];
310     freeDesc = txQ->bdHead;
311     bd1stBuf = txQ->bd1stBuf;
312 
313     if (!prm->length || (prm->length > CEDI_TXD_LMASK)) {
314         vDbgMsg(DBG_GEN_MSG, 5, "Error: bad length specified: %u\n",
315                 prm->length);
316         return EINVAL;
317     }
318 
319     if (emacTxDescFree(pD, prm->queueNum, &nFree)) return EINVAL;
320     if (!nFree) {
321         vDbgMsg(DBG_GEN_MSG, 5, "%s\n", "Error: insufficient buffer descriptors");
322         return ENOENT;
323     }
324 
325     if (NULL!=bd1stBuf) {     /* inc counter after 1st in frame */
326         txQ->descNum++;
327     }
328 
329     /* preserve wrap bit if present in status word */
330     stat = CPS_UncachedRead32(&freeDesc->word[1]) & CEDI_TXD_WRAP;
331     stat |= ((prm->flags & CEDI_TXB_LAST_BUFF)?CEDI_TXD_LAST_BUF:0)
332             | ((prm->flags & CEDI_TXB_NO_AUTO_CRC)?CEDI_TXD_NO_AUTO_CRC:0)
333             | prm->length
334             | ((txQ->descNum>=1)?
335                 ((prm->mssMfs << CEDI_TXD_MSSMFS_SHIFT) & CEDI_TXD_MSSMFS_MASK):0);
336                                 // only set MSS/MFS on second or later descriptor
337 //    vDbgMsg(DBG_GEN_MSG, 10, "descNum = %u, desc wd1 = 0x%08X, mss = %u\n",
338 //            txQ->descNum, stat, (stat>>16) & 0x3FFF);
339 
340     /* Handle a multi-buffer frame */
341     if (!(prm->flags & CEDI_TXB_LAST_BUFF) && (NULL==bd1stBuf)) {
342         /* This is the 1st buf of several; prevent it from going and remember its BD. */
343         stat |= CEDI_TXD_USED
344          /* Also use this condition to set encapsulation flags & TCP stream -
345           * must not set stream if TSO bit clear */
346                 | ((prm->flags & CEDI_TXB_TCP_ENCAP)?
347                         /* TSO settings */
348                    (CEDI_TXD_TSO_ENABLE|
349                     (((prm->tcpStream)<<CEDI_TXD_STREAM_SHIFT)
350                         & CEDI_TXD_STREAM_MASK)|
351                     ((prm->flags & CEDI_TXB_TSO_AUTO_SEQ)?CEDI_TXD_AUTOSEQ_SEL:0)) :
352                         /* UFO bit only */
353                   ((prm->flags & CEDI_TXB_UDP_ENCAP)?CEDI_TXD_UFO_ENABLE:0));
354         txQ->bd1stBuf = freeDesc;
355     }
356 
357     *txQ->vHead = prm->bufAdd->vAddr;
358     CPS_UncachedWrite32(&freeDesc->word[0], prm->bufAdd->pAddr & 0xFFFFFFFF);
359 
360     /* upper 32 bits if 64 bit addressing */
361     if (CEDI_PdVar(cfg).dmaAddrBusWidth) {
362 #ifdef CEDI_64B_COMPILE
363         /* 64-bit addressing */
364         CPS_UncachedWrite32(&freeDesc->word[2],
365                              (prm->bufAdd->pAddr & 0xFFFFFFFF00000000)>>32);
366 #else
367 #endif
368     }
369     CPS_UncachedWrite32(&freeDesc->word[1], stat);
370 
371 
372     if ((prm->flags & CEDI_TXB_LAST_BUFF) && (NULL!=bd1stBuf)) {
373         /* Last buffer of a multibuffer frame is in place, 1st buffer can go. */
374         CPS_UncachedWrite32(&bd1stBuf->word[1],
375             CPS_UncachedRead32(&bd1stBuf->word[1]) & ~CEDI_TXD_USED);
376         /* vDbgMsg(DBG_GEN_MSG, 10,
377                 "set multi-buffer go: 1stBuf=%p, wd1=%08X, transmit queue ptr=%08X\n",
378                 bd1stBuf, CPS_UncachedRead32(&bd1stBuf->word[1]),
379                 CPS_UncachedRead32(CEDI_RegAddr(transmit_q_ptr)));*/
380         txQ->bd1stBuf = NULL;
381         txQ->descNum = 0;
382     }
383 
384     --txQ->descFree;
385     /* if (emacTxDescFree(pD, prm->queueNum, &nFree)) return EINVAL;
386     vDbgMsg(DBG_GEN_MSG, 10,
387             "len=%u, queue=%u, txbdHead=%p, buffV=%p, buffP=%p, wd1=%08X, descFree=%u\n",
388             prm->length, prm->queueNum, freeDesc,
389             (void *)prm->bufAdd->vAddr,
390             (void *)prm->bufAdd->pAddr,
391          CPS_UncachedRead32(&freeDesc->word[1]), nFree);*/
392     inc_txbd(pD, stat, &freeDesc, &txQ->vHead, txQ);
393     txQ->bdHead = freeDesc;
394 
395     /* set going if complete frame queued */
396     if ((prm->flags & CEDI_TXB_LAST_BUFF) && !(prm->flags & CEDI_TXB_NO_AUTO_START)) {
397           ncr = CPS_UncachedRead32(CEDI_RegAddr(network_control));
398           EMAC_REGS__NETWORK_CONTROL__TX_START_PCLK__SET(ncr);
399           CPS_UncachedWrite32(CEDI_RegAddr(network_control), ncr);
400     }
401 
402     return 0;
403 }
404 
405 /* Remove buffer from head of transmit queue in case of error during queueing
406  * and free the corresponding descriptor.
407  * Caller must have knowledge of queueing status, i.e. that frame has not been
408  * completed for transmission (first used bit still set) and how many
409  * descriptors have been queued for untransmitted frame.
410  * @param pD - driver private state info specific to this instance
411  * @param prm - pointer to struct of parameters to return
412  * @return 0 if successful
413  * @return EINVAL if invalid queueNum or NULL parameters
414  * @return ENOENT if no unfree descriptors in queue
415  */
emacDeQTxBuf(void * pD,CEDI_qTxBufParams * prm)416 uint32_t emacDeQTxBuf(void *pD, CEDI_qTxBufParams *prm)
417 {
418     txQueue_t *txQ;
419     txDesc *descToFree;
420     uint32_t stat;
421 
422     if ((pD==NULL) || (prm==NULL) || (prm->bufAdd==NULL) ||
423             (prm->queueNum>=CEDI_PdVar(cfg).txQs))
424         return EINVAL;
425 
426 //    vDbgMsg(DBG_GEN_MSG, 10, "%s entered\n", __func__);
427 
428     txQ = &CEDI_PdVar(txQueue)[prm->queueNum];
429     descToFree = txQ->bdHead;
430 
431     /* Check if any in queue */
432     if (txQ->bdTail==txQ->bdHead)
433         return ENOENT;
434 
435     /* unwind head pointers */
436     dec_txbd(pD, &descToFree, &txQ->vHead, txQ);
437     txQ->bdHead = descToFree;
438 
439     /* get virtual address */
440     prm->bufAdd->vAddr = *txQ->vHead;
441 
442     /* get phys address */
443     prm->bufAdd->pAddr = CPS_UncachedRead32(&descToFree->word[0]);
444 #ifdef CEDI_64B_COMPILE
445     /* upper 32 bits if 64 bit addressing */
446     if (CEDI_PdVar(cfg).dmaAddrBusWidth) {
447         prm->bufAdd->pAddr |= (CPS_UncachedRead32(&descToFree->word[2])<<32);
448     }
449 #endif
450 
451     /* get length */
452     stat = CPS_UncachedRead32(&descToFree->word[1]);
453     prm->length = stat & CEDI_TXD_LEN_MASK;
454     /* set used bit */
455     CPS_UncachedWrite32(&descToFree->word[1], stat | (uint32_t)CEDI_TXD_USED);
456 
457     if (txQ->descNum>0)
458         txQ->descNum--;
459 
460     ++txQ->descFree;
461 
462     return 0;
463 }
464 
465 /* Get number of free descriptors in specified Tx queue
466  * @param pD - driver private state info specific to this instance
467  * @param queueNum - number of Tx queue
468  * @param numFree - pointer for returning number of free descriptors
469  * @return 0 if successful
470  * @return EINVAL if invalid parameter
471  */
emacTxDescFree(void * pD,uint8_t queueNum,uint16_t * numFree)472 uint32_t emacTxDescFree(void *pD, uint8_t queueNum, uint16_t *numFree)
473 {
474     if ((pD==NULL) || (numFree==NULL) || (queueNum>=CEDI_PdVar(cfg).txQs))
475         return EINVAL;
476     *numFree = CEDI_PdVar(txQueue)[queueNum].descFree;
477     return 0;
478 }
479 
480 /*
481  * Read Tx descriptor queue and free used descriptor.
482  *
483  * @param[in] pD driver private state info specific to this instance
484  * @param[in] queueNum number of Tx queue
485  *    $RANGE $FROM 0 $TO CEDI_Config.txQs-1$
486  * @param[out] descData pointer for returning status & descriptor data
487  *   Struct fields:
488  *
489  *    CEDI_BuffAddr bufAdd - addresses of buffer freed up
490  *
491  *    uint32_t txDescStat - descriptor status word. Only valid if first
492  *                           buffer of frame.
493  *
494  *    uint8_t status  - descriptor queue status, one of the following values:
495  *      CEDI_TXDATA_1ST_NOT_LAST :a first descriptor was freed,
496  *                               frame not finished:
497  *                               bufAdd & txDescStat are valid
498  *      CEDI_TXDATA_1ST_AND_LAST :a first descriptor was freed,
499  *                               frame is finished:
500  *                               bufAdd & txDescStat are valid
501  *      CEDI_TXDATA_MID_BUFFER   :a descriptor was freed,
502  *                               (not first in frame),
503  *                               frame not finished: bufAdd valid,
504  *                               txDescStat not valid
505  *      CEDI_TXDATA_LAST_BUFFER  :a descriptor was freed, frame is finished:
506  *                               bufAdd valid, txDescStat not valid
507  *      CEDI_TXDATA_NONE_FREED   :no used descriptor to free:
508  *                               bufAdd & txDescStat not valid
509  *
510  *    CEDI_TimeStampData txTsData - Tx descriptor timestamp when valid
511  *                                  (txTsData->tsValid will be set to 1).
512  * @return 0 if successful (and status is set),
513  * @return ENOENT if the queue is empty (status = CEDI_TXDATA_NONE_FREED), or
514  * @return EIO if an incomplete frame was detected (no lastBuffer flag in
515  *          queue)
516  * @return EINVAL if any parameter invalid
517  */
emacFreeTxDesc(void * pD,uint8_t queueNum,CEDI_TxDescData * descData)518 uint32_t emacFreeTxDesc(void *pD, uint8_t queueNum, CEDI_TxDescData *descData)
519 {
520     txQueue_t *txQ;
521 //    uint16_t nFree = 0;
522 //    txDesc *freedDesc;
523     uint8_t wdNum;
524     uint32_t tsLowerWd, tsUpperWd;
525 //    uintptr_t *nextV;
526 //    txDesc *nextD;
527 //    uint32_t wd1_1, wd1_2, wd1_3, wd1_4, wd1_5;
528 
529     if ((pD==NULL) || (descData==NULL))
530         return EINVAL;
531     if (queueNum>=CEDI_PdVar(cfg).txQs)
532         return EINVAL;
533 
534 //    vDbgMsg(DBG_GEN_MSG, 10, "%s entered\n", __func__);
535     txQ = &CEDI_PdVar(txQueue)[queueNum];
536 
537     /* Check if any to free */
538     if (txQ->bdTail == txQ->bdHead)
539     {
540         descData->status = CEDI_TXDATA_NONE_FREED;
541         return ENOENT;
542     }
543 
544     /* Free next used descriptor in this frame */
545     descData->txDescStat = CPS_UncachedRead32(&(txQ->bdTail->word[1]));
546     if (txQ->firstToFree)
547     {
548         /* look ahead to next desc */
549       /*  nextD = txQ->bdTail;
550         nextV = txQ->vTail;
551         inc_txbd(pD, descData->txDescStat, &nextD, &nextV, txQ);
552         wd1_1 = CPS_UncachedRead32(&(nextD->word[1]));
553         inc_txbd(pD, descData->txDescStat, &nextD, &nextV, txQ);
554         wd1_2 = CPS_UncachedRead32(&(nextD->word[1]));
555         inc_txbd(pD, descData->txDescStat, &nextD, &nextV, txQ);
556         wd1_3 = CPS_UncachedRead32(&(nextD->word[1]));
557         inc_txbd(pD, descData->txDescStat, &nextD, &nextV, txQ);
558         wd1_4 = CPS_UncachedRead32(&(nextD->word[1]));
559         inc_txbd(pD, descData->txDescStat, &nextD, &nextV, txQ);
560         wd1_5 = CPS_UncachedRead32(&(nextD->word[1]));
561         vDbgMsg(DBG_GEN_MSG, 10,
562                 " testing desc:  queue=%u, txBdTail=%p, wd1(0)=%08X,"\
563           " wd1(1)=%08X, wd1(2)=%08X, wd1(3)=%08X, wd1(4)=%08X, wd1(5)=%08X\n",
564           queueNum, txQ->bdTail, descData->txDescStat, wd1_1, wd1_2,
565           wd1_3, wd1_4, wd1_5);*/
566 
567         /* Only test used bit state for first buffer in frame. */
568         if(!(descData->txDescStat & (uint32_t)CEDI_TXD_USED)) {
569             descData->status = CEDI_TXDATA_NONE_FREED;
570             return 0;
571         }
572 
573         /* extract timestamp if available */
574         if ((CEDI_PdVar(cfg).enTxExtBD) &&
575                 (descData->txDescStat & CEDI_TXD_TS_VALID))
576         {
577         uint32_t reg;
578             descData->txTsData.tsValid = 1;
579         // position depends on 32/64 bit addr
580             wdNum = (CEDI_PdVar(cfg).dmaAddrBusWidth)?4:2;
581             tsLowerWd = CPS_UncachedRead32(&(txQ->bdTail->word[wdNum]));
582             tsUpperWd = CPS_UncachedRead32(&(txQ->bdTail->word[wdNum+1]));
583 
584             descData->txTsData.tsNanoSec = tsLowerWd & CEDI_TS_NANO_SEC_MASK;
585             descData->txTsData.tsSecs = ((tsUpperWd & CEDI_TS_SEC1_MASK)
586                                             <<CEDI_TS_SEC1_POS_SHIFT)
587                                            | (tsLowerWd >> CEDI_TS_SEC0_SHIFT);
588 
589         /* The timestamp only contains lower few bits of seconds, so add value from 1588 timer */
590         reg =  CPS_UncachedRead32(CEDI_RegAddr(tsu_timer_sec));
591         /* If the top bit is set in the timestamp, but not in 1588 timer, it has rolled over, so subtract max size */
592         if ((descData->txTsData.tsSecs & (CEDI_TS_SEC_TOP>>1)) && !(reg & (CEDI_TS_SEC_TOP>>1))) {
593         descData->txTsData.tsSecs -= CEDI_TS_SEC_TOP;
594         }
595         descData->txTsData.tsSecs += ((~CEDI_TS_SEC_MASK) & EMAC_REGS__TSU_TIMER_SEC__TIMER__READ(reg));
596     }
597     else{
598         descData->txTsData.tsValid = 0;
599 
600     }
601 
602     if (descData->txDescStat & CEDI_TXD_LAST_BUF)
603         descData->status = CEDI_TXDATA_1ST_AND_LAST;
604     else {
605         txQ->firstToFree = 0;
606         descData->status = CEDI_TXDATA_1ST_NOT_LAST;
607     }
608     }
609     else
610     {
611         /* set later used bits in frame, for consistency */
612         CPS_UncachedWrite32(&(txQ->bdTail->word[1]),
613                                 descData->txDescStat | (uint32_t)CEDI_TXD_USED);
614         if (descData->txDescStat & CEDI_TXD_LAST_BUF) {
615             descData->status = CEDI_TXDATA_LAST_BUFFER;
616             txQ->firstToFree = 1;
617         }
618         else
619             descData->status = CEDI_TXDATA_MID_BUFFER;
620     }
621 
622     descData->bufAdd.pAddr = CPS_UncachedRead32(&(txQ->bdTail->word[0]));
623 
624 #ifdef CEDI_64B_COMPILE
625     /* upper 32 bits if 64 bit addressing */
626     if ((CEDI_PdVar(cfg).dmaAddrBusWidth) &&
627                 (sizeof(descData->bufAdd.pAddr)==sizeof(uint64_t)))
628         descData->bufAdd.pAddr |=
629                 ((uint64_t)CPS_UncachedRead32(&(txQ->bdTail->word[2])))<<32;
630 
631 #endif
632 
633     descData->bufAdd.vAddr = *txQ->vTail;
634 //    freedDesc = txQ->bdTail;
635 
636     /* move queue pointers on */
637     inc_txbd(pD, descData->txDescStat, &txQ->bdTail, &txQ->vTail, txQ);
638     ++txQ->descFree;
639     /*if (0==emacTxDescFree(pD, queueNum, &nFree))
640         vDbgMsg(DBG_GEN_MSG, 15,
641             " free desc:  queue=%u, txBdTail=%p, buffV=%p, buffP=%p, length=%u, descFree=%u\n",
642             queueNum, freedDesc, (void *)descData->bufAdd.vAddr,
643             (void *)descData->bufAdd.pAddr, descData->txDescStat & CEDI_TXD_LMASK, nFree);*/
644 
645     /* paranoid - empty and no last buffer flag (on last freed)? */
646     if ((0==(descData->txDescStat & CEDI_TXD_LAST_BUF)) &&
647             (txQ->descFree==txQ->descMax-CEDI_MIN_TXBD)) {
648         vDbgMsg(DBG_GEN_MSG, 5,
649                 "Error: txQueue %u: LAST bit of frame not found!\n", queueNum);
650         txQ->firstToFree = 1;
651         return EIO;
652     }
653 
654     return 0;
655 }
656 
657 /* Decode the Tx descriptor status into a bit-field struct
658  * @param pD - driver private state info specific to this instance
659  * @param txDStatWord - Tx descriptor status word
660  * @param txDStat - pointer to bit-field struct for decoded status fields
661  */
emacGetTxDescStat(void * pD,uint32_t txDStatWord,CEDI_TxDescStat * txDStat)662 void emacGetTxDescStat(void *pD, uint32_t txDStatWord, CEDI_TxDescStat *txDStat)
663 {
664     uint32_t wd1;
665 
666     if ((NULL==pD) || (NULL==txDStat))
667       return;
668 
669     wd1 = txDStatWord;
670     txDStat->chkOffErr = (wd1 & CEDI_TXD_CHKOFF_MASK) >> CEDI_TXD_CHKOFF_SHIFT;
671     txDStat->lateColl = (wd1 & CEDI_TXD_LATE_COLL)?1:0;
672     txDStat->frameCorr = (wd1 & CEDI_TXD_FR_CORR)?1:0;
673     txDStat->txUnderrun = (wd1 & CEDI_TXD_UNDERRUN)?1:0;
674     txDStat->retryExc = (wd1 & CEDI_TXD_RETRY_EXC)?1:0;
675 }
676 
677 /* Provide the size of descriptor calculated for the current configuration.
678  * @param pD - driver private state info specific to this instance
679  * @param txDescSize - pointer to Tx descriptor Size
680  */
emacGetTxDescSize(void * pD,uint32_t * txDescSize)681 void emacGetTxDescSize(void *pD, uint32_t *txDescSize)
682 {
683     if ((pD==NULL)||(txDescSize==NULL)) return;
684     *txDescSize = CEDI_PdVar(txDescriptorSize);
685 }
686 
687 /* Reset transmit buffer queue. Any untransmitted buffer data will be
688  * discarded and must be re-queued.  Transmission must be disabled
689  * before calling this function.
690  * @param pD - driver private state info specific to this instance
691  * @param queueNum - number of Tx queue
692  * @return 0 if successful
693  * @return EINVAL if invalid parameter
694  */
emacResetTxQ(void * pD,uint8_t queueNum)695 uint32_t emacResetTxQ(void *pD, uint8_t queueNum)
696 {
697 #define CEDI_WR_TXQ_PTR_REG_N_CASE(Q) case Q:\
698     regTmp = CPS_UncachedRead32(CEDI_RegAddr(transmit_q##Q##_ptr));\
699     EMAC_REGS__TRANSMIT_Q_PTR__DMA_TX_Q_PTR__MODIFY(regTmp, pAddr>>2);\
700         CPS_UncachedWrite32(CEDI_RegAddr(transmit_q##Q##_ptr), regTmp);\
701         break;
702 
703     uint32_t result = 0, regTmp;
704     txQueue_t *txQ;
705     txDesc *descStartPerQ;
706     uint32_t pAddr;
707     uintptr_t vAddr;
708     uint16_t q, i;
709 
710     if ((pD==NULL) || (queueNum>=CEDI_PdVar(cfg).txQs))
711         return EINVAL;
712 
713     txQ = &CEDI_PdVar(txQueue)[queueNum];
714     txQ->descFree = CEDI_PdVar(cfg).txQLen[queueNum];
715     txQ->descMax = txQ->descFree + CEDI_MIN_TXBD;
716     vAddr = CEDI_PdVar(cfg).txQAddr;
717     pAddr = CEDI_PdVar(cfg).txQPhyAddr;
718     q = 0;
719     /* find start addresses for this txQ */
720     if (queueNum>0)
721         txQ->vAddrList = CEDI_PdVar(txQueue)[0].vAddrList;
722     while (q<queueNum) {
723         vAddr += txQ->descMax * (CEDI_PdVar(txDescriptorSize));  //sizeof(txDesc);
724         pAddr += txQ->descMax * (CEDI_PdVar(txDescriptorSize));  //sizeof(txDesc);
725         txQ->vAddrList += txQ->descMax;
726         q++;
727     }
728     vDbgMsg(DBG_GEN_MSG, 10, "%s: base address Q%u virt=%08lX phys=%08X vAddrList=%p\n",
729             __func__, queueNum, vAddr, pAddr, txQ->vAddrList);
730     txQ->bdBase = (txDesc *)vAddr;
731 
732     txQ->bdTail = txQ->bdBase;
733     txQ->bdHead = txQ->bdBase;
734     txQ->bd1stBuf = NULL;
735     txQ->vHead = txQ->vAddrList;
736     txQ->vTail = txQ->vAddrList;
737     txQ->firstToFree = 1;
738     txQ->descNum = 0;
739 
740     /* set used flags & last wrap flag */
741     descStartPerQ = txQ->bdBase;
742     for (i = 0; i<txQ->descMax; i++) {
743         CPS_UncachedWrite32((uint32_t *)&(descStartPerQ->word[0]), 0);
744         CPS_UncachedWrite32((uint32_t *)&(descStartPerQ->word[1]),
745                 CEDI_TXD_USED | (i==(txQ->descMax-1)?CEDI_TXD_WRAP:0));
746 
747         descStartPerQ = (txDesc*) (((uintptr_t)(descStartPerQ)) +
748                             (CEDI_PdVar(txDescriptorSize)));
749     }
750 
751     switch (q) {
752     case 0:
753     regTmp = CPS_UncachedRead32(CEDI_RegAddr(transmit_q_ptr));\
754     EMAC_REGS__TRANSMIT_Q_PTR__DMA_TX_Q_PTR__MODIFY(regTmp, pAddr>>2);
755         CPS_UncachedWrite32(CEDI_RegAddr(transmit_q_ptr), regTmp);
756         break;
757     CEDI_WR_TXQ_PTR_REG_N_CASE(1);
758     CEDI_WR_TXQ_PTR_REG_N_CASE(2);
759     CEDI_WR_TXQ_PTR_REG_N_CASE(3);
760     CEDI_WR_TXQ_PTR_REG_N_CASE(4);
761     CEDI_WR_TXQ_PTR_REG_N_CASE(5);
762     CEDI_WR_TXQ_PTR_REG_N_CASE(6);
763     CEDI_WR_TXQ_PTR_REG_N_CASE(7);
764     CEDI_WR_TXQ_PTR_REG_N_CASE(8);
765     CEDI_WR_TXQ_PTR_REG_N_CASE(9);
766     CEDI_WR_TXQ_PTR_REG_N_CASE(10);
767     CEDI_WR_TXQ_PTR_REG_N_CASE(11);
768     CEDI_WR_TXQ_PTR_REG_N_CASE(12);
769     CEDI_WR_TXQ_PTR_REG_N_CASE(13);
770     CEDI_WR_TXQ_PTR_REG_N_CASE(14);
771     CEDI_WR_TXQ_PTR_REG_N_CASE(15);
772     }
773 
774     return result;
775 }
776 
777 /* Enable & start the transmit circuit. Not required during normal
778  * operation, as queueTxBuf will automatically start Tx when complete frame
779  * has been queued, but may be used to restart after a Tx error.
780  * @param pD - driver private state info specific to this instance
781  * @return 0 if successful
782  * @return ECANCELED if no entries in buffer
783  * @return EINVAL if invalid parameter
784  */
emacStartTx(void * pD)785 uint32_t emacStartTx(void *pD)
786 {
787     const CEDI_Config *cfg;
788     uint32_t qNum;
789     uint8_t ok = 0;
790     txQueue_t *txQ;
791     uint32_t ncr;
792 
793     if (pD==NULL) return EINVAL;
794 
795     vDbgMsg(DBG_GEN_MSG, 10, "%s entered\n", __func__);
796 
797     cfg = &((CEDI_PrivateData *)pD)->cfg;
798 
799     if (!emacGetTxEnabled(pD))
800         emacEnableTx(pD);
801 
802     /* if anything to transmit, start transmission */
803     for (qNum = 0; qNum < cfg->txQs; ++qNum) {
804         txQ = &CEDI_PdVar(txQueue)[qNum];
805         if (txQ->bdHead != txQ->bdTail) {
806             ok = 1;
807             break;
808         }
809     }
810     if (!ok)
811         return ECANCELED;
812     else
813     {
814         ncr = CPS_UncachedRead32(CEDI_RegAddr(network_control));
815         EMAC_REGS__NETWORK_CONTROL__TX_START_PCLK__SET(ncr);
816         CPS_UncachedWrite32(CEDI_RegAddr(network_control), ncr);
817     }
818     return 0;
819 }
820 
821 /* Halt transmission as soon as current frame Tx has finished
822  * @param pD - driver private state info specific to this instance
823  */
emacStopTx(void * pD)824 void emacStopTx(void *pD)
825 {
826     uint32_t ncr;
827 
828     if (!pD) return;
829     ncr = CPS_UncachedRead32(CEDI_RegAddr(network_control));
830     EMAC_REGS__NETWORK_CONTROL__TX_HALT_PCLK__SET(ncr);
831     CPS_UncachedWrite32(CEDI_RegAddr(network_control), ncr);
832     return;
833 }
834 
835 /* Immediately disable transmission without waiting for completion.
836  * Since the EMAC will reset to point to the start of transmit descriptor
837  * list, the buffer queues may have to be reset after this call.
838  * @param pD - driver private state info specific to this instance
839  */
emacAbortTx(void * pD)840 void emacAbortTx(void *pD)
841 {
842     uint32_t ncr;
843 
844     if (!pD) return;
845     ncr = CPS_UncachedRead32(CEDI_RegAddr(network_control));
846     EMAC_REGS__NETWORK_CONTROL__ENABLE_TRANSMIT__CLR(ncr);
847     CPS_UncachedWrite32(CEDI_RegAddr(network_control), ncr);
848     return;
849 }
850 
851 /* Get state of transmitter
852  * @param pD - driver private state info specific to this instance
853  * @return 1 if active
854  * @return 0 if idle or pD==NULL
855  */
emacTransmitting(void * pD)856 uint32_t emacTransmitting(void *pD)
857 {
858     if (pD==NULL) return 0;
859 
860     return EMAC_REGS__TRANSMIT_STATUS__TRANSMIT_GO__READ(
861             CPS_UncachedRead32(CEDI_RegAddr(transmit_status)));
862 }
863 
864 /**
865  * Enable the transmit circuit.  This will be done automatically
866  * when call startTx, but it may be desirable to call this earlier,
867  * since some functionality depends on transmit being enabled.
868  * @param[in] pD driver private state info specific to this instance
869  */
emacEnableTx(void * pD)870 void emacEnableTx(void *pD)
871 {
872     uint32_t ncr;
873     if (pD==NULL) return;
874 
875     /* Enable the transmitter */
876     ncr = CPS_UncachedRead32(CEDI_RegAddr(network_control));
877     EMAC_REGS__NETWORK_CONTROL__ENABLE_TRANSMIT__SET(ncr);
878     CPS_UncachedWrite32(CEDI_RegAddr(network_control), ncr);
879 }
880 
881 /**
882  * Get state of transmision enabled
883  * @param pD - driver private state info specific to this instance
884  * @return 1 if transmission enabled
885  * @return 0 if transmission disabled or pD==NULL
886  */
emacGetTxEnabled(void * pD)887 uint32_t emacGetTxEnabled(void *pD)
888 {
889     if (pD==NULL) return 0;
890 
891     return EMAC_REGS__NETWORK_CONTROL__ENABLE_TRANSMIT__READ(
892             CPS_UncachedRead32(CEDI_RegAddr(network_control)));
893 }
894 
895 /* Get the content of EMAC transmit status register
896  * @param pD - driver private state info specific to this instance
897  * @param status - pointer to struct with fields for each flag
898  * @return raw status register value, !=0 if any flags set
899  */
emacGetTxStatus(void * pD,CEDI_TxStatus * status)900 uint32_t emacGetTxStatus(void *pD, CEDI_TxStatus *status)
901 {
902     uint32_t reg;
903     if ((pD==NULL)||(status==NULL))
904         return 0;
905 
906     reg = CPS_UncachedRead32(CEDI_RegAddr(transmit_status));
907 //    vDbgMsg(DBG_GEN_MSG, 10, "-----getTxStatus reads 0x%08X ------\n", reg);
908 
909     status->txComplete =
910             EMAC_REGS__TRANSMIT_STATUS__TRANSMIT_COMPLETE__READ(reg);
911     status->usedBitRead =
912             EMAC_REGS__TRANSMIT_STATUS__USED_BIT_READ__READ(reg);
913     status->collisionOcc =
914             EMAC_REGS__TRANSMIT_STATUS__COLLISION_OCCURRED__READ(reg);
915     status->retryLimExc =
916             EMAC_REGS__TRANSMIT_STATUS__RETRY_LIMIT_EXCEEDED__READ(reg);
917     status->lateCollision =
918             EMAC_REGS__TRANSMIT_STATUS__LATE_COLLISION_OCCURRED__READ(reg);
919     status->txActive =
920             EMAC_REGS__TRANSMIT_STATUS__TRANSMIT_GO__READ(reg);
921     status->txFrameErr =
922             EMAC_REGS__TRANSMIT_STATUS__AMBA_ERROR__READ(reg);
923     status->txUnderRun =
924             EMAC_REGS__TRANSMIT_STATUS__TRANSMIT_UNDER_RUN__READ(reg);
925     status->hRespNotOk =
926             EMAC_REGS__TRANSMIT_STATUS__RESP_NOT_OK__READ(reg);
927 
928     return reg;
929 }
930 
931 /* Reset the bits of EMAC transmit status register as selected in resetStatus
932  * @param pD - driver private state info specific to this instance
933  * @param resetStatus - OR'd combination of CEDI_TXS_ bit-fields
934  */
emacClearTxStatus(void * pD,uint32_t resetStatus)935 void emacClearTxStatus(void *pD, uint32_t resetStatus)
936 {
937     uint32_t dst = 0;
938 
939     if (!pD) return;
940     if (resetStatus & CEDI_TXS_USED_READ)
941         EMAC_REGS__TRANSMIT_STATUS__USED_BIT_READ__MODIFY(dst, 1);
942     if (resetStatus & CEDI_TXS_COLLISION)
943         EMAC_REGS__TRANSMIT_STATUS__COLLISION_OCCURRED__MODIFY(dst, 1);
944     if (resetStatus & CEDI_TXS_RETRY_EXC)
945         EMAC_REGS__TRANSMIT_STATUS__RETRY_LIMIT_EXCEEDED__MODIFY(dst, 1);
946     if (resetStatus & CEDI_TXS_LATE_COLL)
947         EMAC_REGS__TRANSMIT_STATUS__LATE_COLLISION_OCCURRED__MODIFY(dst, 1);
948     /* txActive not resettable */
949     if (resetStatus & CEDI_TXS_FRAME_ERR)
950         EMAC_REGS__TRANSMIT_STATUS__AMBA_ERROR__MODIFY(dst, 1);
951     if (resetStatus & CEDI_TXS_TX_COMPLETE)
952         EMAC_REGS__TRANSMIT_STATUS__TRANSMIT_COMPLETE__MODIFY(dst, 1);
953     if (resetStatus & CEDI_TXS_UNDERRUN)
954         EMAC_REGS__TRANSMIT_STATUS__TRANSMIT_UNDER_RUN__MODIFY(dst, 1);
955     if (resetStatus & CEDI_TXS_HRESP_ERR)
956         EMAC_REGS__TRANSMIT_STATUS__RESP_NOT_OK__MODIFY(dst, 1);
957     if (dst)
958         CPS_UncachedWrite32(CEDI_RegAddr(transmit_status), dst);
959 }
960 
emacSetTxPartialStFwd(void * pD,uint32_t watermark,uint8_t enable)961 uint32_t emacSetTxPartialStFwd(void *pD, uint32_t watermark, uint8_t enable)
962 {
963     uint32_t reg;
964     if (!pD) return EINVAL;
965     if (CEDI_PdVar(hwCfg).tx_pkt_buffer==0)
966         return ENOTSUP;
967     if (enable>1) return EINVAL;
968 
969     if ((enable==1) &&
970         ((watermark<0x14UL) || (watermark>=(1UL<<CEDI_PdVar(hwCfg).tx_pbuf_addr))))
971         return EINVAL;
972 
973     reg = CPS_UncachedRead32(CEDI_RegAddr(pbuf_txcutthru));
974     if (enable) {
975         EMAC_REGS__PBUF_TXCUTTHRU__DMA_TX_CUTTHRU_THRESHOLD__MODIFY(reg,
976                 watermark);
977         EMAC_REGS__PBUF_TXCUTTHRU__DMA_TX_CUTTHRU__SET(reg);
978     }
979     else
980         EMAC_REGS__PBUF_TXCUTTHRU__DMA_TX_CUTTHRU__CLR(reg);
981 
982     CPS_UncachedWrite32(CEDI_RegAddr(pbuf_txcutthru), reg);
983 
984     return 0;
985 }
986 
emacGetTxPartialStFwd(void * pD,uint32_t * watermark,uint8_t * enable)987 uint32_t emacGetTxPartialStFwd(void *pD, uint32_t *watermark, uint8_t *enable)
988 {
989     uint32_t reg;
990     if ((pD==0)||(enable==0)||(watermark==0))
991         return EINVAL;
992     if (CEDI_PdVar(hwCfg).tx_pkt_buffer==0)
993         return ENOTSUP;
994 
995     reg = CPS_UncachedRead32(CEDI_RegAddr(pbuf_txcutthru));
996     (*enable) = EMAC_REGS__PBUF_TXCUTTHRU__DMA_TX_CUTTHRU__READ(reg);
997     if (*enable)
998       (*watermark) = EMAC_REGS__PBUF_TXCUTTHRU__DMA_TX_CUTTHRU_THRESHOLD__READ(reg);
999 
1000         return 0;
1001 }
1002 
1003 
1004 /**
1005  * Enable credit-based shaping (CBS) on the specified queue.  If already
1006  * enabled then first disables, sets a new idle slope value for the queue,
1007  * and re-enables CBS
1008  * @param[in] pD driver private state info specific to this instance
1009  * @param[in] qSel if equal 0 selects highest priority queue (queue A),
1010  *    if equal 1 selects next-highest priority queue (queue B)
1011  *    $RANGE $FROM 0 $TO 1$
1012  * @param[in] idleSlope new idle slope value (in bytes/sec)
1013  * @return 0 if successful
1014  * @return EINVAL if priority queueing not enabled (i.e. only one Tx queue)
1015  *      or invalid parameter
1016  * @return ENOTSUP if CBS has been excluded from h/w config
1017  * $VALIDFAIL if (CEDI_Config.txQs==1) $EXPECT_RETURN EINVAL $
1018  */
emacEnableCbs(void * pD,uint8_t qSel,uint32_t idleSlope)1019 uint32_t emacEnableCbs(void *pD, uint8_t qSel, uint32_t idleSlope)
1020 {
1021     uint32_t tmp, ret;
1022     uint8_t enabled;
1023     uint32_t reg;
1024 
1025     if (pD==NULL) return EINVAL;
1026 
1027     if (CEDI_PdVar(hwCfg).exclude_cbs==1)
1028         return ENOTSUP;
1029 
1030     if (CEDI_PdVar(numQs)==1)
1031         return EINVAL;
1032 
1033     ret = emacGetCbsQSetting(pD, qSel, &enabled, &tmp);
1034     if (ret!=0)
1035         return ret;
1036 
1037     if (enabled)
1038         emacDisableCbs(pD, qSel);
1039 
1040     reg = 0;
1041     if (qSel) {   /* i.e. queue B */
1042         EMAC_REGS__CBS_IDLESLOPE_Q_B__IDLESLOPE_B__MODIFY(reg, idleSlope);
1043         CPS_UncachedWrite32(CEDI_RegAddr(cbs_idleslope_q_b), reg);
1044     }
1045     else {
1046         EMAC_REGS__CBS_IDLESLOPE_Q_A__IDLESLOPE_A__MODIFY(reg, idleSlope);
1047         CPS_UncachedWrite32(CEDI_RegAddr(cbs_idleslope_q_a), reg);
1048     }
1049 
1050     reg = CPS_UncachedRead32(CEDI_RegAddr(cbs_control));
1051     if (qSel)   /* i.e. queue B */
1052         EMAC_REGS__CBS_CONTROL__CBS_ENABLE_QUEUE_B__MODIFY(reg, 1);
1053     else
1054         EMAC_REGS__CBS_CONTROL__CBS_ENABLE_QUEUE_A__MODIFY(reg, 1);
1055     CPS_UncachedWrite32(CEDI_RegAddr(cbs_control), reg);
1056 
1057     return 0;
1058 }
1059 
1060 /* Disable CBS on the specified queue
1061  * @param pD - driver private state info specific to this instance
1062  * @param qSel - if = 0, selects highest priority queue (queue A), else
1063  *    selects next-highest priority queue (queue B)
1064  */
emacDisableCbs(void * pD,uint8_t qSel)1065 void emacDisableCbs(void *pD, uint8_t qSel)
1066 {
1067     uint32_t reg;
1068 
1069     if ((!pD) || (qSel>1) || CEDI_PdVar(hwCfg).exclude_cbs) return;
1070     reg = CPS_UncachedRead32(CEDI_RegAddr(cbs_control));
1071     if (qSel)   /* i.e. queue B */
1072         EMAC_REGS__CBS_CONTROL__CBS_ENABLE_QUEUE_B__MODIFY(reg, 0);
1073     else
1074         EMAC_REGS__CBS_CONTROL__CBS_ENABLE_QUEUE_A__MODIFY(reg, 0);
1075     CPS_UncachedWrite32(CEDI_RegAddr(cbs_control), reg);
1076 }
1077 
1078 /**
1079  * Read CBS setting for the specified queue.
1080  * @param[in] pD driver private state info specific to this instance
1081  * @param[in] qSel if equal 0 selects highest priority queue (queue A),
1082  *    if equal 1 selects next-highest priority queue (queue B)
1083  *    $RANGE $FROM 0 $TO 1$
1084  * @param[out] enable returns: 1 if CBS enabled for the specified queue,
1085  *    0 if not enabled
1086  * @param[out] idleSlope pointer for returning the idleSlope value
1087  *    for selected queue.
1088  * @return 0 for success.
1089  * @return EINVAL for invalid pointer.
1090  * @return ENOTSUP if CBS has been excluded from h/w config
1091  */
emacGetCbsQSetting(void * pD,uint8_t qSel,uint8_t * enable,uint32_t * idleSlope)1092 uint32_t emacGetCbsQSetting(void *pD, uint8_t qSel,
1093                uint8_t *enable, uint32_t *idleSlope)
1094 {
1095     uint32_t reg, enabled;
1096 
1097     if ((pD==0)||(enable==0)||(idleSlope==0))
1098         return EINVAL;
1099     if (CEDI_PdVar(hwCfg).exclude_cbs==1)
1100         return ENOTSUP;
1101     if (qSel>1) return EINVAL;
1102 
1103     reg = CPS_UncachedRead32(CEDI_RegAddr(cbs_control));
1104     if (qSel) { /* i.e. queue B */
1105         enabled = EMAC_REGS__CBS_CONTROL__CBS_ENABLE_QUEUE_B__READ(reg);
1106         if (enabled && (idleSlope!=NULL)) {
1107             reg = CPS_UncachedRead32(CEDI_RegAddr(cbs_idleslope_q_b));
1108             *idleSlope = EMAC_REGS__CBS_IDLESLOPE_Q_B__IDLESLOPE_B__READ(reg);
1109         }
1110     }
1111     else {
1112         enabled = EMAC_REGS__CBS_CONTROL__CBS_ENABLE_QUEUE_A__READ(reg);
1113         if (enabled && (idleSlope!=NULL)) {
1114             reg = CPS_UncachedRead32(CEDI_RegAddr(cbs_idleslope_q_a));
1115             *idleSlope = EMAC_REGS__CBS_IDLESLOPE_Q_A__IDLESLOPE_A__READ(reg);
1116         }
1117     }
1118 
1119     *enable=enabled;
1120     return 0;
1121 }
1122 
1123 /**
1124  * Enable/disable the inter-packet gap (IPG) stretch function.
1125  * @param[in] pD driver private state info specific to this instance
1126  * @param[in] enable if equal 1 then enable IPG stretch, if 0 then disable.
1127  *    $RANGE $FROM 0 $TO 1$
1128  * @param[in] multiplier multiplying factor applied to previous Tx frame
1129  *    length.  Ignored if enable equal 0.
1130  * @param[in] divisor after multiplying previous frame length, divide by
1131  *    (divisor+1) - if result>96 bits, this is used for the Tx IPG.
1132  *    Ignored if enable equal 0.
1133  * @return EINVAL if pD equal NULL
1134  * @return 0 if successful.
1135  */
emacSetIpgStretch(void * pD,uint8_t enable,uint8_t multiplier,uint8_t divisor)1136 uint32_t emacSetIpgStretch(void *pD, uint8_t enable, uint8_t multiplier,
1137         uint8_t divisor)
1138 {
1139     uint32_t reg;
1140 
1141     if (pD==NULL) return EINVAL;
1142     if (enable>1) return EINVAL;
1143     reg = CPS_UncachedRead32(CEDI_RegAddr(network_config));
1144     if (enable) {
1145         EMAC_REGS__NETWORK_CONFIG__IPG_STRETCH_ENABLE__SET(reg);
1146         CPS_UncachedWrite32(CEDI_RegAddr(network_config), reg);
1147         reg = CPS_UncachedRead32(CEDI_RegAddr(stretch_ratio));
1148         EMAC_REGS__STRETCH_RATIO__IPG_STRETCH__MODIFY(reg,
1149                 (divisor << 8) | multiplier);
1150         CPS_UncachedWrite32(CEDI_RegAddr(stretch_ratio), reg);
1151     }
1152     else {
1153         EMAC_REGS__NETWORK_CONFIG__IPG_STRETCH_ENABLE__CLR(reg);
1154         CPS_UncachedWrite32(CEDI_RegAddr(network_config), reg);
1155     }
1156     return 0;
1157 }
1158 
1159 /* Read the inter-packet gap (IPG) stretch settings.
1160  * @param pD - driver private state info specific to this instance
1161  * @param enabled - pointer for returning enabled state: returns 1 if
1162  *                 IPG stretch enabled, 0 if disabled.
1163  * @param multiplier  - pointer for returning IPG multiplying factor.
1164  * @param divisor  - pointer for returning IPG divisor.
1165  * @return =0 if successful, EINVAL if any parameter =NULL
1166  */
emacGetIpgStretch(void * pD,uint8_t * enabled,uint8_t * multiplier,uint8_t * divisor)1167 uint32_t emacGetIpgStretch(void *pD, uint8_t *enabled, uint8_t *multiplier,
1168         uint8_t *divisor)
1169 {
1170     uint32_t reg, stretch;
1171 
1172     if ((pD==NULL) || (enabled==NULL) || (multiplier==NULL) || (divisor==NULL))
1173         return EINVAL;
1174 
1175     reg = CPS_UncachedRead32(CEDI_RegAddr(network_config));
1176     if (EMAC_REGS__NETWORK_CONFIG__IPG_STRETCH_ENABLE__READ(reg)) {
1177         *enabled = 1;
1178         reg = CPS_UncachedRead32(CEDI_RegAddr(stretch_ratio));
1179         stretch = EMAC_REGS__STRETCH_RATIO__IPG_STRETCH__READ(reg);
1180         *multiplier = (stretch & 0xFF);
1181         *divisor = (stretch >> 8) & 0xFF;
1182     }
1183     else {
1184         *enabled = 0;
1185         *multiplier = 0;
1186         *divisor = 0;
1187     }
1188     return 0;
1189 }
1190 
1191 #ifdef __cplusplus
1192 }
1193 #endif
1194 
1195 #endif /* CY_IP_MXETH */
1196 
1197 /* [] END OF FILE    */
1198 
1199