]>
Commit | Line | Data |
---|---|---|
ba94a1bb WD |
1 | /** |
2 | * @file IxEthDataPlane.c | |
3 | * | |
4 | * @author Intel Corporation | |
5 | * @date 12-Feb-2002 | |
6 | * | |
7 | * @brief This file contains the implementation of the IXPxxx | |
8 | * Ethernet Access Data plane component | |
9 | * | |
10 | * Design Notes: | |
11 | * | |
12 | * @par | |
13 | * IXP400 SW Release version 2.0 | |
14 | * | |
15 | * -- Copyright Notice -- | |
16 | * | |
17 | * @par | |
18 | * Copyright 2001-2005, Intel Corporation. | |
19 | * All rights reserved. | |
20 | * | |
21 | * @par | |
22 | * Redistribution and use in source and binary forms, with or without | |
23 | * modification, are permitted provided that the following conditions | |
24 | * are met: | |
25 | * 1. Redistributions of source code must retain the above copyright | |
26 | * notice, this list of conditions and the following disclaimer. | |
27 | * 2. Redistributions in binary form must reproduce the above copyright | |
28 | * notice, this list of conditions and the following disclaimer in the | |
29 | * documentation and/or other materials provided with the distribution. | |
30 | * 3. Neither the name of the Intel Corporation nor the names of its contributors | |
31 | * may be used to endorse or promote products derived from this software | |
32 | * without specific prior written permission. | |
33 | * | |
34 | * @par | |
35 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' | |
36 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
37 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
38 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | |
39 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
40 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
41 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
42 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
43 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
44 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
45 | * SUCH DAMAGE. | |
46 | * | |
47 | * @par | |
48 | * -- End of Copyright Notice -- | |
49 | */ | |
50 | ||
51 | #include "IxNpeMh.h" | |
52 | #include "IxEthAcc.h" | |
53 | #include "IxEthDB.h" | |
54 | #include "IxOsal.h" | |
55 | #include "IxEthDBPortDefs.h" | |
56 | #include "IxFeatureCtrl.h" | |
57 | #include "IxEthAcc_p.h" | |
58 | #include "IxEthAccQueueAssign_p.h" | |
59 | ||
60 | extern PUBLIC IxEthAccMacState ixEthAccMacState[]; | |
61 | extern PUBLIC UINT32 ixEthAccNewSrcMask; | |
62 | ||
63 | /** | |
64 | * private functions prototype | |
65 | */ | |
66 | PRIVATE IX_OSAL_MBUF * | |
67 | ixEthAccEntryFromQConvert(UINT32 qEntry, UINT32 mask); | |
68 | ||
69 | PRIVATE UINT32 | |
70 | ixEthAccMbufRxQPrepare(IX_OSAL_MBUF *mbuf); | |
71 | ||
72 | PRIVATE UINT32 | |
73 | ixEthAccMbufTxQPrepare(IX_OSAL_MBUF *mbuf); | |
74 | ||
75 | PRIVATE IxEthAccStatus | |
76 | ixEthAccTxSwQHighestPriorityGet(IxEthAccPortId portId, | |
77 | IxEthAccTxPriority *priorityPtr); | |
78 | ||
79 | PRIVATE IxEthAccStatus | |
80 | ixEthAccTxFromSwQ(IxEthAccPortId portId, | |
81 | IxEthAccTxPriority priority); | |
82 | ||
83 | PRIVATE IxEthAccStatus | |
84 | ixEthAccRxFreeFromSwQ(IxEthAccPortId portId); | |
85 | ||
86 | PRIVATE void | |
87 | ixEthAccMbufFromTxQ(IX_OSAL_MBUF *mbuf); | |
88 | ||
89 | PRIVATE void | |
90 | ixEthAccMbufFromRxQ(IX_OSAL_MBUF *mbuf); | |
91 | ||
92 | PRIVATE IX_STATUS | |
93 | ixEthAccQmgrLockTxWrite(IxEthAccPortId portId, | |
94 | UINT32 qBuffer); | |
95 | ||
96 | PRIVATE IX_STATUS | |
97 | ixEthAccQmgrLockRxWrite(IxEthAccPortId portId, | |
98 | UINT32 qBuffer); | |
99 | ||
100 | PRIVATE IX_STATUS | |
101 | ixEthAccQmgrTxWrite(IxEthAccPortId portId, | |
102 | UINT32 qBuffer, | |
103 | UINT32 priority); | |
104 | ||
105 | /** | |
106 | * @addtogroup IxEthAccPri | |
107 | *@{ | |
108 | */ | |
109 | ||
110 | /* increment a counter only when stats are enabled */ | |
111 | #define TX_STATS_INC(port,field) \ | |
112 | IX_ETH_ACC_STATS_INC(ixEthAccPortData[port].ixEthAccTxData.stats.field) | |
113 | #define RX_STATS_INC(port,field) \ | |
114 | IX_ETH_ACC_STATS_INC(ixEthAccPortData[port].ixEthAccRxData.stats.field) | |
115 | ||
116 | /* always increment the counter (mainly used for unexpected errors) */ | |
117 | #define TX_INC(port,field) \ | |
118 | ixEthAccPortData[port].ixEthAccTxData.stats.field++ | |
119 | #define RX_INC(port,field) \ | |
120 | ixEthAccPortData[port].ixEthAccRxData.stats.field++ | |
121 | ||
122 | PRIVATE IxEthAccDataPlaneStats ixEthAccDataStats; | |
123 | ||
124 | extern IxEthAccPortDataInfo ixEthAccPortData[]; | |
125 | extern IxEthAccInfo ixEthAccDataInfo; | |
126 | ||
127 | PRIVATE IxOsalFastMutex txWriteMutex[IX_ETH_ACC_NUMBER_OF_PORTS]; | |
128 | PRIVATE IxOsalFastMutex rxWriteMutex[IX_ETH_ACC_NUMBER_OF_PORTS]; | |
129 | ||
130 | /** | |
131 | * | |
132 | * @brief Mbuf header conversion macros : they implement the | |
133 | * different conversions using a temporary value. They also double-check | |
134 | * that the parameters can be converted to/from NPE format. | |
135 | * | |
136 | */ | |
137 | #if defined(__wince) && !defined(IN_KERNEL) | |
138 | #define PTR_VIRT2NPE(ptrSrc,dst) \ | |
139 | do { UINT32 temp; \ | |
140 | IX_OSAL_ENSURE(sizeof(ptrSrc) == sizeof(UINT32), "Wrong parameter type"); \ | |
141 | IX_OSAL_ENSURE(sizeof(dst) == sizeof(UINT32), "Wrong parameter type"); \ | |
142 | temp = (UINT32)IX_OSAL_MBUF_MBUF_VIRTUAL_TO_PHYSICAL_TRANSLATION((IX_OSAL_MBUF*)ptrSrc); \ | |
143 | (dst) = IX_OSAL_SWAP_BE_SHARED_LONG(temp); } \ | |
144 | while(0) | |
145 | ||
146 | #define PTR_NPE2VIRT(type,src,ptrDst) \ | |
147 | do { void *temp; \ | |
148 | IX_OSAL_ENSURE(sizeof(type) == sizeof(UINT32), "Wrong parameter type"); \ | |
149 | IX_OSAL_ENSURE(sizeof(src) == sizeof(UINT32), "Wrong parameter type"); \ | |
150 | IX_OSAL_ENSURE(sizeof(ptrDst) == sizeof(UINT32), "Wrong parameter type"); \ | |
151 | temp = (void *)IX_OSAL_SWAP_BE_SHARED_LONG(src); \ | |
152 | (ptrDst) = (type)IX_OSAL_MBUF_MBUF_PHYSICAL_TO_VIRTUAL_TRANSLATION(temp); } \ | |
153 | while(0) | |
154 | #else | |
155 | #define PTR_VIRT2NPE(ptrSrc,dst) \ | |
156 | do { UINT32 temp; \ | |
157 | IX_OSAL_ENSURE(sizeof(ptrSrc) == sizeof(UINT32), "Wrong parameter type"); \ | |
158 | IX_OSAL_ENSURE(sizeof(dst) == sizeof(UINT32), "Wrong parameter type"); \ | |
159 | temp = (UINT32)IX_OSAL_MMU_VIRT_TO_PHYS(ptrSrc); \ | |
160 | (dst) = IX_OSAL_SWAP_BE_SHARED_LONG(temp); } \ | |
161 | while(0) | |
162 | ||
163 | #define PTR_NPE2VIRT(type,src,ptrDst) \ | |
164 | do { void *temp; \ | |
165 | IX_OSAL_ENSURE(sizeof(type) == sizeof(UINT32), "Wrong parameter type"); \ | |
166 | IX_OSAL_ENSURE(sizeof(src) == sizeof(UINT32), "Wrong parameter type"); \ | |
167 | IX_OSAL_ENSURE(sizeof(ptrDst) == sizeof(UINT32), "Wrong parameter type"); \ | |
168 | temp = (void *)IX_OSAL_SWAP_BE_SHARED_LONG(src); \ | |
169 | (ptrDst) = (type)IX_OSAL_MMU_PHYS_TO_VIRT(temp); } \ | |
170 | while(0) | |
171 | #endif | |
172 | ||
173 | /** | |
174 | * | |
175 | * @brief Mbuf payload pointer conversion macros : Wince has its own | |
176 | * method to convert the buffer pointers | |
177 | */ | |
178 | #if defined(__wince) && !defined(IN_KERNEL) | |
179 | #define DATAPTR_VIRT2NPE(ptrSrc,dst) \ | |
180 | do { UINT32 temp; \ | |
181 | temp = (UINT32)IX_OSAL_MBUF_DATA_VIRTUAL_TO_PHYSICAL_TRANSLATION(ptrSrc); \ | |
182 | (dst) = IX_OSAL_SWAP_BE_SHARED_LONG(temp); } \ | |
183 | while(0) | |
184 | ||
185 | #else | |
186 | #define DATAPTR_VIRT2NPE(ptrSrc,dst) PTR_VIRT2NPE(IX_OSAL_MBUF_MDATA(ptrSrc),dst) | |
187 | #endif | |
188 | ||
189 | ||
190 | /* Flush the shared part of the mbuf header */ | |
191 | #define IX_ETHACC_NE_CACHE_FLUSH(mbufPtr) \ | |
192 | do { \ | |
193 | IX_OSAL_CACHE_FLUSH(IX_ETHACC_NE_SHARED(mbufPtr), \ | |
194 | sizeof(IxEthAccNe)); \ | |
195 | } \ | |
196 | while(0) | |
197 | ||
198 | /* Invalidate the shared part of the mbuf header */ | |
199 | #define IX_ETHACC_NE_CACHE_INVALIDATE(mbufPtr) \ | |
200 | do { \ | |
201 | IX_OSAL_CACHE_INVALIDATE(IX_ETHACC_NE_SHARED(mbufPtr), \ | |
202 | sizeof(IxEthAccNe)); \ | |
203 | } \ | |
204 | while(0) | |
205 | ||
206 | /* Preload one cache line (shared mbuf headers are aligned | |
207 | * and their size is 1 cache line) | |
208 | * | |
209 | * IX_OSAL_CACHED is defined when the mbuf headers are | |
210 | * allocated from cached memory. | |
211 | * | |
212 | * Other processor on emulation environment may not implement | |
213 | * preload function | |
214 | */ | |
215 | #ifdef IX_OSAL_CACHED | |
216 | #if (CPU!=SIMSPARCSOLARIS) && !defined (__wince) | |
217 | #define IX_ACC_DATA_CACHE_PRELOAD(ptr) \ | |
218 | do { /* preload a cache line (Xscale Processor) */ \ | |
219 | __asm__ (" pld [%0]\n": : "r" (ptr)); \ | |
220 | } \ | |
221 | while(0) | |
222 | #else | |
223 | /* preload not implemented on different processor */ | |
224 | #define IX_ACC_DATA_CACHE_PRELOAD(mbufPtr) \ | |
225 | do { /* nothing */ } while (0) | |
226 | #endif | |
227 | #else | |
228 | /* preload not needed if cache is not enabled */ | |
229 | #define IX_ACC_DATA_CACHE_PRELOAD(mbufPtr) \ | |
230 | do { /* nothing */ } while (0) | |
231 | #endif | |
232 | ||
233 | /** | |
234 | * | |
235 | * @brief function to retrieve the correct pointer from | |
236 | * a queue entry posted by the NPE | |
237 | * | |
238 | * @param qEntry : entry from qmgr queue | |
239 | * mask : applicable mask for this queue | |
240 | * (4 most significant bits are used for additional informations) | |
241 | * | |
242 | * @return IX_OSAL_MBUF * pointer to mbuf header | |
243 | * | |
244 | * @internal | |
245 | */ | |
246 | PRIVATE IX_OSAL_MBUF * | |
247 | ixEthAccEntryFromQConvert(UINT32 qEntry, UINT32 mask) | |
248 | { | |
249 | IX_OSAL_MBUF *mbufPtr; | |
250 | ||
251 | if (qEntry != 0) | |
252 | { | |
253 | /* mask NPE bits (e.g. priority, port ...) */ | |
254 | qEntry &= mask; | |
255 | ||
256 | #if IX_ACC_DRAM_PHYS_OFFSET != 0 | |
257 | /* restore the original address pointer (if PHYS_OFFSET is not 0) */ | |
258 | qEntry |= (IX_ACC_DRAM_PHYS_OFFSET & ~IX_ETHNPE_QM_Q_RXENET_ADDR_MASK); | |
259 | #endif | |
260 | /* get the mbuf pointer address from the npe-shared address */ | |
261 | qEntry -= offsetof(IX_OSAL_MBUF,ix_ne); | |
262 | ||
263 | /* phys2virt mbuf */ | |
264 | mbufPtr = (IX_OSAL_MBUF *)IX_OSAL_MMU_PHYS_TO_VIRT(qEntry); | |
265 | ||
266 | /* preload the cacheline shared with NPE */ | |
267 | IX_ACC_DATA_CACHE_PRELOAD(IX_ETHACC_NE_SHARED(mbufPtr)); | |
268 | ||
269 | /* preload the cacheline used by xscale */ | |
270 | IX_ACC_DATA_CACHE_PRELOAD(mbufPtr); | |
271 | } | |
272 | else | |
273 | { | |
274 | mbufPtr = NULL; | |
275 | } | |
276 | ||
277 | return mbufPtr; | |
278 | } | |
279 | ||
280 | /* Convert the mbuf header for NPE transmission */ | |
281 | PRIVATE UINT32 | |
282 | ixEthAccMbufTxQPrepare(IX_OSAL_MBUF *mbuf) | |
283 | { | |
284 | UINT32 qbuf; | |
285 | UINT32 len; | |
286 | ||
287 | /* endianess swap for tci and flags | |
288 | note: this is done only once, even for chained buffers */ | |
289 | IX_ETHACC_NE_FLAGS(mbuf) = IX_OSAL_SWAP_BE_SHARED_SHORT(IX_ETHACC_NE_FLAGS(mbuf)); | |
290 | IX_ETHACC_NE_VLANTCI(mbuf) = IX_OSAL_SWAP_BE_SHARED_SHORT(IX_ETHACC_NE_VLANTCI(mbuf)); | |
291 | ||
292 | /* test for unchained mbufs */ | |
293 | if (IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) == NULL) | |
294 | { | |
295 | /* "best case" scenario : unchained mbufs */ | |
296 | IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedTxMBufs); | |
297 | ||
298 | /* payload pointer conversion */ | |
299 | DATAPTR_VIRT2NPE(mbuf, IX_ETHACC_NE_DATA(mbuf)); | |
300 | ||
301 | /* unchained mbufs : the frame length is the mbuf length | |
302 | * and the 2 identical lengths are stored in the same | |
303 | * word. | |
304 | */ | |
305 | len = IX_OSAL_MBUF_MLEN(mbuf); | |
306 | ||
307 | /* set the length in both length and pktLen 16-bits fields */ | |
308 | len |= (len << IX_ETHNPE_ACC_LENGTH_OFFSET); | |
309 | IX_ETHACC_NE_LEN(mbuf) = IX_OSAL_SWAP_BE_SHARED_LONG(len); | |
310 | ||
311 | /* unchained mbufs : next contains 0 */ | |
312 | IX_ETHACC_NE_NEXT(mbuf) = 0; | |
313 | ||
314 | /* flush shared header after all address conversions */ | |
315 | IX_ETHACC_NE_CACHE_FLUSH(mbuf); | |
316 | } | |
317 | else | |
318 | { | |
319 | /* chained mbufs */ | |
320 | IX_OSAL_MBUF *ptr = mbuf; | |
321 | IX_OSAL_MBUF *nextPtr; | |
322 | UINT32 frmLen; | |
323 | ||
324 | /* get the frame length from the header of the first buffer */ | |
325 | frmLen = IX_OSAL_MBUF_PKT_LEN(mbuf); | |
326 | ||
327 | do | |
328 | { | |
329 | IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedTxMBufs); | |
330 | ||
331 | /* payload pointer */ | |
332 | DATAPTR_VIRT2NPE(ptr,IX_ETHACC_NE_DATA(ptr)); | |
333 | /* Buffer length and frame length are stored in the same word */ | |
334 | len = IX_OSAL_MBUF_MLEN(ptr); | |
335 | len = frmLen | (len << IX_ETHNPE_ACC_LENGTH_OFFSET); | |
336 | IX_ETHACC_NE_LEN(ptr) = IX_OSAL_SWAP_BE_SHARED_LONG(len); | |
337 | ||
338 | /* get the virtual next chain pointer */ | |
339 | nextPtr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr); | |
340 | if (nextPtr != NULL) | |
341 | { | |
342 | /* shared pointer of the next buffer is chained */ | |
343 | PTR_VIRT2NPE(IX_ETHACC_NE_SHARED(nextPtr), | |
344 | IX_ETHACC_NE_NEXT(ptr)); | |
345 | } | |
346 | else | |
347 | { | |
348 | IX_ETHACC_NE_NEXT(ptr) = 0; | |
349 | } | |
350 | ||
351 | /* flush shared header after all address conversions */ | |
352 | IX_ETHACC_NE_CACHE_FLUSH(ptr); | |
353 | ||
354 | /* move to next buffer */ | |
355 | ptr = nextPtr; | |
356 | ||
357 | /* the frame length field is set only in the first buffer | |
358 | * and is zeroed in the next buffers | |
359 | */ | |
360 | frmLen = 0; | |
361 | } | |
362 | while(ptr != NULL); | |
363 | ||
364 | } | |
365 | ||
366 | /* virt2phys mbuf itself */ | |
367 | qbuf = (UINT32)IX_OSAL_MMU_VIRT_TO_PHYS( | |
368 | IX_ETHACC_NE_SHARED(mbuf)); | |
369 | ||
370 | /* Ensure the bits which are reserved to exchange information with | |
371 | * the NPE are cleared | |
372 | * | |
373 | * If the mbuf address is not correctly aligned, or from an | |
374 | * incompatible memory range, there is no point to continue | |
375 | */ | |
376 | IX_OSAL_ENSURE(((qbuf & ~IX_ETHNPE_QM_Q_TXENET_ADDR_MASK) == 0), | |
377 | "Invalid address range"); | |
378 | ||
379 | return qbuf; | |
380 | } | |
381 | ||
382 | /* Convert the mbuf header for NPE reception */ | |
383 | PRIVATE UINT32 | |
384 | ixEthAccMbufRxQPrepare(IX_OSAL_MBUF *mbuf) | |
385 | { | |
386 | UINT32 len; | |
387 | UINT32 qbuf; | |
388 | ||
389 | if (IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) == NULL) | |
390 | { | |
391 | /* "best case" scenario : unchained mbufs */ | |
392 | IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedRxFreeMBufs); | |
393 | ||
394 | /* unchained mbufs : payload pointer */ | |
395 | DATAPTR_VIRT2NPE(mbuf, IX_ETHACC_NE_DATA(mbuf)); | |
396 | ||
397 | /* unchained mbufs : set the buffer length | |
398 | * and the frame length field is zeroed | |
399 | */ | |
400 | len = (IX_OSAL_MBUF_MLEN(mbuf) << IX_ETHNPE_ACC_LENGTH_OFFSET); | |
401 | IX_ETHACC_NE_LEN(mbuf) = IX_OSAL_SWAP_BE_SHARED_LONG(len); | |
402 | ||
403 | /* unchained mbufs : next pointer is null */ | |
404 | IX_ETHACC_NE_NEXT(mbuf) = 0; | |
405 | ||
406 | /* flush shared header after all address conversions */ | |
407 | IX_ETHACC_NE_CACHE_FLUSH(mbuf); | |
408 | ||
409 | /* remove shared header cache line */ | |
410 | IX_ETHACC_NE_CACHE_INVALIDATE(mbuf); | |
411 | } | |
412 | else | |
413 | { | |
414 | /* chained mbufs */ | |
415 | IX_OSAL_MBUF *ptr = mbuf; | |
416 | IX_OSAL_MBUF *nextPtr; | |
417 | ||
418 | do | |
419 | { | |
420 | /* chained mbufs */ | |
421 | IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedRxFreeMBufs); | |
422 | ||
423 | /* we must save virtual next chain pointer */ | |
424 | nextPtr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr); | |
425 | ||
426 | if (nextPtr != NULL) | |
427 | { | |
428 | /* chaining pointer for NPE */ | |
429 | PTR_VIRT2NPE(IX_ETHACC_NE_SHARED(nextPtr), | |
430 | IX_ETHACC_NE_NEXT(ptr)); | |
431 | } | |
432 | else | |
433 | { | |
434 | IX_ETHACC_NE_NEXT(ptr) = 0; | |
435 | } | |
436 | ||
437 | /* payload pointer */ | |
438 | DATAPTR_VIRT2NPE(ptr,IX_ETHACC_NE_DATA(ptr)); | |
439 | ||
440 | /* buffer length */ | |
441 | len = (IX_OSAL_MBUF_MLEN(ptr) << IX_ETHNPE_ACC_LENGTH_OFFSET); | |
442 | IX_ETHACC_NE_LEN(ptr) = IX_OSAL_SWAP_BE_SHARED_LONG(len); | |
443 | ||
444 | /* flush shared header after all address conversions */ | |
445 | IX_ETHACC_NE_CACHE_FLUSH(ptr); | |
446 | ||
447 | /* remove shared header cache line */ | |
448 | IX_ETHACC_NE_CACHE_INVALIDATE(ptr); | |
449 | ||
450 | /* next mbuf in the chain */ | |
451 | ptr = nextPtr; | |
452 | } | |
453 | while(ptr != NULL); | |
454 | } | |
455 | ||
456 | /* virt2phys mbuf itself */ | |
457 | qbuf = (UINT32)IX_OSAL_MMU_VIRT_TO_PHYS( | |
458 | IX_ETHACC_NE_SHARED(mbuf)); | |
459 | ||
460 | /* Ensure the bits which are reserved to exchange information with | |
461 | * the NPE are cleared | |
462 | * | |
463 | * If the mbuf address is not correctly aligned, or from an | |
464 | * incompatible memory range, there is no point to continue | |
465 | */ | |
466 | IX_OSAL_ENSURE(((qbuf & ~IX_ETHNPE_QM_Q_RXENET_ADDR_MASK) == 0), | |
467 | "Invalid address range"); | |
468 | ||
469 | return qbuf; | |
470 | } | |
471 | ||
472 | /* Convert the mbuf header after NPE transmission | |
473 | * Since there is nothing changed by the NPE, there is no need | |
474 | * to process anything but the update of internal stats | |
475 | * when they are enabled | |
476 | */ | |
477 | PRIVATE void | |
478 | ixEthAccMbufFromTxQ(IX_OSAL_MBUF *mbuf) | |
479 | { | |
480 | #ifndef NDEBUG | |
481 | /* test for unchained mbufs */ | |
482 | if (IX_ETHACC_NE_NEXT(mbuf) == 0) | |
483 | { | |
484 | /* unchained mbufs : update the stats */ | |
485 | IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedTxDoneMBufs); | |
486 | } | |
487 | else | |
488 | { | |
489 | /* chained mbufs : walk the chain and update the stats */ | |
490 | IX_OSAL_MBUF *ptr = mbuf; | |
491 | ||
492 | do | |
493 | { | |
494 | IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedTxDoneMBufs); | |
495 | ptr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr); | |
496 | } | |
497 | while (ptr != NULL); | |
498 | } | |
499 | #endif | |
500 | } | |
501 | ||
502 | /* Convert the mbuf header after NPE reception */ | |
503 | PRIVATE void | |
504 | ixEthAccMbufFromRxQ(IX_OSAL_MBUF *mbuf) | |
505 | { | |
506 | UINT32 len; | |
507 | ||
508 | /* endianess swap for tci and flags | |
509 | note: this is done only once, even for chained buffers */ | |
510 | IX_ETHACC_NE_FLAGS(mbuf) = IX_OSAL_SWAP_BE_SHARED_SHORT(IX_ETHACC_NE_FLAGS(mbuf)); | |
511 | IX_ETHACC_NE_VLANTCI(mbuf) = IX_OSAL_SWAP_BE_SHARED_SHORT(IX_ETHACC_NE_VLANTCI(mbuf)); | |
512 | ||
513 | /* test for unchained mbufs */ | |
514 | if (IX_ETHACC_NE_NEXT(mbuf) == 0) | |
515 | { | |
516 | /* unchained mbufs */ | |
517 | IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedRxMBufs); | |
518 | ||
519 | /* get the frame length. it is the same than the buffer length */ | |
520 | len = IX_OSAL_SWAP_BE_SHARED_LONG(IX_ETHACC_NE_LEN(mbuf)); | |
521 | len &= IX_ETHNPE_ACC_PKTLENGTH_MASK; | |
522 | IX_OSAL_MBUF_PKT_LEN(mbuf) = IX_OSAL_MBUF_MLEN(mbuf) = len; | |
523 | ||
524 | /* clears the next packet field */ | |
525 | IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) = NULL; | |
526 | } | |
527 | else | |
528 | { | |
529 | IX_OSAL_MBUF *ptr = mbuf; | |
530 | IX_OSAL_MBUF *nextPtr; | |
531 | UINT32 frmLen; | |
532 | ||
533 | /* convert the frame length */ | |
534 | frmLen = IX_OSAL_SWAP_BE_SHARED_LONG(IX_ETHACC_NE_LEN(mbuf)); | |
535 | IX_OSAL_MBUF_PKT_LEN(mbuf) = (frmLen & IX_ETHNPE_ACC_PKTLENGTH_MASK); | |
536 | ||
537 | /* chained mbufs */ | |
538 | do | |
539 | { | |
540 | IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedRxMBufs); | |
541 | ||
542 | /* convert the length */ | |
543 | len = IX_OSAL_SWAP_BE_SHARED_LONG(IX_ETHACC_NE_LEN(ptr)); | |
544 | IX_OSAL_MBUF_MLEN(ptr) = (len >> IX_ETHNPE_ACC_LENGTH_OFFSET); | |
545 | ||
546 | /* get the next pointer */ | |
547 | PTR_NPE2VIRT(IX_OSAL_MBUF *,IX_ETHACC_NE_NEXT(ptr), nextPtr); | |
548 | if (nextPtr != NULL) | |
549 | { | |
550 | nextPtr = (IX_OSAL_MBUF *)((UINT8 *)nextPtr - offsetof(IX_OSAL_MBUF,ix_ne)); | |
551 | } | |
552 | /* set the next pointer */ | |
553 | IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr) = nextPtr; | |
554 | ||
555 | /* move to the next buffer */ | |
556 | ptr = nextPtr; | |
557 | } | |
558 | while (ptr != NULL); | |
559 | } | |
560 | } | |
561 | ||
562 | /* write to qmgr if possible and report an overflow if not possible | |
563 | * Use a fast lock to protect the queue write. | |
564 | * This way, the tx feature is reentrant. | |
565 | */ | |
566 | PRIVATE IX_STATUS | |
567 | ixEthAccQmgrLockTxWrite(IxEthAccPortId portId, UINT32 qBuffer) | |
568 | { | |
569 | IX_STATUS qStatus; | |
570 | if (ixOsalFastMutexTryLock(&txWriteMutex[portId]) == IX_SUCCESS) | |
571 | { | |
572 | qStatus = ixQMgrQWrite( | |
573 | IX_ETH_ACC_PORT_TO_TX_Q_ID(portId), | |
574 | &qBuffer); | |
575 | #ifndef NDEBUG | |
576 | if (qStatus != IX_SUCCESS) | |
577 | { | |
578 | TX_STATS_INC(portId, txOverflow); | |
579 | } | |
580 | #endif | |
581 | ixOsalFastMutexUnlock(&txWriteMutex[portId]); | |
582 | } | |
583 | else | |
584 | { | |
585 | TX_STATS_INC(portId, txLock); | |
586 | qStatus = IX_QMGR_Q_OVERFLOW; | |
587 | } | |
588 | return qStatus; | |
589 | } | |
590 | ||
591 | /* write to qmgr if possible and report an overflow if not possible | |
592 | * Use a fast lock to protect the queue write. | |
593 | * This way, the Rx feature is reentrant. | |
594 | */ | |
595 | PRIVATE IX_STATUS | |
596 | ixEthAccQmgrLockRxWrite(IxEthAccPortId portId, UINT32 qBuffer) | |
597 | { | |
598 | IX_STATUS qStatus; | |
599 | if (ixOsalFastMutexTryLock(&rxWriteMutex[portId]) == IX_SUCCESS) | |
600 | { | |
601 | qStatus = ixQMgrQWrite( | |
602 | IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId), | |
603 | &qBuffer); | |
604 | #ifndef NDEBUG | |
605 | if (qStatus != IX_SUCCESS) | |
606 | { | |
607 | RX_STATS_INC(portId, rxFreeOverflow); | |
608 | } | |
609 | #endif | |
610 | ixOsalFastMutexUnlock(&rxWriteMutex[portId]); | |
611 | } | |
612 | else | |
613 | { | |
614 | RX_STATS_INC(portId, rxFreeLock); | |
615 | qStatus = IX_QMGR_Q_OVERFLOW; | |
616 | } | |
617 | return qStatus; | |
618 | } | |
619 | ||
620 | /* | |
621 | * Set the priority and write to a qmgr queue. | |
622 | */ | |
623 | PRIVATE IX_STATUS | |
624 | ixEthAccQmgrTxWrite(IxEthAccPortId portId, UINT32 qBuffer, UINT32 priority) | |
625 | { | |
626 | /* fill the priority field */ | |
627 | qBuffer |= (priority << IX_ETHNPE_QM_Q_FIELD_PRIOR_R); | |
628 | ||
629 | return ixEthAccQmgrLockTxWrite(portId, qBuffer); | |
630 | } | |
631 | ||
632 | /** | |
633 | * | |
634 | * @brief This function will discover the highest priority S/W Tx Q that | |
635 | * has entries in it | |
636 | * | |
637 | * @param portId - (in) the id of the port whose S/W Tx queues are to be searched | |
638 | * priorityPtr - (out) the priority of the highest priority occupied q will be written | |
639 | * here | |
640 | * | |
641 | * @return IX_ETH_ACC_SUCCESS if an occupied Q is found | |
642 | * IX_ETH_ACC_FAIL if no Q has entries | |
643 | * | |
644 | * @internal | |
645 | */ | |
646 | PRIVATE IxEthAccStatus | |
647 | ixEthAccTxSwQHighestPriorityGet(IxEthAccPortId portId, | |
648 | IxEthAccTxPriority *priorityPtr) | |
649 | { | |
650 | if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline | |
651 | == FIFO_NO_PRIORITY) | |
652 | { | |
653 | if(IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId]. | |
654 | ixEthAccTxData.txQ[IX_ETH_ACC_TX_DEFAULT_PRIORITY])) | |
655 | { | |
656 | return IX_ETH_ACC_FAIL; | |
657 | } | |
658 | else | |
659 | { | |
660 | *priorityPtr = IX_ETH_ACC_TX_DEFAULT_PRIORITY; | |
661 | TX_STATS_INC(portId,txPriority[*priorityPtr]); | |
662 | return IX_ETH_ACC_SUCCESS; | |
663 | } | |
664 | } | |
665 | else | |
666 | { | |
667 | IxEthAccTxPriority highestPriority = IX_ETH_ACC_TX_PRIORITY_7; | |
668 | while(1) | |
669 | { | |
670 | if(!IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId]. | |
671 | ixEthAccTxData.txQ[highestPriority])) | |
672 | { | |
673 | ||
674 | *priorityPtr = highestPriority; | |
675 | TX_STATS_INC(portId,txPriority[highestPriority]); | |
676 | return IX_ETH_ACC_SUCCESS; | |
677 | ||
678 | } | |
679 | if (highestPriority == IX_ETH_ACC_TX_PRIORITY_0) | |
680 | { | |
681 | return IX_ETH_ACC_FAIL; | |
682 | } | |
683 | highestPriority--; | |
684 | } | |
685 | } | |
686 | } | |
687 | ||
688 | /** | |
689 | * | |
690 | * @brief This function will take a buffer from a TX S/W Q and attempt | |
691 | * to add it to the relevant TX H/W Q | |
692 | * | |
693 | * @param portId - the port whose TX queue is to be written to | |
694 | * priority - identifies the queue from which the entry is to be read | |
695 | * | |
696 | * @internal | |
697 | */ | |
698 | PRIVATE IxEthAccStatus | |
699 | ixEthAccTxFromSwQ(IxEthAccPortId portId, | |
700 | IxEthAccTxPriority priority) | |
701 | { | |
702 | IX_OSAL_MBUF *mbuf; | |
703 | IX_STATUS qStatus; | |
704 | ||
705 | IX_OSAL_ENSURE((UINT32)priority <= (UINT32)7, "Invalid priority"); | |
706 | ||
707 | IX_ETH_ACC_DATAPLANE_REMOVE_MBUF_FROM_Q_HEAD( | |
708 | ixEthAccPortData[portId].ixEthAccTxData.txQ[priority], | |
709 | mbuf); | |
710 | ||
711 | if (mbuf != NULL) | |
712 | { | |
713 | /* | |
714 | * Add the Tx buffer to the H/W Tx Q | |
715 | * We do not need to flush here as it is already done | |
716 | * in TxFrameSubmit(). | |
717 | */ | |
718 | qStatus = ixEthAccQmgrTxWrite( | |
719 | portId, | |
720 | IX_OSAL_MMU_VIRT_TO_PHYS((UINT32)IX_ETHACC_NE_SHARED(mbuf)), | |
721 | priority); | |
722 | ||
723 | if (qStatus == IX_SUCCESS) | |
724 | { | |
725 | TX_STATS_INC(portId,txFromSwQOK); | |
726 | return IX_SUCCESS; | |
727 | } | |
728 | else if (qStatus == IX_QMGR_Q_OVERFLOW) | |
729 | { | |
730 | /* | |
731 | * H/W Q overflow, need to save the buffer | |
732 | * back on the s/w Q. | |
733 | * we must put it back on the head of the q to avoid | |
734 | * reordering packet tx | |
735 | */ | |
736 | TX_STATS_INC(portId,txFromSwQDelayed); | |
737 | IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD( | |
738 | ixEthAccPortData[portId].ixEthAccTxData.txQ[priority], | |
739 | mbuf); | |
740 | ||
741 | /*enable Q notification*/ | |
742 | qStatus = ixQMgrNotificationEnable( | |
743 | IX_ETH_ACC_PORT_TO_TX_Q_ID(portId), | |
744 | IX_ETH_ACC_PORT_TO_TX_Q_SOURCE(portId)); | |
745 | ||
746 | if (qStatus != IX_SUCCESS && qStatus != IX_QMGR_WARNING) | |
747 | { | |
748 | TX_INC(portId,txUnexpectedError); | |
749 | IX_ETH_ACC_FATAL_LOG( | |
750 | "ixEthAccTxFromSwQ:Unexpected Error: %u\n", | |
751 | qStatus, 0, 0, 0, 0, 0); | |
752 | } | |
753 | } | |
754 | else | |
755 | { | |
756 | TX_INC(portId,txUnexpectedError); | |
757 | ||
758 | /* recovery attempt */ | |
759 | IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD( | |
760 | ixEthAccPortData[portId].ixEthAccTxData.txQ[priority], | |
761 | mbuf); | |
762 | ||
763 | IX_ETH_ACC_FATAL_LOG( | |
764 | "ixEthAccTxFromSwQ:Error: unexpected QM status 0x%08X\n", | |
765 | qStatus, 0, 0, 0, 0, 0); | |
766 | } | |
767 | } | |
768 | else | |
769 | { | |
770 | /* sw queue is empty */ | |
771 | } | |
772 | return IX_ETH_ACC_FAIL; | |
773 | } | |
774 | ||
775 | /** | |
776 | * | |
777 | * @brief This function will take a buffer from a RXfree S/W Q and attempt | |
778 | * to add it to the relevant RxFree H/W Q | |
779 | * | |
780 | * @param portId - the port whose RXFree queue is to be written to | |
781 | * | |
782 | * @internal | |
783 | */ | |
784 | PRIVATE IxEthAccStatus | |
785 | ixEthAccRxFreeFromSwQ(IxEthAccPortId portId) | |
786 | { | |
787 | IX_OSAL_MBUF *mbuf; | |
788 | IX_STATUS qStatus = IX_SUCCESS; | |
789 | ||
790 | IX_ETH_ACC_DATAPLANE_REMOVE_MBUF_FROM_Q_HEAD( | |
791 | ixEthAccPortData[portId].ixEthAccRxData.freeBufferList, | |
792 | mbuf); | |
793 | if (mbuf != NULL) | |
794 | { | |
795 | /* | |
796 | * Add The Rx Buffer to the H/W Free buffer Q if possible | |
797 | */ | |
798 | qStatus = ixEthAccQmgrLockRxWrite(portId, | |
799 | IX_OSAL_MMU_VIRT_TO_PHYS( | |
800 | (UINT32)IX_ETHACC_NE_SHARED(mbuf))); | |
801 | ||
802 | if (qStatus == IX_SUCCESS) | |
803 | { | |
804 | RX_STATS_INC(portId,rxFreeRepFromSwQOK); | |
805 | /* | |
806 | * Buffer added to h/w Q. | |
807 | */ | |
808 | return IX_SUCCESS; | |
809 | } | |
810 | else if (qStatus == IX_QMGR_Q_OVERFLOW) | |
811 | { | |
812 | /* | |
813 | * H/W Q overflow, need to save the buffer back on the s/w Q. | |
814 | */ | |
815 | RX_STATS_INC(portId,rxFreeRepFromSwQDelayed); | |
816 | ||
817 | IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD( | |
818 | ixEthAccPortData[portId].ixEthAccRxData.freeBufferList, | |
819 | mbuf); | |
820 | } | |
821 | else | |
822 | { | |
823 | /* unexpected qmgr error */ | |
824 | RX_INC(portId,rxUnexpectedError); | |
825 | ||
826 | IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD( | |
827 | ixEthAccPortData[portId].ixEthAccRxData.freeBufferList, | |
828 | mbuf); | |
829 | ||
830 | IX_ETH_ACC_FATAL_LOG("IxEthAccRxFreeFromSwQ:Error: unexpected QM status 0x%08X\n", | |
831 | qStatus, 0, 0, 0, 0, 0); | |
832 | } | |
833 | } | |
834 | else | |
835 | { | |
836 | /* sw queue is empty */ | |
837 | } | |
838 | return IX_ETH_ACC_FAIL; | |
839 | } | |
840 | ||
841 | ||
842 | IX_ETH_ACC_PUBLIC | |
843 | IxEthAccStatus ixEthAccInitDataPlane() | |
844 | { | |
845 | UINT32 portId; | |
846 | ||
847 | /* | |
848 | * Initialize the service and register callback to other services. | |
849 | */ | |
850 | ||
851 | IX_ETH_ACC_MEMSET(&ixEthAccDataStats, | |
852 | 0, | |
853 | sizeof(ixEthAccDataStats)); | |
854 | ||
855 | for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++) | |
856 | { | |
857 | ixOsalFastMutexInit(&txWriteMutex[portId]); | |
858 | ixOsalFastMutexInit(&rxWriteMutex[portId]); | |
859 | ||
860 | IX_ETH_ACC_MEMSET(&ixEthAccPortData[portId], | |
861 | 0, | |
862 | sizeof(ixEthAccPortData[portId])); | |
863 | ||
864 | ixEthAccPortData[portId].ixEthAccTxData.schDiscipline = FIFO_NO_PRIORITY; | |
865 | } | |
866 | ||
867 | return (IX_ETH_ACC_SUCCESS); | |
868 | } | |
869 | ||
870 | ||
871 | IX_ETH_ACC_PUBLIC | |
872 | IxEthAccStatus ixEthAccPortTxDoneCallbackRegister(IxEthAccPortId portId, | |
873 | IxEthAccPortTxDoneCallback | |
874 | txCallbackFn, | |
875 | UINT32 callbackTag) | |
876 | { | |
877 | if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED()) | |
878 | { | |
879 | return (IX_ETH_ACC_FAIL); | |
880 | } | |
881 | if (!IX_ETH_ACC_IS_PORT_VALID(portId)) | |
882 | { | |
883 | return (IX_ETH_ACC_INVALID_PORT); | |
884 | } | |
885 | ||
886 | /* HACK: removing this code to enable NPE-A preliminary testing | |
887 | * if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) | |
888 | * { | |
889 | * IX_ETH_ACC_WARNING_LOG("ixEthAccPortTxDoneCallbackRegister: Unavailable Eth %d: Cannot register TxDone Callback.\n",(INT32)portId,0,0,0,0,0); | |
890 | * return IX_ETH_ACC_SUCCESS ; | |
891 | * } | |
892 | */ | |
893 | ||
894 | if (!IX_ETH_IS_PORT_INITIALIZED(portId)) | |
895 | { | |
896 | return (IX_ETH_ACC_PORT_UNINITIALIZED); | |
897 | } | |
898 | if (txCallbackFn == 0) | |
899 | /* Check for null function pointer here. */ | |
900 | { | |
901 | return (IX_ETH_ACC_INVALID_ARG); | |
902 | } | |
903 | ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn = txCallbackFn; | |
904 | ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag = callbackTag; | |
905 | return (IX_ETH_ACC_SUCCESS); | |
906 | } | |
907 | ||
908 | ||
909 | IX_ETH_ACC_PUBLIC | |
910 | IxEthAccStatus ixEthAccPortRxCallbackRegister(IxEthAccPortId portId, | |
911 | IxEthAccPortRxCallback | |
912 | rxCallbackFn, | |
913 | UINT32 callbackTag) | |
914 | { | |
915 | IxEthAccPortId port; | |
916 | ||
917 | if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED()) | |
918 | { | |
919 | return (IX_ETH_ACC_FAIL); | |
920 | } | |
921 | if (!IX_ETH_ACC_IS_PORT_VALID(portId)) | |
922 | { | |
923 | return (IX_ETH_ACC_INVALID_PORT); | |
924 | } | |
925 | ||
926 | if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) | |
927 | { | |
928 | IX_ETH_ACC_WARNING_LOG("ixEthAccPortRxCallbackRegister: Unavailable Eth %d: Cannot register Rx Callback.\n",(INT32)portId,0,0,0,0,0); | |
929 | return IX_ETH_ACC_SUCCESS ; | |
930 | } | |
931 | ||
932 | if (!IX_ETH_IS_PORT_INITIALIZED(portId)) | |
933 | { | |
934 | return (IX_ETH_ACC_PORT_UNINITIALIZED); | |
935 | } | |
936 | ||
937 | /* Check for null function pointer here. */ | |
938 | if (rxCallbackFn == NULL) | |
939 | { | |
940 | return (IX_ETH_ACC_INVALID_ARG); | |
941 | } | |
942 | ||
943 | /* Check the user is not changing the callback type | |
944 | * when the port is enabled. | |
945 | */ | |
946 | if (ixEthAccMacState[portId].portDisableState == ACTIVE) | |
947 | { | |
948 | for (port = 0; port < IX_ETH_ACC_NUMBER_OF_PORTS; port++) | |
949 | { | |
950 | if ((ixEthAccMacState[port].portDisableState == ACTIVE) | |
951 | && (ixEthAccPortData[port].ixEthAccRxData.rxMultiBufferCallbackInUse == TRUE)) | |
952 | { | |
953 | /* one of the active ports has a different rx callback type. | |
954 | * Changing the callback type when the port is enabled | |
955 | * is not safe | |
956 | */ | |
957 | return (IX_ETH_ACC_INVALID_ARG); | |
958 | } | |
959 | } | |
960 | } | |
961 | ||
962 | /* update the callback pointer : this is done before | |
963 | * registering the new qmgr callback | |
964 | */ | |
965 | ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn = rxCallbackFn; | |
966 | ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag = callbackTag; | |
967 | ||
968 | /* update the qmgr callback for rx queues */ | |
969 | if (ixEthAccQMgrRxCallbacksRegister(ixEthRxFrameQMCallback) | |
970 | != IX_ETH_ACC_SUCCESS) | |
971 | { | |
972 | /* unexpected qmgr error */ | |
973 | IX_ETH_ACC_FATAL_LOG("ixEthAccPortRxCallbackRegister: unexpected QMgr error, " \ | |
974 | "could not register Rx single-buffer callback\n", 0, 0, 0, 0, 0, 0); | |
975 | ||
976 | RX_INC(portId,rxUnexpectedError); | |
977 | return (IX_ETH_ACC_INVALID_ARG); | |
978 | } | |
979 | ||
980 | ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackInUse = FALSE; | |
981 | ||
982 | return (IX_ETH_ACC_SUCCESS); | |
983 | } | |
984 | ||
985 | IX_ETH_ACC_PUBLIC | |
986 | IxEthAccStatus ixEthAccPortMultiBufferRxCallbackRegister( | |
987 | IxEthAccPortId portId, | |
988 | IxEthAccPortMultiBufferRxCallback | |
989 | rxCallbackFn, | |
990 | UINT32 callbackTag) | |
991 | { | |
992 | IxEthAccPortId port; | |
993 | ||
994 | if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED()) | |
995 | { | |
996 | return (IX_ETH_ACC_FAIL); | |
997 | } | |
998 | if (!IX_ETH_ACC_IS_PORT_VALID(portId)) | |
999 | { | |
1000 | return (IX_ETH_ACC_INVALID_PORT); | |
1001 | } | |
1002 | ||
1003 | if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) | |
1004 | { | |
1005 | IX_ETH_ACC_WARNING_LOG("ixEthAccPortMultiBufferRxCallbackRegister: Unavailable Eth %d: Cannot register Rx Callback.\n",(INT32)portId,0,0,0,0,0); | |
1006 | return IX_ETH_ACC_SUCCESS ; | |
1007 | } | |
1008 | ||
1009 | if (!IX_ETH_IS_PORT_INITIALIZED(portId)) | |
1010 | { | |
1011 | return (IX_ETH_ACC_PORT_UNINITIALIZED); | |
1012 | } | |
1013 | ||
1014 | /* Check for null function pointer here. */ | |
1015 | if (rxCallbackFn == NULL) | |
1016 | { | |
1017 | return (IX_ETH_ACC_INVALID_ARG); | |
1018 | } | |
1019 | ||
1020 | /* Check the user is not changing the callback type | |
1021 | * when the port is enabled. | |
1022 | */ | |
1023 | if (ixEthAccMacState[portId].portDisableState == ACTIVE) | |
1024 | { | |
1025 | for (port = 0; port < IX_ETH_ACC_NUMBER_OF_PORTS; port++) | |
1026 | { | |
1027 | if ((ixEthAccMacState[port].portDisableState == ACTIVE) | |
1028 | && (ixEthAccPortData[port].ixEthAccRxData.rxMultiBufferCallbackInUse == FALSE)) | |
1029 | { | |
1030 | /* one of the active ports has a different rx callback type. | |
1031 | * Changing the callback type when the port is enabled | |
1032 | * is not safe | |
1033 | */ | |
1034 | return (IX_ETH_ACC_INVALID_ARG); | |
1035 | } | |
1036 | } | |
1037 | } | |
1038 | ||
1039 | /* update the callback pointer : this is done before | |
1040 | * registering the new qmgr callback | |
1041 | */ | |
1042 | ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackFn = rxCallbackFn; | |
1043 | ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackTag = callbackTag; | |
1044 | ||
1045 | /* update the qmgr callback for rx queues */ | |
1046 | if (ixEthAccQMgrRxCallbacksRegister(ixEthRxMultiBufferQMCallback) | |
1047 | != IX_ETH_ACC_SUCCESS) | |
1048 | { | |
1049 | /* unexpected qmgr error */ | |
1050 | RX_INC(portId,rxUnexpectedError); | |
1051 | ||
1052 | IX_ETH_ACC_FATAL_LOG("ixEthAccPortMultiBufferRxCallbackRegister: unexpected QMgr error, " \ | |
1053 | "could not register Rx multi-buffer callback\n", 0, 0, 0, 0, 0, 0); | |
1054 | ||
1055 | return (IX_ETH_ACC_INVALID_ARG); | |
1056 | } | |
1057 | ||
1058 | ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackInUse = TRUE; | |
1059 | ||
1060 | return (IX_ETH_ACC_SUCCESS); | |
1061 | } | |
1062 | ||
1063 | IX_ETH_ACC_PUBLIC | |
1064 | IxEthAccStatus ixEthAccPortTxFrameSubmit(IxEthAccPortId portId, | |
1065 | IX_OSAL_MBUF *buffer, | |
1066 | IxEthAccTxPriority priority) | |
1067 | { | |
1068 | IX_STATUS qStatus = IX_SUCCESS; | |
1069 | UINT32 qBuffer; | |
1070 | IxEthAccTxPriority highestPriority; | |
1071 | IxQMgrQStatus txQStatus; | |
1072 | ||
1073 | #ifndef NDEBUG | |
1074 | if (buffer == NULL) | |
1075 | { | |
1076 | return (IX_ETH_ACC_FAIL); | |
1077 | } | |
1078 | if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED()) | |
1079 | { | |
1080 | return (IX_ETH_ACC_FAIL); | |
1081 | } | |
1082 | if (!IX_ETH_ACC_IS_PORT_VALID(portId)) | |
1083 | { | |
1084 | return (IX_ETH_ACC_INVALID_PORT); | |
1085 | } | |
1086 | ||
1087 | if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) | |
1088 | { | |
1089 | IX_ETH_ACC_FATAL_LOG("ixEthAccPortTxFrameSubmit: Unavailable Eth %d: Cannot submit Tx Frame.\n", | |
1090 | (INT32)portId,0,0,0,0,0); | |
1091 | return IX_ETH_ACC_PORT_UNINITIALIZED ; | |
1092 | } | |
1093 | ||
1094 | if (!IX_ETH_IS_PORT_INITIALIZED(portId)) | |
1095 | { | |
1096 | return (IX_ETH_ACC_PORT_UNINITIALIZED); | |
1097 | } | |
1098 | if ((UINT32)priority > (UINT32)IX_ETH_ACC_TX_PRIORITY_7) | |
1099 | { | |
1100 | return (IX_ETH_ACC_INVALID_ARG); | |
1101 | } | |
1102 | #endif | |
1103 | ||
1104 | /* | |
1105 | * Need to Flush the MBUF and its contents (data) as it may be | |
1106 | * read from the NPE. Convert virtual addresses to physical addresses also. | |
1107 | */ | |
1108 | qBuffer = ixEthAccMbufTxQPrepare(buffer); | |
1109 | ||
1110 | /* | |
1111 | * If no fifo priority set on Xscale ... | |
1112 | */ | |
1113 | if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline == | |
1114 | FIFO_NO_PRIORITY) | |
1115 | { | |
1116 | /* | |
1117 | * Add The Tx Buffer to the H/W Tx Q if possible | |
1118 | * (the priority is passed to the NPE, because | |
1119 | * the NPE is able to reorder the frames | |
1120 | * before transmission to the underlying hardware) | |
1121 | */ | |
1122 | qStatus = ixEthAccQmgrTxWrite(portId, | |
1123 | qBuffer, | |
1124 | IX_ETH_ACC_TX_DEFAULT_PRIORITY); | |
1125 | ||
1126 | if (qStatus == IX_SUCCESS) | |
1127 | { | |
1128 | TX_STATS_INC(portId,txQOK); | |
1129 | ||
1130 | /* | |
1131 | * "best case" scenario : Buffer added to h/w Q. | |
1132 | */ | |
1133 | return (IX_SUCCESS); | |
1134 | } | |
1135 | else if (qStatus == IX_QMGR_Q_OVERFLOW) | |
1136 | { | |
1137 | /* | |
1138 | * We were unable to write the buffer to the | |
1139 | * appropriate H/W Q, Save it in the sw Q. | |
1140 | * (use the default priority queue regardless of | |
1141 | * input parameter) | |
1142 | */ | |
1143 | priority = IX_ETH_ACC_TX_DEFAULT_PRIORITY; | |
1144 | } | |
1145 | else | |
1146 | { | |
1147 | /* unexpected qmgr error */ | |
1148 | TX_INC(portId,txUnexpectedError); | |
1149 | IX_ETH_ACC_FATAL_LOG( | |
1150 | "ixEthAccPortTxFrameSubmit:Error: qStatus = %u\n", | |
1151 | (UINT32)qStatus, 0, 0, 0, 0, 0); | |
1152 | return (IX_ETH_ACC_FAIL); | |
1153 | } | |
1154 | } | |
1155 | else if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline == | |
1156 | FIFO_PRIORITY) | |
1157 | { | |
1158 | ||
1159 | /* | |
1160 | * For priority transmission, put the frame directly on the H/W queue | |
1161 | * if the H/W queue is empty, otherwise, put it in a S/W Q | |
1162 | */ | |
1163 | ixQMgrQStatusGet(IX_ETH_ACC_PORT_TO_TX_Q_ID(portId), &txQStatus); | |
1164 | if((txQStatus & IX_QMGR_Q_STATUS_E_BIT_MASK) != 0) | |
1165 | { | |
1166 | /*The tx queue is empty, check whether there are buffers on the s/w queues*/ | |
1167 | if(ixEthAccTxSwQHighestPriorityGet(portId, &highestPriority) | |
1168 | !=IX_ETH_ACC_FAIL) | |
1169 | { | |
1170 | /*there are buffers on the s/w queues, submit them*/ | |
1171 | ixEthAccTxFromSwQ(portId, highestPriority); | |
1172 | ||
1173 | /* the queue was empty, 1 buffer is already supplied | |
1174 | * but is likely to be immediately transmitted and the | |
1175 | * hw queue is likely to be empty again, so submit | |
1176 | * more from the sw queues | |
1177 | */ | |
1178 | if(ixEthAccTxSwQHighestPriorityGet(portId, &highestPriority) | |
1179 | !=IX_ETH_ACC_FAIL) | |
1180 | { | |
1181 | ixEthAccTxFromSwQ(portId, highestPriority); | |
1182 | /* | |
1183 | * and force the buffer supplied to be placed | |
1184 | * on a priority queue | |
1185 | */ | |
1186 | qStatus = IX_QMGR_Q_OVERFLOW; | |
1187 | } | |
1188 | else | |
1189 | { | |
1190 | /*there are no buffers in the s/w queues, submit directly*/ | |
1191 | qStatus = ixEthAccQmgrTxWrite(portId, qBuffer, priority); | |
1192 | } | |
1193 | } | |
1194 | else | |
1195 | { | |
1196 | /*there are no buffers in the s/w queues, submit directly*/ | |
1197 | qStatus = ixEthAccQmgrTxWrite(portId, qBuffer, priority); | |
1198 | } | |
1199 | } | |
1200 | else | |
1201 | { | |
1202 | qStatus = IX_QMGR_Q_OVERFLOW; | |
1203 | } | |
1204 | } | |
1205 | else | |
1206 | { | |
1207 | TX_INC(portId,txUnexpectedError); | |
1208 | IX_ETH_ACC_FATAL_LOG( | |
1209 | "ixEthAccPortTxFrameSubmit:Error: wrong schedule discipline setup\n", | |
1210 | 0, 0, 0, 0, 0, 0); | |
1211 | return (IX_ETH_ACC_FAIL); | |
1212 | } | |
1213 | ||
1214 | if(qStatus == IX_SUCCESS ) | |
1215 | { | |
1216 | TX_STATS_INC(portId,txQOK); | |
1217 | return IX_ETH_ACC_SUCCESS; | |
1218 | } | |
1219 | else if(qStatus == IX_QMGR_Q_OVERFLOW) | |
1220 | { | |
1221 | TX_STATS_INC(portId,txQDelayed); | |
1222 | /* | |
1223 | * We were unable to write the buffer to the | |
1224 | * appropriate H/W Q, Save it in a s/w Q. | |
1225 | */ | |
1226 | IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_TAIL( | |
1227 | ixEthAccPortData[portId]. | |
1228 | ixEthAccTxData.txQ[priority], | |
1229 | buffer); | |
1230 | ||
1231 | qStatus = ixQMgrNotificationEnable( | |
1232 | IX_ETH_ACC_PORT_TO_TX_Q_ID(portId), | |
1233 | IX_ETH_ACC_PORT_TO_TX_Q_SOURCE(portId)); | |
1234 | ||
1235 | if (qStatus != IX_SUCCESS) | |
1236 | { | |
1237 | if (qStatus == IX_QMGR_WARNING) | |
1238 | { | |
1239 | /* notification is enabled for a queue | |
1240 | * which is already empty (the condition is already met) | |
1241 | * and there will be no more queue event to drain the sw queue | |
1242 | */ | |
1243 | TX_STATS_INC(portId,txLateNotificationEnabled); | |
1244 | ||
1245 | /* pull a buffer from the sw queue */ | |
1246 | if(ixEthAccTxSwQHighestPriorityGet(portId, &highestPriority) | |
1247 | !=IX_ETH_ACC_FAIL) | |
1248 | { | |
1249 | /*there are buffers on the s/w queues, submit from them*/ | |
1250 | ixEthAccTxFromSwQ(portId, highestPriority); | |
1251 | } | |
1252 | } | |
1253 | else | |
1254 | { | |
1255 | TX_INC(portId,txUnexpectedError); | |
1256 | IX_ETH_ACC_FATAL_LOG( | |
1257 | "ixEthAccPortTxFrameSubmit: unexpected Error: %u\n", | |
1258 | qStatus, 0, 0, 0, 0, 0); | |
1259 | } | |
1260 | } | |
1261 | } | |
1262 | else | |
1263 | { | |
1264 | TX_INC(portId,txUnexpectedError); | |
1265 | IX_ETH_ACC_FATAL_LOG( | |
1266 | "ixEthAccPortTxFrameSubmit: unexpected Error: %u\n", | |
1267 | qStatus, 0, 0, 0, 0, 0); | |
1268 | return (IX_ETH_ACC_FAIL); | |
1269 | } | |
1270 | ||
1271 | return (IX_ETH_ACC_SUCCESS); | |
1272 | } | |
1273 | ||
1274 | ||
1275 | /** | |
1276 | * | |
1277 | * @brief replenish: convert a chain of mbufs to the format | |
1278 | * expected by the NPE | |
1279 | * | |
1280 | */ | |
1281 | ||
1282 | IX_ETH_ACC_PUBLIC | |
1283 | IxEthAccStatus ixEthAccPortRxFreeReplenish(IxEthAccPortId portId, | |
1284 | IX_OSAL_MBUF *buffer) | |
1285 | { | |
1286 | IX_STATUS qStatus = IX_SUCCESS; | |
1287 | UINT32 qBuffer; | |
1288 | ||
1289 | /* | |
1290 | * Check buffer is valid. | |
1291 | */ | |
1292 | ||
1293 | #ifndef NDEBUG | |
1294 | /* check parameter value */ | |
1295 | if (buffer == 0) | |
1296 | { | |
1297 | return (IX_ETH_ACC_FAIL); | |
1298 | } | |
1299 | if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED()) | |
1300 | { | |
1301 | return (IX_ETH_ACC_FAIL); | |
1302 | } | |
1303 | if (!IX_ETH_ACC_IS_PORT_VALID(portId)) | |
1304 | { | |
1305 | return (IX_ETH_ACC_INVALID_PORT); | |
1306 | } | |
1307 | ||
1308 | /* check initialisation is done */ | |
1309 | if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) | |
1310 | { | |
1311 | IX_ETH_ACC_FATAL_LOG(" ixEthAccPortRxFreeReplenish: Unavailable Eth %d: Cannot replenish Rx Free Q.\n",(INT32)portId,0,0,0,0,0); | |
1312 | return IX_ETH_ACC_PORT_UNINITIALIZED ; | |
1313 | } | |
1314 | ||
1315 | if (!IX_ETH_IS_PORT_INITIALIZED(portId)) | |
1316 | { | |
1317 | return (IX_ETH_ACC_PORT_UNINITIALIZED); | |
1318 | } | |
1319 | /* check boundaries and constraints */ | |
1320 | if (IX_OSAL_MBUF_MLEN(buffer) < IX_ETHNPE_ACC_RXFREE_BUFFER_LENGTH_MIN) | |
1321 | { | |
1322 | return (IX_ETH_ACC_FAIL); | |
1323 | } | |
1324 | #endif | |
1325 | ||
1326 | qBuffer = ixEthAccMbufRxQPrepare(buffer); | |
1327 | ||
1328 | /* | |
1329 | * Add The Rx Buffer to the H/W Free buffer Q if possible | |
1330 | */ | |
1331 | qStatus = ixEthAccQmgrLockRxWrite(portId, qBuffer); | |
1332 | ||
1333 | if (qStatus == IX_SUCCESS) | |
1334 | { | |
1335 | RX_STATS_INC(portId,rxFreeRepOK); | |
1336 | /* | |
1337 | * Buffer added to h/w Q. | |
1338 | */ | |
1339 | return (IX_SUCCESS); | |
1340 | } | |
1341 | else if (qStatus == IX_QMGR_Q_OVERFLOW) | |
1342 | { | |
1343 | RX_STATS_INC(portId,rxFreeRepDelayed); | |
1344 | /* | |
1345 | * We were unable to write the buffer to the approprate H/W Q, | |
1346 | * Save it in a s/w Q. | |
1347 | */ | |
1348 | IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_TAIL( | |
1349 | ixEthAccPortData[portId].ixEthAccRxData.freeBufferList, | |
1350 | buffer); | |
1351 | ||
1352 | qStatus = ixQMgrNotificationEnable( | |
1353 | IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId), | |
1354 | IX_ETH_ACC_PORT_TO_RX_FREE_Q_SOURCE(portId)); | |
1355 | ||
1356 | if (qStatus != IX_SUCCESS) | |
1357 | { | |
1358 | if (qStatus == IX_QMGR_WARNING) | |
1359 | { | |
1360 | /* notification is enabled for a queue | |
1361 | * which is already empty (the condition is already met) | |
1362 | * and there will be no more queue event to drain the sw queue | |
1363 | * move an entry from the sw queue to the hw queue */ | |
1364 | RX_STATS_INC(portId,rxFreeLateNotificationEnabled); | |
1365 | ixEthAccRxFreeFromSwQ(portId); | |
1366 | } | |
1367 | else | |
1368 | { | |
1369 | RX_INC(portId,rxUnexpectedError); | |
1370 | IX_ETH_ACC_FATAL_LOG( | |
1371 | "ixEthAccRxPortFreeReplenish:Error: %u\n", | |
1372 | qStatus, 0, 0, 0, 0, 0); | |
1373 | } | |
1374 | } | |
1375 | } | |
1376 | else | |
1377 | { | |
1378 | RX_INC(portId,rxUnexpectedError); | |
1379 | IX_ETH_ACC_FATAL_LOG( | |
1380 | "ixEthAccRxPortFreeReplenish:Error: qStatus = %u\n", | |
1381 | (UINT32)qStatus, 0, 0, 0, 0, 0); | |
1382 | return(IX_ETH_ACC_FAIL); | |
1383 | } | |
1384 | return (IX_ETH_ACC_SUCCESS); | |
1385 | } | |
1386 | ||
1387 | ||
1388 | IX_ETH_ACC_PUBLIC | |
1389 | IxEthAccStatus ixEthAccTxSchedulingDisciplineSetPriv(IxEthAccPortId portId, | |
1390 | IxEthAccSchedulerDiscipline | |
1391 | sched) | |
1392 | { | |
1393 | if (!IX_ETH_ACC_IS_PORT_VALID(portId)) | |
1394 | { | |
1395 | return (IX_ETH_ACC_INVALID_PORT); | |
1396 | } | |
1397 | ||
1398 | if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) | |
1399 | { | |
1400 | IX_ETH_ACC_WARNING_LOG("ixEthAccTxSchedulingDisciplineSet: Unavailable Eth %d: Cannot set Tx Scheduling Discipline.\n",(INT32)portId,0,0,0,0,0); | |
1401 | return IX_ETH_ACC_SUCCESS ; | |
1402 | } | |
1403 | ||
1404 | if (!IX_ETH_IS_PORT_INITIALIZED(portId)) | |
1405 | { | |
1406 | return (IX_ETH_ACC_PORT_UNINITIALIZED); | |
1407 | } | |
1408 | ||
1409 | if (sched != FIFO_PRIORITY && sched != FIFO_NO_PRIORITY) | |
1410 | { | |
1411 | return (IX_ETH_ACC_INVALID_ARG); | |
1412 | } | |
1413 | ||
1414 | ixEthAccPortData[portId].ixEthAccTxData.schDiscipline = sched; | |
1415 | return (IX_ETH_ACC_SUCCESS); | |
1416 | } | |
1417 | ||
1418 | IX_ETH_ACC_PUBLIC | |
1419 | IxEthAccStatus ixEthAccRxSchedulingDisciplineSetPriv(IxEthAccSchedulerDiscipline | |
1420 | sched) | |
1421 | { | |
1422 | if (sched != FIFO_PRIORITY && sched != FIFO_NO_PRIORITY) | |
1423 | { | |
1424 | return (IX_ETH_ACC_INVALID_ARG); | |
1425 | } | |
1426 | ||
1427 | ixEthAccDataInfo.schDiscipline = sched; | |
1428 | ||
1429 | return (IX_ETH_ACC_SUCCESS); | |
1430 | } | |
1431 | ||
1432 | ||
1433 | /** | |
1434 | * @fn ixEthRxFrameProcess(IxEthAccPortId portId, IX_OSAL_MBUF *mbufPtr) | |
1435 | * | |
1436 | * @brief process incoming frame : | |
1437 | * | |
1438 | * @param @ref IxQMgrCallback IxQMgrMultiBufferCallback | |
1439 | * | |
1440 | * @return none | |
1441 | * | |
1442 | * @internal | |
1443 | * | |
1444 | */ | |
1445 | IX_ETH_ACC_PRIVATE BOOL | |
1446 | ixEthRxFrameProcess(IxEthAccPortId portId, IX_OSAL_MBUF *mbufPtr) | |
1447 | { | |
1448 | UINT32 flags; | |
1449 | IxEthDBStatus result; | |
1450 | ||
1451 | #ifndef NDEBUG | |
1452 | /* Prudent to at least check the port is within range */ | |
1453 | if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS) | |
1454 | { | |
1455 | ixEthAccDataStats.unexpectedError++; | |
1456 | IX_ETH_ACC_FATAL_LOG( | |
1457 | "ixEthRxFrameProcess: Illegal port: %u\n", | |
1458 | (UINT32)portId, 0, 0, 0, 0, 0); | |
1459 | return FALSE; | |
1460 | } | |
1461 | #endif | |
1462 | ||
1463 | /* convert fields from mbuf header */ | |
1464 | ixEthAccMbufFromRxQ(mbufPtr); | |
1465 | ||
1466 | /* check about any special processing for this frame */ | |
1467 | flags = IX_ETHACC_NE_FLAGS(mbufPtr); | |
1468 | if ((flags & (IX_ETHACC_NE_FILTERMASK | IX_ETHACC_NE_NEWSRCMASK)) == 0) | |
1469 | { | |
1470 | /* "best case" scenario : nothing special to do for this frame */ | |
1471 | return TRUE; | |
1472 | } | |
1473 | ||
1474 | #ifdef CONFIG_IXP425_COMPONENT_ETHDB | |
1475 | /* if a new source MAC address is detected by the NPE, | |
1476 | * update IxEthDB with the portId and the MAC address. | |
1477 | */ | |
1478 | if ((flags & IX_ETHACC_NE_NEWSRCMASK & ixEthAccNewSrcMask) != 0) | |
1479 | { | |
1480 | result = ixEthDBFilteringDynamicEntryProvision(portId, | |
1481 | (IxEthDBMacAddr *) IX_ETHACC_NE_SOURCEMAC(mbufPtr)); | |
1482 | ||
1483 | if (result != IX_ETH_DB_SUCCESS && result != IX_ETH_DB_FEATURE_UNAVAILABLE) | |
1484 | { | |
1485 | if ((ixEthAccMacState[portId].portDisableState == ACTIVE) && (result != IX_ETH_DB_BUSY)) | |
1486 | { | |
1487 | RX_STATS_INC(portId, rxUnexpectedError); | |
1488 | IX_ETH_ACC_FATAL_LOG("ixEthRxFrameProcess: Failed to add source MAC \ | |
1489 | to the Learning/Filtering database\n", 0, 0, 0, 0, 0, 0); | |
1490 | } | |
1491 | else | |
1492 | { | |
1493 | /* we expect this to fail during PortDisable, as EthDB is disabled for | |
1494 | * that port and will refuse to learn new addresses | |
1495 | */ | |
1496 | } | |
1497 | } | |
1498 | else | |
1499 | { | |
1500 | RX_STATS_INC(portId, rxUnlearnedMacAddress); | |
1501 | } | |
1502 | } | |
1503 | #endif | |
1504 | ||
1505 | /* check if this frame should have been filtered | |
1506 | * by the NPE and take the appropriate action | |
1507 | */ | |
1508 | if (((flags & IX_ETHACC_NE_FILTERMASK) != 0) | |
1509 | && (ixEthAccMacState[portId].portDisableState == ACTIVE)) | |
1510 | { | |
1511 | /* If the mbuf was allocated with a small data size, or the current data pointer is not | |
1512 | * within the allocated data area, then the buffer is non-standard and has to be | |
1513 | * replenished with the minimum size only | |
1514 | */ | |
1515 | if( (IX_OSAL_MBUF_ALLOCATED_BUFF_LEN(mbufPtr) < IX_ETHNPE_ACC_RXFREE_BUFFER_LENGTH_MIN) | |
1516 | || ((UINT8 *)IX_OSAL_MBUF_ALLOCATED_BUFF_DATA(mbufPtr) > IX_OSAL_MBUF_MDATA(mbufPtr)) | |
1517 | || ((UINT8 *)(IX_OSAL_MBUF_ALLOCATED_BUFF_DATA(mbufPtr) + | |
1518 | IX_OSAL_MBUF_ALLOCATED_BUFF_LEN(mbufPtr)) | |
1519 | < IX_OSAL_MBUF_MDATA(mbufPtr)) ) | |
1520 | { | |
1521 | /* set to minimum length */ | |
1522 | IX_OSAL_MBUF_MLEN(mbufPtr) = IX_OSAL_MBUF_PKT_LEN(mbufPtr) = | |
1523 | IX_ETHNPE_ACC_RXFREE_BUFFER_LENGTH_MIN; | |
1524 | } | |
1525 | else | |
1526 | { | |
1527 | /* restore original length */ | |
1528 | IX_OSAL_MBUF_MLEN(mbufPtr) = IX_OSAL_MBUF_PKT_LEN(mbufPtr) = | |
1529 | ( IX_OSAL_MBUF_ALLOCATED_BUFF_LEN(mbufPtr) - | |
1530 | (IX_OSAL_MBUF_MDATA(mbufPtr) - (UINT8 *)IX_OSAL_MBUF_ALLOCATED_BUFF_DATA(mbufPtr)) ); | |
1531 | } | |
1532 | ||
1533 | /* replenish from here */ | |
1534 | if (ixEthAccPortRxFreeReplenish(portId, mbufPtr) != IX_ETH_ACC_SUCCESS) | |
1535 | { | |
1536 | IX_ETH_ACC_FATAL_LOG("ixEthRxFrameProcess: Failed to replenish with filtered frame\ | |
1537 | on port %d\n", portId, 0, 0, 0, 0, 0); | |
1538 | } | |
1539 | ||
1540 | RX_STATS_INC(portId, rxFiltered); | |
1541 | ||
1542 | /* indicate that frame should not be subjected to further processing */ | |
1543 | return FALSE; | |
1544 | } | |
1545 | ||
1546 | return TRUE; | |
1547 | } | |
1548 | ||
1549 | ||
1550 | /** | |
1551 | * @fn ixEthRxFrameQMCallback | |
1552 | * | |
1553 | * @brief receive callback for Frame receive Q from NPE | |
1554 | * | |
1555 | * Frames are passed one-at-a-time to the user | |
1556 | * | |
1557 | * @param @ref IxQMgrCallback | |
1558 | * | |
1559 | * @return none | |
1560 | * | |
1561 | * @internal | |
1562 | * | |
1563 | * Design note : while processing the entry X, entry X+1 is preloaded | |
1564 | * into memory to reduce the number of stall cycles | |
1565 | * | |
1566 | */ | |
1567 | void ixEthRxFrameQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId) | |
1568 | { | |
1569 | IX_OSAL_MBUF *mbufPtr; | |
1570 | IX_OSAL_MBUF *nextMbufPtr; | |
1571 | UINT32 qEntry; | |
1572 | UINT32 nextQEntry; | |
1573 | UINT32 *qEntryPtr; | |
1574 | UINT32 portId; | |
1575 | UINT32 destPortId; | |
1576 | UINT32 npeId; | |
1577 | UINT32 rxQReadStatus; | |
1578 | ||
1579 | /* | |
1580 | * Design note : entries are read in a buffer, This buffer contains | |
1581 | * an extra zeroed entry so the loop will | |
1582 | * always terminate on a null entry, whatever the result of Burst read is. | |
1583 | */ | |
1584 | UINT32 rxQEntry[IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK + 1]; | |
1585 | ||
1586 | /* | |
1587 | * Indication of the number of times the callback is used. | |
1588 | */ | |
1589 | IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackCounter); | |
1590 | ||
1591 | do | |
1592 | { | |
1593 | /* | |
1594 | * Indication of the number of times the queue is drained | |
1595 | */ | |
1596 | IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackBurstRead); | |
1597 | ||
1598 | /* ensure the last entry of the array contains a zeroed value */ | |
1599 | qEntryPtr = rxQEntry; | |
1600 | qEntryPtr[IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK] = 0; | |
1601 | ||
1602 | rxQReadStatus = ixQMgrQBurstRead(qId, | |
1603 | IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK, | |
1604 | qEntryPtr); | |
1605 | ||
1606 | #ifndef NDEBUG | |
1607 | if ((rxQReadStatus != IX_QMGR_Q_UNDERFLOW) | |
1608 | && (rxQReadStatus != IX_SUCCESS)) | |
1609 | { | |
1610 | ixEthAccDataStats.unexpectedError++; | |
1611 | /*major error*/ | |
1612 | IX_ETH_ACC_FATAL_LOG( | |
1613 | "ixEthRxFrameQMCallback:Error: %u\n", | |
1614 | (UINT32)rxQReadStatus, 0, 0, 0, 0, 0); | |
1615 | return; | |
1616 | } | |
1617 | #endif | |
1618 | ||
1619 | /* convert and preload the next entry | |
1620 | * (the conversion function takes care about null pointers which | |
1621 | * are used to mark the end of the loop) | |
1622 | */ | |
1623 | nextQEntry = *qEntryPtr; | |
1624 | nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry, | |
1625 | IX_ETHNPE_QM_Q_RXENET_ADDR_MASK); | |
1626 | ||
1627 | while(nextQEntry != 0) | |
1628 | { | |
1629 | /* get the next entry */ | |
1630 | qEntry = nextQEntry; | |
1631 | mbufPtr = nextMbufPtr; | |
1632 | ||
1633 | #ifndef NDEBUG | |
1634 | if (mbufPtr == NULL) | |
1635 | { | |
1636 | ixEthAccDataStats.unexpectedError++; | |
1637 | IX_ETH_ACC_FATAL_LOG( | |
1638 | "ixEthRxFrameQMCallback: Null Mbuf Ptr\n", | |
1639 | 0, 0, 0, 0, 0, 0); | |
1640 | return; | |
1641 | } | |
1642 | #endif | |
1643 | ||
1644 | /* convert the next entry | |
1645 | * (the conversion function takes care about null pointers which | |
1646 | * are used to mark the end of the loop) | |
1647 | */ | |
1648 | nextQEntry = *(++qEntryPtr); | |
1649 | nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry, | |
1650 | IX_ETHNPE_QM_Q_RXENET_ADDR_MASK); | |
1651 | ||
1652 | /* | |
1653 | * Get Port and Npe ID from message. | |
1654 | */ | |
1655 | npeId = ((IX_ETHNPE_QM_Q_RXENET_NPEID_MASK & | |
1656 | qEntry) >> IX_ETHNPE_QM_Q_FIELD_NPEID_R); | |
1657 | portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId); | |
1658 | ||
1659 | /* process frame, check the return code and skip the remaining of | |
1660 | * the loop if the frame is to be filtered out | |
1661 | */ | |
1662 | if (ixEthRxFrameProcess(portId, mbufPtr)) | |
1663 | { | |
1664 | /* destination portId for this packet */ | |
1665 | destPortId = IX_ETHACC_NE_DESTPORTID(mbufPtr); | |
1666 | ||
1667 | if (destPortId != IX_ETH_DB_UNKNOWN_PORT) | |
1668 | { | |
1669 | destPortId = IX_ETH_DB_NPE_LOGICAL_ID_TO_PORT_ID(destPortId); | |
1670 | } | |
1671 | ||
1672 | /* test if QoS is enabled in ethAcc | |
1673 | */ | |
1674 | if (ixEthAccDataInfo.schDiscipline == FIFO_PRIORITY) | |
1675 | { | |
1676 | /* check if there is a higher priority queue | |
1677 | * which may require processing and then process it. | |
1678 | */ | |
1679 | if (ixEthAccDataInfo.higherPriorityQueue[qId] < IX_QMGR_MAX_NUM_QUEUES) | |
1680 | { | |
1681 | ixEthRxFrameQMCallback(ixEthAccDataInfo.higherPriorityQueue[qId], | |
1682 | callbackId); | |
1683 | } | |
1684 | } | |
1685 | ||
1686 | /* | |
1687 | * increment priority stats | |
1688 | */ | |
1689 | RX_STATS_INC(portId,rxPriority[IX_ETHACC_NE_QOS(mbufPtr)]); | |
1690 | ||
1691 | /* | |
1692 | * increment callback count stats | |
1693 | */ | |
1694 | RX_STATS_INC(portId,rxFrameClientCallback); | |
1695 | ||
1696 | /* | |
1697 | * Call user level callback. | |
1698 | */ | |
1699 | ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn( | |
1700 | ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag, | |
1701 | mbufPtr, | |
1702 | destPortId); | |
1703 | } | |
1704 | } | |
1705 | } while (rxQReadStatus == IX_SUCCESS); | |
1706 | } | |
1707 | ||
1708 | /** | |
1709 | * @fn ixEthRxMultiBufferQMCallback | |
1710 | * | |
1711 | * @brief receive callback for Frame receive Q from NPE | |
1712 | * | |
1713 | * Frames are passed as an array to the user | |
1714 | * | |
1715 | * @param @ref IxQMgrCallback | |
1716 | * | |
1717 | * @return none | |
1718 | * | |
1719 | * @internal | |
1720 | * | |
1721 | * Design note : while processing the entry X, entry X+1 is preloaded | |
1722 | * into memory to reduce the number of stall cycles | |
1723 | * | |
1724 | */ | |
1725 | void ixEthRxMultiBufferQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId) | |
1726 | { | |
1727 | IX_OSAL_MBUF *mbufPtr; | |
1728 | IX_OSAL_MBUF *nextMbufPtr; | |
1729 | UINT32 qEntry; | |
1730 | UINT32 nextQEntry; | |
1731 | UINT32 *qEntryPtr; | |
1732 | UINT32 portId; | |
1733 | UINT32 npeId; | |
1734 | UINT32 rxQReadStatus; | |
1735 | /* | |
1736 | * Design note : entries are read in a static buffer, This buffer contains | |
1737 | * an extra zeroed entry so the loop will | |
1738 | * always terminate on a null entry, whatever the result of Burst read is. | |
1739 | */ | |
1740 | static UINT32 rxQEntry[IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK + 1]; | |
1741 | static IX_OSAL_MBUF *rxMbufPortArray[IX_ETH_ACC_NUMBER_OF_PORTS][IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK + 1]; | |
1742 | IX_OSAL_MBUF **rxMbufPtr[IX_ETH_ACC_NUMBER_OF_PORTS]; | |
1743 | ||
1744 | for (portId = 0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++) | |
1745 | { | |
1746 | rxMbufPtr[portId] = rxMbufPortArray[portId]; | |
1747 | } | |
1748 | ||
1749 | /* | |
1750 | * Indication of the number of times the callback is used. | |
1751 | */ | |
1752 | IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackCounter); | |
1753 | ||
1754 | do | |
1755 | { | |
1756 | /* | |
1757 | * Indication of the number of times the queue is drained | |
1758 | */ | |
1759 | IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackBurstRead); | |
1760 | ||
1761 | /* ensure the last entry of the array contains a zeroed value */ | |
1762 | qEntryPtr = rxQEntry; | |
1763 | qEntryPtr[IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK] = 0; | |
1764 | ||
1765 | rxQReadStatus = ixQMgrQBurstRead(qId, | |
1766 | IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK, | |
1767 | qEntryPtr); | |
1768 | ||
1769 | #ifndef NDEBUG | |
1770 | if ((rxQReadStatus != IX_QMGR_Q_UNDERFLOW) | |
1771 | && (rxQReadStatus != IX_SUCCESS)) | |
1772 | { | |
1773 | ixEthAccDataStats.unexpectedError++; | |
1774 | /*major error*/ | |
1775 | IX_ETH_ACC_FATAL_LOG( | |
1776 | "ixEthRxFrameMultiBufferQMCallback:Error: %u\n", | |
1777 | (UINT32)rxQReadStatus, 0, 0, 0, 0, 0); | |
1778 | return; | |
1779 | } | |
1780 | #endif | |
1781 | ||
1782 | /* convert and preload the next entry | |
1783 | * (the conversion function takes care about null pointers which | |
1784 | * are used to mark the end of the loop) | |
1785 | */ | |
1786 | nextQEntry = *qEntryPtr; | |
1787 | nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry, | |
1788 | IX_ETHNPE_QM_Q_RXENET_ADDR_MASK); | |
1789 | ||
1790 | while(nextQEntry != 0) | |
1791 | { | |
1792 | /* get the next entry */ | |
1793 | qEntry = nextQEntry; | |
1794 | mbufPtr = nextMbufPtr; | |
1795 | ||
1796 | #ifndef NDEBUG | |
1797 | if (mbufPtr == NULL) | |
1798 | { | |
1799 | ixEthAccDataStats.unexpectedError++; | |
1800 | IX_ETH_ACC_FATAL_LOG( | |
1801 | "ixEthRxFrameMultiBufferQMCallback:Error: Null Mbuf Ptr\n", | |
1802 | 0, 0, 0, 0, 0, 0); | |
1803 | return; | |
1804 | } | |
1805 | #endif | |
1806 | ||
1807 | /* convert the next entry | |
1808 | * (the conversion function takes care about null pointers which | |
1809 | * are used to mark the end of the loop) | |
1810 | */ | |
1811 | nextQEntry = *(++qEntryPtr); | |
1812 | nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry, | |
1813 | IX_ETHNPE_QM_Q_RXENET_ADDR_MASK); | |
1814 | ||
1815 | /* | |
1816 | * Get Port and Npe ID from message. | |
1817 | */ | |
1818 | npeId = ((IX_ETHNPE_QM_Q_RXENET_NPEID_MASK & | |
1819 | qEntry) >> | |
1820 | IX_ETHNPE_QM_Q_FIELD_NPEID_R); | |
1821 | portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId); | |
1822 | ||
1823 | /* skip the remaining of the loop if the frame is | |
1824 | * to be filtered out | |
1825 | */ | |
1826 | if (ixEthRxFrameProcess(portId, mbufPtr)) | |
1827 | { | |
1828 | /* store a mbuf pointer in an array */ | |
1829 | *rxMbufPtr[portId]++ = mbufPtr; | |
1830 | ||
1831 | /* | |
1832 | * increment priority stats | |
1833 | */ | |
1834 | RX_STATS_INC(portId,rxPriority[IX_ETHACC_NE_QOS(mbufPtr)]); | |
1835 | } | |
1836 | ||
1837 | /* test for QoS enabled in ethAcc */ | |
1838 | if (ixEthAccDataInfo.schDiscipline == FIFO_PRIORITY) | |
1839 | { | |
1840 | /* check if there is a higher priority queue | |
1841 | * which may require processing and then process it. | |
1842 | */ | |
1843 | if (ixEthAccDataInfo.higherPriorityQueue[qId] < IX_QMGR_MAX_NUM_QUEUES) | |
1844 | { | |
1845 | ixEthRxMultiBufferQMCallback(ixEthAccDataInfo.higherPriorityQueue[qId], | |
1846 | callbackId); | |
1847 | } | |
1848 | } | |
1849 | } | |
1850 | ||
1851 | /* check if any of the the arrays contains any entry */ | |
1852 | for (portId = 0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++) | |
1853 | { | |
1854 | if (rxMbufPtr[portId] != rxMbufPortArray[portId]) | |
1855 | { | |
1856 | /* add a last NULL pointer at the end of the | |
1857 | * array of mbuf pointers | |
1858 | */ | |
1859 | *rxMbufPtr[portId] = NULL; | |
1860 | ||
1861 | /* | |
1862 | * increment callback count stats | |
1863 | */ | |
1864 | RX_STATS_INC(portId,rxFrameClientCallback); | |
1865 | ||
1866 | /* | |
1867 | * Call user level callback with an array of | |
1868 | * buffers (NULL terminated) | |
1869 | */ | |
1870 | ixEthAccPortData[portId].ixEthAccRxData. | |
1871 | rxMultiBufferCallbackFn( | |
1872 | ixEthAccPortData[portId].ixEthAccRxData. | |
1873 | rxMultiBufferCallbackTag, | |
1874 | rxMbufPortArray[portId]); | |
1875 | ||
1876 | /* reset the buffer pointer to the beginning of | |
1877 | * the array | |
1878 | */ | |
1879 | rxMbufPtr[portId] = rxMbufPortArray[portId]; | |
1880 | } | |
1881 | } | |
1882 | ||
1883 | } while (rxQReadStatus == IX_SUCCESS); | |
1884 | } | |
1885 | ||
1886 | ||
1887 | /** | |
1888 | * @brief rxFree low event handler | |
1889 | * | |
1890 | */ | |
1891 | void ixEthRxFreeQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId) | |
1892 | { | |
1893 | IxEthAccPortId portId = (IxEthAccPortId) callbackId; | |
1894 | int lockVal; | |
1895 | UINT32 maxQWritesToPerform = IX_ETH_ACC_MAX_RX_FREE_BUFFERS_LOAD; | |
1896 | IX_STATUS qStatus = IX_SUCCESS; | |
1897 | ||
1898 | /* | |
1899 | * We have reached a low threshold on one of the Rx Free Qs | |
1900 | */ | |
1901 | ||
1902 | /*note that due to the fact that we are working off an Empty threshold, this callback | |
1903 | need only write a single entry to the Rx Free queue in order to re-arm the notification | |
1904 | */ | |
1905 | ||
1906 | RX_STATS_INC(portId,rxFreeLowCallback); | |
1907 | ||
1908 | /* | |
1909 | * Get buffers from approprite S/W Rx freeBufferList Q. | |
1910 | */ | |
1911 | ||
1912 | #ifndef NDEBUG | |
1913 | if (!IX_ETH_ACC_IS_PORT_VALID(portId)) | |
1914 | { | |
1915 | ixEthAccDataStats.unexpectedError++; | |
1916 | IX_ETH_ACC_FATAL_LOG( | |
1917 | "ixEthRxFreeQMCallback:Error: Invalid Port 0x%08X\n", | |
1918 | portId, 0, 0, 0, 0, 0); | |
1919 | return; | |
1920 | } | |
1921 | #endif | |
1922 | IX_ETH_ACC_DATA_PLANE_LOCK(lockVal); | |
1923 | if (IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId]. | |
1924 | ixEthAccRxData.freeBufferList)) | |
1925 | { | |
1926 | /* | |
1927 | * Turn off Q callback notification for Q in Question. | |
1928 | */ | |
1929 | qStatus = ixQMgrNotificationDisable( | |
1930 | IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId)); | |
1931 | ||
1932 | ||
1933 | IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal); | |
1934 | ||
1935 | if (qStatus != IX_SUCCESS) | |
1936 | { | |
1937 | RX_INC(portId,rxUnexpectedError); | |
1938 | IX_ETH_ACC_FATAL_LOG( | |
1939 | "ixEthRxFreeQMCallback:Error: unexpected QM status 0x%08X\n", | |
1940 | qStatus, 0, 0, 0, 0, 0); | |
1941 | return; | |
1942 | } | |
1943 | } | |
1944 | else | |
1945 | { | |
1946 | IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal); | |
1947 | /* | |
1948 | * Load the H/W Q with buffers from the s/w Q. | |
1949 | */ | |
1950 | ||
1951 | do | |
1952 | { | |
1953 | /* | |
1954 | * Consume Q entries. - Note Q contains Physical addresss, | |
1955 | * and have already been flushed to memory, | |
1956 | * And endianess converted if required. | |
1957 | */ | |
1958 | if (ixEthAccRxFreeFromSwQ(portId) != IX_SUCCESS) | |
1959 | { | |
1960 | /* | |
1961 | * No more entries in s/w Q. | |
1962 | * Turn off Q callback indication | |
1963 | */ | |
1964 | ||
1965 | IX_ETH_ACC_DATA_PLANE_LOCK(lockVal); | |
1966 | if (IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId]. | |
1967 | ixEthAccRxData.freeBufferList)) | |
1968 | { | |
1969 | qStatus = ixQMgrNotificationDisable( | |
1970 | IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId)); | |
1971 | } | |
1972 | IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal); | |
1973 | break; | |
1974 | } | |
1975 | } | |
1976 | while (--maxQWritesToPerform); | |
1977 | } | |
1978 | } | |
1979 | /** | |
1980 | * @fn Tx queue low event handler | |
1981 | * | |
1982 | */ | |
1983 | void | |
1984 | ixEthTxFrameQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId) | |
1985 | { | |
1986 | IxEthAccPortId portId = (IxEthAccPortId) callbackId; | |
1987 | int lockVal; | |
1988 | UINT32 maxQWritesToPerform = IX_ETH_ACC_MAX_TX_FRAME_TX_CONSUME_PER_CALLBACK; | |
1989 | IX_STATUS qStatus = IX_SUCCESS; | |
1990 | IxEthAccTxPriority highestPriority; | |
1991 | ||
1992 | ||
1993 | /* | |
1994 | * We have reached a low threshold on the Tx Q, and are being asked to | |
1995 | * supply a buffer for transmission from our S/W TX queues | |
1996 | */ | |
1997 | TX_STATS_INC(portId,txLowThreshCallback); | |
1998 | ||
1999 | /* | |
2000 | * Get buffers from approprite Q. | |
2001 | */ | |
2002 | ||
2003 | #ifndef NDEBUG | |
2004 | if (!IX_ETH_ACC_IS_PORT_VALID(portId)) | |
2005 | { | |
2006 | ixEthAccDataStats.unexpectedError++; | |
2007 | IX_ETH_ACC_FATAL_LOG( | |
2008 | "ixEthTxFrameQMCallback:Error: Invalid Port 0x%08X\n", | |
2009 | portId, 0, 0, 0, 0, 0); | |
2010 | return; | |
2011 | } | |
2012 | #endif | |
2013 | ||
2014 | do | |
2015 | { | |
2016 | /* | |
2017 | * Consume Q entries. - Note Q contains Physical addresss, | |
2018 | * and have already been flushed to memory, | |
2019 | * and endianess already sone if required. | |
2020 | */ | |
2021 | ||
2022 | IX_ETH_ACC_DATA_PLANE_LOCK(lockVal); | |
2023 | ||
2024 | if(ixEthAccTxSwQHighestPriorityGet(portId, &highestPriority) == | |
2025 | IX_ETH_ACC_FAIL) | |
2026 | { | |
2027 | /* | |
2028 | * No more entries in s/w Q. | |
2029 | * Turn off Q callback indication | |
2030 | */ | |
2031 | qStatus = ixQMgrNotificationDisable( | |
2032 | IX_ETH_ACC_PORT_TO_TX_Q_ID(portId)); | |
2033 | ||
2034 | IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal); | |
2035 | ||
2036 | if (qStatus != IX_SUCCESS) | |
2037 | { | |
2038 | ixEthAccDataStats.unexpectedError++; | |
2039 | IX_ETH_ACC_FATAL_LOG( | |
2040 | "ixEthTxFrameQMCallback:Error: unexpected QM status 0x%08X\n", | |
2041 | qStatus, 0, 0, 0, 0, 0); | |
2042 | } | |
2043 | ||
2044 | return; | |
2045 | } | |
2046 | else | |
2047 | { | |
2048 | IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal); | |
2049 | if (ixEthAccTxFromSwQ(portId,highestPriority)!=IX_SUCCESS) | |
2050 | { | |
2051 | /* nothing left in the sw queue or the hw queues are | |
2052 | * full. There is no point to continue to drain the | |
2053 | * sw queues | |
2054 | */ | |
2055 | return; | |
2056 | } | |
2057 | } | |
2058 | } | |
2059 | while (--maxQWritesToPerform); | |
2060 | } | |
2061 | ||
2062 | /** | |
2063 | * @brief TxDone event handler | |
2064 | * | |
2065 | * Design note : while processing the entry X, entry X+1 is preloaded | |
2066 | * into memory to reduce the number of stall cycles | |
2067 | * | |
2068 | */ | |
2069 | ||
2070 | void | |
2071 | ixEthTxFrameDoneQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId) | |
2072 | { | |
2073 | IX_OSAL_MBUF *mbufPtr; | |
2074 | UINT32 qEntry; | |
2075 | UINT32 *qEntryPtr; | |
2076 | UINT32 txDoneQReadStatus; | |
2077 | UINT32 portId; | |
2078 | UINT32 npeId; | |
2079 | ||
2080 | /* | |
2081 | * Design note : entries are read in a static buffer, This buffer contains | |
2082 | * an extra entyry (which is zeroed by the compiler), so the loop will | |
2083 | * always terminate on a null entry, whatever the result of Burst read is. | |
2084 | */ | |
2085 | static UINT32 txDoneQEntry[IX_ETH_ACC_MAX_TX_FRAME_DONE_CONSUME_PER_CALLBACK + 1]; | |
2086 | ||
2087 | /* | |
2088 | * Indication that Tx frames have been transmitted from the NPE. | |
2089 | */ | |
2090 | ||
2091 | IX_ETH_ACC_STATS_INC(ixEthAccDataStats.txDoneCallbackCounter); | |
2092 | ||
2093 | do{ | |
2094 | qEntryPtr = txDoneQEntry; | |
2095 | txDoneQReadStatus = ixQMgrQBurstRead(IX_ETH_ACC_TX_FRAME_DONE_ETH_Q, | |
2096 | IX_ETH_ACC_MAX_TX_FRAME_DONE_CONSUME_PER_CALLBACK, | |
2097 | qEntryPtr); | |
2098 | ||
2099 | #ifndef NDEBUG | |
2100 | if (txDoneQReadStatus != IX_QMGR_Q_UNDERFLOW | |
2101 | && (txDoneQReadStatus != IX_SUCCESS)) | |
2102 | { | |
2103 | /*major error*/ | |
2104 | ixEthAccDataStats.unexpectedError++; | |
2105 | IX_ETH_ACC_FATAL_LOG( | |
2106 | "ixEthTxFrameDoneQMCallback:Error: %u\n", | |
2107 | (UINT32)txDoneQReadStatus, 0, 0, 0, 0, 0); | |
2108 | return; | |
2109 | } | |
2110 | #endif | |
2111 | ||
2112 | qEntry = *qEntryPtr; | |
2113 | ||
2114 | while(qEntry != 0) | |
2115 | { | |
2116 | mbufPtr = ixEthAccEntryFromQConvert(qEntry, | |
2117 | IX_ETHNPE_QM_Q_TXENET_ADDR_MASK); | |
2118 | ||
2119 | #ifndef NDEBUG | |
2120 | if (mbufPtr == NULL) | |
2121 | { | |
2122 | ixEthAccDataStats.unexpectedError++; | |
2123 | IX_ETH_ACC_FATAL_LOG( | |
2124 | "ixEthTxFrameDoneQMCallback:Error: Null Mbuf Ptr\n", | |
2125 | 0, 0, 0, 0, 0, 0); | |
2126 | return; | |
2127 | } | |
2128 | #endif | |
2129 | ||
2130 | /* endianness conversions and stats updates */ | |
2131 | ixEthAccMbufFromTxQ(mbufPtr); | |
2132 | ||
2133 | /* | |
2134 | * Get NPE id from message, then convert to portId. | |
2135 | */ | |
2136 | npeId = ((IX_ETHNPE_QM_Q_TXENETDONE_NPEID_MASK & | |
2137 | qEntry) >> | |
2138 | IX_ETHNPE_QM_Q_FIELD_NPEID_R); | |
2139 | portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId); | |
2140 | ||
2141 | #ifndef NDEBUG | |
2142 | /* Prudent to at least check the port is within range */ | |
2143 | if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS) | |
2144 | { | |
2145 | ixEthAccDataStats.unexpectedError++; | |
2146 | IX_ETH_ACC_FATAL_LOG( | |
2147 | "ixEthTxFrameDoneQMCallback: Illegal port: %u\n", | |
2148 | (UINT32)portId, 0, 0, 0, 0, 0); | |
2149 | return; | |
2150 | } | |
2151 | #endif | |
2152 | ||
2153 | TX_STATS_INC(portId,txDoneClientCallback); | |
2154 | ||
2155 | /* | |
2156 | * Call user level callback. | |
2157 | */ | |
2158 | ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn( | |
2159 | ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag, | |
2160 | mbufPtr); | |
2161 | ||
2162 | /* move to next queue entry */ | |
2163 | qEntry = *(++qEntryPtr); | |
2164 | ||
2165 | } | |
2166 | } while( txDoneQReadStatus == IX_SUCCESS ); | |
2167 | } | |
2168 | ||
2169 | IX_ETH_ACC_PUBLIC | |
2170 | void ixEthAccDataPlaneShow(void) | |
2171 | { | |
2172 | UINT32 numTx0Entries; | |
2173 | UINT32 numTx1Entries; | |
2174 | UINT32 numTxDoneEntries; | |
2175 | UINT32 numRxEntries; | |
2176 | UINT32 numRxFree0Entries; | |
2177 | UINT32 numRxFree1Entries; | |
2178 | UINT32 portId; | |
2179 | #ifdef __ixp46X | |
2180 | UINT32 numTx2Entries; | |
2181 | UINT32 numRxFree2Entries; | |
2182 | #endif | |
2183 | #ifndef NDEBUG | |
2184 | UINT32 priority; | |
2185 | UINT32 numBuffersInRx=0; | |
2186 | UINT32 numBuffersInTx=0; | |
2187 | UINT32 numBuffersInSwQ=0; | |
2188 | UINT32 totalBuffers=0; | |
2189 | UINT32 rxFreeCallbackCounter = 0; | |
2190 | UINT32 txCallbackCounter = 0; | |
2191 | #endif | |
2192 | UINT32 key; | |
2193 | ||
2194 | /* snapshot of stats */ | |
2195 | IxEthAccTxDataStats tx[IX_ETH_ACC_NUMBER_OF_PORTS]; | |
2196 | IxEthAccRxDataStats rx[IX_ETH_ACC_NUMBER_OF_PORTS]; | |
2197 | IxEthAccDataPlaneStats stats; | |
2198 | ||
2199 | if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED()) | |
2200 | { | |
2201 | return; | |
2202 | } | |
2203 | ||
2204 | /* get a reliable snapshot */ | |
2205 | key = ixOsalIrqLock(); | |
2206 | ||
2207 | numTx0Entries = 0; | |
2208 | ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET0_Q, &numTx0Entries); | |
2209 | numTx1Entries = 0; | |
2210 | ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET1_Q, &numTx1Entries); | |
2211 | numTxDoneEntries = 0; | |
2212 | ixQMgrQNumEntriesGet( IX_ETH_ACC_TX_FRAME_DONE_ETH_Q, &numTxDoneEntries); | |
2213 | numRxEntries = 0; | |
2214 | ixEthAccQMgrRxQEntryGet(&numRxEntries); | |
2215 | numRxFree0Entries = 0; | |
2216 | ixQMgrQNumEntriesGet(IX_ETH_ACC_RX_FREE_BUFF_ENET0_Q, &numRxFree0Entries); | |
2217 | numRxFree1Entries = 0; | |
2218 | ixQMgrQNumEntriesGet(IX_ETH_ACC_RX_FREE_BUFF_ENET1_Q, &numRxFree1Entries); | |
2219 | ||
2220 | #ifdef __ixp46X | |
2221 | numTx2Entries = 0; | |
2222 | ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET2_Q, &numTx2Entries); | |
2223 | numRxFree2Entries = 0; | |
2224 | ixQMgrQNumEntriesGet(IX_ETH_ACC_RX_FREE_BUFF_ENET2_Q, &numRxFree2Entries); | |
2225 | #endif | |
2226 | ||
2227 | for(portId=IX_ETH_PORT_1; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++) | |
2228 | { | |
2229 | memcpy(&tx[portId], | |
2230 | &ixEthAccPortData[portId].ixEthAccTxData.stats, | |
2231 | sizeof(tx[portId])); | |
2232 | memcpy(&rx[portId], | |
2233 | &ixEthAccPortData[portId].ixEthAccRxData.stats, | |
2234 | sizeof(rx[portId])); | |
2235 | } | |
2236 | memcpy(&stats, &ixEthAccDataStats, sizeof(stats)); | |
2237 | ||
2238 | ixOsalIrqUnlock(key); | |
2239 | ||
2240 | #ifdef NDEBUG | |
2241 | printf("Detailed statistics collection not supported in this load\n"); | |
2242 | #endif | |
2243 | ||
2244 | /* print snapshot */ | |
2245 | for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++) | |
2246 | { | |
2247 | /* If not IXP42X A0 stepping, proceed to check for existence of coprocessors */ | |
2248 | if ((IX_FEATURE_CTRL_SILICON_TYPE_A0 != | |
2249 | (ixFeatureCtrlProductIdRead() & IX_FEATURE_CTRL_SILICON_STEPPING_MASK)) | |
2250 | || (IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X != ixFeatureCtrlDeviceRead ())) | |
2251 | { | |
2252 | if ((IX_ETH_PORT_1 == portId) && | |
2253 | (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH0) == | |
2254 | IX_FEATURE_CTRL_COMPONENT_DISABLED)) | |
2255 | { | |
2256 | continue ; | |
2257 | } | |
2258 | if ((IX_ETH_PORT_2 == portId) && | |
2259 | (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) == | |
2260 | IX_FEATURE_CTRL_COMPONENT_DISABLED)) | |
2261 | { | |
2262 | continue ; | |
2263 | } | |
2264 | if ((IX_ETH_PORT_3 == portId) && | |
2265 | (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_NPEA_ETH) == | |
2266 | IX_FEATURE_CTRL_COMPONENT_DISABLED)) | |
2267 | { | |
2268 | continue ; | |
2269 | } | |
2270 | } | |
2271 | ||
2272 | printf("PORT %u --------------------------------\n", | |
2273 | portId); | |
2274 | #ifndef NDEBUG | |
2275 | printf("Tx Done Frames : %u\n", | |
2276 | tx[portId].txDoneClientCallback + | |
2277 | tx[portId].txDoneSwQDuringDisable + | |
2278 | tx[portId].txDoneDuringDisable); | |
2279 | printf("Tx Frames : %u\n", | |
2280 | tx[portId].txQOK + tx[portId].txQDelayed); | |
2281 | printf("Tx H/W Q Added OK : %u\n", | |
2282 | tx[portId].txQOK); | |
2283 | printf("Tx H/W Q Delayed : %u\n", | |
2284 | tx[portId].txQDelayed); | |
2285 | printf("Tx From S/W Q Added OK : %u\n", | |
2286 | tx[portId].txFromSwQOK); | |
2287 | printf("Tx From S/W Q Delayed : %u\n", | |
2288 | tx[portId].txFromSwQDelayed); | |
2289 | printf("Tx Overflow : %u\n", | |
2290 | tx[portId].txOverflow); | |
2291 | printf("Tx Mutual Lock : %u\n", | |
2292 | tx[portId].txLock); | |
2293 | printf("Tx Late Ntf Enabled : %u\n", | |
2294 | tx[portId].txLateNotificationEnabled); | |
2295 | printf("Tx Low Thresh CB : %u\n", | |
2296 | tx[portId].txLowThreshCallback); | |
2297 | printf("Tx Done from H/W Q (Disable) : %u\n", | |
2298 | tx[portId].txDoneDuringDisable); | |
2299 | printf("Tx Done from S/W Q (Disable) : %u\n", | |
2300 | tx[portId].txDoneSwQDuringDisable); | |
2301 | for (priority = IX_ETH_ACC_TX_PRIORITY_0; | |
2302 | priority <= IX_ETH_ACC_TX_PRIORITY_7; | |
2303 | priority++) | |
2304 | { | |
2305 | if (tx[portId].txPriority[priority]) | |
2306 | { | |
2307 | printf("Tx Priority %u : %u\n", | |
2308 | priority, | |
2309 | tx[portId].txPriority[priority]); | |
2310 | } | |
2311 | } | |
2312 | #endif | |
2313 | printf("Tx unexpected errors : %u (should be 0)\n", | |
2314 | tx[portId].txUnexpectedError); | |
2315 | ||
2316 | #ifndef NDEBUG | |
2317 | printf("Rx Frames : %u\n", | |
2318 | rx[portId].rxFrameClientCallback + | |
2319 | rx[portId].rxSwQDuringDisable+ | |
2320 | rx[portId].rxDuringDisable); | |
2321 | printf("Rx Free Replenish : %u\n", | |
2322 | rx[portId].rxFreeRepOK + rx[portId].rxFreeRepDelayed); | |
2323 | printf("Rx Free H/W Q Added OK : %u\n", | |
2324 | rx[portId].rxFreeRepOK); | |
2325 | printf("Rx Free H/W Q Delayed : %u\n", | |
2326 | rx[portId].rxFreeRepDelayed); | |
2327 | printf("Rx Free From S/W Q Added OK : %u\n", | |
2328 | rx[portId].rxFreeRepFromSwQOK); | |
2329 | printf("Rx Free From S/W Q Delayed : %u\n", | |
2330 | rx[portId].rxFreeRepFromSwQDelayed); | |
2331 | printf("Rx Free Overflow : %u\n", | |
2332 | rx[portId].rxFreeOverflow); | |
2333 | printf("Rx Free Mutual Lock : %u\n", | |
2334 | rx[portId].rxFreeLock); | |
2335 | printf("Rx Free Late Ntf Enabled : %u\n", | |
2336 | rx[portId].rxFreeLateNotificationEnabled); | |
2337 | printf("Rx Free Low CB : %u\n", | |
2338 | rx[portId].rxFreeLowCallback); | |
2339 | printf("Rx From H/W Q (Disable) : %u\n", | |
2340 | rx[portId].rxDuringDisable); | |
2341 | printf("Rx From S/W Q (Disable) : %u\n", | |
2342 | rx[portId].rxSwQDuringDisable); | |
2343 | printf("Rx unlearned Mac Address : %u\n", | |
2344 | rx[portId].rxUnlearnedMacAddress); | |
2345 | printf("Rx Filtered (Rx => RxFree) : %u\n", | |
2346 | rx[portId].rxFiltered); | |
2347 | ||
2348 | for (priority = IX_ETH_ACC_TX_PRIORITY_0; | |
2349 | priority <= IX_ETH_ACC_TX_PRIORITY_7; | |
2350 | priority++) | |
2351 | { | |
2352 | if (rx[portId].rxPriority[priority]) | |
2353 | { | |
2354 | printf("Rx Priority %u : %u\n", | |
2355 | priority, | |
2356 | rx[portId].rxPriority[priority]); | |
2357 | } | |
2358 | } | |
2359 | #endif | |
2360 | printf("Rx unexpected errors : %u (should be 0)\n", | |
2361 | rx[portId].rxUnexpectedError); | |
2362 | ||
2363 | #ifndef NDEBUG | |
2364 | numBuffersInTx = tx[portId].txQOK + | |
2365 | tx[portId].txQDelayed - | |
2366 | tx[portId].txDoneClientCallback - | |
2367 | tx[portId].txDoneSwQDuringDisable - | |
2368 | tx[portId].txDoneDuringDisable; | |
2369 | ||
2370 | printf("# Tx Buffers currently for transmission : %u\n", | |
2371 | numBuffersInTx); | |
2372 | ||
2373 | numBuffersInRx = rx[portId].rxFreeRepOK + | |
2374 | rx[portId].rxFreeRepDelayed - | |
2375 | rx[portId].rxFrameClientCallback - | |
2376 | rx[portId].rxSwQDuringDisable - | |
2377 | rx[portId].rxDuringDisable; | |
2378 | ||
2379 | printf("# Rx Buffers currently for reception : %u\n", | |
2380 | numBuffersInRx); | |
2381 | ||
2382 | totalBuffers += numBuffersInRx + numBuffersInTx; | |
2383 | #endif | |
2384 | } | |
2385 | ||
2386 | printf("---------------------------------------\n"); | |
2387 | ||
2388 | #ifndef NDEBUG | |
2389 | printf("\n"); | |
2390 | printf("Mbufs :\n"); | |
2391 | printf("Tx Unchained mbufs : %u\n", | |
2392 | stats.unchainedTxMBufs); | |
2393 | printf("Tx Chained bufs : %u\n", | |
2394 | stats.chainedTxMBufs); | |
2395 | printf("TxDone Unchained mbufs : %u\n", | |
2396 | stats.unchainedTxDoneMBufs); | |
2397 | printf("TxDone Chained bufs : %u\n", | |
2398 | stats.chainedTxDoneMBufs); | |
2399 | printf("RxFree Unchained mbufs : %u\n", | |
2400 | stats.unchainedRxFreeMBufs); | |
2401 | printf("RxFree Chained bufs : %u\n", | |
2402 | stats.chainedRxFreeMBufs); | |
2403 | printf("Rx Unchained mbufs : %u\n", | |
2404 | stats.unchainedRxMBufs); | |
2405 | printf("Rx Chained bufs : %u\n", | |
2406 | stats.chainedRxMBufs); | |
2407 | ||
2408 | printf("\n"); | |
2409 | printf("Software queue usage :\n"); | |
2410 | printf("Buffers added to S/W Q : %u\n", | |
2411 | stats.addToSwQ); | |
2412 | printf("Buffers removed from S/W Q : %u\n", | |
2413 | stats.removeFromSwQ); | |
2414 | ||
2415 | printf("\n"); | |
2416 | printf("Hardware queues callbacks :\n"); | |
2417 | ||
2418 | for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++) | |
2419 | { | |
2420 | rxFreeCallbackCounter += rx[portId].rxFreeLowCallback; | |
2421 | txCallbackCounter += tx[portId].txLowThreshCallback; | |
2422 | } | |
2423 | printf("Tx Done QM Callback invoked : %u\n", | |
2424 | stats.txDoneCallbackCounter); | |
2425 | printf("Tx QM Callback invoked : %u\n", | |
2426 | txCallbackCounter); | |
2427 | printf("Rx QM Callback invoked : %u\n", | |
2428 | stats.rxCallbackCounter); | |
2429 | printf("Rx QM Callback burst read : %u\n", | |
2430 | stats.rxCallbackBurstRead); | |
2431 | printf("Rx Free QM Callback invoked : %u\n", | |
2432 | rxFreeCallbackCounter); | |
2433 | #endif | |
2434 | printf("Unexpected errors in CB : %u (should be 0)\n", | |
2435 | stats.unexpectedError); | |
2436 | printf("\n"); | |
2437 | ||
2438 | printf("Hardware queues levels :\n"); | |
2439 | printf("Transmit Port 1 Q : %u \n",numTx0Entries); | |
2440 | printf("Transmit Port 2 Q : %u \n",numTx1Entries); | |
2441 | #ifdef __ixp46X | |
2442 | printf("Transmit Port 3 Q : %u \n",numTx2Entries); | |
2443 | #endif | |
2444 | printf("Transmit Done Q : %u \n",numTxDoneEntries); | |
2445 | printf("Receive Q : %u \n",numRxEntries); | |
2446 | printf("Receive Free Port 1 Q : %u \n",numRxFree0Entries); | |
2447 | printf("Receive Free Port 2 Q : %u \n",numRxFree1Entries); | |
2448 | #ifdef __ixp46X | |
2449 | printf("Receive Free Port 3 Q : %u \n",numRxFree2Entries); | |
2450 | #endif | |
2451 | ||
2452 | #ifndef NDEBUG | |
2453 | printf("\n"); | |
2454 | printf("# Total Buffers accounted for : %u\n", | |
2455 | totalBuffers); | |
2456 | ||
2457 | numBuffersInSwQ = ixEthAccDataStats.addToSwQ - | |
2458 | ixEthAccDataStats.removeFromSwQ; | |
2459 | ||
2460 | printf(" Buffers in S/W Qs : %u\n", | |
2461 | numBuffersInSwQ); | |
2462 | printf(" Buffers in H/W Qs or NPEs : %u\n", | |
2463 | totalBuffers - numBuffersInSwQ); | |
2464 | #endif | |
2465 | ||
2466 | printf("Rx QoS Discipline : %s\n", | |
2467 | (ixEthAccDataInfo.schDiscipline == | |
2468 | FIFO_PRIORITY ) ? "Enabled" : "Disabled"); | |
2469 | ||
2470 | for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++) | |
2471 | { | |
2472 | printf("Tx QoS Discipline port %u : %s\n", | |
2473 | portId, | |
2474 | (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline == | |
2475 | FIFO_PRIORITY ) ? "Enabled" : "Disabled"); | |
2476 | } | |
2477 | printf("\n"); | |
2478 | } | |
2479 | ||
2480 | ||
2481 | ||
2482 | ||
2483 |