[processor-sdk/pdk.git] / packages / ti / drv / icss_emac / firmware / icss_dualemac / src / emac_MII_Rcv.asm
1 ;
2 ; TEXAS INSTRUMENTS TEXT FILE LICENSE
3 ;
4 ; Copyright (c) 2017-2019 Texas Instruments Incorporated
5 ;
6 ; All rights reserved not granted herein.
7 ;
8 ; Limited License.
9 ;
10 ; Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive
11 ; license under copyrights and patents it now or hereafter owns or controls to
12 ; make, have made, use, import, offer to sell and sell ("Utilize") this software
13 ; subject to the terms herein. With respect to the foregoing patent license,
14 ; such license is granted solely to the extent that any such patent is necessary
15 ; to Utilize the software alone. The patent license shall not apply to any
16 ; combinations which include this software, other than combinations with devices
17 ; manufactured by or for TI (“TI Devices”). No hardware patent is licensed hereunder.
18 ;
19 ; Redistributions must preserve existing copyright notices and reproduce this license
20 ; (including the above copyright notice and the disclaimer and (if applicable) source
21 ; code license limitations below) in the documentation and/or other materials provided
22 ; with the distribution.
23 ;
24 ; Redistribution and use in binary form, without modification, are permitted provided
25 ; that the following conditions are met:
26 ; No reverse engineering, decompilation, or disassembly of this software is
27 ; permitted with respect to any software provided in binary form.
28 ; Any redistribution and use are licensed by TI for use only with TI Devices.
29 ; Nothing shall obligate TI to provide you with source code for the software
30 ; licensed and provided to you in object code.
31 ;
32 ; If software source code is provided to you, modification and redistribution of the
33 ; source code are permitted provided that the following conditions are met:
34 ; Any redistribution and use of the source code, including any resulting derivative
35 ; works, are licensed by TI for use only with TI Devices.
36 ; Any redistribution and use of any object code compiled from the source code
37 ; and any resulting derivative works, are licensed by TI for use only with TI Devices.
38 ;
39 ; Neither the name of Texas Instruments Incorporated nor the names of its suppliers
40 ; may be used to endorse or promote products derived from this software without
41 ; specific prior written permission.
42 ;
43 ; DISCLAIMER.
44 ;
45 ; THIS SOFTWARE IS PROVIDED BY TI AND TI’S LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED
46 ; WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
47 ; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TI AND TI’S
48 ; LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49 ; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
50 ; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
51 ; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52 ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
53 ; EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 ;
55 ; file: emac_MII_Rcv.asm
56 ;
57 ; brief: Receive Task
58 ;
59 ;
60 ; (C) Copyright 2017-2019, Texas Instruments, Inc
61 ;
62 ;
64 .if !$defined("__mii_rcv_p")
65 __mii_rcv_p .set 1
67 ;;///////////////////////////////////////////////////////
68 ; Includes Section
69 ;;///////////////////////////////////////////////////////
70 .include "emac_MII_Rcv.h"
71 .include "icss_macros.h"
72 ; .include "icss_regs.h"
73 .if $defined("ICSS_SWITCH_BUILD")
74 .include "icss_switch_macros.h"
76 .if $defined("ICSS_STP_SWITCH")
77 .include "icss_stp_switch_macros.h"
78 .cdecls C,NOLIST
79 %{
80 #include "icss_stp_switch.h"
81 %}
82 .endif ; ICSS_STP_SWITCH
84 .endif
85 .include "micro_scheduler.h"
86 .include "emac_MII_Xmt.h"
87 .include "icss_miirt_regs.h"
89 .if $defined(PTP)
90 .include "icss_ptp.h"
91 .include "icss_ptp_macro.h"
92 .cdecls C,NOLIST
93 %{
94 #include "icss_timeSync_memory_map.h"
95 %}
96 .endif ;PTP
98 .global FN_RCV_FB
99 .global FN_RCV_NB
100 .global FN_RCV_LB
101 .global XMT_QUEUE
102 .global TASK_EXECUTION_FINISHED
103 .global FN_TIMESTAMP_GPTP_PACKET
104 .global FN_CHECK_AND_CLR_PTP_FWD_FLAG
105 .global FN_CHECK_AND_CLR_PTP_FWD_FLAG_L2
106 .global FN_COMPARE_DELAY_RESP_ID
109 ;****************************************************************************
110 ;
111 ; NAME : FN_RCV_FB
112 ; DESCRIPTION : receives the first block of data from new frame (out of RX L2)
113 ; RETURNS :
114 ; ARGS :
115 ; USES :
116 ; INVOKES :
117 ;
118 ;****************************************************************************
119 FN_RCV_FB:
120 ; Data is already present in the registers. So, no need to read it again.
122 ZERO &MII_RCV, $sizeof(MII_RCV) ; init MII_RCV parameter
123 ; OPT: Possible to make them both context next to each other
124 .if $defined("TWO_PORT_CFG")
125 ZERO &MII_RCV_PORT, $sizeof(MII_RCV_PORT) ; init MII_RCV parameter (R14....R17)
126 .endif
127 ; Check if RX port is enabled (information provided by host)
128 LDI R10.w0 , PORT_CONTROL_ADDR
129 LBCO &R10, PRU_DMEM_ADDR, R10.w0, 10 ; 4 + 6 bytes of Interface MAC Addr
131 ; OPT: Port can be disabled directly in the MII Hardware
132 ; Is port enabled?
133 QBBC EXIT_FB, R10, 0
135 .if $defined("ICSS_STP_SWITCH")
136 CHECK_STP_DISABLE:
137 ; Prepare STP State register address
138 .if $defined("PRU0")
139 ; Read Port 1 STP state
140 LDI32 RCV_TEMP_REG_3, ICSS_EMAC_FW_FDB__STP_P1_STP_STATE_ADDR
141 .else
142 ; Read Port 2 STP state
143 LDI32 RCV_TEMP_REG_3, ICSS_EMAC_FW_FDB__STP_P2_STP_STATE_ADDR
144 .endif ; $defined("PRU0")
145 LBBO &RCV_TEMP_REG_1.b0, RCV_TEMP_REG_3, 0, 1 ; read state from memory
146 AND STP_STATE__R22_BYTE, STP_STATE__R22_BYTE, STP_STATE__R22_INV_MASK ; clear relevant bits in R22
147 OR STP_STATE__R22_BYTE, STP_STATE__R22_BYTE, RCV_TEMP_REG_1.b0 ; set the relevant bits in R22
149 ; If Port disabled, disable directly in MII Hardware
150 AND RCV_TEMP_REG_1.b0, STP_STATE__R22_BYTE, STP_STATE__R22_MASK ; read STP state in R22
151 QBEQ EXIT_FB, RCV_TEMP_REG_1.b0, STP_STATE_DISABLED
153 ; If STP state is invalid, log error statistics and drop packet
154 QBGE CONTINUE_PROCESSING, RCV_TEMP_REG_1.b0, STP_STATE_BLOCKING
155 LDI RCV_TEMP_REG_3 , STP_INVALID_STATE_OFFSET ; else drop frame and increase the stats
156 QBA COUNT_RX_STATS
157 .endif ; ICSS_STP_SWITCH
159 CONTINUE_PROCESSING:
160 .if $defined("ICSS_STP_SWITCH")
161 .if $defined("ICSS_SWITCH_BUILD")
162 ; We are in a valid STP state, thus there is a chance packets get to the host
163 ; By default, both of these flags should be cleared
164 CLR R22, R22, FDB_LOOKUP_SUCCESS__R22_BIT
165 CLR R22, R22, PKT_FLOODED__R22_BIT
166 .endif
167 .endif ; ICSS_STP_SWITCH
169 ; set Rcv_active flag to indicate an ongoing reception
170 SET R23 , R23 , Rcv_active
172 ;*********************************Check for Errors*****************************************
173 ;******************************************************************************************
174 .if $defined("ICSS_DUAL_EMAC_BUILD")
175 ;check for SFD Errors
176 .if $defined("HALF_DUPLEX_ENABLED")
177 ; below code not needed for Full Duple
178 .if $defined("PRU0")
179 LBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1 ;read the PRUSS_MII_RT_RX_ERR0 register
180 QBBC CHECK_FOR_SHORT_SFD, RCV_TEMP_REG_3, 1 ; check for any error if not then jump else continue
181 ;clear error and writeback
182 SET RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 1
183 SBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1
184 QBA COUNT_SFD_ERROR
185 CHECK_FOR_SHORT_SFD:
186 QBBC CONTINUE_PROCESSING_PKT, RCV_TEMP_REG_3, 0 ; check for any error if not then jump else continue
187 ;clear error and writeback
188 SET RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 0
189 SBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1
190 QBA COUNT_SFD_ERROR
191 .else
192 LBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1 ;read the PRUSS_MII_RT_RX_ERR0 register
193 QBBC CHECK_FOR_SHORT_SFD, RCV_TEMP_REG_3, 1 ; check for any error if not then jump else continue
194 ;clear error and writeback
195 SET RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 1
196 SBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1
197 QBA COUNT_SFD_ERROR
198 CHECK_FOR_SHORT_SFD:
199 QBBC CONTINUE_PROCESSING_PKT, RCV_TEMP_REG_3, 0 ; check for any error if not then jump else continue
200 ;clear error and writeback
201 SET RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 0
202 SBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1
203 QBA COUNT_SFD_ERROR
204 .endif
206 ;check R31 bit 19 for error
207 QBBC CONTINUE_PROCESSING_PKT, R31, 19
208 ;clear the error
209 M_CMD16 D_RX_ERROR_CLEAR
211 ;set error flag
212 LDI RCV_TEMP_REG_3 , RX_ERROR_OFFSET
213 QBA COUNT_RX_STATS
214 ; Check if SA matches with Slave's Interface MAC addr
215 .endif ;HALF_DUPLEX_ENABLED
216 .endif ;ICSS_DUAL_EMAC_BUILD
217 CONTINUE_PROCESSING_PKT:
219 .if $defined("ICSS_STP_SWITCH")
220 CHECK_STP_DISCARDING:
221 ; Listening and Blocking states all resolve to the same action:
222 ; .. only allow BPDU frames to pass. Aka DISCARDING in RSTP.
224 ; STP State for current port is stored in R22
225 AND RCV_TEMP_REG_1.b0, STP_STATE__R22_BYTE, STP_STATE__R22_MASK ; read STP state in R22
226 QBEQ STP_DISCARD, RCV_TEMP_REG_1.b0, STP_STATE_BLOCKING
227 QBEQ STP_DISCARD, RCV_TEMP_REG_1.b0, STP_STATE_LISTENING
229 ; Not discarding, continue processing
230 QBA CHECK_RSVD_ADDR
232 STP_DISCARD:
233 ; Only allow BPDU packets
234 CHECK_MC_BPDU:
235 ; Check Multicast BPDU Address (allow all 01:80:c2:xx:xx:xx traffic)
236 LDI RCV_TEMP_REG_3.w0, 0x8001
237 QBNE CHECK_VLAN_BPDU, EthWord.DstWord_01, RCV_TEMP_REG_3.w0
238 LDI RCV_TEMP_REG_3.b0, 0xC2
239 MOV RCV_TEMP_REG_3.b2, EthByte.DstByte_2
240 QBNE CHECK_VLAN_BPDU, RCV_TEMP_REG_3.b0, RCV_TEMP_REG_3.b2
242 ; Address is Multicast BPDU
243 QBA CHECK_RSVD_ADDR
245 CHECK_VLAN_BPDU:
246 ; Check VLAN BPDU Address
247 LDI RCV_TEMP_REG_3.w0, 0x0001
248 LDI RCV_TEMP_REG_3.w2, 0xCC0C
249 QBNE DROP_PKT, Ethernet.DstAddr_0123, RCV_TEMP_REG_3
250 LDI RCV_TEMP_REG_3.w0, 0xCDCC
251 QBNE DROP_PKT, Ethernet.DstAddr_45, RCV_TEMP_REG_3.w0
253 CHECK_RSVD_ADDR:
254 ; Reserved addresses are 01:80:c2:00:00:00 - 01:80:c2:00:00:10
255 LDI RCV_TEMP_REG_3.w0, 0x8001
256 LDI RCV_TEMP_REG_3.w2, 0x00C2
257 QBNE CHECK_PKT_SOURCE, Ethernet.DstAddr_0123, RCV_TEMP_REG_3
258 MOV RCV_TEMP_REG_3.w2, Ethernet.DstAddr_45
259 QBNE CHECK_PKT_SOURCE, RCV_TEMP_REG_3.b2, 0x00
260 QBLT CHECK_PKT_SOURCE, RCV_TEMP_REG_3.b3, 0x10
262 ; Packets for reserved addresses are not to be forwarded
263 ; .. so set the local STP state to "Learning"
264 AND STP_STATE__R22_BYTE, STP_STATE__R22_BYTE, STP_STATE__R22_INV_MASK ; clr STP state in R22
265 OR STP_STATE__R22_BYTE, STP_STATE__R22_BYTE, STP_STATE_LEARNING
267 ; Address is VLAN BPDU, continue
268 .endif ; ICSS_STP_SWITCH
270 CHECK_PKT_SOURCE:
271 QBNE FB_SA_NO_MATCH_INTERFACE_MAC, Ethernet.SrcAddr_01, R11.w0 ;Check if Source Address matches with own address
272 QBNE FB_SA_NO_MATCH_INTERFACE_MAC, Ethernet.SrcAddr_23, R11.w2 ;Source Address is stored into 3 words (16 bits)
273 QBNE FB_SA_NO_MATCH_INTERFACE_MAC, Ethernet.SrcAddr_45, R12.w0
275 .if $defined("ICSS_STP_SWITCH")
276 DROP_PKT:
277 .endif ; ICSS_STP_SWITCH
278 LDI RCV_TEMP_REG_3 , RX_DROPPED_FRAMES_OFFSET ; else drop frame and increase the stats
279 QBA COUNT_RX_STATS
280 ;QBA EXIT_FB
281 .if $defined("HALF_DUPLEX_ENABLED")
282 COUNT_SFD_ERROR:
283 LDI RCV_TEMP_REG_3 , SFD_ERROR_OFFSET
284 .endif ;HALF_DUPLEX_ENABLED
286 COUNT_RX_STATS:
287 ;count statistics based on offset set in RCV_TEMP_REG_3
288 LBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
289 ADD RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1
290 SBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
291 EXIT_FB:
292 SET MII_RCV.rx_flags , MII_RCV.rx_flags , rx_frame_error_shift
293 QBA FB_DONE
295 FB_SA_NO_MATCH_INTERFACE_MAC:
296 .if $defined(PTP)
297 M_GPTP_CHECK_AND_SET_FLAGS
298 .endif ;PTP
299 ; optimize the program memory by loading the promiscuous mode offset
300 ; before jumping to multicast or broadcast packet check
301 ; this would save loading the same when needed to check to bypass
302 ; the storm prevention later when promiscuous mode is enabled
303 .if $defined("ICSS_DUAL_EMAC_BUILD")
304 LDI RCV_TEMP_REG_3.w0 , ICSS_EMAC_FIRMWARE_PROMISCUOUS_MODE_OFFSET
305 LBCO &RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_3.w0, 4
306 .endif
307 ; check for multi-cast
308 .if $defined("ICSS_STP_SWITCH")
309 QBBS SKIP_SELF_CHECK, EthByte.DstByte_0, 0 ; if packet is destined for multi/broadcast, skip the self-reference check and DST FDB lookup
310 .else
311 QBBS FB_MULTI_OR_BROADCAST, EthByte.DstByte_0, 0 ; check if packet is Multi/Broad cast type
312 .endif ; ICSS_STP_SWITCH
314 ;*********************************
315 ; uni-cast handling
316 ;*********************************
317 FB_UNICAST:
319 FB_UNICAST_SA_NO_MATCH:
320 .if $defined("ICSS_DUAL_EMAC_BUILD")
321 QBBS FB_PROMISCUOUS_MODE_ENABLE, RCV_TEMP_REG_2, ICSS_EMAC_PROMISCOUS_BIT
322 .endif
323 ; check if DA matches with our Interface MAC address
324 QBNE FB_UNICAST_DA_NO_MATCH, Ethernet.DstAddr_0123, R11 ;Check if Destination Address matches with own address
325 QBNE FB_UNICAST_DA_NO_MATCH, Ethernet.DstAddr_45, R12.w0
327 FB_PROMISCUOUS_MODE_ENABLE:
328 ; the frame DST address matches with our own address
329 SET MII_RCV.rx_flags , MII_RCV.rx_flags , host_rcv_flag_shift ; set flag that host queue will receive data
330 .if $defined("TWO_PORT_CFG")
331 .if !$defined("ICSS_STP_SWITCH") ; STP needs to do an FDB lookup
332 QBA FB_LT_VT
333 .endif
334 .else
335 QBA FB_UNICAST_CHECK_CT
336 .endif
338 FB_UNICAST_DA_NO_MATCH:
339 .if $defined("ICSS_STP_SWITCH")
340 ;; Linux needs to also check if the packet is destined for the other port MAC
341 LDI RCV_TEMP_REG_1.w0, PORT_MAC_ADDR ; Read from other port DMEM
342 LBCO &RCV_TEMP_REG_1, PRU_CROSS_DMEM, RCV_TEMP_REG_1.w0, 6 ; 6 bytes of MAC
344 ; check if DA matches with other port MAC address
345 QBNE FB_UNICAST_DA_NO_MATCH_OTHER_PORT, Ethernet.DstAddr_0123, RCV_TEMP_REG_1
346 QBNE FB_UNICAST_DA_NO_MATCH_OTHER_PORT, Ethernet.DstAddr_45, RCV_TEMP_REG_2.w0
348 ; the frame DST address matches with other port addr
349 SET MII_RCV.rx_flags , MII_RCV.rx_flags , host_rcv_flag_shift ; set flag that host queue will receive data
351 FB_UNICAST_DA_NO_MATCH_OTHER_PORT:
352 .endif
354 .if $defined("TWO_PORT_CFG")
356 .if $defined("ICSS_STP_SWITCH")
357 SKIP_SELF_CHECK:
358 FDB_LOCK:
359 ; Take the lock and check for timeout
360 LDI RCV_TEMP_REG_1.w0, 0x8F
361 M_SPIN_LOCK RCV_TEMP_REG_4.b2, RCV_TEMP_REG_1.w0
362 QBNE FDB_CHECK_DST, RCV_TEMP_REG_4.b2, 0 ; continue if no timeout
364 ; Flood/insert upon timeout
365 SET MII_RCV.rx_flags , MII_RCV.rx_flags , host_rcv_flag_shift
366 SET R22, R22, PKT_FLOODED__R22_BIT
367 QBA FDB_UNLOCK
369 FDB_CHECK_DST:
370 ; If the packet is multi/broadcast, then skip DST lookup
371 QBBS FDB_SRC_LOOKUP, EthByte.DstByte_0, 0
373 ; If the packet is not destined for the Host, continue with DST lookup
374 QBBC FDB_DST_LOOKUP, MII_RCV.rx_flags, host_rcv_flag_shift
376 ; Set the local STP state to "Learning" as a way to ensure we can check the
377 ; .. SRC address but not forward the packet. This will not affect the global
378 ; .. STP state.
379 AND STP_STATE__R22_BYTE, STP_STATE__R22_BYTE, STP_STATE__R22_INV_MASK ; clr STP state in R22
380 OR STP_STATE__R22_BYTE, STP_STATE__R22_BYTE, STP_STATE_LEARNING
382 QBA FDB_SRC_LOOKUP ; skip DST lookup
384 FDB_DST_LOOKUP:
385 ; Look up the destination in the FDB to determine if it needs to be flooded or directly forwarded
386 M_UNICAST_FDB_HASH_LOOKUP EthWord.DstWord_01, EthWord.DstWord_23, Ethernet.DstAddr_45, RCV_TEMP_REG_1.b2
388 ; Check lookup success
389 QBEQ FDB_DST_LOOKUP_SUCCESS, RCV_TEMP_REG_1.b2, 1
391 ; Not found in FDB, flood the packet
392 FLOOD_UNICAST_PACKET:
393 ; Unicast address not found in FDB, flood it by forwarding the packet
394 ; to the host as well as the other port
395 SET MII_RCV.rx_flags , MII_RCV.rx_flags , host_rcv_flag_shift
396 SET R22, R22, PKT_FLOODED__R22_BIT
397 QBA FDB_DST_LOOKUP_END
399 FDB_DST_LOOKUP_SUCCESS:
400 ; Check destination port is not current port
401 LBBO &RCV_TEMP_REG_1.b0, RCV_TEMP_REG_3, FDB_MAC_INFO__PORT_NO__OFFSET, FDB_MAC_INFO__PORT_NO__SIZE ; TEMP_REG_3 still has the table pointer from lookup
403 ; If the destination port is the current port, set the local STP state
404 ; .. to "Learning" so we don't forward the packet
405 .if $defined("PRU0")
406 QBNE FDB_DST_LOOKUP_END, RCV_TEMP_REG_1.b0, 0x0 ; Port 1
407 .else
408 QBNE FDB_DST_LOOKUP_END, RCV_TEMP_REG_1.b0, 0x1 ; Port 2
409 .endif
411 ; Set the local STP state to "Learning" as a way to ensure we can learn the
412 ; .. SRC address but not forward the packet. This will not affect the global
413 ; .. STP state.
414 AND STP_STATE__R22_BYTE, STP_STATE__R22_BYTE, STP_STATE__R22_INV_MASK ; clr STP state in R22
415 OR STP_STATE__R22_BYTE, STP_STATE__R22_BYTE, STP_STATE_LEARNING
417 FDB_DST_LOOKUP_END:
418 FDB_SRC_LOOKUP:
419 ; If the src addr is multi/broadcast, then skip the SRC lookup
420 QBBS FDB_SRC_LOOKUP_END, EthByte.SrcByte_0, 0
422 ; Now we must look up the source address in the FDB for learning purposes
423 M_UNICAST_FDB_HASH_LOOKUP Ethernet.SrcAddr_01, Ethernet.SrcAddr_23, Ethernet.SrcAddr_45, RCV_TEMP_REG_1.b3
425 ; Check lookup success
426 QBEQ FDB_SRC_LOOKUP_FAIL, RCV_TEMP_REG_1.b3, 0
428 FDB_SRC_LOOKUP_SUCCESS:
429 ; The source address was found in the FDB, alert the host and proceed to reset the ageing timer
430 SET R22, R22, FDB_LOOKUP_SUCCESS__R22_BIT
432 FDB_TOUCH_ENTRY:
433 ; Reset FDB entry age and update port number information
435 ; Reset ageing timer
436 LDI RCV_TEMP_REG_1.w0, 0x0000
438 ; Set port information
439 .if $defined("PRU0")
440 LDI RCV_TEMP_REG_1.b2, 0x0 ; Port 1
441 .else
442 LDI RCV_TEMP_REG_1.b2, 0x1 ; Port 2
443 .endif
445 SBBO &RCV_TEMP_REG_1, RCV_TEMP_REG_3, FDB_MAC_INFO__AGE__OFFSET, (FDB_MAC_INFO__AGE__SIZE + FDB_MAC_INFO__PORT_NO__SIZE) ; TEMP_REG_3 still has the table pointer from lookup
446 QBA FDB_SRC_LOOKUP_END
448 FDB_SRC_LOOKUP_FAIL:
449 ; The source MAC isn't found in the FDB, send to the host for insertion
450 SET MII_RCV.rx_flags , MII_RCV.rx_flags , host_rcv_flag_shift
452 FDB_SRC_LOOKUP_END:
453 FDB_UNLOCK:
454 ; Release the lock
455 M_SPIN_UNLOCK
457 ; If the packet is multi/broadcast, process it as such
458 QBBS FB_MULTI_OR_BROADCAST, EthByte.DstByte_0, 0
459 .endif ; ICSS_STP_SWITCH
460 ; Begin process of forwarding unicast packet, cut-through if possible
461 QBA FB_UNICAST_CHECK_CT
463 .else
464 LDI RCV_TEMP_REG_3 , RX_DROPPED_FRAMES_OFFSET
465 QBA COUNT_RX_STATS
466 .endif
467 ;*********************************
468 ; multicast/broadcast handling
469 ;*********************************
470 FB_MULTI_OR_BROADCAST:
471 FB_CONTINUE:
472 ; Check if destination is broadcast
473 FILL &RCV_TEMP_REG_1, 4 ; Fill with 0xffffffff
474 QBNE FB_MULTICAST, Ethernet.DstAddr_0123, RCV_TEMP_REG_1
475 QBNE FB_MULTICAST, Ethernet.DstAddr_45, RCV_TEMP_REG_1.w0
477 FB_BROADCAST:
478 SET R22 , R22 , RX_BC_FRAME ; set broad-cast bit to indicate the broadcast frame
479 SET MII_RCV.rx_flags , MII_RCV.rx_flags , host_rcv_flag_shift
480 QBA FB_BROADCAST_CHECK_CT
482 FB_MULTICAST:
483 SET MII_RCV.rx_flags , MII_RCV.rx_flags , host_rcv_flag_shift
484 SET R22 , R22 , RX_MC_FRAME ; set multi-cast bit to indicate the multicast frame
486 .if $defined("ICSS_DUAL_EMAC_BUILD") | $defined("ICSS_STP_SWITCH")
487 ; check if multicast filtering is enabled or not i.e. check MULTICAST_CONTROL_BIT in PRU1 data memory
488 LDI RCV_TEMP_REG_3.w0, ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET
489 LBCO &RCV_TEMP_REG_3.b0, PRU_DMEM_ADDR, RCV_TEMP_REG_3.w0, 1
490 QBEQ FB_MULTICAST_CONTINUE, RCV_TEMP_REG_3.b0, ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_DISABLED ; one byte field : 0 -> multicast filtering disabled | 1 -> multicast filtering enabled
492 ; search in multicast table to determine if host receive is to be enabled or not for the incoming multicast frame
493 M_MULTICAST_TABLE_SEARCH_OP
494 ; QBA FB_MULTICAST_CONTINUE
495 .endif
497 FB_MULTICAST_CONTINUE:
498 FB_UNICAST_CHECK_CT:
499 FB_BROADCAST_CHECK_CT:
500 .if $defined("ICSS_DUAL_EMAC_BUILD") | $defined("ICSS_STP_SWITCH")
501 ; check if VLAN filtering is enabled or not i.e. check VLAN_FLTR_CTRL_SHIFT in VLAN_FLTR_CTRL_BYTE stored in data memory
502 LDI RCV_TEMP_REG_3.w0, ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET
503 LBCO &RCV_TEMP_REG_3.b0, PRU_DMEM_ADDR, RCV_TEMP_REG_3.w0, 1
504 ;-----------------------------------------------------------
505 ; VLAN_FLTR_CTRL_BYTE | | | | R13 | RCV_TEMP_REG_3
506 ;-----------------------------------------------------------
507 QBBC FB_SKIP_VLAN_FLTR, RCV_TEMP_REG_3.b0, ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLE_BIT ; one bit field | 0 : VLAN filter disabled | 1 : VLAN filter enabled
509 ; search in VLAN table to determine if host receive is to be enabled or not for the incoming frame
510 M_VLAN_FLTR_SRCH_OP
512 FB_SKIP_VLAN_FLTR:
513 .endif
515 ; Storm Prevention
516 QBBC FB_STORM_NOT_MC, R22, RX_MC_FRAME
517 LDI RCV_TEMP_REG_3 , STORM_PREVENTION_OFFSET_MC
518 ;Do storm prevention here
519 LBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4 ; load the current storm prevent count
520 QBBC FB_CONT_CT_CHECK, RCV_TEMP_REG_2, 0
521 LSR RCV_TEMP_REG_2, RCV_TEMP_REG_2, 8
522 QBGT FB_DISCARD_MC, RCV_TEMP_REG_2.w0, 1 ; check if the counter is less than zero and discard packet
523 SUB RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1
524 LSL RCV_TEMP_REG_2, RCV_TEMP_REG_2, 8
525 SET RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 0
526 SBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
528 QBA FB_CONT_CT_CHECK
529 FB_STORM_NOT_MC:
530 QBBC FB_STORM_NOT_BC, R22, RX_BC_FRAME
531 LDI RCV_TEMP_REG_3 , STORM_PREVENTION_OFFSET_BC
532 ;Do storm prevention here
533 LBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4 ; load the current storm prevent count
534 QBBC FB_CONT_CT_CHECK, RCV_TEMP_REG_2, 0
535 LSR RCV_TEMP_REG_2, RCV_TEMP_REG_2, 8
536 QBGT FB_DISCARD_BC, RCV_TEMP_REG_2.w0, 1 ; check if the counter is less than zero and discard packet
537 SUB RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1
538 LSL RCV_TEMP_REG_2, RCV_TEMP_REG_2, 8
539 SET RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 0
540 SBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
542 QBA FB_CONT_CT_CHECK
543 FB_STORM_NOT_BC:
544 LDI RCV_TEMP_REG_3 , STORM_PREVENTION_OFFSET_UC
545 ;Do storm prevention here
546 LBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4 ; load the current storm prevent count
547 QBBC FB_CONT_CT_CHECK, RCV_TEMP_REG_2, 0
548 LSR RCV_TEMP_REG_2, RCV_TEMP_REG_2, 8
549 QBGT FB_DISCARD_UC, RCV_TEMP_REG_2.w0, 1 ; check if the counter is less than zero and discard packet
550 SUB RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1
551 LSL RCV_TEMP_REG_2, RCV_TEMP_REG_2, 8
552 SET RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 0
553 SBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
555 QBA FB_CONT_CT_CHECK
557 FB_DISCARD_MC:
558 LDI RCV_TEMP_REG_3 , STORM_PREVENTION_COUNTER_MC
559 QBA COUNT_RX_STATS
560 FB_DISCARD_BC:
561 LDI RCV_TEMP_REG_3 , STORM_PREVENTION_COUNTER_BC
562 QBA COUNT_RX_STATS
563 FB_DISCARD_UC:
564 LDI RCV_TEMP_REG_3 , STORM_PREVENTION_COUNTER_UC
565 QBA COUNT_RX_STATS
567 FB_CONT_CT_CHECK:
568 .if $defined("TWO_PORT_CFG")
570 .if $defined("ICSS_STP_SWITCH")
571 CHECK_STP_LEARNING:
572 ; Only forward packet if STP state is FORWARDING
573 AND RCV_TEMP_REG_1.b0, STP_STATE__R22_BYTE, STP_STATE__R22_MASK ; read STP state in R22
574 QBNE SKIP_FORWARDING, RCV_TEMP_REG_1.b0, STP_STATE_FORWARDING ; STP State for current port is stored in R22
576 ; Only forward packet if the OTHER port state is FORWARDING
577 .if $defined("PRU0")
578 ; Read Port 2 STP state
579 LDI32 RCV_TEMP_REG_3, ICSS_EMAC_FW_FDB__STP_P2_STP_STATE_ADDR
580 .else
581 ; Read Port 1 STP state
582 LDI32 RCV_TEMP_REG_3, ICSS_EMAC_FW_FDB__STP_P1_STP_STATE_ADDR
583 .endif ; $defined("PRU0")
584 LBBO &RCV_TEMP_REG_1.b0, RCV_TEMP_REG_3, 0, 1
586 QBNE SKIP_FORWARDING, RCV_TEMP_REG_1.b0, STP_STATE_FORWARDING
588 SET_FORWARDING:
589 .endif ; ICSS_STP_SWITCH
590 QBBS FB_NO_CT, R23, 0 ;Xmt_active ; check if we can set cut-through
591 QBBC FB_NO_CT, R22, 31 ;PACKET_TX_ALLOWED
592 QBA FB_CT_HANDLING
594 FB_NO_CT:
595 SET MII_RCV.rx_flags, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
596 JMP FB_LT_VT
597 FB_CT_HANDLING:
598 SET MII_RCV.tx_flags, MII_RCV.tx_flags, cut_through_flag_shift ;MII_RCV.tx_flags.cut_through_flag
600 .if $defined("ICSS_STP_SWITCH")
601 SKIP_FORWARDING:
602 .endif ; ICSS_STP_SWITCH
603 FB_LT_VT:
605 ;check link on other port
606 QBBS FB_EGRESS_LINK_UP, R22, 10 ;replaced: QBBS FB_EGRESS_LINK_UP, OPPOSITE_PORT_LINK_UP
608 ; OPT: See whether they can be moved next to each other
609 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, fwd_flag_shift
610 CLR MII_RCV.tx_flags, MII_RCV.tx_flags, cut_through_flag_shift
612 ;If host receive flag is not set then increment statistics for dropped frames
613 QBBS FB_EGRESS_LINK_UP, MII_RCV.rx_flags, host_rcv_flag_shift
614 LDI RCV_TEMP_REG_3, RX_DROPPED_FRAMES_OFFSET
615 CLR R22, R22, RX_BC_FRAME
616 CLR R22, R22, RX_MC_FRAME
617 LBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
618 ADD RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1
619 SBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
622 FB_EGRESS_LINK_UP:
624 QBBC FB_LT_VT_2, MII_RCV.tx_flags, cut_through_flag_shift
626 LDI CUT_THROUGH_BYTE_CNT, 0x0000
628 ; Insert first 12 bytes in the TX FIFO of opposit
629 .if $defined("ICSS_REV1")
630 LDI TX_DATA_WORD_MASK , 0xffff
631 AND TX_DATA_BYTE , BUFFER.b0 , BUFFER.b0
632 M_PUSH_BYTE
633 AND TX_DATA_BYTE , BUFFER.b1 , BUFFER.b1
634 M_PUSH_BYTE
636 ;MOV loop_cnt, 2
637 LDI TX_DATA_POINTER, buffer_ptr + 2
638 loop FB_RCV_EndLoop_1, 2
639 MVIW TX_DATA_WORD, *TX_DATA_POINTER
640 M_PUSH_WORD_CMD
641 ADD TX_DATA_POINTER, TX_DATA_POINTER, 2
642 FB_RCV_EndLoop_1:
643 .endif
644 .if $defined("ICSS_REV2")
645 LDI TX_DATA_POINTER, buffer_ptr
646 loop FB_RCV_EndLoop_1, 3
647 MVID TX_DATA_DOUBLE_WORD, *TX_DATA_POINTER
648 ADD TX_DATA_POINTER, TX_DATA_POINTER, 4
649 FB_RCV_EndLoop_1:
650 .endif
651 .endif ;TWO_PORT_CFG
652 FB_LT_VT_2: ; Quality of service --> select RX queue priority based on Ethernet frame tags
654 XIN RX_L2_BANK0_ID, &R18, RANGE_R18_b0 ; XIN RX L2 bank 0 R18 value
655 XIN RX_L2_BANK0_ID, &R2, RANGE_R2_R13 ; XIN RX L2 bank 0 R2 - R13 value
657 .if $defined(PTP)
658 M_GPTP_ASSIGN_QOS
659 .endif ;PTP
661 .if $defined("TWO_PORT_CFG")
662 ; The naming of the QoS queue goes from 1..4, but we need to count from 0..3
663 LDI MII_RCV.qos_queue, 4-1 ; default (lowest priority) queue is 4
665 FB_QOS_APPLY_RULES:
666 LDI RCV_TEMP_REG_1.w0, 0x0081 ; 0x8100 --> indicates QOS tagged frame
667 QBNE FB_QOS_DONE, Ethernet.TPID, RCV_TEMP_REG_1.w0
668 LSR RCV_TEMP_REG_1.b0, R5.b2, 5 ; extract PCP info. FIXME: clpru : Ethernet.TCI.b0 -> R5.b2
669 QBGT FB_QOS_CHECK_FOR_PRIO2, RCV_TEMP_REG_1.b0, 6 ; PCP == 7/6
670 LDI MII_RCV.qos_queue, 1-1 ; highest priority is 1, select queue 1
672 QBA FB_QOS_DONE
673 FB_QOS_CHECK_FOR_PRIO2:
674 QBGT FB_QOS_CHECK_FOR_PRIO3, RCV_TEMP_REG_1.b0, 4 ; PCP == 5/4
675 LDI MII_RCV.qos_queue, 2-1 ; priority is 2, select queue 2
676 QBA FB_QOS_DONE
677 FB_QOS_CHECK_FOR_PRIO3:
678 QBGT FB_QOS_DONE, RCV_TEMP_REG_1.b0, 2 ; PCP == 3/2
679 LDI MII_RCV.qos_queue, 3-1 ; priority is 3, select queue 3
680 QBA FB_QOS_DONE
681 ; if PCP == 1/0, this priority 4, default queue already selected
682 FB_QOS_LOADED:
683 FB_QOS_DONE:
684 FB_DONE:
685 .else
686 .if $defined("PRU0")
687 ; The naming of the QoS queue goes from 1..4, but we need to count from 0..3
688 LDI MII_RCV.qos_queue, 2-1 ; default (lowest priority) queue is 2 for PRU0
689 .else
690 LDI MII_RCV.qos_queue, 4-1 ; default (lowest priority) queue is 4 for PRU1
691 .endif
693 FB_QOS_APPLY_RULES:
694 LDI RCV_TEMP_REG_1.w0, 0x0081 ; 0x8100 --> indicates QOS tagged frame
695 QBNE FB_QOS_DONE, Ethernet.TPID, RCV_TEMP_REG_1.w0
696 LSR RCV_TEMP_REG_1.b0, Ethernet.TCI.x_b.b0, 5 ; extract PCP info
698 .if $defined("PRU0")
699 QBGT FB_QOS_DONE, RCV_TEMP_REG_1.b0, 4 ; PCP == 7/6
700 LDI MII_RCV.qos_queue, 1-1 ; highest priority is 1, select queue 1
701 .else
702 QBGT FB_QOS_DONE, RCV_TEMP_REG_1.b0, 4 ; PCP == 7/6
703 LDI MII_RCV.qos_queue, 3-1 ; highest priority is 3, select queue 3
704 .endif
705 QBA FB_QOS_DONE
707 ; if PCP == 1/0, this priority 4, default queue already selected
708 FB_QOS_LOADED:
709 FB_QOS_DONE:
710 FB_DONE:
711 .endif ;TWO_PORT_CFG
713 .if $defined("TWO_PORT_CFG")
714 ;Check if cut-through bit is set ..if yes then push 10 more bytes in Tx_fifo and remain in Rx_Task itself
715 ; OPT : Below bytes can be pushed early in the Profinet
716 QBBC FB_DONE_NORMAL, MII_RCV.tx_flags, cut_through_flag_shift ; is cut-through flag set?
717 ; We enter the task with 14 bytes but here we always have 16 bytes even for non HSR frames
718 .if $defined("ICSS_REV1")
719 loop FB_RCV_EndLoop_2, 5
720 MVIW TX_DATA_WORD, *TX_DATA_POINTER
721 M_PUSH_WORD_CMD
722 ADD TX_DATA_POINTER, TX_DATA_POINTER, 2
723 FB_RCV_EndLoop_2:
724 .endif
725 .if $defined("ICSS_REV2")
726 MVID TX_DATA_DOUBLE_WORD, *TX_DATA_POINTER
727 ADD TX_DATA_POINTER, TX_DATA_POINTER, 4
728 .endif
730 LDI PREVIOUS_R18_RCV_BYTECOUNT, 16
731 ADD CUT_THROUGH_BYTE_CNT, CUT_THROUGH_BYTE_CNT, 16
733 FB_DONE_NORMAL:
734 .endif
735 ; Fill the rcv context with host/port queue base pointer, rd_ptr and wrk_pointer
736 QBNE FB_CHECK_QUEUE_2, MII_RCV.qos_queue, 0
737 .if $defined("TWO_PORT_CFG")
738 LDI RX_CONTEXT_OFFSET, P0_Q1_RX_CONTEXT_OFFSET
740 .if $defined("PRU0")
741 LDI RX_PORT_CONTEXT_OFFSET, P2_Q1_RX_CONTEXT_OFFSET
742 .else
743 LDI RX_PORT_CONTEXT_OFFSET, P1_Q1_RX_CONTEXT_OFFSET
744 .endif
745 .else
746 LDI RX_CONTEXT_OFFSET , HOST_Q1_RX_CONTEXT_OFFSET ; Select queue based on QOS
747 .endif
748 QBA Initialize_rcv_context
750 ;end_buffer_desc_offset
751 FB_CHECK_QUEUE_2:
752 QBNE FB_CHECK_QUEUE_3, MII_RCV.qos_queue, 1
753 .if $defined("TWO_PORT_CFG")
754 LDI RX_CONTEXT_OFFSET, P0_Q2_RX_CONTEXT_OFFSET
755 .if $defined("PRU0")
756 LDI RX_PORT_CONTEXT_OFFSET, P2_Q2_RX_CONTEXT_OFFSET
757 .else
758 LDI RX_PORT_CONTEXT_OFFSET, P1_Q2_RX_CONTEXT_OFFSET
759 .endif
761 .else
762 LDI RX_CONTEXT_OFFSET , HOST_Q2_RX_CONTEXT_OFFSET ; Select queue based on QOS
763 .endif
764 QBA Initialize_rcv_context
766 FB_CHECK_QUEUE_3:
767 QBNE FB_CHECK_QUEUE_4, MII_RCV.qos_queue, 2
768 .if $defined("TWO_PORT_CFG")
770 LDI RX_CONTEXT_OFFSET, P0_Q3_RX_CONTEXT_OFFSET
772 .if $defined("PRU0")
773 LDI RX_PORT_CONTEXT_OFFSET, P2_Q3_RX_CONTEXT_OFFSET
774 .else
775 LDI RX_PORT_CONTEXT_OFFSET, P1_Q3_RX_CONTEXT_OFFSET
776 .endif
778 .else
779 LDI RX_CONTEXT_OFFSET , HOST_Q3_RX_CONTEXT_OFFSET ; Select queue based on QOS
780 .endif
781 QBA Initialize_rcv_context
783 FB_CHECK_QUEUE_4:
784 .if $defined("TWO_PORT_CFG")
786 LDI RX_CONTEXT_OFFSET, P0_Q4_RX_CONTEXT_OFFSET
787 .if $defined("PRU0")
788 LDI RX_PORT_CONTEXT_OFFSET, P2_Q4_RX_CONTEXT_OFFSET
789 .else
790 LDI RX_PORT_CONTEXT_OFFSET, P1_Q4_RX_CONTEXT_OFFSET
791 .endif
792 .else
793 LDI RX_CONTEXT_OFFSET , HOST_Q4_RX_CONTEXT_OFFSET ; Select queue based on QOS
794 .endif
796 Initialize_rcv_context:
797 QBBC FB_FILL_RCV_CONTEXT_PORT_QUEUE, MII_RCV.rx_flags, host_rcv_flag_shift
798 ; Read the RX Context of Host Port of 8 bytes
799 .if $defined("TWO_PORT_CFG")
800 LBCO &MII_RCV.base_buffer_index, PRU1_DMEM_CONST, RX_CONTEXT_OFFSET, 8
801 .else
802 LBCO &MII_RCV.base_buffer_index, ICSS_SHARED_CONST, RX_CONTEXT_OFFSET, 8
803 .endif
805 FB_FILL_RCV_CONTEXT_PORT_QUEUE:
806 .if $defined("TWO_PORT_CFG")
808 QBBC FB_PKT_NOT_FORWARDED, MII_RCV.rx_flags, fwd_flag_shift
809 ; Read the RX Context of Port of 8 bytes
810 LBCO &MII_RCV_PORT.base_buffer_index, PRU1_DMEM_CONST, RX_PORT_CONTEXT_OFFSET, 8
811 FB_PKT_NOT_FORWARDED:
812 .endif ;TWO_PORT_CFG
813 ; OPT: If R0.b0 is not changed then remove below instruction. it is to make sure at R0.b0 is 0
814 LDI R0.b0, SHIFT_NONE
815 .if $defined("PRU0")
816 XOUT BANK1, &MII_RCV, $sizeof(MII_RCV) ; store task parameters in parameter bank
817 .else
818 XOUT BANK2, &MII_RCV, $sizeof(MII_RCV) ; store task parameters in parameter bank
819 .endif
820 .if $defined("TWO_PORT_CFG")
821 .if $defined("PRU0")
822 LDI R0.b0, SHIFT_R14_TO_R0
823 XOUT BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT) ; store task parameters in parameter bank
824 .else
825 LDI R0.b0, SHIFT_R14_TO_R4
826 XOUT BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT) ; store task parameters in parameter bank
827 .endif
830 QBBS FN_RCV_NB, MII_RCV.tx_flags, cut_through_flag_shift
831 .endif ;TWO_PORT_CFG
833 .if $defined("ICSS_DUAL_EMAC_BUILD")
834 ;The following check is required in case of firmware lag
835 ;when the firmware runs late compared to RX L2 FIFO.
836 ;This was being experienced in Profinet Switch and the same is possible here.
837 ;Haven't been able to reproduce this in EMAC.
838 XIN RX_L2_BANK0_ID, &R18, RANGE_R18_b0
839 QBGT FB_RCV_EXIT, R18.b0, 32
840 LDI CURRENT_TASK_POINTER, TX_TASK_POINTER
841 JMP FN_RCV_NB
842 .endif
844 FB_RCV_EXIT:
845 JMP CALL_REG
848 ;****************************************************************************
849 ;
850 ; NAME : FN_RCV_NB
851 ; DESCRIPTION : receives the next 32Byte block of RX L2
852 ; RETURNS :
853 ; ARGS :
854 ; USES :
855 ; INVOKES :
856 ;
857 ;****************************************************************************
858 FN_RCV_NB:
860 ; for XIN, make sure that shift is set to 0
861 LDI R0.b0, SHIFT_NONE
862 ; restore task parameters in parameter bank
863 .if $defined("PRU0")
864 XIN BANK1, &MII_RCV, $sizeof(MII_RCV)
865 .else
866 XIN BANK2, &MII_RCV, $sizeof(MII_RCV)
867 .endif
868 .if $defined("TWO_PORT_CFG")
869 ;parameters for Port Receive
870 ; OPT: Move it after the XIN of data
871 .if $defined("PRU0")
872 LDI R0.b0, SHIFT_R14_TO_R0
873 XIN BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT)
874 .else
875 LDI R0.b0, SHIFT_R14_TO_R4
876 XIN BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT)
877 .endif
878 .endif
879 ; this task is getting called by MS, first check is to see if we are currently receiving
880 QBBC NB_DONE_NO_PARAM_STORE, R23, Rcv_active
881 QBBS NB_DONE_NO_PARAM_STORE, MII_RCV.rx_flags, rx_frame_error_shift
883 FN_RCV_NB_CT_NO_RxEOF: ; If Rx EOF has not come yet then directly return here ..saves 6 cycles and that helps in finding faster
884 ; that L2 fifo has received 32 or 64 bytes ..which helps in calling NB_PROCESS_32BYTES early
885 ; depending on the bank index, we load bank 0 or bank 1
886 QBBS NB_XIN_UPPER_BANK, MII_RCV.rx_flags, rx_bank_index_shift
888 NB_XIN_LOWER_BANK:
889 ; OPT: Just one XIN is needed
890 XIN RX_L2_BANK0_ID, &R18, RANGE_R18_b0
891 XIN RX_L2_BANK0_ID, &R2, RANGE_R2_R13 ; XIN RX L2 bank 0
892 QBA NB_CHECK_AMOUNT_OF_BYTES
893 NB_XIN_UPPER_BANK:
894 ; OPT: Just one XIN is needed
895 XIN RX_L2_BANK1_ID, &R18, RANGE_R18_b0
896 XIN RX_L2_BANK1_ID, &R2, RANGE_R2_R13 ; XIN RX L2 bank 1
898 NB_CHECK_AMOUNT_OF_BYTES:
899 .if $defined("ICSS_SWITCH_BUILD")
900 QBBC check_for_32bytes, MII_RCV.tx_flags, cut_through_flag_shift ;MII_RCV.tx_flags.cut_through_flag
901 SUB RCV_TEMP_REG_1, R18_RCV_BYTECOUNT, PREVIOUS_R18_RCV_BYTECOUNT
902 .if $defined("ICSS_REV1")
903 QBGT NB_DONE, RCV_TEMP_REG_1, 2
905 NB_PUSH_NEXT_WORD_TO_FIFO:
906 QBEQ check_for_32bytes, R1.b3, 0x28
907 ADD PREVIOUS_R18_RCV_BYTECOUNT, PREVIOUS_R18_RCV_BYTECOUNT, 2
908 MVIW TX_DATA_WORD, *R1.b3
909 M_PUSH_WORD_CMD
910 ADD CUT_THROUGH_BYTE_CNT, CUT_THROUGH_BYTE_CNT, 2
911 ADD R1.b3, R1.b3, 2
912 SUB RCV_TEMP_REG_1, RCV_TEMP_REG_1, 2
913 QBLE NB_PUSH_NEXT_WORD_TO_FIFO, RCV_TEMP_REG_1, 2
914 .endif
915 .if $defined("ICSS_REV2")
916 QBGT NB_DONE, RCV_TEMP_REG_1, 4
918 NB_PUSH_NEXT_DOUBLE_WORD_TO_FIFO:
919 QBEQ check_for_32bytes, R1.b3, 0x28
920 ADD PREVIOUS_R18_RCV_BYTECOUNT, PREVIOUS_R18_RCV_BYTECOUNT, 4
921 MVID TX_DATA_DOUBLE_WORD, *R1.b3
922 ADD CUT_THROUGH_BYTE_CNT, CUT_THROUGH_BYTE_CNT, 4
923 ADD R1.b3, R1.b3, 4
924 SUB RCV_TEMP_REG_1, RCV_TEMP_REG_1, 4
925 QBLE NB_PUSH_NEXT_DOUBLE_WORD_TO_FIFO, RCV_TEMP_REG_1, 4
926 .endif
927 check_for_32bytes:
928 .endif
929 QBBS NB_CHECK_AMOUNT_OF_BYTES_BIGGER_32_BANK1, MII_RCV.rx_flags, rx_bank_index_shift ; check which bank to read
931 ; for bank 0, R18.b0 >=32 bytes
932 QBGT NB_DONE, R18_RCV_BYTECOUNT, 32
933 ;LDI R1.b3, buffer_ptr
934 QBA NB_PROCESS_32BYTES
936 NB_CHECK_AMOUNT_OF_BYTES_BIGGER_32_BANK1:
938 ; for bank 1, R18.b0 <32 bytes
939 QBLE NB_DONE, R18_RCV_BYTECOUNT, 32
941 .if $defined("ICSS_SWITCH_BUILD")
942 QBBC NB_PROCESS_32BYTES_CT, MII_RCV.tx_flags, cut_through_flag_shift ;MII_RCV.tx_flags.cut_through_flag
943 QBEQ NB_PROCESS_32BYTES_CT, R1.b3, 0x28
944 .if $defined("ICSS_REV1")
945 MVIW TX_DATA_WORD, *R1.b3
946 M_PUSH_WORD_CMD
947 ADD CUT_THROUGH_BYTE_CNT, CUT_THROUGH_BYTE_CNT, 2
948 .endif
949 .if $defined("ICSS_REV2")
950 MVID TX_DATA_DOUBLE_WORD, *R1.b3
951 ADD CUT_THROUGH_BYTE_CNT, CUT_THROUGH_BYTE_CNT, 4
952 .endif
953 NB_PROCESS_32BYTES_CT:
954 .endif
955 LDI PREVIOUS_R18_RCV_BYTECOUNT, 0x00
957 ;***********************************
958 ; 32 bytes handling, no cut through
959 ;***********************************
960 NB_PROCESS_32BYTES: ; 32 Bytes of new data are in the buffer
962 LDI R1.b3, buffer_ptr ; load the buffer pointer
964 NB_PROCESS_CHECK_BYTE_CNTR:
965 ; if this is the first 32 bytes of data, need to init the buffer queues
966 QBNE NB_PROCESS_32BYTES_CHECK_FLAGS, MII_RCV.byte_cntr, 0
968 .if $defined("ICSS_SWITCH_BUILD")
969 .if $defined("TWO_PORT_CFG")
970 QBNE NB_PROCESS_32BYTES_CHECK_FLAGS, MII_RCV_PORT.byte_cntr, 0
971 .endif ;TWO_PORT_CFG
973 QBBC NB_PROCESS_32BYTES_INIT_PORT_QUEUE, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
975 NB_PROCESS_32BYTES_INIT_HOST_QUEUE:
976 .if $defined("TWO_PORT_CFG")
977 LDI RCV_TEMP_REG_3.w0, P0_QUEUE_DESC_OFFSET
978 LDI RCV_TEMP_REG_3.w2, P0_COL_QUEUE_DESC_OFFSET
979 ; Calling for host queue
980 LDI RCV_TEMP_REG_1.b1, 0
981 ; get queue
982 JAL CALL_REG, FN_QUEUE_ARBITRATION
983 ;RCV_TEMP_REG_1.b0 --> OUTPUT: returns information if the queue has been
984 ;aquired successful ((0-failed to aquire; 1-queue; 2-collision)
985 QBNE NB_PROCESS_32BYTES_INIT_HOST_QUEUE_OK, RCV_TEMP_REG_1.b0, 0
986 ; OPT: Can't fail
987 NB_PROCESS_32BYTES_INIT_HOST_QUEUE_FAILED:
988 ; clear host receive flag
989 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, host_rcv_flag_shift
991 ; ToDo: Do we need to add code for statistics? We should never fail to aquire the queue or the coll-queue
992 QBA NB_PROCESS_32BYTES_INIT_PORT_QUEUE
993 NB_PROCESS_32BYTES_INIT_HOST_QUEUE_OK:
994 ;CLR MII_RCV.rx_flags.host_collision_queue_selected ; ToDo: this could be removed when parameter are init with 0 at b/o frame
995 ; 2-collision selected?
996 QBNE NB_PROCESS_32BYTES_INIT_HOST_QUEUE_NO_COLL_SELECTED, RCV_TEMP_REG_1.b0, COLLISION_AQUIRED
998 ; Initialize the RCV CONTEXT with the data of Host Collision Queue
999 SET MII_RCV.rx_flags, MII_RCV.rx_flags, host_collision_queue_selected_shift
1000 LDI RCV_TEMP_REG_1.w0, COL_RX_CONTEXT_P0_OFFSET_ADDR
1001 LBCO &MII_RCV.buffer_index, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 10
1002 .endif ;TWO_PORT_CFG
1003 NB_PROCESS_32BYTES_INIT_HOST_QUEUE_NO_COLL_SELECTED:
1004 .endif
1005 ;Initialize the wrkng_wr_ptr and rd_ptr here as the other PRU might have changed them between Now and RCV_FB
1006 LBCO &RCV_QUEUE_DESC_REG, QUEUE_DESP_BASE, MII_RCV.rcv_queue_pointer, 4
1007 AND MII_RCV.rd_ptr , RCV_QUEUE_DESC_REG.rd_ptr , RCV_QUEUE_DESC_REG.rd_ptr
1008 AND MII_RCV.wrkng_wr_ptr , RCV_QUEUE_DESC_REG.wr_ptr , RCV_QUEUE_DESC_REG.wr_ptr
1010 ; Rx interrupt pacing
1011 ; If the rd_ptr & wr_ptr are equal => queue is empty => SET HOST_QUEUE_EMPTY_STATUS
1012 QBNE HOST_QUEUE_NOT_EMPTY, RCV_QUEUE_DESC_REG.rd_ptr, RCV_QUEUE_DESC_REG.wr_ptr
1013 SET R22, R22, HOST_QUEUE_EMPTY_STATUS
1015 HOST_QUEUE_NOT_EMPTY:
1016 .if $defined("TWO_PORT_CFG")
1017 QBBS NB_RCV_CONTEXT_INITIALIZED_WITH_COLLISION, MII_RCV.rx_flags, host_collision_queue_selected_shift
1018 .endif ;TWO_PORT_CFG
1019 ; Compute the adress in L3 RAM where the packet is received
1020 SUB RCV_BUFFER_DESC_OFFSET, MII_RCV.wrkng_wr_ptr, MII_RCV.base_buffer_desc_offset
1021 LSL RCV_BUFFER_DESC_OFFSET, RCV_BUFFER_DESC_OFFSET, 3
1022 ADD MII_RCV.buffer_index, MII_RCV.base_buffer_index, RCV_BUFFER_DESC_OFFSET
1024 .if $defined("ICSS_SWITCH_BUILD")
1025 NB_RCV_CONTEXT_INITIALIZED_WITH_COLLISION:
1027 NB_PROCESS_32BYTES_INIT_PORT_QUEUE:
1028 ; check if selected
1029 .if $defined("TWO_PORT_CFG")
1031 QBBC NB_PROCESS_32BYTES_CHECK_FLAGS, MII_RCV.rx_flags, fwd_flag_shift
1033 .if $defined("PRU0")
1034 LDI RCV_TEMP_REG_3.w0, P2_QUEUE_DESC_OFFSET
1035 LDI RCV_TEMP_REG_3.w2, P2_COL_QUEUE_DESC_OFFSET
1036 .else
1037 LDI RCV_TEMP_REG_3.w0, P1_QUEUE_DESC_OFFSET
1038 LDI RCV_TEMP_REG_3.w2, P1_COL_QUEUE_DESC_OFFSET
1039 .endif
1040 ; get queue
1041 ;CALL FN_QUEUE_ARBITRATION_PORT_RCV
1042 ; Calling for port queue
1043 LDI RCV_TEMP_REG_1.b1, 1
1044 JAL CALL_REG, FN_QUEUE_ARBITRATION
1045 ;RCV_TEMP_REG_1.b0 --> OUTPUT: returns information if the queue has
1046 ;been acquired successful ((0-failed to acquire; 1-queue; 2-collision)
1047 QBNE NB_PROCESS_32BYTES_INIT_PORT_QUEUE_OK, RCV_TEMP_REG_1.b0, 0
1048 ; OPT: Can't fail
1049 NB_PROCESS_32BYTES_INIT_PORT_QUEUE_FAILED:
1052 ; clear port receive flag
1053 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, fwd_flag_shift
1054 ; ToDo: Do we need to add code for statistics? We should never fail to aquire the queue or the coll-queue
1055 QBA NB_PROCESS_32BYTES_CHECK_FLAGS
1056 NB_PROCESS_32BYTES_INIT_PORT_QUEUE_OK:
1057 ;CLR MII_RCV.rx_flags.port_collision_queue_selected ; ToDo: this could be removed when parameter are init with 0 at b/o frame
1058 ; 2-collision selected?
1059 QBNE NB_PROCESS_32BYTES_INIT_PORT_QUEUE_NO_COLL_SELECTED, RCV_TEMP_REG_1.b0, 2
1061 ; Initialize the RCV CONTEXT with the data of Port Collision Queue
1062 SET MII_RCV.rx_flags, MII_RCV.rx_flags, port_collision_queue_selected_shift
1063 .if $defined("PRU0")
1064 LDI RCV_TEMP_REG_1.w0, COL_RX_CONTEXT_P2_OFFSET_ADDR
1065 .else
1066 LDI RCV_TEMP_REG_1.w0, COL_RX_CONTEXT_P1_OFFSET_ADDR
1067 .endif
1068 LBCO &MII_RCV_PORT.buffer_index, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 10
1070 NB_PROCESS_32BYTES_INIT_PORT_QUEUE_NO_COLL_SELECTED:
1071 ;Initialize the wrkng_wr_ptr and rd_ptr here as the other PRU might have changed them between Now and RCV_FB
1072 LBCO &RCV_QUEUE_DESC_REG, QUEUE_DESP_BASE, MII_RCV_PORT.rcv_queue_pointer, 4
1073 AND MII_RCV_PORT.rd_ptr , RCV_QUEUE_DESC_REG.rd_ptr , RCV_QUEUE_DESC_REG.rd_ptr ;Warning: converted from MOV
1074 AND MII_RCV_PORT.wrkng_wr_ptr , RCV_QUEUE_DESC_REG.wr_ptr , RCV_QUEUE_DESC_REG.wr_ptr ;Warning: converted from MOV
1075 QBBS NB_RCV_PORT_CONTEXT_INITIALIZED_WITH_COLLISION, MII_RCV.rx_flags, port_collision_queue_selected_shift
1076 ; Compute the adress in L3 RAM where the packet is received
1077 SUB RCV_BUFFER_DESC_OFFSET, MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.base_buffer_desc_offset
1078 LSL RCV_BUFFER_DESC_OFFSET, RCV_BUFFER_DESC_OFFSET, 3
1079 ADD MII_RCV_PORT.buffer_index, MII_RCV_PORT.base_buffer_index, RCV_BUFFER_DESC_OFFSET
1081 NB_RCV_PORT_CONTEXT_INITIALIZED_WITH_COLLISION:
1082 .endif ;TWO_PORT_CFG
1083 .endif ;ICSS_SWITCH_BUILD
1085 NB_PROCESS_32BYTES_CHECK_FLAGS:
1087 .if $defined("ICSS_SWITCH_BUILD")
1088 QBBC NB_PROCESS_32BYTES_CHECK_FWD_FLAG, MII_RCV.rx_flags, host_rcv_flag_shift ; MII_RCV.rx_flags.host_rcv_flag
1089 .endif
1091 QBGE LESS_THAN_64_BYTES_RCVD, MII_RCV.byte_cntr, 32
1092 QBA EXIT_PREPROCESSING_NB
1094 LESS_THAN_64_BYTES_RCVD:
1095 ;between 32 and 64 bytes
1096 QBGE LESS_THAN_32_BYTES_RCVD, MII_RCV.byte_cntr, 0
1098 .if $defined(PTP)
1099 LDI RCV_TEMP_REG_3.w2, PTP_IPV4_UDP_E2E_ENABLE
1100 LBCO &RCV_TEMP_REG_3.b2, ICSS_SHARED_CONST, RCV_TEMP_REG_3.w2, 1
1101 QBEQ PTP_NOT_ENABLED_RX_B2, RCV_TEMP_REG_3.b2, 0
1102 QBBC PTP_NOT_ENABLED_RX_B2, R22, RX_IS_UDP_PTP_BIT
1103 CLR R22, R22, RX_IS_UDP_PTP_BIT
1104 JAL RCV_TEMP_REG_3.w2, FN_TIMESTAMP_GPTP_PACKET
1105 JAL RCV_TEMP_REG_3.w2, FN_CHECK_AND_CLR_PTP_FWD_FLAG
1106 PTP_NOT_ENABLED_RX_B2:
1107 .endif ; "PTP"
1108 QBA EXIT_PREPROCESSING_NB
1110 LESS_THAN_32_BYTES_RCVD:
1112 .if $defined(PTP)
1113 ;we don't want to execute this for UDP frames, since this will be executed again later
1114 QBBS PTP_SKIP_EARLY_TS_FOR_UDP_1, R22, RX_IS_UDP_PTP_BIT
1115 JAL RCV_TEMP_REG_3.w2, FN_CHECK_AND_CLR_PTP_FWD_FLAG_L2
1116 JAL RCV_TEMP_REG_3.w2, FN_TIMESTAMP_GPTP_PACKET
1117 PTP_SKIP_EARLY_TS_FOR_UDP_1:
1118 .endif ;PTP
1120 EXIT_PREPROCESSING_NB:
1121 SBCO &Ethernet, L3_OCMC_RAM_CONST, MII_RCV.buffer_index, 32
1122 ADD MII_RCV.byte_cntr , MII_RCV.byte_cntr , 32 ; increment byte count by 32
1124 ; Compare current wrk pointer to top_most queue desc pointer ..check for wrap around
1125 QBNE RCV_NB_NO_QUEUE_WRAP, MII_RCV.wrkng_wr_ptr, MII_RCV.top_most_buffer_desc_offset
1126 AND MII_RCV.wrkng_wr_ptr , MII_RCV.base_buffer_desc_offset , MII_RCV.base_buffer_desc_offset
1127 AND MII_RCV.buffer_index , MII_RCV.base_buffer_index , MII_RCV.base_buffer_index
1128 QBA RCV_NB_QUEUE_WRAPPED
1129 RCV_NB_NO_QUEUE_WRAP:
1130 ADD MII_RCV.buffer_index, MII_RCV.buffer_index, 32
1131 ADD MII_RCV.wrkng_wr_ptr, MII_RCV.wrkng_wr_ptr, 4
1133 RCV_NB_QUEUE_WRAPPED:
1135 ; Prepare for next call of RCV_NB ..whether next 32 bytes can be received or not
1136 QBNE NB_PROCESS_32BYTES_CHECK_FLAGS_QUEUE_NOT_FULL, MII_RCV.wrkng_wr_ptr, MII_RCV.rd_ptr
1138 CLR MII_RCV.rx_flags , MII_RCV.rx_flags , host_rcv_flag_shift
1139 SET MII_RCV.rx_flags_extended , MII_RCV.rx_flags_extended , host_queue_overflow_shift
1140 .if $defined("ICSS_DUAL_EMAC_BUILD")
1141 ;For EMAC mode, set rx_frame_error bit. This saves cycles in FN_RCV_LB.
1142 SET MII_RCV.rx_flags , MII_RCV.rx_flags , 4
1143 .endif
1145 NB_PROCESS_32BYTES_CHECK_FLAGS_QUEUE_NOT_FULL:
1146 .if $defined("ICSS_SWITCH_BUILD")
1147 NB_PROCESS_32BYTES_CHECK_FWD_FLAG:
1148 .if $defined("TWO_PORT_CFG")
1150 QBBC NB_PROCESS_32BYTES_CHECK_FLAG_DONE, MII_RCV.rx_flags, 1 ;MII_RCV.rx_flags.fwd_flag
1151 SBCO &Ethernet, L3_OCMC_RAM_CONST, MII_RCV_PORT.buffer_index, 32
1152 ADD MII_RCV_PORT.byte_cntr, MII_RCV_PORT.byte_cntr, 32
1154 ; Compare current wrk pointer to top_most queue desc pointer ..check for wrap around
1155 QBNE RCV_NB_PORT_NO_QUEUE_WRAP, MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.top_most_buffer_desc_offset
1156 AND MII_RCV_PORT.wrkng_wr_ptr , MII_RCV_PORT.base_buffer_desc_offset , MII_RCV_PORT.base_buffer_desc_offset ;Warning: converted from MOV
1157 AND MII_RCV_PORT.buffer_index , MII_RCV_PORT.base_buffer_index , MII_RCV_PORT.base_buffer_index ;Warning: converted from MOV
1158 QBA RCV_NB_PORT_QUEUE_WRAPPED
1159 RCV_NB_PORT_NO_QUEUE_WRAP:
1160 ADD MII_RCV_PORT.buffer_index, MII_RCV_PORT.buffer_index, 32
1161 ADD MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.wrkng_wr_ptr, 4
1162 RCV_NB_PORT_QUEUE_WRAPPED:
1164 ; Prepare for next call of RCV_NB ..whether next 32 bytes can be received or not
1165 QBNE NB_PROCESS_32BYTES_CHECK_FWD_FLAG_NOT_FULL, MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.rd_ptr
1166 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, fwd_flag_shift
1167 SET MII_RCV.rx_flags_extended, MII_RCV.rx_flags_extended, port_queue_overflow_shift
1169 NB_PROCESS_32BYTES_CHECK_FWD_FLAG_NOT_FULL:
1171 NB_PROCESS_32BYTES_CHECK_FLAG_DONE:
1172 .endif ;TWO_PORT_CFG
1174 NB_PROCESS_DONE:
1175 .endif
1176 XOR MII_RCV.rx_flags, MII_RCV.rx_flags, (1<<rx_bank_index_shift) ; toggle rx_bank_index flag
1178 NB_DONE:
1180 ; restore call register pointer
1181 AND CALL_REG , L1_CALL_REG , L1_CALL_REG
1183 ; store task parameters from parameter bank
1184 NB_STORE_CONTEXT:
1185 LDI R0.b0, SHIFT_NONE
1186 .if $defined("PRU0")
1187 XOUT BANK1, &MII_RCV, $sizeof(MII_RCV)
1188 .else
1189 XOUT BANK2, &MII_RCV, $sizeof(MII_RCV)
1190 .endif
1192 .if $defined("ICSS_SWITCH_BUILD")
1193 .if $defined("TWO_PORT_CFG")
1194 .if $defined("PRU0")
1195 LDI R0.b0, SHIFT_R14_TO_R0
1196 XOUT BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT)
1197 .else
1198 LDI R0.b0, SHIFT_R14_TO_R4
1199 XOUT BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT)
1200 .endif
1201 QBBS NB_PROCESS_CUT_THROUGH, MII_RCV.tx_flags, cut_through_flag_shift ;MII_RCV.tx_flags.cut_through_flag
1202 .endif ;TWO_PORT_CFG
1203 .endif
1205 .if $defined("ICSS_REV1")
1206 M_RCV_RX_EOF_CHECK_ICSS_REV1 ; check for EOF for REV1
1207 .endif
1208 .if $defined("ICSS_REV2")
1209 M_RCV_RX_EOF_CHECK_ICSS_REV2 ; check for EOF for REV2
1210 .endif
1212 NB_DONE_NO_PARAM_STORE:
1213 JMP TASK_EXECUTION_FINISHED
1215 process_rx_eof_rx_nb:
1216 JMP FN_RCV_LB
1218 .if $defined("ICSS_SWITCH_BUILD")
1219 .if $defined("TWO_PORT_CFG")
1220 NB_PROCESS_CUT_THROUGH:
1221 ; check for RX EOF condition
1222 .if $defined("ICSS_REV1")
1223 .if $defined("PRU0")
1224 QBBC FN_RCV_NB_CT_NO_RxEOF, R31, 30 ;replaced: QBBC FN_RCV_NB_CT_NO_RxEOF, R31.t30
1225 .else
1226 QBBC FN_RCV_NB_CT_NO_RxEOF, R31, 31 ;replaced: QBBC FN_RCV_NB_CT_NO_RxEOF, R31.t31
1227 .endif
1228 .endif
1229 .if $defined("ICSS_REV2")
1230 QBBC FN_RCV_NB_CT_NO_RxEOF, R31, 20 ; Port0 Rx EOF
1231 .endif
1233 FN_RCV_NB_CT_RxEOF:
1234 QBBS CT_NB_XIN_UPPER_BANK, MII_RCV.rx_flags, rx_bank_index_shift ;MII_RCV.rx_flags.rx_bank_index
1236 CT_NB_XIN_LOWER_BANK:
1238 XIN RX_L2_BANK0_ID, &R18, RANGE_R18_b0
1239 XIN RX_L2_BANK0_ID, &R2, RANGE_R2_R13 ; XIN RX L2 bank 0
1241 QBA CT_NB_CHECK_AMOUNT_OF_BYTES
1242 CT_NB_XIN_UPPER_BANK:
1244 XIN RX_L2_BANK1_ID, &R18, RANGE_R18_b0
1245 XIN RX_L2_BANK1_ID, &R2, RANGE_R2_R13 ; XIN RX L2 bank 1
1247 CT_NB_CHECK_AMOUNT_OF_BYTES:
1248 ; Put the remaining bytes in Tx_FIFO at this point of time itself
1249 AND RCV_TEMP_REG_1.b0, CUT_THROUGH_BYTE_CNT, 0x003f
1250 ; Below code added to fix a bug when for a 65 byte packet R18 has 1 but cut_through_byte_cnt is 62.
1251 ; Check whether cut_through_byte_cnt is more than R18 count
1252 QBGE CT_R18_IS_GREATER_OR_EQUAL, RCV_TEMP_REG_1.b0, R18_RCV_BYTECOUNT
1253 LDI RCV_TEMP_REG_2.b0, 64 ; Subtract from 64 bytes
1254 SUB RCV_TEMP_REG_1.b0, RCV_TEMP_REG_2.b0, RCV_TEMP_REG_1.b0
1255 ; L2 FIFO wrapped around but few bytes of upper bank didn't get pushed in fifo. It is possible that RX EOF is detected before pushing
1256 ; the last two bytes and R18 gets wrapped around by the time we reach here
1257 ADD RCV_TEMP_REG_1.b0, RCV_TEMP_REG_1.b0, R18_RCV_BYTECOUNT
1258 QBA CT_R18_IS_LESS
1259 CT_R18_IS_GREATER_OR_EQUAL:
1261 SUB RCV_TEMP_REG_1.b0, R18_RCV_BYTECOUNT, RCV_TEMP_REG_1.b0
1263 CT_R18_IS_LESS:
1264 .if $defined("ICSS_REV1")
1265 ;QBEQ CT_PUSH_LB_LASTBYTE_nb, RCV_TEMP_REG_1.b0, 1
1266 LSR loop_cnt, RCV_TEMP_REG_1.b0, 1
1267 ; OPT: Use function for the loop below
1268 ;QBEQ ct_assert_eof_nb, loop_cnt, 0x0000
1269 LOOP CT_NB_ENDLOOP, loop_cnt
1270 MVIW TX_DATA_WORD, *TX_DATA_POINTER
1271 M_PUSH_WORD_CMD
1272 ADD TX_DATA_POINTER, TX_DATA_POINTER, 2
1273 CT_NB_ENDLOOP:
1274 QBBC ct_assert_eof_nb, RCV_TEMP_REG_1.b0, 0
1275 CT_PUSH_LB_LASTBYTE_nb:
1276 MVIB TX_DATA_BYTE, *R1.b3
1277 M_PUSH_BYTE
1278 ct_assert_eof_nb:
1279 ;M_PUSH_TX_EOF
1280 .endif
1281 .if $defined("ICSS_REV2")
1282 LSR loop_cnt, RCV_TEMP_REG_1.b0, 2
1284 loop CT_NB_ENDLOOP, loop_cnt
1285 MVID TX_DATA_DOUBLE_WORD, *TX_DATA_POINTER
1286 ADD TX_DATA_POINTER, TX_DATA_POINTER, 4
1287 CT_NB_ENDLOOP:
1289 AND RCV_TEMP_REG_2.b0, RCV_TEMP_REG_1.b0, 0x03
1290 QBEQ ct_assert_eof_nb, RCV_TEMP_REG_2.b0, 0
1291 QBEQ CT_PUSH_LB_LASTBYTE_nb, RCV_TEMP_REG_2.b0, 1
1292 MVIW TX_DATA_WORD, *TX_DATA_POINTER
1293 ADD TX_DATA_POINTER, TX_DATA_POINTER, 2
1294 QBEQ ct_assert_eof_nb, RCV_TEMP_REG_2.b0, 2
1295 CT_PUSH_LB_LASTBYTE_nb:
1296 MVIB TX_DATA_BYTE, *R1.b3
1298 ct_assert_eof_nb:
1299 ; Insert the TX_EOF for outgoing frame
1300 LDI R31.w2, 0x2000
1301 .endif
1302 ADD CUT_THROUGH_BYTE_CNT, CUT_THROUGH_BYTE_CNT, RCV_TEMP_REG_1.b0
1303 ct_deassert_ct:
1304 SKIP_CRC_PUSH:
1306 LDI R0.b0, SHIFT_NONE
1307 .if $defined("PRU0")
1308 XOUT BANK1, &MII_RCV, $sizeof(MII_RCV)
1309 .else
1310 XOUT BANK2, &MII_RCV, $sizeof(MII_RCV)
1311 .endif
1312 CLR R22, R22, PACKET_TX_ALLOWED
1313 ;Check for CRC
1314 LDI RCV_TEMP_REG_2.w0, 0x0204
1315 LBCO &RCV_TEMP_REG_1, ICSS_INTC_CONST, RCV_TEMP_REG_2.w0, 4
1316 .if $defined("PRU0")
1317 QBBC NO_CRC_ERROR_CT, RCV_TEMP_REG_1, 4 ;replaced: QBBC NO_CRC_ERROR_CT, RCV_TEMP_REG_1.t4
1318 .else
1319 QBBC NO_CRC_ERROR_CT, RCV_TEMP_REG_1, 16 ;replaced: QBBC NO_CRC_ERROR_CT, RCV_TEMP_REG_1.t16
1320 .endif
1321 LDI RCV_TEMP_REG_3 , RX_CRC_COUNT_OFFSET
1323 ;Add to statistics counter
1324 LBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1325 ADD RCV_TEMP_REG_1, RCV_TEMP_REG_1, 1
1326 SBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1327 NO_CRC_ERROR_CT:
1328 .endif ;TWO_PORT_CFG
1329 .endif ;ICSS_SWITCH_BUILD
1331 ;****************************************************************************
1332 ;
1333 ; NAME : FN_RCV_LB
1334 ; DESCRIPTION : receives the last block(s) of RX L2
1335 ; RETURNS :
1336 ; ARGS :
1337 ; USES :
1338 ; INVOKES :
1339 ;
1340 ;****************************************************************************
1341 FN_RCV_LB:
1343 ; Check if RCV_Active is set. If not drop the frame. It handles the case of undersize errors
1344 QBBS RCV_LB_PROCESS_NORMAL, R23, Rcv_active
1346 LB_CHECK_ERRORS:
1347 ;Short frame received then increment the error offset statistics
1348 LDI RCV_TEMP_REG_3 , RX_ERROR_OFFSET
1349 LBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1350 ADD RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1
1351 SBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1352 .if $defined("ICSS_DUAL_EMAC_BUILD")
1353 .if $defined("HALF_DUPLEX_ENABLED")
1354 ;check R31 error
1355 QBBC NO_R31_ERROR, R31, 19 ; if cleared so no error and continue normal operation
1356 ;else clear the error
1357 M_CMD16 D_RX_ERROR_CLEAR ; else clear error flag
1359 NO_R31_ERROR:
1360 ;check for SFD Errors
1361 .if $defined("PRU0")
1362 LBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1 ;read the PRUSS_MII_RT_RX_ERR0 register
1363 QBBC CHECK_FOR_SHORT_SFD1, RCV_TEMP_REG_3, 1 ; check if not error then jump else count stats
1364 ;clear error and writeback
1365 SET RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 1
1366 SBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1
1367 QBA COUNT_SFD_ERROR1
1368 CHECK_FOR_SHORT_SFD1:
1369 QBBC NO_PREAMBLE_ERROR, RCV_TEMP_REG_3, 0 ; check if not error then jump else count stats
1370 ;clear error and writeback
1371 SET RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 0
1372 SBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1
1373 .else
1374 LBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1 ;read the PRUSS_MII_RT_RX_ERR0 register
1375 QBBC CHECK_FOR_SHORT_SFD1, RCV_TEMP_REG_3, 1 ; check if not error then jump else count stats
1376 ;clear error and writeback
1377 SET RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 1
1378 SBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1
1379 QBA COUNT_SFD_ERROR1
1380 CHECK_FOR_SHORT_SFD1:
1381 QBBC NO_PREAMBLE_ERROR, RCV_TEMP_REG_3, 0 ; check if not error then jump else count stats
1382 ;clear error and writeback
1383 SET RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 0
1384 SBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1
1385 .endif
1387 COUNT_SFD_ERROR1:
1388 ;increment and store the count
1389 LDI RCV_TEMP_REG_3 , SFD_ERROR_OFFSET
1390 LBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1391 ADD RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1
1392 SBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1393 .endif ;HALF_DUPLEX_ENABLED
1394 .endif ;ICSS_DUAL_EMAC_BUILD
1395 NO_PREAMBLE_ERROR:
1397 ; RCV_CONTEXT is not initialized for this error frame.
1398 ; reset RX FIFO, this places the R18 counter back to position 0
1399 CLR R23 , R23 , Rcv_active
1400 M_SET_CMD D_RESET_RXFIFO
1401 QBA LB_NO_RX_STAT
1402 RCV_LB_PROCESS_NORMAL:
1404 ; for XIN, make sure that shift is set to 0
1405 LDI R0.b0, SHIFT_NONE
1406 ; restore task parameters from parameter bank
1407 .if $defined("PRU0")
1408 XIN BANK1, &MII_RCV, $sizeof(MII_RCV)
1409 .else
1410 XIN BANK2, &MII_RCV, $sizeof(MII_RCV)
1411 .endif
1413 .if $defined("TWO_PORT_CFG")
1414 ; OPT: MOve the port context read after the XIN of data
1415 ; for port receive
1416 .if $defined("PRU0")
1417 LDI R0.b0, SHIFT_R14_TO_R0
1418 XIN BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT)
1419 .else
1420 LDI R0.b0, SHIFT_R14_TO_R4
1421 XIN BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT)
1422 .endif
1423 .endif ;TWO_PORT_CFG
1424 QBBS LB_RESET_RX_FIFO, MII_RCV.rx_flags, rx_frame_error_shift
1425 ; depending on the bank index, we load bank 0 or bank 1
1426 QBBS LB_XIN_UPPER_BANK, MII_RCV.rx_flags, rx_bank_index_shift
1428 LB_XIN_LOWER_BANK:
1429 XIN RX_L2_BANK0_ID, &R18, RANGE_R18_b0
1430 XIN RX_L2_BANK0_ID, &R2, RANGE_R2_R13 ; XIN RX L2 bank 0
1432 ; have we received more than 32 bytes?
1433 QBGE LB_XIN_STORE_LESS_THAN_32_FROM_LOWER_BANK, R18_RCV_BYTECOUNT, 32
1434 QBA LB_STORE_FIRST_32_BYTES
1436 LB_XIN_UPPER_BANK:
1437 XIN RX_L2_BANK1_ID, &R18, RANGE_R18_b0
1438 XIN RX_L2_BANK1_ID, &R2, RANGE_R2_R13 ; XIN RX L2 bank 1
1440 ;For PTP frames if flow comes here it
1441 ; can only mean that 32-64 bytes have been received
1442 .if $defined("PTP")
1443 LDI RCV_TEMP_REG_1.w0, PTP_IPV4_UDP_E2E_ENABLE
1444 LBCO &RCV_TEMP_REG_1.b0, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 1
1445 QBEQ PTP_NOT_ENABLED_RX_LB, RCV_TEMP_REG_1.b0, 0
1446 QBBC PTP_NOT_ENABLED_RX_LB, R22, RX_IS_UDP_PTP_BIT
1447 CLR R22, R22, RX_IS_UDP_PTP_BIT
1448 JAL RCV_TEMP_REG_3.w2, FN_TIMESTAMP_GPTP_PACKET
1449 JAL RCV_TEMP_REG_3.w2, FN_CHECK_AND_CLR_PTP_FWD_FLAG
1450 PTP_NOT_ENABLED_RX_LB:
1451 .endif ; "PTP"
1453 ; have we received more than 32 bytes?
1454 QBLE LB_XIN_STORE_LESS_THAN_32_FROM_UPPER_BANK, R18_RCV_BYTECOUNT, 32
1456 LB_STORE_FIRST_32_BYTES:
1457 .if $defined("ICSS_SWITCH_BUILD")
1458 QBBC LB_PROCESS_32BYTES_CHECK_FWD_FLAG, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
1459 .endif
1460 .if $defined(PTP)
1461 ADD RCV_TEMP_REG_3.w2, MII_RCV.byte_cntr, 32
1462 QBLT MORE_THAN_32_BYTES_RCVD, RCV_TEMP_REG_3.w2, 32
1464 ;we don't want to execute this for UDP frames, since this will be executed again later
1465 QBBS MORE_THAN_32_BYTES_RCVD, R22, RX_IS_UDP_PTP_BIT
1466 JAL RCV_TEMP_REG_3.w2, FN_CHECK_AND_CLR_PTP_FWD_FLAG_L2
1467 JAL RCV_TEMP_REG_3.w2, FN_TIMESTAMP_GPTP_PACKET
1469 MORE_THAN_32_BYTES_RCVD:
1470 .endif ;PTP
1471 SBCO &Ethernet, L3_OCMC_RAM_CONST, MII_RCV.buffer_index, 32
1472 ADD MII_RCV.byte_cntr, MII_RCV.byte_cntr, 32
1474 ; Update the buffer descriptor for the received packet
1475 ; Compare current wrk pointer to top_most queue desc pointer ..check for wrap around
1476 QBNE RCV_LB_NO_QUEUE_WRAP_LOWER, MII_RCV.wrkng_wr_ptr, MII_RCV.top_most_buffer_desc_offset
1477 AND MII_RCV.wrkng_wr_ptr , MII_RCV.base_buffer_desc_offset , MII_RCV.base_buffer_desc_offset
1478 AND MII_RCV.buffer_index , MII_RCV.base_buffer_index , MII_RCV.base_buffer_index
1479 QBA RCV_LB_QUEUE_WRAPPED_LOWER
1480 RCV_LB_NO_QUEUE_WRAP_LOWER:
1481 ADD MII_RCV.buffer_index, MII_RCV.buffer_index, 32
1482 ADD MII_RCV.wrkng_wr_ptr, MII_RCV.wrkng_wr_ptr, 4
1484 RCV_LB_QUEUE_WRAPPED_LOWER:
1485 ; Check if the queue got completely filled with the last few bytes and the remaining bytes cannot be added.
1486 ;This scenario of queue overflow has been verified by dry run.
1487 QBNE LB_PROCESS_32BYTES_CHECK_FLAGS_QUEUE_NOT_FULL_1, MII_RCV.wrkng_wr_ptr, MII_RCV.rd_ptr
1488 CLR MII_RCV.rx_flags , MII_RCV.rx_flags , host_rcv_flag_shift
1489 SET MII_RCV.rx_flags_extended , MII_RCV.rx_flags_extended , host_queue_overflow_shift
1490 .if $defined("ICSS_DUAL_EMAC_BUILD")
1491 ;For EMAC mode, set rx_frame_error bit.
1492 SET MII_RCV.rx_flags , MII_RCV.rx_flags , 4
1493 .endif
1494 LB_PROCESS_32BYTES_CHECK_FLAGS_QUEUE_NOT_FULL_1:
1495 .if $defined("ICSS_SWITCH_BUILD")
1496 LB_PROCESS_32BYTES_CHECK_FWD_FLAG:
1497 .if $defined("TWO_PORT_CFG")
1498 QBBC LB_PROCESS_32BYTES_CHECK_FLAG_DONE, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
1500 SBCO &Ethernet, L3_OCMC_RAM_CONST, MII_RCV_PORT.buffer_index, 32
1501 ADD MII_RCV_PORT.byte_cntr, MII_RCV_PORT.byte_cntr, 32
1503 ; Update the buffer descriptor for the received packet
1504 ; Compare current wrk pointer to top_most queue desc pointer ..check for wrap around
1505 QBNE RCV_LB_NO_PORT_QUEUE_WRAP_LOWER, MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.top_most_buffer_desc_offset
1506 AND MII_RCV_PORT.wrkng_wr_ptr , MII_RCV_PORT.base_buffer_desc_offset , MII_RCV_PORT.base_buffer_desc_offset ;Warning: converted from MOV
1507 AND MII_RCV_PORT.buffer_index , MII_RCV_PORT.base_buffer_index , MII_RCV_PORT.base_buffer_index ;Warning: converted from MOV
1508 QBA RCV_LB_PORT_QUEUE_WRAPPED_LOWER
1509 RCV_LB_NO_PORT_QUEUE_WRAP_LOWER:
1510 ADD MII_RCV_PORT.buffer_index, MII_RCV_PORT.buffer_index, 32
1511 ADD MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.wrkng_wr_ptr, 4
1513 RCV_LB_PORT_QUEUE_WRAPPED_LOWER:
1514 ; Prepare for next call of RCV_LB ..whether next 32 bytes can be received or not
1515 QBNE LB_PROCESS_32BYTES_CHECK_FLAGS_PORT_QUEUE_NOT_FULL_1, MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.rd_ptr
1516 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
1517 SET MII_RCV.rx_flags_extended, MII_RCV.rx_flags_extended, port_queue_overflow_shift ;MII_RCV.rx_flags_extended.port_queue_overflow
1519 LB_PROCESS_32BYTES_CHECK_FLAGS_PORT_QUEUE_NOT_FULL_1:
1521 LB_PROCESS_32BYTES_CHECK_FLAG_DONE:
1522 .endif ;TWO_PORT_CFG
1523 .endif ;ICSS_SWITCH_BUILD
1524 QBBC LB_STORE_UPPER_DATA, MII_RCV.rx_flags, rx_bank_index_shift
1526 ; get and store lower data
1527 XIN RX_L2_BANK0_ID, &R2, RANGE_R2_R9 ; recieve the remaining data
1528 QBA LB_XIN_STORE_LESS_THAN_32_FROM_LOWER_BANK
1529 LB_STORE_UPPER_DATA:
1530 ; get and store upper data
1531 XIN RX_L2_BANK1_ID, &R2, RANGE_R2_R13 ; recieve the remaining data
1533 LB_XIN_STORE_LESS_THAN_32_FROM_UPPER_BANK:
1534 SUB R0.b1, R18, 32 ; count remaining data
1535 QBA LB_STORE_FROM_UPPER_BUFFER
1536 LB_XIN_STORE_LESS_THAN_32_FROM_LOWER_BANK:
1537 AND R0.b1 , R18 , R18
1538 LB_STORE_FROM_UPPER_BUFFER:
1540 QBBS RCV_LB_APPEND_TS, R22, 14 ;check PTP flag
1541 ; Check if 0 bytes are there to store
1542 QBEQ LB_PROCESS_CHECK_FWD_FLAG, R0.b1, 0
1544 ; Receive for Host Queue
1545 .if $defined("ICSS_SWITCH_BUILD")
1546 QBBC LB_PROCESS_CHECK_FWD_FLAG, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
1547 .endif
1548 SBCO &Ethernet, L3_OCMC_RAM_CONST, MII_RCV.buffer_index, b1
1550 ADD MII_RCV.byte_cntr, MII_RCV.byte_cntr, R0.b1 ; increment the count by R1 bytes
1551 QBGE LB_PROCESS_CHECK_FWD_FLAG, R0.b1, 4 ;If only CRC is left to store then skip
1552 QBNE RCV_LB_NO_QUEUE_WRAP_2, MII_RCV.wrkng_wr_ptr, MII_RCV.top_most_buffer_desc_offset
1553 AND MII_RCV.wrkng_wr_ptr , MII_RCV.base_buffer_desc_offset , MII_RCV.base_buffer_desc_offset
1554 QBA RCV_LB_QUEUE_WRAPPED_2
1555 RCV_LB_NO_QUEUE_WRAP_2:
1556 ADD MII_RCV.wrkng_wr_ptr, MII_RCV.wrkng_wr_ptr, 4
1557 RCV_LB_QUEUE_WRAPPED_2:
1558 QBA RCV_LB_CHECK_OVERFLOW
1559 RCV_LB_APPEND_TS:
1560 ;--------------Logic to append 10 bytes timestamp to the end of packet----------
1561 .if $defined("ICSS_SWITCH_BUILD")
1562 QBBC LB_PROCESS_CHECK_FWD_FLAG, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
1563 .endif
1565 ;If there are 0 bytes to store then append timestamp in new block
1566 QBEQ LB_TS_STORE_TS, R0.b1, 0
1567 ADD MII_RCV.byte_cntr, MII_RCV.byte_cntr, R0.b1 ; increment the count by b1 bytes
1568 QBGE LB_TS_STORE_TS, R0.b1, 4 ;If only CRC is left to store then skip and append TS
1570 SBCO &Ethernet, L3_OCMC_RAM_CONST, MII_RCV.buffer_index, b1 ;Store the data
1572 ;Compare current wrk pointer to top_most queue desc pointer ..check for wrap around
1573 QBNE LB_TS_NO_WRAP_1, MII_RCV.wrkng_wr_ptr, MII_RCV.top_most_buffer_desc_offset
1574 AND MII_RCV.wrkng_wr_ptr , MII_RCV.base_buffer_desc_offset , MII_RCV.base_buffer_desc_offset
1575 AND MII_RCV.buffer_index , MII_RCV.base_buffer_index , MII_RCV.base_buffer_index
1576 QBA LB_TS_STORE_TS
1577 LB_TS_NO_WRAP_1:
1578 ADD MII_RCV.buffer_index, MII_RCV.buffer_index, 32
1579 ADD MII_RCV.wrkng_wr_ptr, MII_RCV.wrkng_wr_ptr, 4
1581 LB_TS_STORE_TS: ;store timestamp in new 32B block
1583 ;Load offset
1584 .if $defined(PTP)
1585 M_GPTP_LOAD_TS_OFFSET
1586 .endif
1588 ;Load the TS from Shared RAM
1589 LBCO &R10, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 10
1590 ;Store into L3 OCMC
1591 SBCO &R10, L3_OCMC_RAM_CONST, MII_RCV.buffer_index, 10
1593 ;check wraparound
1594 QBNE LB_TS_NO_WRAP_2, MII_RCV.wrkng_wr_ptr, MII_RCV.top_most_buffer_desc_offset
1595 AND MII_RCV.wrkng_wr_ptr , MII_RCV.base_buffer_desc_offset , MII_RCV.base_buffer_desc_offset
1596 QBA RCV_LB_CHECK_OVERFLOW
1597 LB_TS_NO_WRAP_2:
1598 ADD MII_RCV.wrkng_wr_ptr, MII_RCV.wrkng_wr_ptr, 4
1600 RCV_LB_CHECK_OVERFLOW:
1601 .if $defined("ICSS_DUAL_EMAC_BUILD")
1602 ; Check if the queue got completely filled with the last few bytes.
1603 ;If yes, the wr_ptr and rd_prt might become equal and there could be
1604 ;possible data overwrite when the next packet arrives.
1605 ;This has been verfied by dry run.
1606 QBNE LB_PROCESS_CHECK_FLAGS_QUEUE_NOT_FULL, MII_RCV.wrkng_wr_ptr, MII_RCV.rd_ptr
1607 CLR MII_RCV.rx_flags , MII_RCV.rx_flags , 0
1608 SET MII_RCV.rx_flags_extended , MII_RCV.rx_flags_extended , 6
1609 ;For EMAC mode, set rx_frame_error bit
1610 SET MII_RCV.rx_flags , MII_RCV.rx_flags , 4
1612 LB_PROCESS_CHECK_FLAGS_QUEUE_NOT_FULL:
1613 .endif ;ICSS_DUAL_EMAC_BUILD
1614 LB_PROCESS_CHECK_FWD_FLAG:
1615 .if $defined("ICSS_SWITCH_BUILD")
1616 ; Receive for Port Queue
1617 .if $defined("TWO_PORT_CFG")
1618 QBBC LB_CLEAR_RX_FIFO, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
1619 SBCO &Ethernet, L3_OCMC_RAM_CONST, MII_RCV_PORT.buffer_index, b1
1620 ADD MII_RCV_PORT.byte_cntr, MII_RCV_PORT.byte_cntr, R0.b1
1621 QBGE LB_CLEAR_RX_FIFO, R0.b1, 4
1622 QBNE RCV_LB_NO_PORT_QUEUE_WRAP_2, MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.top_most_buffer_desc_offset
1623 AND MII_RCV_PORT.wrkng_wr_ptr , MII_RCV_PORT.base_buffer_desc_offset , MII_RCV_PORT.base_buffer_desc_offset ;Warning: converted from MOV
1624 QBA RCV_LB_PORT_QUEUE_WRAPPED_2
1625 RCV_LB_NO_PORT_QUEUE_WRAP_2:
1626 ADD MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.wrkng_wr_ptr, 4
1627 RCV_LB_PORT_QUEUE_WRAPPED_2:
1628 .endif ;TWO_PORT_CFG
1630 LB_CLEAR_RX_FIFO:
1632 QBBS LB_CHECK_RX_ERRORS, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
1633 QBBC LB_RESET_RX_FIFO, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
1635 LB_CHECK_RX_ERRORS:
1636 .endif ;ICSS_SWITCH_BUILD
1637 ; Check for CRC Error in the received frame
1638 LDI RCV_TEMP_REG_1.w0, 0x0204
1639 LBCO &RCV_TEMP_REG_2, ICSS_INTC_CONST, RCV_TEMP_REG_1.w0, 4 ;load value of INTC_SRSR1
1641 ;check odd nibble error
1642 CHECK_MISALIGNMENT_ERROR:
1643 .if $defined("PRU0")
1644 QBBC CHECK_CRC_ERROR, RCV_TEMP_REG_2, 5 ; if interrupt line is clear check for CRC error else continue
1645 .else
1646 QBBC CHECK_CRC_ERROR, RCV_TEMP_REG_2, 17 ; if interrupt line is clear check for CRC error else continue
1647 .endif
1648 LDI RCV_TEMP_REG_3 , RX_MISALIGNMENT_COUNT_OFFSET
1650 ;Add to statistics counter
1651 LBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1652 ADD RCV_TEMP_REG_1, RCV_TEMP_REG_1, 1
1653 SBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1654 .if $defined("ICSS_DUAL_EMAC_BUILD")
1655 SET MII_RCV.rx_flags , MII_RCV.rx_flags , 4
1656 .endif
1658 CHECK_CRC_ERROR:
1659 .if $defined("PRU0")
1660 QBBC LB_CHECK_MIN_FRM_ERR, RCV_TEMP_REG_2, 4
1661 .else
1662 QBBC LB_CHECK_MIN_FRM_ERR, RCV_TEMP_REG_2, 16
1663 .endif
1664 LDI RCV_TEMP_REG_3 , RX_CRC_COUNT_OFFSET
1666 ;Add to statistics counter
1667 LBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1668 ADD RCV_TEMP_REG_1, RCV_TEMP_REG_1, 1
1669 SBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1670 SET MII_RCV.rx_flags , MII_RCV.rx_flags , rx_frame_error_shift
1672 ;Check whether received frame length is less then defined min value
1673 LB_CHECK_MIN_FRM_ERR:
1674 .if $defined("PRU0")
1675 LBCO &RCV_TEMP_REG_2.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1
1676 .else
1677 LBCO &RCV_TEMP_REG_2.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1
1678 .endif
1679 QBBC LB_CHECK_MAX_FRM_ERR, RCV_TEMP_REG_2, 2 ; check if undersize error exist
1680 LDI RCV_TEMP_REG_3 , RX_UNDERSIZED_FRAME_OFFSET
1681 QBA LB_CLR_RX_ERROR_REG
1683 ;Check whether received frame length is more then defined max value
1684 LB_CHECK_MAX_FRM_ERR:
1685 QBBC LB_RESET_RX_FIFO, RCV_TEMP_REG_2, 3 ; check for oversize error
1686 LDI RCV_TEMP_REG_3 , RX_OVERSIZED_FRAME_OFFSET
1688 LB_CLR_RX_ERROR_REG:
1690 ;Add to statistics counter
1691 LBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1692 ADD RCV_TEMP_REG_1, RCV_TEMP_REG_1, 1
1693 SBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1695 ; Clear the RX MIN or RX MAX ERROR
1696 LDI RCV_TEMP_REG_2.b1, 0x0c
1697 .if $defined("PRU0")
1698 SBCO &RCV_TEMP_REG_2.b1, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1
1699 .else
1700 SBCO &RCV_TEMP_REG_2.b1, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1
1701 .endif
1702 SET MII_RCV.rx_flags , MII_RCV.rx_flags , rx_frame_error_shift
1704 LB_RESET_RX_FIFO:
1705 ; reset RX fifo, this places the R18 counter back to position 0
1706 M_SET_CMD D_RESET_RXFIFO
1709 QBBC LB_NO_RX_FRAME_ERROR, MII_RCV.rx_flags, rx_frame_error_shift ;replaced: QBBC LB_NO_RX_FRAME_ERROR, MII_RCV.rx_flags.rx_frame_error
1710 ;clear RX_BC_FRAME & RX_MC_FRAME flags
1711 CLR R22 , R22 , RX_BC_FRAME
1712 CLR R22 , R22 , RX_MC_FRAME
1713 JMP LB_RELEASE_QUEUE ; Clear the EOF and other possible error flags.
1715 LB_NO_RX_FRAME_ERROR:
1717 .if $defined("ICSS_SWITCH_BUILD")
1718 .if $defined(PTP)
1719 QBBS LB_RELEASE_PORT_QUEUE, R22, PTP_RELEASE_PORT_QUEUE_BIT
1721 PTP_PORT_QUEUE_RELEASE_DONE:
1723 .endif ;PTP
1724 .endif ;ICSS_SWITCH_BUILD
1726 LDI R0.b0, 0
1727 .if $defined("PRU0")
1728 XOUT BANK1, &MII_RCV, $sizeof(MII_RCV) ; store task parameters from parameter bank
1729 .else
1730 XOUT BANK2, &MII_RCV, $sizeof(MII_RCV) ; store task parameters from parameter bank
1731 .endif
1733 .if $defined("TWO_PORT_CFG")
1735 .if $defined("PRU0")
1736 LDI R0.b0, SHIFT_R14_TO_R0
1737 XOUT BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT) ; store task parameters from parameter bank
1738 .else
1739 LDI R0.b0, SHIFT_R14_TO_R4
1740 XOUT BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT)
1741 .endif
1742 ; For Host Receive
1743 QBBC LB_UPDATE_CHECK_FWD_FLAG, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
1744 .endif ;TWO_PORT_CFG
1745 LDI R0.b0, SHIFT_R2_TO_R26
1746 .if $defined("PRU0")
1747 XIN BANK1, &RCV_CONTEXT, $sizeof(MII_RCV_PORT) ; store task parameters from parameter bank
1748 .else
1749 XIN BANK2, &RCV_CONTEXT, $sizeof(MII_RCV_PORT) ; store task parameters from parameter bank
1750 .endif
1751 .if $defined("TWO_PORT_CFG")
1752 CLR R6 , R6 , 0
1753 QBA LB_UPDATE_FOR_HOST_RECEIVE
1754 LB_UPDATE_CHECK_FWD_FLAG:
1756 QBBC LB_UPDATE_CHECK_DONE, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
1757 .if $defined("PRU0")
1758 LDI R0.b0, SHIFT_R2_TO_R0
1759 XIN BANK0, &RCV_CONTEXT, $sizeof(MII_RCV_PORT) ; store task parameters from parameter bank
1760 .else
1761 LDI R0.b0, SHIFT_R2_TO_R4
1762 XIN BANK0, &RCV_CONTEXT, $sizeof(MII_RCV_PORT) ; store task parameters from parameter bank
1763 .endif
1764 SET R6 , R6 , 0
1765 .else
1766 ;store the length of the packet for statistics
1767 LDI RCV_TEMP_REG_2 , RX_PKT_SIZE_OFFSET
1768 SBCO &RCV_CONTEXT.byte_cntr, PRU_DMEM_ADDR, RCV_TEMP_REG_2, 2 ; load the byte count in working register
1770 .endif ;TWO_PORT_CFG
1771 LB_UPDATE_FOR_HOST_RECEIVE:
1772 ; Update the Receive Buffer Descriptor
1773 ; Read the wr_ptr of first buffer descriptor
1774 .if $defined("TWO_PORT_CFG")
1775 LBCO &RCV_TEMP_REG_1, PRU1_DMEM_CONST, RCV_CONTEXT.rcv_queue_pointer, 4
1776 .else
1777 LBCO &RCV_TEMP_REG_1, ICSS_SHARED_CONST, RCV_CONTEXT.rcv_queue_pointer, 4
1778 .endif ;TWO_PORT_CFG
1779 ; clear length field (18..28) and update length with current received frame
1780 LDI RCV_TEMP_REG_2.w0, 0
1781 SUB RCV_TEMP_REG_2.w2, RCV_CONTEXT.byte_cntr, 4 ;4 byte of FCS
1782 LSL RCV_TEMP_REG_2.w2, RCV_TEMP_REG_2.w2, 2
1784 ;Set the Port number on which packet was received
1785 .if $defined("PRU0")
1786 SET RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 16 ; Port 1
1787 .else
1788 SET RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 17 ;Port 2
1789 .endif
1791 CLR RCV_TEMP_REG_2, RCV_TEMP_REG_2, 15 ;Clear PTP descriptor bit
1793 .if $defined(PTP) ;check if bit 15 needs to be set
1794 QBBC LB_SKIP_PTP_DESC_BIT_SET, R22, RX_IS_PTP_BIT
1795 CLR R22, R22, RX_IS_PTP_BIT
1796 SET RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 15 ;Indicate to the driver that this is a PTP frame
1797 LB_SKIP_PTP_DESC_BIT_SET:
1798 .endif ;PTP
1800 .if $defined("ICSS_STP_SWITCH")
1801 ; Set FDB Lookup Success bit if the FDB lookup was successful
1802 QBBC FDB_LOOKUP_FAIL, R22, FDB_LOOKUP_SUCCESS__R22_BIT
1803 SET RCV_TEMP_REG_2, RCV_TEMP_REG_2, FDB_LOOKUP_SUCCESS__BD_BIT
1804 FDB_LOOKUP_FAIL:
1806 ; Set Packet Flooded bit if the packet was indeed flooded
1807 QBBC PKT_NOT_FLOODED, R22, PKT_FLOODED__R22_BIT
1808 SET RCV_TEMP_REG_2, RCV_TEMP_REG_2, PKT_FLOODED__BD_BIT
1809 PKT_NOT_FLOODED:
1810 .endif ; ICSS_STP_SWITCH
1812 ; the first buffer descriptor of the frame has been updated with length and port information
1813 SBCO &RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w2, 4
1815 ;Update the queue max fill level
1816 QBGT LB_RCV_QUEUE_WRAP, RCV_CONTEXT.wrkng_wr_ptr, RCV_CONTEXT.rd_ptr
1817 SUB RCV_TEMP_REG_2.w0, RCV_CONTEXT.wrkng_wr_ptr, RCV_CONTEXT.rd_ptr
1818 JMP SKIP_LB_RCV_QUEUE_WRAP
1820 LB_RCV_QUEUE_WRAP:
1821 ; add queue size to rd_ptr and then subtract wr_ptr
1822 SUB RCV_TEMP_REG_2.w0, RCV_CONTEXT.top_most_buffer_desc_offset, RCV_CONTEXT.rd_ptr
1823 ADD RCV_TEMP_REG_2.w0, RCV_TEMP_REG_2.w0, 4
1824 SUB RCV_TEMP_REG_2.w2, RCV_CONTEXT.wrkng_wr_ptr, RCV_CONTEXT.base_buffer_desc_offset
1825 ADD RCV_TEMP_REG_2.w0, RCV_TEMP_REG_2.w0, RCV_TEMP_REG_2.w2
1827 SKIP_LB_RCV_QUEUE_WRAP:
1828 ;divide the queue fill level by 4
1829 LSR RCV_TEMP_REG_2.w0, RCV_TEMP_REG_2.w0, 2
1830 ;Read the queue max fill level
1831 ADD RCV_TEMP_REG_1.w0, RCV_CONTEXT.rcv_queue_pointer, Q_MAX_FILL_LEVEL_OFFSET
1832 .if $defined("TWO_PORT_CFG")
1833 LBCO &RCV_TEMP_REG_2.b2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 1 ;RCV_TEMP_REG_2.w2.b0
1834 .else
1835 LBCO &RCV_TEMP_REG_2.b2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 1
1837 .endif ;TWO_PORT_CFG
1838 ;compare the new queue fill level with max fill level
1839 QBGE LB_SKIP_NEW_FILL_LEVEL, RCV_TEMP_REG_2.b0, RCV_TEMP_REG_2.b2
1840 AND RCV_TEMP_REG_2.b2 , RCV_TEMP_REG_2.b0 , RCV_TEMP_REG_2.b0
1841 ; store the new max fill level
1842 .if $defined("TWO_PORT_CFG")
1843 SBCO &RCV_TEMP_REG_2.b2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 1 ;RCV_TEMP_REG_2.w2.b0
1844 .else
1845 SBCO &RCV_TEMP_REG_2.b2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 1
1847 .endif ;TWO_PORT_CFG
1848 LB_SKIP_NEW_FILL_LEVEL:
1849 LB_HOST_PORT_QUEUE_OVERFLOW_CHECK:
1850 LB_HOST_QUEUE_OVERFLOW:
1852 ADD RCV_TEMP_REG_1.w0, RCV_CONTEXT.rcv_queue_pointer, Q_OVERFLOW_CNT_OFFSET
1853 QBBS LB_PORT_QUEUE_OVERFLOW_CHECK, R6, 0 ;replaced: QBBS LB_PORT_QUEUE_OVERFLOW_CHECK, CODE_EXECUTING_FOR_PORT_RECEIVE ; 0 -> host recieve | 1 -> port recieve
1854 QBBC LB_HOST_PORT_QUEUE_OVERFLOW_CHECK_DONE, MII_RCV.rx_flags_extended, 6 ;replaced: QBBC LB_HOST_PORT_QUEUE_OVERFLOW_CHECK_DONE, MII_RCV.rx_flags_extended.host_queue_overflow
1855 QBA HOST_QUEUE_OVERFLOW_STATS
1857 LB_PORT_QUEUE_OVERFLOW_CHECK:
1858 QBBC LB_HOST_PORT_QUEUE_OVERFLOW_CHECK_DONE, MII_RCV.rx_flags_extended, 7 ;replaced: QBBC LB_HOST_PORT_QUEUE_OVERFLOW_CHECK_DONE, MII_RCV.rx_flags_extended.port_queue_overflow
1860 HOST_QUEUE_OVERFLOW_STATS:
1861 PORT_QUEUE_OVERFLOW_STATS:
1863 .if $defined("TWO_PORT_CFG")
1864 LBCO &RCV_TEMP_REG_2.b2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 1
1865 .else
1866 LBCO &RCV_TEMP_REG_2.b2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 1
1867 .endif
1868 ADD RCV_TEMP_REG_2.b2, RCV_TEMP_REG_2.b2, 1
1869 .if $defined("TWO_PORT_CFG")
1870 SBCO &RCV_TEMP_REG_2.b2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 1
1871 .else
1872 SBCO &RCV_TEMP_REG_2.b2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 1
1873 .endif
1874 LB_HOST_PORT_QUEUE_OVERFLOW_CHECK_DONE:
1875 ; Update the Queue Descriptor with the new wr_ptr
1876 ADD RCV_TEMP_REG_1.w0, RCV_CONTEXT.rcv_queue_pointer, Q_RD_PTR_SIZE
1877 .if $defined("TWO_PORT_CFG")
1878 SBCO &RCV_CONTEXT.wrkng_wr_ptr, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, Q_WR_PTR_SIZE
1879 .else
1880 SBCO &RCV_CONTEXT.wrkng_wr_ptr, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, Q_WR_PTR_SIZE
1881 .endif ;TWO_PORT_CFG
1882 .if $defined("ICSS_SWITCH_BUILD")
1883 .if $defined("TWO_PORT_CFG")
1884 QBBS LB_CHECK_COLLISION_FOR_PORT, R6, 0 ;CODE_EXECUTING_FOR_PORT_RECEIVE
1885 ; Update the collision status register with info required by the collision task.
1886 QBBC LB_UPDATE_CHECK_FWD_FLAG, MII_RCV.rx_flags, host_collision_queue_selected_shift ;MII_RCV.rx_flags.host_collision_queue_selected
1887 QBA LB_UPDATE_COLLISION_STATUS
1888 .endif ;TWO_PORT_CFG
1889 LB_CHECK_COLLISION_FOR_PORT:
1890 .if $defined("TWO_PORT_CFG")
1891 ; Update the collision status register with info required by the collision task.
1892 QBBC LB_NO_COLLISIION_OCCURED, MII_RCV.rx_flags, port_collision_queue_selected_shift ;MII_RCV.rx_flags.port_collision_queue_selected
1893 LB_UPDATE_COLLISION_STATUS:
1894 LDI RCV_TEMP_REG_1.w0, COLLISION_STATUS_ADDR
1895 AND COLLISION_STATUS_REG.b2 , MII_RCV.qos_queue , MII_RCV.qos_queue ;Warning: converted from MOV
1896 LSL COLLISION_STATUS_REG.b2, COLLISION_STATUS_REG.b2, 1
1897 OR COLLISION_STATUS_REG.b2, COLLISION_STATUS_REG.b2, 0x01
1898 QBBC LB_COLLISION_SATUS_FOR_HOST_QUEUE, R6, 0 ;CODE_EXECUTING_FOR_PORT_RECEIVE
1899 .if $defined("PRU0")
1900 ADD RCV_TEMP_REG_1.w0, RCV_TEMP_REG_1.w0, 2
1901 .else
1902 ADD RCV_TEMP_REG_1.w0, RCV_TEMP_REG_1.w0, 1
1903 .endif
1905 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, port_collision_queue_selected_shift ; Clear the collision bit for port
1906 LB_COLLISION_SATUS_FOR_HOST_QUEUE:
1907 SBCO &COLLISION_STATUS_REG.b2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 1
1909 QBBC LB_UPDATE_CHECK_FWD_FLAG, R6, 0 ;CODE_EXECUTING_FOR_PORT_RECEIVE
1910 .endif ;TWO_PORT_CFG
1911 LB_NO_COLLISIION_OCCURED:
1912 LB_UPDATE_CHECK_DONE:
1913 .endif ;ICSS_SWITCH_BUILD
1914 LB_RELEASE_QUEUE:
1915 .if $defined("ICSS_SWITCH_BUILD")
1916 QBBS LB_RELEASE_HOST_QUEUE, MII_RCV.rx_flags_extended, host_queue_overflow_shift ;MII_RCV.rx_flags_extended.host_queue_overflow
1917 QBBC LB_RELEASE_QUEUE_CHECK_FWD_FLAG, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
1918 .endif ;ICSS_SWITCH_BUILD
1919 LB_RELEASE_HOST_QUEUE:
1920 ;Release the Receive Queue. De-assert the Queue busy bit
1921 ; PRU0 is master so it clear's only "busy_m" bit
1922 .if $defined("PRU0")
1923 ADD RCV_TEMP_REG_1.w0, MII_RCV.rcv_queue_pointer, Q_STATUS_OFFSET
1924 .if $defined("TWO_PORT_CFG")
1925 LBCO &RCV_TEMP_REG_2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 3
1926 .else
1927 LBCO &RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 3
1929 .endif ;TWO_PORT_CFG
1930 AND RCV_TEMP_REG_2.b0, RCV_TEMP_REG_2.b0, 0xFC ; !(1<<Q_BUSY_M_BIT | 1<<Q_COLLISION_BIT)
1931 QBBC LB_NO_HOST_QUEUE_OVERFLOW_OCCURED, MII_RCV.rx_flags_extended, host_queue_overflow_shift ;replaced: QBBC LB_NO_HOST_QUEUE_OVERFLOW_OCCURED, MII_RCV.rx_flags_extended.host_queue_overflow
1932 OR RCV_TEMP_REG_2.b0, RCV_TEMP_REG_2.b0, 0x04 ; set the overflow bit
1933 ADD RCV_TEMP_REG_2.b2, RCV_TEMP_REG_2.b2, 1 ; increment the overflow count by 1
1934 LB_NO_HOST_QUEUE_OVERFLOW_OCCURED:
1935 .if $defined("TWO_PORT_CFG")
1936 SBCO &RCV_TEMP_REG_2.b0, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 3
1937 .else
1938 SBCO &RCV_TEMP_REG_2.b0, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 3
1939 .endif ;TWO_PORT_CFG
1941 .else
1942 ; PRU1 is slave so it clear's only "busy_s" bit
1943 ADD RCV_TEMP_REG_1.w0, MII_RCV.rcv_queue_pointer, Q_BUSY_S_OFFSET
1944 .if $defined("TWO_PORT_CFG")
1945 LBCO &RCV_TEMP_REG_2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 4
1946 .else
1947 LBCO &RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 4
1948 .endif ;TWO_PORT_CFG
1949 LDI RCV_TEMP_REG_2.b0, 0
1950 QBBC LB_NO_HOST_QUEUE_OVERFLOW_OCCURED_SLAVE, MII_RCV.rx_flags_extended, host_queue_overflow_shift ;replaced: QBBC LB_NO_HOST_QUEUE_OVERFLOW_OCCURED_SLAVE, MII_RCV.rx_flags_extended.host_queue_overflow
1951 OR RCV_TEMP_REG_2.b1, RCV_TEMP_REG_2.b1, 0x04 ; set the overflow bit
1952 ADD RCV_TEMP_REG_2.b3, RCV_TEMP_REG_2.b3, 1 ; increment the overflow count by 1
1953 LB_NO_HOST_QUEUE_OVERFLOW_OCCURED_SLAVE:
1954 .if $defined("TWO_PORT_CFG")
1955 SBCO &RCV_TEMP_REG_2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 4
1956 .else
1957 SBCO &RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 4
1958 .endif ;TWO_PORT_CFG
1959 .endif
1961 LB_RELEASE_QUEUE_CHECK_FWD_FLAG:
1962 .if $defined("ICSS_SWITCH_BUILD")
1963 QBBS LB_RELEASE_PORT_QUEUE, MII_RCV.rx_flags_extended, port_queue_overflow_shift ;MII_RCV.rx_flags_extended.port_queue_overflow
1964 QBBC LB_RELEASE_QUEUE_CHECK_DONE, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
1966 LB_RELEASE_PORT_QUEUE:
1967 ;Release the Port Receive Queue. clear busy_m bit in status as PRU is master
1969 ADD RCV_TEMP_REG_1.w0, MII_RCV_PORT.rcv_queue_pointer, Q_STATUS_OFFSET
1970 .if $defined("TWO_PORT_CFG")
1971 LBCO &RCV_TEMP_REG_2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 3
1972 .else
1973 LBCO &RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 3
1974 .endif ;TWO_PORT_CFG
1975 AND RCV_TEMP_REG_2.b0, RCV_TEMP_REG_2.b0, 0xFC ; !(1<<Q_BUSY_M_BIT | 1<<Q_COLLISION_BIT)
1976 QBBC LB_NO_PORT_QUEUE_OVERFLOW_OCCURED, MII_RCV.rx_flags_extended, port_queue_overflow_shift ;MII_RCV.rx_flags_extended.port_queue_overflow
1977 OR RCV_TEMP_REG_2.b0, RCV_TEMP_REG_2.b0, 0x04 ; set the overflow bit
1978 ADD RCV_TEMP_REG_2.b2, RCV_TEMP_REG_2.b2, 1 ; increment the overflow count by 1
1979 LB_NO_PORT_QUEUE_OVERFLOW_OCCURED:
1980 .if $defined("TWO_PORT_CFG")
1981 SBCO &RCV_TEMP_REG_2.b0, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 3
1982 .else
1983 SBCO &RCV_TEMP_REG_2.b0, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 3
1984 .endif ;TWO_PORT_CFG
1985 .if $defined(PTP)
1986 QBBC LB_RELEASE_QUEUE_CHECK_DONE, R22, PTP_RELEASE_PORT_QUEUE_BIT
1987 CLR R22, R22, PTP_RELEASE_PORT_QUEUE_BIT
1988 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, fwd_flag_shift
1989 QBA PTP_PORT_QUEUE_RELEASE_DONE
1990 .endif
1991 LB_RELEASE_QUEUE_CHECK_DONE:
1992 LB_MAINTENANCE:
1993 .endif ;ICSS_SWITCH_BUILD
1995 CLR R23 , R23 , Rcv_active ; indicate that rcv has been completed
1996 QBBS LB_NO_RX_STAT, MII_RCV.rx_flags, rx_frame_error_shift ;replaced: QBBS LB_NO_RX_STAT, MII_RCV.rx_flags.rx_frame_error
1997 SET R23 , R23 , RX_STAT_PEND
1999 .if $defined("ICSS_SWITCH_BUILD")
2000 QBBC LB_DONE, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
2001 .if $defined("TWO_PORT_CFG")
2002 QBBS LB_DONE, MII_RCV.rx_flags, host_collision_queue_selected_shift ;MII_RCV.rx_flags.host_collision_queue_selected
2003 .endif ;TWO_PORT_CFG
2004 .endif ;ICSS_SWITCH_BUILD
2006 M_RCV_RX_EOF_INTERRUPT_RAISE_INTC ; raise RX interrupt on intc controller.
2008 .if $defined("ICSS_SWITCH_BUILD")
2009 LB_DONE:
2010 .if $defined("TWO_PORT_CFG")
2011 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, host_collision_queue_selected_shift ;MII_RCV.rx_flags.host_collision_queue_selected
2012 .endif ;TWO_PORT_CFG
2013 QBBC DO_NOT_SET_RX_FWD, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
2014 .if $defined("TWO_PORT_CFG")
2015 SET R22, R22, RX_FWD_FLAG
2016 .endif ;TWO_PORT_CFG
2018 DO_NOT_SET_RX_FWD:
2019 .endif ;ICSS_SWITCH_BUILD
2021 LB_NO_RX_STAT:
2023 .if $defined("ICSS_REV1")
2024 M_RCV_RX_EOF_CLEAR_INTC_ICSS_REV1
2025 .endif ;ICSS_REV1
2027 .if $defined("ICSS_REV2")
2028 M_RCV_RX_EOF_CLEAR_INTC_ICSS_REV2
2029 .endif ;ICSS_REV2
2031 ; Execute the TX Task as next task
2032 QBBC TASK_EXECUTION_FINISHED_inter, R23, 0 ;replaced: QBBC TASK_EXECUTION_FINISHED_inter, Xmt_active
2033 LDI CURRENT_TASK_POINTER, BG_TASK_POINTER
2034 JMP XMT_QUEUE
2036 TASK_EXECUTION_FINISHED_inter:
2037 JMP TASK_EXECUTION_FINISHED
2039 .if $defined("TWO_PORT_CFG")
2040 ;/////////////////////////////// Experimenting Start /////////////////////////////////////////////////////
2042 ;-------------------------------------------------------------------------------------------
2043 ; Function: F_QUEUE_ARBITRATION
2044 ; Description: Function will aquire token for either queue or collision buffer
2045 ; Input: MII_RCV.qos_queue - contains the Qos queue number as been determined by the RX_FB function
2046 ; Input: RCV_TEMP_REG_3.w0 - contains the base address of host/port queue
2047 ; Input: RCV_TEMP_REG_3.w2 - contains the base address of the collision queue
2048 ; Input: RCV_TEMP_REG_1.b1 - contains information about whether called for host or port queue arbitration
2049 ; Output: RCV_TEMP_REG_1.b0 - returns value for caller, to indicate that the queue has been aquired
2050 ; successful ((0-failed to aquire; 1-queue; 2-collision)
2051 ; Output: RCV_TEMP_REG_2.w0 - returns the queue pointer after aquiring the queue
2052 ; Output: RCV_TEMP_REG_2.w2 - returns the current write pointer of the queue that has been aquired
2053 ; is used as wrkng_wr_ptr during the following packet processing
2054 ; RCV_TEMP_REG_1.w2 - temporayr use
2055 ;-------------------------------------------------------------------------------------------
2057 FN_QUEUE_ARBITRATION:
2058 LDI RCV_TEMP_REG_1.b0, 0x00
2059 QAM_CHECK:
2060 LSL RCV_TEMP_REG_1.w2, MII_RCV.qos_queue, 3 ; adjust queue-number offset to 8byte boundaries
2061 QBNE PICK_NORMAL_QUEUE, RCV_TEMP_REG_1.b0, COLLISION_AQUIRED
2062 LDI RCV_TEMP_REG_1.w2, 0x0
2063 PICK_NORMAL_QUEUE:
2064 ADD RCV_TEMP_REG_1.w2, RCV_TEMP_REG_3.w0, RCV_TEMP_REG_1.w2 ; adjust for queue base address
2065 ADD RCV_TEMP_REG_3.w0, RCV_TEMP_REG_1.w2, Q_BUSY_S_OFFSET ; .w2 points to Q_BUSY_S_OFFSET
2066 ADD RCV_TEMP_REG_1.w2, RCV_TEMP_REG_1.w2, Q_STATUS_OFFSET ; .w0 points to Q_STATUS_OFFSET
2067 LBCO &RCV_TEMP_REG_2.w2, PRU1_DMEM_CONST, RCV_TEMP_REG_3.w0, Q_BUSY_S_SIZE + Q_STATUS_SIZE ; load busy_s + status of this queue
2068 ; Check if it is called for the Port Arbitration
2069 QBBS PORT_QUEUE_ARBITRATION, RCV_TEMP_REG_1.b1, 0 ;RCV_TEMP_REG_1.b1.t0
2070 .if $defined("PRU0")
2071 QBBS QAM_BUSY, RCV_TEMP_REG_2.b2, Q_BUSY_S_BIT ; is queue already busy? PRU0 is master ;RCV_TEMP_REG_2.w2.b0
2072 SET RCV_TEMP_REG_2.b3, RCV_TEMP_REG_2.b3, Q_BUSY_M_BIT ;RCV_TEMP_REG_2.w2.b1
2073 SBCO &RCV_TEMP_REG_2.b3, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w2, Q_STATUS_SIZE ; set busy_m into memory
2074 QBA QAM_CALC_QUEUE_POINTER
2075 .else
2076 QBBS QAM_BUSY, RCV_TEMP_REG_2.b3, Q_BUSY_M_BIT ; is queue already busy? PRU1 is slave ;RCV_TEMP_REG_2.w2.b1
2077 SET RCV_TEMP_REG_2.b2, RCV_TEMP_REG_2.b2, Q_BUSY_S_BIT ;RCV_TEMP_REG_2.w2.b0
2078 SBCO &RCV_TEMP_REG_2.b2, PRU1_DMEM_CONST, RCV_TEMP_REG_3.w0, Q_BUSY_S_SIZE ; set busy_s into memory
2079 ; load again busy_m ..only for Slave because it needs to check that master has not acquired the queue inbetween
2080 LBCO &RCV_TEMP_REG_2.b3, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w2, Q_STATUS_SIZE ;RCV_TEMP_REG_2.w2.b1
2081 QBBC QAM_CALC_QUEUE_POINTER, RCV_TEMP_REG_2.b3, Q_BUSY_M_BIT ; is queue already busy?
2082 ; Clear busy_s bit because busy_m bit is set
2083 CLR RCV_TEMP_REG_2.b2, RCV_TEMP_REG_2.b2, Q_BUSY_S_BIT ;RCV_TEMP_REG_2.w2.b0
2084 SBCO &RCV_TEMP_REG_2.b2, PRU1_DMEM_CONST, RCV_TEMP_REG_3.w0, Q_BUSY_S_SIZE ; clear busy_s into memory ;RCV_TEMP_REG_2.w2.b0
2085 QBA QAM_BUSY
2086 .endif
2088 PORT_QUEUE_ARBITRATION:
2089 QBBS QAM_BUSY, RCV_TEMP_REG_2.b2, Q_BUSY_S_BIT ; is queue already busy? PRU0 is master ;RCV_TEMP_REG_2.w2.b0
2090 SET RCV_TEMP_REG_2.b3, RCV_TEMP_REG_2.b3, Q_BUSY_M_BIT ;RCV_TEMP_REG_2.w2.b1
2091 SBCO &RCV_TEMP_REG_2.b3, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w2, Q_STATUS_SIZE ; set busy_m into memory
2092 QBA QAM_CALC_QUEUE_POINTER
2094 QAM_BUSY: ; failed to aquire the queue, now try the colission
2095 QBEQ QAM_FAILED, RCV_TEMP_REG_1.b0, COLLISION_AQUIRED
2096 AND RCV_TEMP_REG_3.w0 , RCV_TEMP_REG_3.w2 , RCV_TEMP_REG_3.w2
2097 LDI RCV_TEMP_REG_1.b0, COLLISION_AQUIRED ; failed to aquire the queue, indicate this to macro caller by returing 0
2098 ;check that host has emptied the queue before acquiring it
2099 LDI RCV_TEMP_REG_1.w2, COLLISION_STATUS_ADDR
2100 ADD RCV_TEMP_REG_1.w2, RCV_TEMP_REG_1.w2, 3
2101 LBCO &RCV_TEMP_REG_1.b3, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w2, 1
2102 QBBC QAM_CHECK, RCV_TEMP_REG_1, 3 ;replaced: QBBC QAM_CHECK, RCV_TEMP_REG_1.HOST_COLLISION_READ_PENDING
2104 QAM_FAILED:
2105 LDI RCV_TEMP_REG_1.b0, QUEUE_FAILED ; failed to aquire queue & collision
2106 LDI RCV_TEMP_REG_2.w2, 0
2107 QBA QAM_DONE
2108 QAM_CALC_QUEUE_POINTER:
2109 QBEQ PICK_COL_QUEUE, RCV_TEMP_REG_1.b0, COLLISION_AQUIRED
2110 ; return value that queue had been aquired OK.
2111 LDI RCV_TEMP_REG_1.b0, QUEUE_AQUIRED
2112 PICK_COL_QUEUE:
2113 ; adjust the pointer to the wr_ptr offset
2114 SUB RCV_TEMP_REG_2.w0, RCV_TEMP_REG_1.w2, Q_STATUS_OFFSET - Q_WR_PTR_OFFSET
2115 ; load wr_ptr from memory, and us it to init the wrkng_wr_ptr
2116 LBCO &RCV_TEMP_REG_2.w2, PRU1_DMEM_CONST, RCV_TEMP_REG_2.w0, Q_WR_PTR_SIZE
2117 ; ToDo: this can be optimized!
2118 SUB RCV_TEMP_REG_2.w0, RCV_TEMP_REG_2.w0, Q_WR_PTR_OFFSET
2119 QAM_DONE:
2120 JMP CALL_REG
2122 ;////////////////////////////// Experimenting End ////////////////////////////////////////////////////////////////////
2123 .endif ;TWO_PORT_CFG
2124 .endif ; e/o MII_Rcv_p