[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 ;PINDSW-4577: Fix to avoid cut-through packets from going via Storm Prevention
516 ;Storm prevention is done only if host receive flag is set
517 QBBC FB_CONT_CT_CHECK, MII_RCV.rx_flags , host_rcv_flag_shift
519 ; Storm Prevention
520 QBBC FB_STORM_NOT_MC, R22, RX_MC_FRAME
521 LDI RCV_TEMP_REG_3 , STORM_PREVENTION_OFFSET_MC
522 ;Do storm prevention here
523 LBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4 ; load the current storm prevent count
524 QBBC FB_CONT_CT_CHECK, RCV_TEMP_REG_2, 0
525 LSR RCV_TEMP_REG_2, RCV_TEMP_REG_2, 8
526 QBGT FB_DISCARD_MC, RCV_TEMP_REG_2.w0, 1 ; check if the counter is less than zero and discard packet
527 SUB RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1
528 LSL RCV_TEMP_REG_2, RCV_TEMP_REG_2, 8
529 SET RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 0
530 SBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
532 QBA FB_CONT_CT_CHECK
533 FB_STORM_NOT_MC:
534 QBBC FB_STORM_NOT_BC, R22, RX_BC_FRAME
535 LDI RCV_TEMP_REG_3 , STORM_PREVENTION_OFFSET_BC
536 ;Do storm prevention here
537 LBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4 ; load the current storm prevent count
538 QBBC FB_CONT_CT_CHECK, RCV_TEMP_REG_2, 0
539 LSR RCV_TEMP_REG_2, RCV_TEMP_REG_2, 8
540 QBGT FB_DISCARD_BC, RCV_TEMP_REG_2.w0, 1 ; check if the counter is less than zero and discard packet
541 SUB RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1
542 LSL RCV_TEMP_REG_2, RCV_TEMP_REG_2, 8
543 SET RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 0
544 SBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
546 QBA FB_CONT_CT_CHECK
547 FB_STORM_NOT_BC:
548 LDI RCV_TEMP_REG_3 , STORM_PREVENTION_OFFSET_UC
549 ;Do storm prevention here
550 LBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4 ; load the current storm prevent count
551 QBBC FB_CONT_CT_CHECK, RCV_TEMP_REG_2, 0
552 LSR RCV_TEMP_REG_2, RCV_TEMP_REG_2, 8
553 QBGT FB_DISCARD_UC, RCV_TEMP_REG_2.w0, 1 ; check if the counter is less than zero and discard packet
554 SUB RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1
555 LSL RCV_TEMP_REG_2, RCV_TEMP_REG_2, 8
556 SET RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 0
557 SBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
559 QBA FB_CONT_CT_CHECK
561 FB_DISCARD_MC:
562 LDI RCV_TEMP_REG_3 , STORM_PREVENTION_COUNTER_MC
563 QBA COUNT_RX_STATS
564 FB_DISCARD_BC:
565 LDI RCV_TEMP_REG_3 , STORM_PREVENTION_COUNTER_BC
566 QBA COUNT_RX_STATS
567 FB_DISCARD_UC:
568 LDI RCV_TEMP_REG_3 , STORM_PREVENTION_COUNTER_UC
569 QBA COUNT_RX_STATS
571 FB_CONT_CT_CHECK:
572 .if $defined("TWO_PORT_CFG")
574 .if $defined("ICSS_STP_SWITCH")
575 CHECK_STP_LEARNING:
576 ; Only forward packet if STP state is FORWARDING
577 AND RCV_TEMP_REG_1.b0, STP_STATE__R22_BYTE, STP_STATE__R22_MASK ; read STP state in R22
578 QBNE SKIP_FORWARDING, RCV_TEMP_REG_1.b0, STP_STATE_FORWARDING ; STP State for current port is stored in R22
580 ; Only forward packet if the OTHER port state is FORWARDING
581 .if $defined("PRU0")
582 ; Read Port 2 STP state
583 LDI32 RCV_TEMP_REG_3, ICSS_EMAC_FW_FDB__STP_P2_STP_STATE_ADDR
584 .else
585 ; Read Port 1 STP state
586 LDI32 RCV_TEMP_REG_3, ICSS_EMAC_FW_FDB__STP_P1_STP_STATE_ADDR
587 .endif ; $defined("PRU0")
588 LBBO &RCV_TEMP_REG_1.b0, RCV_TEMP_REG_3, 0, 1
590 QBNE SKIP_FORWARDING, RCV_TEMP_REG_1.b0, STP_STATE_FORWARDING
592 SET_FORWARDING:
593 .endif ; ICSS_STP_SWITCH
594 QBBS FB_NO_CT, R23, 0 ;Xmt_active ; check if we can set cut-through
595 QBBC FB_NO_CT, R22, 31 ;PACKET_TX_ALLOWED
596 QBA FB_CT_HANDLING
598 FB_NO_CT:
599 SET MII_RCV.rx_flags, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
600 JMP FB_LT_VT
601 FB_CT_HANDLING:
602 SET MII_RCV.tx_flags, MII_RCV.tx_flags, cut_through_flag_shift ;MII_RCV.tx_flags.cut_through_flag
604 .if $defined("ICSS_STP_SWITCH")
605 SKIP_FORWARDING:
606 .endif ; ICSS_STP_SWITCH
607 FB_LT_VT:
609 ;check link on other port
610 QBBS FB_EGRESS_LINK_UP, R22, 10 ;replaced: QBBS FB_EGRESS_LINK_UP, OPPOSITE_PORT_LINK_UP
612 ; OPT: See whether they can be moved next to each other
613 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, fwd_flag_shift
614 CLR MII_RCV.tx_flags, MII_RCV.tx_flags, cut_through_flag_shift
616 ;If host receive flag is not set then increment statistics for dropped frames
617 QBBS FB_EGRESS_LINK_UP, MII_RCV.rx_flags, host_rcv_flag_shift
618 LDI RCV_TEMP_REG_3, RX_DROPPED_FRAMES_OFFSET
619 CLR R22, R22, RX_BC_FRAME
620 CLR R22, R22, RX_MC_FRAME
621 LBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
622 ADD RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1
623 SBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
626 FB_EGRESS_LINK_UP:
628 QBBC FB_LT_VT_2, MII_RCV.tx_flags, cut_through_flag_shift
630 LDI CUT_THROUGH_BYTE_CNT, 0x0000
632 ; Insert first 12 bytes in the TX FIFO of opposit
633 .if $defined("ICSS_REV1")
634 LDI TX_DATA_WORD_MASK , 0xffff
635 AND TX_DATA_BYTE , BUFFER.b0 , BUFFER.b0
636 M_PUSH_BYTE
637 AND TX_DATA_BYTE , BUFFER.b1 , BUFFER.b1
638 M_PUSH_BYTE
640 ;MOV loop_cnt, 2
641 LDI TX_DATA_POINTER, buffer_ptr + 2
642 loop FB_RCV_EndLoop_1, 2
643 MVIW TX_DATA_WORD, *TX_DATA_POINTER
644 M_PUSH_WORD_CMD
645 ADD TX_DATA_POINTER, TX_DATA_POINTER, 2
646 FB_RCV_EndLoop_1:
647 .endif
648 .if $defined("ICSS_REV2")
649 LDI TX_DATA_POINTER, buffer_ptr
650 loop FB_RCV_EndLoop_1, 3
651 MVID TX_DATA_DOUBLE_WORD, *TX_DATA_POINTER
652 ADD TX_DATA_POINTER, TX_DATA_POINTER, 4
653 FB_RCV_EndLoop_1:
654 .endif
655 .endif ;TWO_PORT_CFG
656 FB_LT_VT_2: ; Quality of service --> select RX queue priority based on Ethernet frame tags
658 XIN RX_L2_BANK0_ID, &R18, RANGE_R18_b0 ; XIN RX L2 bank 0 R18 value
659 XIN RX_L2_BANK0_ID, &R2, RANGE_R2_R13 ; XIN RX L2 bank 0 R2 - R13 value
661 .if $defined(PTP)
662 M_GPTP_ASSIGN_QOS
663 .endif ;PTP
665 .if $defined("TWO_PORT_CFG")
666 ; The naming of the QoS queue goes from 1..4, but we need to count from 0..3
667 LDI MII_RCV.qos_queue, 4-1 ; default (lowest priority) queue is 4
669 FB_QOS_APPLY_RULES:
670 LDI RCV_TEMP_REG_1.w0, 0x0081 ; 0x8100 --> indicates QOS tagged frame
671 QBNE FB_QOS_DONE, Ethernet.TPID, RCV_TEMP_REG_1.w0
672 LSR RCV_TEMP_REG_1.b0, R5.b2, 5 ; extract PCP info. FIXME: clpru : Ethernet.TCI.b0 -> R5.b2
673 QBGT FB_QOS_CHECK_FOR_PRIO2, RCV_TEMP_REG_1.b0, 6 ; PCP == 7/6
674 LDI MII_RCV.qos_queue, 1-1 ; highest priority is 1, select queue 1
676 QBA FB_QOS_DONE
677 FB_QOS_CHECK_FOR_PRIO2:
678 QBGT FB_QOS_CHECK_FOR_PRIO3, RCV_TEMP_REG_1.b0, 4 ; PCP == 5/4
679 LDI MII_RCV.qos_queue, 2-1 ; priority is 2, select queue 2
680 QBA FB_QOS_DONE
681 FB_QOS_CHECK_FOR_PRIO3:
682 QBGT FB_QOS_DONE, RCV_TEMP_REG_1.b0, 2 ; PCP == 3/2
683 LDI MII_RCV.qos_queue, 3-1 ; priority is 3, select queue 3
684 QBA FB_QOS_DONE
685 ; if PCP == 1/0, this priority 4, default queue already selected
686 FB_QOS_LOADED:
687 FB_QOS_DONE:
688 FB_DONE:
689 .else
690 .if $defined("PRU0")
691 ; The naming of the QoS queue goes from 1..4, but we need to count from 0..3
692 LDI MII_RCV.qos_queue, 2-1 ; default (lowest priority) queue is 2 for PRU0
693 .else
694 LDI MII_RCV.qos_queue, 4-1 ; default (lowest priority) queue is 4 for PRU1
695 .endif
697 FB_QOS_APPLY_RULES:
698 LDI RCV_TEMP_REG_1.w0, 0x0081 ; 0x8100 --> indicates QOS tagged frame
699 QBNE FB_QOS_DONE, Ethernet.TPID, RCV_TEMP_REG_1.w0
700 LSR RCV_TEMP_REG_1.b0, Ethernet.TCI.x_b.b0, 5 ; extract PCP info
702 .if $defined("PRU0")
703 QBGT FB_QOS_DONE, RCV_TEMP_REG_1.b0, 4 ; PCP == 7/6
704 LDI MII_RCV.qos_queue, 1-1 ; highest priority is 1, select queue 1
705 .else
706 QBGT FB_QOS_DONE, RCV_TEMP_REG_1.b0, 4 ; PCP == 7/6
707 LDI MII_RCV.qos_queue, 3-1 ; highest priority is 3, select queue 3
708 .endif
709 QBA FB_QOS_DONE
711 ; if PCP == 1/0, this priority 4, default queue already selected
712 FB_QOS_LOADED:
713 FB_QOS_DONE:
714 FB_DONE:
715 .endif ;TWO_PORT_CFG
717 .if $defined("TWO_PORT_CFG")
718 ;Check if cut-through bit is set ..if yes then push 10 more bytes in Tx_fifo and remain in Rx_Task itself
719 ; OPT : Below bytes can be pushed early in the Profinet
720 QBBC FB_DONE_NORMAL, MII_RCV.tx_flags, cut_through_flag_shift ; is cut-through flag set?
721 ; We enter the task with 14 bytes but here we always have 16 bytes even for non HSR frames
722 .if $defined("ICSS_REV1")
723 loop FB_RCV_EndLoop_2, 5
724 MVIW TX_DATA_WORD, *TX_DATA_POINTER
725 M_PUSH_WORD_CMD
726 ADD TX_DATA_POINTER, TX_DATA_POINTER, 2
727 FB_RCV_EndLoop_2:
728 .endif
729 .if $defined("ICSS_REV2")
730 MVID TX_DATA_DOUBLE_WORD, *TX_DATA_POINTER
731 ADD TX_DATA_POINTER, TX_DATA_POINTER, 4
732 .endif
734 LDI PREVIOUS_R18_RCV_BYTECOUNT, 16
735 ADD CUT_THROUGH_BYTE_CNT, CUT_THROUGH_BYTE_CNT, 16
737 FB_DONE_NORMAL:
738 .endif
739 ; Fill the rcv context with host/port queue base pointer, rd_ptr and wrk_pointer
740 QBNE FB_CHECK_QUEUE_2, MII_RCV.qos_queue, 0
741 .if $defined("TWO_PORT_CFG")
742 LDI RX_CONTEXT_OFFSET, P0_Q1_RX_CONTEXT_OFFSET
744 .if $defined("PRU0")
745 LDI RX_PORT_CONTEXT_OFFSET, P2_Q1_RX_CONTEXT_OFFSET
746 .else
747 LDI RX_PORT_CONTEXT_OFFSET, P1_Q1_RX_CONTEXT_OFFSET
748 .endif
749 .else
750 LDI RX_CONTEXT_OFFSET , HOST_Q1_RX_CONTEXT_OFFSET ; Select queue based on QOS
751 .endif
752 QBA Initialize_rcv_context
754 ;end_buffer_desc_offset
755 FB_CHECK_QUEUE_2:
756 QBNE FB_CHECK_QUEUE_3, MII_RCV.qos_queue, 1
757 .if $defined("TWO_PORT_CFG")
758 LDI RX_CONTEXT_OFFSET, P0_Q2_RX_CONTEXT_OFFSET
759 .if $defined("PRU0")
760 LDI RX_PORT_CONTEXT_OFFSET, P2_Q2_RX_CONTEXT_OFFSET
761 .else
762 LDI RX_PORT_CONTEXT_OFFSET, P1_Q2_RX_CONTEXT_OFFSET
763 .endif
765 .else
766 LDI RX_CONTEXT_OFFSET , HOST_Q2_RX_CONTEXT_OFFSET ; Select queue based on QOS
767 .endif
768 QBA Initialize_rcv_context
770 FB_CHECK_QUEUE_3:
771 QBNE FB_CHECK_QUEUE_4, MII_RCV.qos_queue, 2
772 .if $defined("TWO_PORT_CFG")
774 LDI RX_CONTEXT_OFFSET, P0_Q3_RX_CONTEXT_OFFSET
776 .if $defined("PRU0")
777 LDI RX_PORT_CONTEXT_OFFSET, P2_Q3_RX_CONTEXT_OFFSET
778 .else
779 LDI RX_PORT_CONTEXT_OFFSET, P1_Q3_RX_CONTEXT_OFFSET
780 .endif
782 .else
783 LDI RX_CONTEXT_OFFSET , HOST_Q3_RX_CONTEXT_OFFSET ; Select queue based on QOS
784 .endif
785 QBA Initialize_rcv_context
787 FB_CHECK_QUEUE_4:
788 .if $defined("TWO_PORT_CFG")
790 LDI RX_CONTEXT_OFFSET, P0_Q4_RX_CONTEXT_OFFSET
791 .if $defined("PRU0")
792 LDI RX_PORT_CONTEXT_OFFSET, P2_Q4_RX_CONTEXT_OFFSET
793 .else
794 LDI RX_PORT_CONTEXT_OFFSET, P1_Q4_RX_CONTEXT_OFFSET
795 .endif
796 .else
797 LDI RX_CONTEXT_OFFSET , HOST_Q4_RX_CONTEXT_OFFSET ; Select queue based on QOS
798 .endif
800 Initialize_rcv_context:
801 QBBC FB_FILL_RCV_CONTEXT_PORT_QUEUE, MII_RCV.rx_flags, host_rcv_flag_shift
802 ; Read the RX Context of Host Port of 8 bytes
803 .if $defined("TWO_PORT_CFG")
804 LBCO &MII_RCV.base_buffer_index, PRU1_DMEM_CONST, RX_CONTEXT_OFFSET, 8
805 .else
806 LBCO &MII_RCV.base_buffer_index, ICSS_SHARED_CONST, RX_CONTEXT_OFFSET, 8
807 .endif
809 FB_FILL_RCV_CONTEXT_PORT_QUEUE:
810 .if $defined("TWO_PORT_CFG")
812 QBBC FB_PKT_NOT_FORWARDED, MII_RCV.rx_flags, fwd_flag_shift
813 ; Read the RX Context of Port of 8 bytes
814 LBCO &MII_RCV_PORT.base_buffer_index, PRU1_DMEM_CONST, RX_PORT_CONTEXT_OFFSET, 8
815 FB_PKT_NOT_FORWARDED:
816 .endif ;TWO_PORT_CFG
817 ; OPT: If R0.b0 is not changed then remove below instruction. it is to make sure at R0.b0 is 0
818 LDI R0.b0, SHIFT_NONE
819 .if $defined("PRU0")
820 XOUT BANK1, &MII_RCV, $sizeof(MII_RCV) ; store task parameters in parameter bank
821 .else
822 XOUT BANK2, &MII_RCV, $sizeof(MII_RCV) ; store task parameters in parameter bank
823 .endif
824 .if $defined("TWO_PORT_CFG")
825 .if $defined("PRU0")
826 LDI R0.b0, SHIFT_R14_TO_R0
827 XOUT BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT) ; store task parameters in parameter bank
828 .else
829 LDI R0.b0, SHIFT_R14_TO_R4
830 XOUT BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT) ; store task parameters in parameter bank
831 .endif
834 QBBS FN_RCV_NB, MII_RCV.tx_flags, cut_through_flag_shift
835 .endif ;TWO_PORT_CFG
837 .if $defined("ICSS_DUAL_EMAC_BUILD")
838 ;The following check is required in case of firmware lag
839 ;when the firmware runs late compared to RX L2 FIFO.
840 ;This was being experienced in Profinet Switch and the same is possible here.
841 ;Haven't been able to reproduce this in EMAC.
842 XIN RX_L2_BANK0_ID, &R18, RANGE_R18_b0
843 QBGT FB_RCV_EXIT, R18.b0, 32
844 LDI CURRENT_TASK_POINTER, TX_TASK_POINTER
845 JMP FN_RCV_NB
846 .endif
848 FB_RCV_EXIT:
849 JMP CALL_REG
852 ;****************************************************************************
853 ;
854 ; NAME : FN_RCV_NB
855 ; DESCRIPTION : receives the next 32Byte block of RX L2
856 ; RETURNS :
857 ; ARGS :
858 ; USES :
859 ; INVOKES :
860 ;
861 ;****************************************************************************
862 FN_RCV_NB:
864 ; for XIN, make sure that shift is set to 0
865 LDI R0.b0, SHIFT_NONE
866 ; restore task parameters in parameter bank
867 .if $defined("PRU0")
868 XIN BANK1, &MII_RCV, $sizeof(MII_RCV)
869 .else
870 XIN BANK2, &MII_RCV, $sizeof(MII_RCV)
871 .endif
872 .if $defined("TWO_PORT_CFG")
873 ;parameters for Port Receive
874 ; OPT: Move it after the XIN of data
875 .if $defined("PRU0")
876 LDI R0.b0, SHIFT_R14_TO_R0
877 XIN BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT)
878 .else
879 LDI R0.b0, SHIFT_R14_TO_R4
880 XIN BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT)
881 .endif
882 .endif
883 ; this task is getting called by MS, first check is to see if we are currently receiving
884 QBBC NB_DONE_NO_PARAM_STORE, R23, Rcv_active
885 QBBS NB_DONE_NO_PARAM_STORE, MII_RCV.rx_flags, rx_frame_error_shift
887 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
888 ; that L2 fifo has received 32 or 64 bytes ..which helps in calling NB_PROCESS_32BYTES early
889 ; depending on the bank index, we load bank 0 or bank 1
890 QBBS NB_XIN_UPPER_BANK, MII_RCV.rx_flags, rx_bank_index_shift
892 NB_XIN_LOWER_BANK:
893 ; OPT: Just one XIN is needed
894 XIN RX_L2_BANK0_ID, &R18, RANGE_R18_b0
895 XIN RX_L2_BANK0_ID, &R2, RANGE_R2_R13 ; XIN RX L2 bank 0
896 QBA NB_CHECK_AMOUNT_OF_BYTES
897 NB_XIN_UPPER_BANK:
898 ; OPT: Just one XIN is needed
899 XIN RX_L2_BANK1_ID, &R18, RANGE_R18_b0
900 XIN RX_L2_BANK1_ID, &R2, RANGE_R2_R13 ; XIN RX L2 bank 1
902 NB_CHECK_AMOUNT_OF_BYTES:
903 .if $defined("ICSS_SWITCH_BUILD")
904 QBBC check_for_32bytes, MII_RCV.tx_flags, cut_through_flag_shift ;MII_RCV.tx_flags.cut_through_flag
905 SUB RCV_TEMP_REG_1, R18_RCV_BYTECOUNT, PREVIOUS_R18_RCV_BYTECOUNT
906 .if $defined("ICSS_REV1")
907 QBGT NB_DONE, RCV_TEMP_REG_1, 2
909 NB_PUSH_NEXT_WORD_TO_FIFO:
910 QBEQ check_for_32bytes, R1.b3, 0x28
911 ADD PREVIOUS_R18_RCV_BYTECOUNT, PREVIOUS_R18_RCV_BYTECOUNT, 2
912 MVIW TX_DATA_WORD, *R1.b3
913 M_PUSH_WORD_CMD
914 ADD CUT_THROUGH_BYTE_CNT, CUT_THROUGH_BYTE_CNT, 2
915 ADD R1.b3, R1.b3, 2
916 SUB RCV_TEMP_REG_1, RCV_TEMP_REG_1, 2
917 QBLE NB_PUSH_NEXT_WORD_TO_FIFO, RCV_TEMP_REG_1, 2
918 .endif
919 .if $defined("ICSS_REV2")
920 QBGT NB_DONE, RCV_TEMP_REG_1, 4
922 NB_PUSH_NEXT_DOUBLE_WORD_TO_FIFO:
923 QBEQ check_for_32bytes, R1.b3, 0x28
924 ADD PREVIOUS_R18_RCV_BYTECOUNT, PREVIOUS_R18_RCV_BYTECOUNT, 4
925 MVID TX_DATA_DOUBLE_WORD, *R1.b3
926 ADD CUT_THROUGH_BYTE_CNT, CUT_THROUGH_BYTE_CNT, 4
927 ADD R1.b3, R1.b3, 4
928 SUB RCV_TEMP_REG_1, RCV_TEMP_REG_1, 4
929 QBLE NB_PUSH_NEXT_DOUBLE_WORD_TO_FIFO, RCV_TEMP_REG_1, 4
930 .endif
931 check_for_32bytes:
932 .endif
933 QBBS NB_CHECK_AMOUNT_OF_BYTES_BIGGER_32_BANK1, MII_RCV.rx_flags, rx_bank_index_shift ; check which bank to read
935 ; for bank 0, R18.b0 >=32 bytes
936 QBGT NB_DONE, R18_RCV_BYTECOUNT, 32
937 ;LDI R1.b3, buffer_ptr
938 QBA NB_PROCESS_32BYTES
940 NB_CHECK_AMOUNT_OF_BYTES_BIGGER_32_BANK1:
942 ; for bank 1, R18.b0 <32 bytes
943 QBLE NB_DONE, R18_RCV_BYTECOUNT, 32
945 .if $defined("ICSS_SWITCH_BUILD")
946 QBBC NB_PROCESS_32BYTES_CT, MII_RCV.tx_flags, cut_through_flag_shift ;MII_RCV.tx_flags.cut_through_flag
947 QBEQ NB_PROCESS_32BYTES_CT, R1.b3, 0x28
948 .if $defined("ICSS_REV1")
949 MVIW TX_DATA_WORD, *R1.b3
950 M_PUSH_WORD_CMD
951 ADD CUT_THROUGH_BYTE_CNT, CUT_THROUGH_BYTE_CNT, 2
952 .endif
953 .if $defined("ICSS_REV2")
954 MVID TX_DATA_DOUBLE_WORD, *R1.b3
955 ADD CUT_THROUGH_BYTE_CNT, CUT_THROUGH_BYTE_CNT, 4
956 .endif
957 NB_PROCESS_32BYTES_CT:
958 .endif
959 LDI PREVIOUS_R18_RCV_BYTECOUNT, 0x00
961 ;***********************************
962 ; 32 bytes handling, no cut through
963 ;***********************************
964 NB_PROCESS_32BYTES: ; 32 Bytes of new data are in the buffer
966 LDI R1.b3, buffer_ptr ; load the buffer pointer
968 NB_PROCESS_CHECK_BYTE_CNTR:
969 ; if this is the first 32 bytes of data, need to init the buffer queues
970 QBNE NB_PROCESS_32BYTES_CHECK_FLAGS, MII_RCV.byte_cntr, 0
972 .if $defined("ICSS_SWITCH_BUILD")
973 .if $defined("TWO_PORT_CFG")
974 QBNE NB_PROCESS_32BYTES_CHECK_FLAGS, MII_RCV_PORT.byte_cntr, 0
975 .endif ;TWO_PORT_CFG
977 QBBC NB_PROCESS_32BYTES_INIT_PORT_QUEUE, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
979 NB_PROCESS_32BYTES_INIT_HOST_QUEUE:
980 .if $defined("TWO_PORT_CFG")
981 LDI RCV_TEMP_REG_3.w0, P0_QUEUE_DESC_OFFSET
982 LDI RCV_TEMP_REG_3.w2, P0_COL_QUEUE_DESC_OFFSET
983 ; Calling for host queue
984 LDI RCV_TEMP_REG_1.b1, 0
985 ; get queue
986 JAL CALL_REG, FN_QUEUE_ARBITRATION
987 ;RCV_TEMP_REG_1.b0 --> OUTPUT: returns information if the queue has been
988 ;aquired successful ((0-failed to aquire; 1-queue; 2-collision)
989 QBNE NB_PROCESS_32BYTES_INIT_HOST_QUEUE_OK, RCV_TEMP_REG_1.b0, 0
990 ; OPT: Can't fail
991 NB_PROCESS_32BYTES_INIT_HOST_QUEUE_FAILED:
992 ; clear host receive flag
993 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, host_rcv_flag_shift
995 ; ToDo: Do we need to add code for statistics? We should never fail to aquire the queue or the coll-queue
996 QBA NB_PROCESS_32BYTES_INIT_PORT_QUEUE
997 NB_PROCESS_32BYTES_INIT_HOST_QUEUE_OK:
998 ;CLR MII_RCV.rx_flags.host_collision_queue_selected ; ToDo: this could be removed when parameter are init with 0 at b/o frame
999 ; 2-collision selected?
1000 QBNE NB_PROCESS_32BYTES_INIT_HOST_QUEUE_NO_COLL_SELECTED, RCV_TEMP_REG_1.b0, COLLISION_AQUIRED
1002 ; Initialize the RCV CONTEXT with the data of Host Collision Queue
1003 SET MII_RCV.rx_flags, MII_RCV.rx_flags, host_collision_queue_selected_shift
1004 LDI RCV_TEMP_REG_1.w0, COL_RX_CONTEXT_P0_OFFSET_ADDR
1005 LBCO &MII_RCV.buffer_index, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 10
1006 .endif ;TWO_PORT_CFG
1007 NB_PROCESS_32BYTES_INIT_HOST_QUEUE_NO_COLL_SELECTED:
1008 .endif
1009 ;Initialize the wrkng_wr_ptr and rd_ptr here as the other PRU might have changed them between Now and RCV_FB
1010 LBCO &RCV_QUEUE_DESC_REG, QUEUE_DESP_BASE, MII_RCV.rcv_queue_pointer, 4
1011 AND MII_RCV.rd_ptr , RCV_QUEUE_DESC_REG.rd_ptr , RCV_QUEUE_DESC_REG.rd_ptr
1012 AND MII_RCV.wrkng_wr_ptr , RCV_QUEUE_DESC_REG.wr_ptr , RCV_QUEUE_DESC_REG.wr_ptr
1014 ; Rx interrupt pacing
1015 ; If the rd_ptr & wr_ptr are equal => queue is empty => SET HOST_QUEUE_EMPTY_STATUS
1016 QBNE HOST_QUEUE_NOT_EMPTY, RCV_QUEUE_DESC_REG.rd_ptr, RCV_QUEUE_DESC_REG.wr_ptr
1017 SET R22, R22, HOST_QUEUE_EMPTY_STATUS
1019 HOST_QUEUE_NOT_EMPTY:
1020 .if $defined("TWO_PORT_CFG")
1021 QBBS NB_RCV_CONTEXT_INITIALIZED_WITH_COLLISION, MII_RCV.rx_flags, host_collision_queue_selected_shift
1022 .endif ;TWO_PORT_CFG
1023 ; Compute the adress in L3 RAM where the packet is received
1024 SUB RCV_BUFFER_DESC_OFFSET, MII_RCV.wrkng_wr_ptr, MII_RCV.base_buffer_desc_offset
1025 LSL RCV_BUFFER_DESC_OFFSET, RCV_BUFFER_DESC_OFFSET, 3
1026 ADD MII_RCV.buffer_index, MII_RCV.base_buffer_index, RCV_BUFFER_DESC_OFFSET
1028 .if $defined("ICSS_SWITCH_BUILD")
1029 NB_RCV_CONTEXT_INITIALIZED_WITH_COLLISION:
1031 NB_PROCESS_32BYTES_INIT_PORT_QUEUE:
1032 ; check if selected
1033 .if $defined("TWO_PORT_CFG")
1035 QBBC NB_PROCESS_32BYTES_CHECK_FLAGS, MII_RCV.rx_flags, fwd_flag_shift
1037 .if $defined("PRU0")
1038 LDI RCV_TEMP_REG_3.w0, P2_QUEUE_DESC_OFFSET
1039 LDI RCV_TEMP_REG_3.w2, P2_COL_QUEUE_DESC_OFFSET
1040 .else
1041 LDI RCV_TEMP_REG_3.w0, P1_QUEUE_DESC_OFFSET
1042 LDI RCV_TEMP_REG_3.w2, P1_COL_QUEUE_DESC_OFFSET
1043 .endif
1044 ; get queue
1045 ;CALL FN_QUEUE_ARBITRATION_PORT_RCV
1046 ; Calling for port queue
1047 LDI RCV_TEMP_REG_1.b1, 1
1048 JAL CALL_REG, FN_QUEUE_ARBITRATION
1049 ;RCV_TEMP_REG_1.b0 --> OUTPUT: returns information if the queue has
1050 ;been acquired successful ((0-failed to acquire; 1-queue; 2-collision)
1051 QBNE NB_PROCESS_32BYTES_INIT_PORT_QUEUE_OK, RCV_TEMP_REG_1.b0, 0
1052 ; OPT: Can't fail
1053 NB_PROCESS_32BYTES_INIT_PORT_QUEUE_FAILED:
1056 ; clear port receive flag
1057 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, fwd_flag_shift
1058 ; ToDo: Do we need to add code for statistics? We should never fail to aquire the queue or the coll-queue
1059 QBA NB_PROCESS_32BYTES_CHECK_FLAGS
1060 NB_PROCESS_32BYTES_INIT_PORT_QUEUE_OK:
1061 ;CLR MII_RCV.rx_flags.port_collision_queue_selected ; ToDo: this could be removed when parameter are init with 0 at b/o frame
1062 ; 2-collision selected?
1063 QBNE NB_PROCESS_32BYTES_INIT_PORT_QUEUE_NO_COLL_SELECTED, RCV_TEMP_REG_1.b0, 2
1065 ; Initialize the RCV CONTEXT with the data of Port Collision Queue
1066 SET MII_RCV.rx_flags, MII_RCV.rx_flags, port_collision_queue_selected_shift
1067 .if $defined("PRU0")
1068 LDI RCV_TEMP_REG_1.w0, COL_RX_CONTEXT_P2_OFFSET_ADDR
1069 .else
1070 LDI RCV_TEMP_REG_1.w0, COL_RX_CONTEXT_P1_OFFSET_ADDR
1071 .endif
1072 LBCO &MII_RCV_PORT.buffer_index, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 10
1074 NB_PROCESS_32BYTES_INIT_PORT_QUEUE_NO_COLL_SELECTED:
1075 ;Initialize the wrkng_wr_ptr and rd_ptr here as the other PRU might have changed them between Now and RCV_FB
1076 LBCO &RCV_QUEUE_DESC_REG, QUEUE_DESP_BASE, MII_RCV_PORT.rcv_queue_pointer, 4
1077 AND MII_RCV_PORT.rd_ptr , RCV_QUEUE_DESC_REG.rd_ptr , RCV_QUEUE_DESC_REG.rd_ptr ;Warning: converted from MOV
1078 AND MII_RCV_PORT.wrkng_wr_ptr , RCV_QUEUE_DESC_REG.wr_ptr , RCV_QUEUE_DESC_REG.wr_ptr ;Warning: converted from MOV
1079 QBBS NB_RCV_PORT_CONTEXT_INITIALIZED_WITH_COLLISION, MII_RCV.rx_flags, port_collision_queue_selected_shift
1080 ; Compute the adress in L3 RAM where the packet is received
1081 SUB RCV_BUFFER_DESC_OFFSET, MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.base_buffer_desc_offset
1082 LSL RCV_BUFFER_DESC_OFFSET, RCV_BUFFER_DESC_OFFSET, 3
1083 ADD MII_RCV_PORT.buffer_index, MII_RCV_PORT.base_buffer_index, RCV_BUFFER_DESC_OFFSET
1085 NB_RCV_PORT_CONTEXT_INITIALIZED_WITH_COLLISION:
1086 .endif ;TWO_PORT_CFG
1087 .endif ;ICSS_SWITCH_BUILD
1089 NB_PROCESS_32BYTES_CHECK_FLAGS:
1091 .if $defined("ICSS_SWITCH_BUILD")
1092 QBBC NB_PROCESS_32BYTES_CHECK_FWD_FLAG, MII_RCV.rx_flags, host_rcv_flag_shift ; MII_RCV.rx_flags.host_rcv_flag
1093 .endif
1095 QBGE LESS_THAN_64_BYTES_RCVD, MII_RCV.byte_cntr, 32
1096 QBA EXIT_PREPROCESSING_NB
1098 LESS_THAN_64_BYTES_RCVD:
1099 ;between 32 and 64 bytes
1100 QBGE LESS_THAN_32_BYTES_RCVD, MII_RCV.byte_cntr, 0
1102 .if $defined(PTP)
1103 LDI RCV_TEMP_REG_3.w2, PTP_IPV4_UDP_E2E_ENABLE
1104 LBCO &RCV_TEMP_REG_3.b2, ICSS_SHARED_CONST, RCV_TEMP_REG_3.w2, 1
1105 QBEQ PTP_NOT_ENABLED_RX_B2, RCV_TEMP_REG_3.b2, 0
1106 QBBC PTP_NOT_ENABLED_RX_B2, R22, RX_IS_UDP_PTP_BIT
1107 CLR R22, R22, RX_IS_UDP_PTP_BIT
1108 JAL RCV_TEMP_REG_3.w2, FN_TIMESTAMP_GPTP_PACKET
1109 JAL RCV_TEMP_REG_3.w2, FN_CHECK_AND_CLR_PTP_FWD_FLAG
1110 PTP_NOT_ENABLED_RX_B2:
1111 .endif ; "PTP"
1112 QBA EXIT_PREPROCESSING_NB
1114 LESS_THAN_32_BYTES_RCVD:
1116 .if $defined(PTP)
1117 ;we don't want to execute this for UDP frames, since this will be executed again later
1118 QBBS PTP_SKIP_EARLY_TS_FOR_UDP_1, R22, RX_IS_UDP_PTP_BIT
1119 JAL RCV_TEMP_REG_3.w2, FN_CHECK_AND_CLR_PTP_FWD_FLAG_L2
1120 JAL RCV_TEMP_REG_3.w2, FN_TIMESTAMP_GPTP_PACKET
1121 PTP_SKIP_EARLY_TS_FOR_UDP_1:
1122 .endif ;PTP
1124 EXIT_PREPROCESSING_NB:
1125 SBCO &Ethernet, L3_OCMC_RAM_CONST, MII_RCV.buffer_index, 32
1126 ADD MII_RCV.byte_cntr , MII_RCV.byte_cntr , 32 ; increment byte count by 32
1128 ; Compare current wrk pointer to top_most queue desc pointer ..check for wrap around
1129 QBNE RCV_NB_NO_QUEUE_WRAP, MII_RCV.wrkng_wr_ptr, MII_RCV.top_most_buffer_desc_offset
1130 AND MII_RCV.wrkng_wr_ptr , MII_RCV.base_buffer_desc_offset , MII_RCV.base_buffer_desc_offset
1131 AND MII_RCV.buffer_index , MII_RCV.base_buffer_index , MII_RCV.base_buffer_index
1132 QBA RCV_NB_QUEUE_WRAPPED
1133 RCV_NB_NO_QUEUE_WRAP:
1134 ADD MII_RCV.buffer_index, MII_RCV.buffer_index, 32
1135 ADD MII_RCV.wrkng_wr_ptr, MII_RCV.wrkng_wr_ptr, 4
1137 RCV_NB_QUEUE_WRAPPED:
1139 ; Prepare for next call of RCV_NB ..whether next 32 bytes can be received or not
1140 QBNE NB_PROCESS_32BYTES_CHECK_FLAGS_QUEUE_NOT_FULL, MII_RCV.wrkng_wr_ptr, MII_RCV.rd_ptr
1142 CLR MII_RCV.rx_flags , MII_RCV.rx_flags , host_rcv_flag_shift
1143 SET MII_RCV.rx_flags_extended , MII_RCV.rx_flags_extended , host_queue_overflow_shift
1144 .if $defined("ICSS_DUAL_EMAC_BUILD")
1145 ;For EMAC mode, set rx_frame_error bit. This saves cycles in FN_RCV_LB.
1146 SET MII_RCV.rx_flags , MII_RCV.rx_flags , 4
1147 .endif
1149 NB_PROCESS_32BYTES_CHECK_FLAGS_QUEUE_NOT_FULL:
1150 .if $defined("ICSS_SWITCH_BUILD")
1151 NB_PROCESS_32BYTES_CHECK_FWD_FLAG:
1152 .if $defined("TWO_PORT_CFG")
1154 QBBC NB_PROCESS_32BYTES_CHECK_FLAG_DONE, MII_RCV.rx_flags, 1 ;MII_RCV.rx_flags.fwd_flag
1155 SBCO &Ethernet, L3_OCMC_RAM_CONST, MII_RCV_PORT.buffer_index, 32
1156 ADD MII_RCV_PORT.byte_cntr, MII_RCV_PORT.byte_cntr, 32
1158 ; Compare current wrk pointer to top_most queue desc pointer ..check for wrap around
1159 QBNE RCV_NB_PORT_NO_QUEUE_WRAP, MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.top_most_buffer_desc_offset
1160 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
1161 AND MII_RCV_PORT.buffer_index , MII_RCV_PORT.base_buffer_index , MII_RCV_PORT.base_buffer_index ;Warning: converted from MOV
1162 QBA RCV_NB_PORT_QUEUE_WRAPPED
1163 RCV_NB_PORT_NO_QUEUE_WRAP:
1164 ADD MII_RCV_PORT.buffer_index, MII_RCV_PORT.buffer_index, 32
1165 ADD MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.wrkng_wr_ptr, 4
1166 RCV_NB_PORT_QUEUE_WRAPPED:
1168 ; Prepare for next call of RCV_NB ..whether next 32 bytes can be received or not
1169 QBNE NB_PROCESS_32BYTES_CHECK_FWD_FLAG_NOT_FULL, MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.rd_ptr
1170 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, fwd_flag_shift
1171 SET MII_RCV.rx_flags_extended, MII_RCV.rx_flags_extended, port_queue_overflow_shift
1173 NB_PROCESS_32BYTES_CHECK_FWD_FLAG_NOT_FULL:
1175 NB_PROCESS_32BYTES_CHECK_FLAG_DONE:
1176 .endif ;TWO_PORT_CFG
1178 NB_PROCESS_DONE:
1179 .endif
1180 XOR MII_RCV.rx_flags, MII_RCV.rx_flags, (1<<rx_bank_index_shift) ; toggle rx_bank_index flag
1182 NB_DONE:
1184 ; restore call register pointer
1185 AND CALL_REG , L1_CALL_REG , L1_CALL_REG
1187 ; store task parameters from parameter bank
1188 NB_STORE_CONTEXT:
1189 LDI R0.b0, SHIFT_NONE
1190 .if $defined("PRU0")
1191 XOUT BANK1, &MII_RCV, $sizeof(MII_RCV)
1192 .else
1193 XOUT BANK2, &MII_RCV, $sizeof(MII_RCV)
1194 .endif
1196 .if $defined("ICSS_SWITCH_BUILD")
1197 .if $defined("TWO_PORT_CFG")
1198 .if $defined("PRU0")
1199 LDI R0.b0, SHIFT_R14_TO_R0
1200 XOUT BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT)
1201 .else
1202 LDI R0.b0, SHIFT_R14_TO_R4
1203 XOUT BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT)
1204 .endif
1205 QBBS NB_PROCESS_CUT_THROUGH, MII_RCV.tx_flags, cut_through_flag_shift ;MII_RCV.tx_flags.cut_through_flag
1206 .endif ;TWO_PORT_CFG
1207 .endif
1209 .if $defined("ICSS_REV1")
1210 M_RCV_RX_EOF_CHECK_ICSS_REV1 ; check for EOF for REV1
1211 .endif
1212 .if $defined("ICSS_REV2")
1213 M_RCV_RX_EOF_CHECK_ICSS_REV2 ; check for EOF for REV2
1214 .endif
1216 NB_DONE_NO_PARAM_STORE:
1217 JMP TASK_EXECUTION_FINISHED
1219 process_rx_eof_rx_nb:
1220 JMP FN_RCV_LB
1222 .if $defined("ICSS_SWITCH_BUILD")
1223 .if $defined("TWO_PORT_CFG")
1224 NB_PROCESS_CUT_THROUGH:
1225 ; check for RX EOF condition
1226 .if $defined("ICSS_REV1")
1227 .if $defined("PRU0")
1228 QBBC FN_RCV_NB_CT_NO_RxEOF, R31, 30 ;replaced: QBBC FN_RCV_NB_CT_NO_RxEOF, R31.t30
1229 .else
1230 QBBC FN_RCV_NB_CT_NO_RxEOF, R31, 31 ;replaced: QBBC FN_RCV_NB_CT_NO_RxEOF, R31.t31
1231 .endif
1232 .endif
1233 .if $defined("ICSS_REV2")
1234 QBBC FN_RCV_NB_CT_NO_RxEOF, R31, 20 ; Port0 Rx EOF
1235 .endif
1237 FN_RCV_NB_CT_RxEOF:
1238 QBBS CT_NB_XIN_UPPER_BANK, MII_RCV.rx_flags, rx_bank_index_shift ;MII_RCV.rx_flags.rx_bank_index
1240 CT_NB_XIN_LOWER_BANK:
1242 XIN RX_L2_BANK0_ID, &R18, RANGE_R18_b0
1243 XIN RX_L2_BANK0_ID, &R2, RANGE_R2_R13 ; XIN RX L2 bank 0
1245 QBA CT_NB_CHECK_AMOUNT_OF_BYTES
1246 CT_NB_XIN_UPPER_BANK:
1248 XIN RX_L2_BANK1_ID, &R18, RANGE_R18_b0
1249 XIN RX_L2_BANK1_ID, &R2, RANGE_R2_R13 ; XIN RX L2 bank 1
1251 CT_NB_CHECK_AMOUNT_OF_BYTES:
1252 ; Put the remaining bytes in Tx_FIFO at this point of time itself
1253 AND RCV_TEMP_REG_1.b0, CUT_THROUGH_BYTE_CNT, 0x003f
1254 ; Below code added to fix a bug when for a 65 byte packet R18 has 1 but cut_through_byte_cnt is 62.
1255 ; Check whether cut_through_byte_cnt is more than R18 count
1256 QBGE CT_R18_IS_GREATER_OR_EQUAL, RCV_TEMP_REG_1.b0, R18_RCV_BYTECOUNT
1257 LDI RCV_TEMP_REG_2.b0, 64 ; Subtract from 64 bytes
1258 SUB RCV_TEMP_REG_1.b0, RCV_TEMP_REG_2.b0, RCV_TEMP_REG_1.b0
1259 ; 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
1260 ; the last two bytes and R18 gets wrapped around by the time we reach here
1261 ADD RCV_TEMP_REG_1.b0, RCV_TEMP_REG_1.b0, R18_RCV_BYTECOUNT
1262 QBA CT_R18_IS_LESS
1263 CT_R18_IS_GREATER_OR_EQUAL:
1265 SUB RCV_TEMP_REG_1.b0, R18_RCV_BYTECOUNT, RCV_TEMP_REG_1.b0
1267 CT_R18_IS_LESS:
1268 .if $defined("ICSS_REV1")
1269 ;QBEQ CT_PUSH_LB_LASTBYTE_nb, RCV_TEMP_REG_1.b0, 1
1270 LSR loop_cnt, RCV_TEMP_REG_1.b0, 1
1271 ; OPT: Use function for the loop below
1272 ;QBEQ ct_assert_eof_nb, loop_cnt, 0x0000
1273 LOOP CT_NB_ENDLOOP, loop_cnt
1274 MVIW TX_DATA_WORD, *TX_DATA_POINTER
1275 M_PUSH_WORD_CMD
1276 ADD TX_DATA_POINTER, TX_DATA_POINTER, 2
1277 CT_NB_ENDLOOP:
1278 QBBC ct_assert_eof_nb, RCV_TEMP_REG_1.b0, 0
1279 CT_PUSH_LB_LASTBYTE_nb:
1280 MVIB TX_DATA_BYTE, *R1.b3
1281 M_PUSH_BYTE
1282 ct_assert_eof_nb:
1283 ;M_PUSH_TX_EOF
1284 .endif
1285 .if $defined("ICSS_REV2")
1286 LSR loop_cnt, RCV_TEMP_REG_1.b0, 2
1288 loop CT_NB_ENDLOOP, loop_cnt
1289 MVID TX_DATA_DOUBLE_WORD, *TX_DATA_POINTER
1290 ADD TX_DATA_POINTER, TX_DATA_POINTER, 4
1291 CT_NB_ENDLOOP:
1293 AND RCV_TEMP_REG_2.b0, RCV_TEMP_REG_1.b0, 0x03
1294 QBEQ ct_assert_eof_nb, RCV_TEMP_REG_2.b0, 0
1295 QBEQ CT_PUSH_LB_LASTBYTE_nb, RCV_TEMP_REG_2.b0, 1
1296 MVIW TX_DATA_WORD, *TX_DATA_POINTER
1297 ADD TX_DATA_POINTER, TX_DATA_POINTER, 2
1298 QBEQ ct_assert_eof_nb, RCV_TEMP_REG_2.b0, 2
1299 CT_PUSH_LB_LASTBYTE_nb:
1300 MVIB TX_DATA_BYTE, *R1.b3
1302 ct_assert_eof_nb:
1303 ; Insert the TX_EOF for outgoing frame
1304 LDI R31.w2, 0x2000
1305 .endif
1306 ADD CUT_THROUGH_BYTE_CNT, CUT_THROUGH_BYTE_CNT, RCV_TEMP_REG_1.b0
1307 ct_deassert_ct:
1308 SKIP_CRC_PUSH:
1310 LDI R0.b0, SHIFT_NONE
1311 .if $defined("PRU0")
1312 XOUT BANK1, &MII_RCV, $sizeof(MII_RCV)
1313 .else
1314 XOUT BANK2, &MII_RCV, $sizeof(MII_RCV)
1315 .endif
1316 CLR R22, R22, PACKET_TX_ALLOWED
1317 ;Check for CRC
1318 LDI RCV_TEMP_REG_2.w0, 0x0204
1319 LBCO &RCV_TEMP_REG_1, ICSS_INTC_CONST, RCV_TEMP_REG_2.w0, 4
1320 .if $defined("PRU0")
1321 QBBC NO_CRC_ERROR_CT, RCV_TEMP_REG_1, 4 ;replaced: QBBC NO_CRC_ERROR_CT, RCV_TEMP_REG_1.t4
1322 .else
1323 QBBC NO_CRC_ERROR_CT, RCV_TEMP_REG_1, 16 ;replaced: QBBC NO_CRC_ERROR_CT, RCV_TEMP_REG_1.t16
1324 .endif
1325 LDI RCV_TEMP_REG_3 , RX_CRC_COUNT_OFFSET
1327 ;Add to statistics counter
1328 LBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1329 ADD RCV_TEMP_REG_1, RCV_TEMP_REG_1, 1
1330 SBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1331 NO_CRC_ERROR_CT:
1332 .endif ;TWO_PORT_CFG
1333 .endif ;ICSS_SWITCH_BUILD
1335 ;****************************************************************************
1336 ;
1337 ; NAME : FN_RCV_LB
1338 ; DESCRIPTION : receives the last block(s) of RX L2
1339 ; RETURNS :
1340 ; ARGS :
1341 ; USES :
1342 ; INVOKES :
1343 ;
1344 ;****************************************************************************
1345 FN_RCV_LB:
1347 ; Check if RCV_Active is set. If not drop the frame. It handles the case of undersize errors
1348 QBBS RCV_LB_PROCESS_NORMAL, R23, Rcv_active
1350 LB_CHECK_ERRORS:
1351 ;Short frame received then increment the error offset statistics
1352 LDI RCV_TEMP_REG_3 , RX_ERROR_OFFSET
1353 LBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1354 ADD RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1
1355 SBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1356 .if $defined("ICSS_DUAL_EMAC_BUILD")
1357 .if $defined("HALF_DUPLEX_ENABLED")
1358 ;check R31 error
1359 QBBC NO_R31_ERROR, R31, 19 ; if cleared so no error and continue normal operation
1360 ;else clear the error
1361 M_CMD16 D_RX_ERROR_CLEAR ; else clear error flag
1363 NO_R31_ERROR:
1364 ;check for SFD Errors
1365 .if $defined("PRU0")
1366 LBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1 ;read the PRUSS_MII_RT_RX_ERR0 register
1367 QBBC CHECK_FOR_SHORT_SFD1, RCV_TEMP_REG_3, 1 ; check if not error then jump else count stats
1368 ;clear error and writeback
1369 SET RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 1
1370 SBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1
1371 QBA COUNT_SFD_ERROR1
1372 CHECK_FOR_SHORT_SFD1:
1373 QBBC NO_PREAMBLE_ERROR, RCV_TEMP_REG_3, 0 ; check if not error then jump else count stats
1374 ;clear error and writeback
1375 SET RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 0
1376 SBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1
1377 .else
1378 LBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1 ;read the PRUSS_MII_RT_RX_ERR0 register
1379 QBBC CHECK_FOR_SHORT_SFD1, RCV_TEMP_REG_3, 1 ; check if not error then jump else count stats
1380 ;clear error and writeback
1381 SET RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 1
1382 SBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1
1383 QBA COUNT_SFD_ERROR1
1384 CHECK_FOR_SHORT_SFD1:
1385 QBBC NO_PREAMBLE_ERROR, RCV_TEMP_REG_3, 0 ; check if not error then jump else count stats
1386 ;clear error and writeback
1387 SET RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 0
1388 SBCO &RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1
1389 .endif
1391 COUNT_SFD_ERROR1:
1392 ;increment and store the count
1393 LDI RCV_TEMP_REG_3 , SFD_ERROR_OFFSET
1394 LBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1395 ADD RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1
1396 SBCO &RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1397 .endif ;HALF_DUPLEX_ENABLED
1398 .endif ;ICSS_DUAL_EMAC_BUILD
1399 NO_PREAMBLE_ERROR:
1401 ; RCV_CONTEXT is not initialized for this error frame.
1402 ; reset RX FIFO, this places the R18 counter back to position 0
1403 CLR R23 , R23 , Rcv_active
1404 M_SET_CMD D_RESET_RXFIFO
1405 QBA LB_NO_RX_STAT
1406 RCV_LB_PROCESS_NORMAL:
1408 ; for XIN, make sure that shift is set to 0
1409 LDI R0.b0, SHIFT_NONE
1410 ; restore task parameters from parameter bank
1411 .if $defined("PRU0")
1412 XIN BANK1, &MII_RCV, $sizeof(MII_RCV)
1413 .else
1414 XIN BANK2, &MII_RCV, $sizeof(MII_RCV)
1415 .endif
1417 .if $defined("TWO_PORT_CFG")
1418 ; OPT: MOve the port context read after the XIN of data
1419 ; for port receive
1420 .if $defined("PRU0")
1421 LDI R0.b0, SHIFT_R14_TO_R0
1422 XIN BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT)
1423 .else
1424 LDI R0.b0, SHIFT_R14_TO_R4
1425 XIN BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT)
1426 .endif
1427 .endif ;TWO_PORT_CFG
1428 QBBS LB_RESET_RX_FIFO, MII_RCV.rx_flags, rx_frame_error_shift
1429 ; depending on the bank index, we load bank 0 or bank 1
1430 QBBS LB_XIN_UPPER_BANK, MII_RCV.rx_flags, rx_bank_index_shift
1432 LB_XIN_LOWER_BANK:
1433 XIN RX_L2_BANK0_ID, &R18, RANGE_R18_b0
1434 XIN RX_L2_BANK0_ID, &R2, RANGE_R2_R13 ; XIN RX L2 bank 0
1436 ; have we received more than 32 bytes?
1437 QBGE LB_XIN_STORE_LESS_THAN_32_FROM_LOWER_BANK, R18_RCV_BYTECOUNT, 32
1438 QBA LB_STORE_FIRST_32_BYTES
1440 LB_XIN_UPPER_BANK:
1441 XIN RX_L2_BANK1_ID, &R18, RANGE_R18_b0
1442 XIN RX_L2_BANK1_ID, &R2, RANGE_R2_R13 ; XIN RX L2 bank 1
1444 ;For PTP frames if flow comes here it
1445 ; can only mean that 32-64 bytes have been received
1446 .if $defined("PTP")
1447 LDI RCV_TEMP_REG_1.w0, PTP_IPV4_UDP_E2E_ENABLE
1448 LBCO &RCV_TEMP_REG_1.b0, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 1
1449 QBEQ PTP_NOT_ENABLED_RX_LB, RCV_TEMP_REG_1.b0, 0
1450 QBBC PTP_NOT_ENABLED_RX_LB, R22, RX_IS_UDP_PTP_BIT
1451 CLR R22, R22, RX_IS_UDP_PTP_BIT
1452 JAL RCV_TEMP_REG_3.w2, FN_TIMESTAMP_GPTP_PACKET
1453 JAL RCV_TEMP_REG_3.w2, FN_CHECK_AND_CLR_PTP_FWD_FLAG
1454 PTP_NOT_ENABLED_RX_LB:
1455 .endif ; "PTP"
1457 ; have we received more than 32 bytes?
1458 QBLE LB_XIN_STORE_LESS_THAN_32_FROM_UPPER_BANK, R18_RCV_BYTECOUNT, 32
1460 LB_STORE_FIRST_32_BYTES:
1461 .if $defined("ICSS_SWITCH_BUILD")
1462 QBBC LB_PROCESS_32BYTES_CHECK_FWD_FLAG, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
1463 .endif
1464 .if $defined(PTP)
1465 ADD RCV_TEMP_REG_3.w2, MII_RCV.byte_cntr, 32
1466 QBLT MORE_THAN_32_BYTES_RCVD, RCV_TEMP_REG_3.w2, 32
1468 ;we don't want to execute this for UDP frames, since this will be executed again later
1469 QBBS MORE_THAN_32_BYTES_RCVD, R22, RX_IS_UDP_PTP_BIT
1470 JAL RCV_TEMP_REG_3.w2, FN_CHECK_AND_CLR_PTP_FWD_FLAG_L2
1471 JAL RCV_TEMP_REG_3.w2, FN_TIMESTAMP_GPTP_PACKET
1473 MORE_THAN_32_BYTES_RCVD:
1474 .endif ;PTP
1475 SBCO &Ethernet, L3_OCMC_RAM_CONST, MII_RCV.buffer_index, 32
1476 ADD MII_RCV.byte_cntr, MII_RCV.byte_cntr, 32
1478 ; Update the buffer descriptor for the received packet
1479 ; Compare current wrk pointer to top_most queue desc pointer ..check for wrap around
1480 QBNE RCV_LB_NO_QUEUE_WRAP_LOWER, MII_RCV.wrkng_wr_ptr, MII_RCV.top_most_buffer_desc_offset
1481 AND MII_RCV.wrkng_wr_ptr , MII_RCV.base_buffer_desc_offset , MII_RCV.base_buffer_desc_offset
1482 AND MII_RCV.buffer_index , MII_RCV.base_buffer_index , MII_RCV.base_buffer_index
1483 QBA RCV_LB_QUEUE_WRAPPED_LOWER
1484 RCV_LB_NO_QUEUE_WRAP_LOWER:
1485 ADD MII_RCV.buffer_index, MII_RCV.buffer_index, 32
1486 ADD MII_RCV.wrkng_wr_ptr, MII_RCV.wrkng_wr_ptr, 4
1488 RCV_LB_QUEUE_WRAPPED_LOWER:
1489 ; Check if the queue got completely filled with the last few bytes and the remaining bytes cannot be added.
1490 ;This scenario of queue overflow has been verified by dry run.
1491 QBNE LB_PROCESS_32BYTES_CHECK_FLAGS_QUEUE_NOT_FULL_1, MII_RCV.wrkng_wr_ptr, MII_RCV.rd_ptr
1492 CLR MII_RCV.rx_flags , MII_RCV.rx_flags , host_rcv_flag_shift
1493 SET MII_RCV.rx_flags_extended , MII_RCV.rx_flags_extended , host_queue_overflow_shift
1494 .if $defined("ICSS_DUAL_EMAC_BUILD")
1495 ;For EMAC mode, set rx_frame_error bit.
1496 SET MII_RCV.rx_flags , MII_RCV.rx_flags , 4
1497 .endif
1498 LB_PROCESS_32BYTES_CHECK_FLAGS_QUEUE_NOT_FULL_1:
1499 .if $defined("ICSS_SWITCH_BUILD")
1500 LB_PROCESS_32BYTES_CHECK_FWD_FLAG:
1501 .if $defined("TWO_PORT_CFG")
1502 QBBC LB_PROCESS_32BYTES_CHECK_FLAG_DONE, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
1504 SBCO &Ethernet, L3_OCMC_RAM_CONST, MII_RCV_PORT.buffer_index, 32
1505 ADD MII_RCV_PORT.byte_cntr, MII_RCV_PORT.byte_cntr, 32
1507 ; Update the buffer descriptor for the received packet
1508 ; Compare current wrk pointer to top_most queue desc pointer ..check for wrap around
1509 QBNE RCV_LB_NO_PORT_QUEUE_WRAP_LOWER, MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.top_most_buffer_desc_offset
1510 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
1511 AND MII_RCV_PORT.buffer_index , MII_RCV_PORT.base_buffer_index , MII_RCV_PORT.base_buffer_index ;Warning: converted from MOV
1512 QBA RCV_LB_PORT_QUEUE_WRAPPED_LOWER
1513 RCV_LB_NO_PORT_QUEUE_WRAP_LOWER:
1514 ADD MII_RCV_PORT.buffer_index, MII_RCV_PORT.buffer_index, 32
1515 ADD MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.wrkng_wr_ptr, 4
1517 RCV_LB_PORT_QUEUE_WRAPPED_LOWER:
1518 ; Prepare for next call of RCV_LB ..whether next 32 bytes can be received or not
1519 QBNE LB_PROCESS_32BYTES_CHECK_FLAGS_PORT_QUEUE_NOT_FULL_1, MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.rd_ptr
1520 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
1521 SET MII_RCV.rx_flags_extended, MII_RCV.rx_flags_extended, port_queue_overflow_shift ;MII_RCV.rx_flags_extended.port_queue_overflow
1523 LB_PROCESS_32BYTES_CHECK_FLAGS_PORT_QUEUE_NOT_FULL_1:
1525 LB_PROCESS_32BYTES_CHECK_FLAG_DONE:
1526 .endif ;TWO_PORT_CFG
1527 .endif ;ICSS_SWITCH_BUILD
1528 QBBC LB_STORE_UPPER_DATA, MII_RCV.rx_flags, rx_bank_index_shift
1530 ; get and store lower data
1531 XIN RX_L2_BANK0_ID, &R2, RANGE_R2_R9 ; recieve the remaining data
1532 QBA LB_XIN_STORE_LESS_THAN_32_FROM_LOWER_BANK
1533 LB_STORE_UPPER_DATA:
1534 ; get and store upper data
1535 XIN RX_L2_BANK1_ID, &R2, RANGE_R2_R13 ; recieve the remaining data
1537 LB_XIN_STORE_LESS_THAN_32_FROM_UPPER_BANK:
1538 SUB R0.b1, R18, 32 ; count remaining data
1539 QBA LB_STORE_FROM_UPPER_BUFFER
1540 LB_XIN_STORE_LESS_THAN_32_FROM_LOWER_BANK:
1541 AND R0.b1 , R18 , R18
1542 LB_STORE_FROM_UPPER_BUFFER:
1544 QBBS RCV_LB_APPEND_TS, R22, 14 ;check PTP flag
1545 ; Check if 0 bytes are there to store
1546 QBEQ LB_PROCESS_CHECK_FWD_FLAG, R0.b1, 0
1548 ; Receive for Host Queue
1549 .if $defined("ICSS_SWITCH_BUILD")
1550 QBBC LB_PROCESS_CHECK_FWD_FLAG, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
1551 .endif
1552 SBCO &Ethernet, L3_OCMC_RAM_CONST, MII_RCV.buffer_index, b1
1554 ADD MII_RCV.byte_cntr, MII_RCV.byte_cntr, R0.b1 ; increment the count by R1 bytes
1555 QBGE LB_PROCESS_CHECK_FWD_FLAG, R0.b1, 4 ;If only CRC is left to store then skip
1556 QBNE RCV_LB_NO_QUEUE_WRAP_2, MII_RCV.wrkng_wr_ptr, MII_RCV.top_most_buffer_desc_offset
1557 AND MII_RCV.wrkng_wr_ptr , MII_RCV.base_buffer_desc_offset , MII_RCV.base_buffer_desc_offset
1558 QBA RCV_LB_QUEUE_WRAPPED_2
1559 RCV_LB_NO_QUEUE_WRAP_2:
1560 ADD MII_RCV.wrkng_wr_ptr, MII_RCV.wrkng_wr_ptr, 4
1561 RCV_LB_QUEUE_WRAPPED_2:
1562 QBA RCV_LB_CHECK_OVERFLOW
1563 RCV_LB_APPEND_TS:
1564 ;--------------Logic to append 10 bytes timestamp to the end of packet----------
1565 .if $defined("ICSS_SWITCH_BUILD")
1566 QBBC LB_PROCESS_CHECK_FWD_FLAG, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
1567 .endif
1569 ;If there are 0 bytes to store then append timestamp in new block
1570 QBEQ LB_TS_STORE_TS, R0.b1, 0
1571 ADD MII_RCV.byte_cntr, MII_RCV.byte_cntr, R0.b1 ; increment the count by b1 bytes
1572 QBGE LB_TS_STORE_TS, R0.b1, 4 ;If only CRC is left to store then skip and append TS
1574 SBCO &Ethernet, L3_OCMC_RAM_CONST, MII_RCV.buffer_index, b1 ;Store the data
1576 ;Compare current wrk pointer to top_most queue desc pointer ..check for wrap around
1577 QBNE LB_TS_NO_WRAP_1, MII_RCV.wrkng_wr_ptr, MII_RCV.top_most_buffer_desc_offset
1578 AND MII_RCV.wrkng_wr_ptr , MII_RCV.base_buffer_desc_offset , MII_RCV.base_buffer_desc_offset
1579 AND MII_RCV.buffer_index , MII_RCV.base_buffer_index , MII_RCV.base_buffer_index
1580 QBA LB_TS_STORE_TS
1581 LB_TS_NO_WRAP_1:
1582 ADD MII_RCV.buffer_index, MII_RCV.buffer_index, 32
1583 ADD MII_RCV.wrkng_wr_ptr, MII_RCV.wrkng_wr_ptr, 4
1585 LB_TS_STORE_TS: ;store timestamp in new 32B block
1587 ;Load offset
1588 .if $defined(PTP)
1589 M_GPTP_LOAD_TS_OFFSET
1590 .endif
1592 ;Load the TS from Shared RAM
1593 LBCO &R10, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 10
1594 ;Store into L3 OCMC
1595 SBCO &R10, L3_OCMC_RAM_CONST, MII_RCV.buffer_index, 10
1597 ;check wraparound
1598 QBNE LB_TS_NO_WRAP_2, MII_RCV.wrkng_wr_ptr, MII_RCV.top_most_buffer_desc_offset
1599 AND MII_RCV.wrkng_wr_ptr , MII_RCV.base_buffer_desc_offset , MII_RCV.base_buffer_desc_offset
1600 QBA RCV_LB_CHECK_OVERFLOW
1601 LB_TS_NO_WRAP_2:
1602 ADD MII_RCV.wrkng_wr_ptr, MII_RCV.wrkng_wr_ptr, 4
1604 RCV_LB_CHECK_OVERFLOW:
1605 .if $defined("ICSS_DUAL_EMAC_BUILD")
1606 ; Check if the queue got completely filled with the last few bytes.
1607 ;If yes, the wr_ptr and rd_prt might become equal and there could be
1608 ;possible data overwrite when the next packet arrives.
1609 ;This has been verfied by dry run.
1610 QBNE LB_PROCESS_CHECK_FLAGS_QUEUE_NOT_FULL, MII_RCV.wrkng_wr_ptr, MII_RCV.rd_ptr
1611 CLR MII_RCV.rx_flags , MII_RCV.rx_flags , 0
1612 SET MII_RCV.rx_flags_extended , MII_RCV.rx_flags_extended , 6
1613 ;For EMAC mode, set rx_frame_error bit
1614 SET MII_RCV.rx_flags , MII_RCV.rx_flags , 4
1616 LB_PROCESS_CHECK_FLAGS_QUEUE_NOT_FULL:
1617 .endif ;ICSS_DUAL_EMAC_BUILD
1618 LB_PROCESS_CHECK_FWD_FLAG:
1619 .if $defined("ICSS_SWITCH_BUILD")
1620 ; Receive for Port Queue
1621 .if $defined("TWO_PORT_CFG")
1622 QBBC LB_CLEAR_RX_FIFO, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
1623 SBCO &Ethernet, L3_OCMC_RAM_CONST, MII_RCV_PORT.buffer_index, b1
1624 ADD MII_RCV_PORT.byte_cntr, MII_RCV_PORT.byte_cntr, R0.b1
1625 QBGE LB_CLEAR_RX_FIFO, R0.b1, 4
1626 QBNE RCV_LB_NO_PORT_QUEUE_WRAP_2, MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.top_most_buffer_desc_offset
1627 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
1628 QBA RCV_LB_PORT_QUEUE_WRAPPED_2
1629 RCV_LB_NO_PORT_QUEUE_WRAP_2:
1630 ADD MII_RCV_PORT.wrkng_wr_ptr, MII_RCV_PORT.wrkng_wr_ptr, 4
1631 RCV_LB_PORT_QUEUE_WRAPPED_2:
1632 .endif ;TWO_PORT_CFG
1634 LB_CLEAR_RX_FIFO:
1636 QBBS LB_CHECK_RX_ERRORS, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
1637 QBBC LB_RESET_RX_FIFO, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
1639 LB_CHECK_RX_ERRORS:
1640 .endif ;ICSS_SWITCH_BUILD
1641 ; Check for CRC Error in the received frame
1642 LDI RCV_TEMP_REG_1.w0, 0x0204
1643 LBCO &RCV_TEMP_REG_2, ICSS_INTC_CONST, RCV_TEMP_REG_1.w0, 4 ;load value of INTC_SRSR1
1645 ;check odd nibble error
1646 CHECK_MISALIGNMENT_ERROR:
1647 .if $defined("PRU0")
1648 QBBC CHECK_CRC_ERROR, RCV_TEMP_REG_2, 5 ; if interrupt line is clear check for CRC error else continue
1649 .else
1650 QBBC CHECK_CRC_ERROR, RCV_TEMP_REG_2, 17 ; if interrupt line is clear check for CRC error else continue
1651 .endif
1652 LDI RCV_TEMP_REG_3 , RX_MISALIGNMENT_COUNT_OFFSET
1654 ;Add to statistics counter
1655 LBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1656 ADD RCV_TEMP_REG_1, RCV_TEMP_REG_1, 1
1657 SBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1658 .if $defined("ICSS_DUAL_EMAC_BUILD")
1659 SET MII_RCV.rx_flags , MII_RCV.rx_flags , 4
1660 .endif
1662 CHECK_CRC_ERROR:
1663 .if $defined("PRU0")
1664 QBBC LB_CHECK_MIN_FRM_ERR, RCV_TEMP_REG_2, 4
1665 .else
1666 QBBC LB_CHECK_MIN_FRM_ERR, RCV_TEMP_REG_2, 16
1667 .endif
1668 LDI RCV_TEMP_REG_3 , RX_CRC_COUNT_OFFSET
1670 ;Add to statistics counter
1671 LBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1672 ADD RCV_TEMP_REG_1, RCV_TEMP_REG_1, 1
1673 SBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1674 SET MII_RCV.rx_flags , MII_RCV.rx_flags , rx_frame_error_shift
1676 ;Check whether received frame length is less then defined min value
1677 LB_CHECK_MIN_FRM_ERR:
1678 .if $defined("PRU0")
1679 LBCO &RCV_TEMP_REG_2.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1
1680 .else
1681 LBCO &RCV_TEMP_REG_2.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1
1682 .endif
1683 QBBC LB_CHECK_MAX_FRM_ERR, RCV_TEMP_REG_2, 2 ; check if undersize error exist
1684 LDI RCV_TEMP_REG_3 , RX_UNDERSIZED_FRAME_OFFSET
1685 QBA LB_CLR_RX_ERROR_REG
1687 ;Check whether received frame length is more then defined max value
1688 LB_CHECK_MAX_FRM_ERR:
1689 QBBC LB_RESET_RX_FIFO, RCV_TEMP_REG_2, 3 ; check for oversize error
1690 LDI RCV_TEMP_REG_3 , RX_OVERSIZED_FRAME_OFFSET
1692 LB_CLR_RX_ERROR_REG:
1694 ;Add to statistics counter
1695 LBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1696 ADD RCV_TEMP_REG_1, RCV_TEMP_REG_1, 1
1697 SBCO &RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4
1699 ; Clear the RX MIN or RX MAX ERROR
1700 LDI RCV_TEMP_REG_2.b1, 0x0c
1701 .if $defined("PRU0")
1702 SBCO &RCV_TEMP_REG_2.b1, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1
1703 .else
1704 SBCO &RCV_TEMP_REG_2.b1, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1
1705 .endif
1706 SET MII_RCV.rx_flags , MII_RCV.rx_flags , rx_frame_error_shift
1708 LB_RESET_RX_FIFO:
1709 ; reset RX fifo, this places the R18 counter back to position 0
1710 M_SET_CMD D_RESET_RXFIFO
1713 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
1714 ;clear RX_BC_FRAME & RX_MC_FRAME flags
1715 CLR R22 , R22 , RX_BC_FRAME
1716 CLR R22 , R22 , RX_MC_FRAME
1717 JMP LB_RELEASE_QUEUE ; Clear the EOF and other possible error flags.
1719 LB_NO_RX_FRAME_ERROR:
1721 .if $defined("ICSS_SWITCH_BUILD")
1722 .if $defined(PTP)
1723 ;This code is used to control PTP packet forwarding from driver, if mem location
1724 ;is set to 1 then FW skips the flow. By default (0) flow is taken
1725 LBCO &RCV_TEMP_REG_2.b0, ICSS_SHARED_CONST, DISABLE_PTP_FRAME_FORWARDING_CTRL_OFFSET, 1
1726 QBEQ PTP_PORT_QUEUE_RELEASE_DONE, RCV_TEMP_REG_2.b0, 1
1727 QBBS LB_RELEASE_PORT_QUEUE, R22, PTP_RELEASE_PORT_QUEUE_BIT
1729 PTP_PORT_QUEUE_RELEASE_DONE:
1731 .endif ;PTP
1732 .endif ;ICSS_SWITCH_BUILD
1734 LDI R0.b0, 0
1735 .if $defined("PRU0")
1736 XOUT BANK1, &MII_RCV, $sizeof(MII_RCV) ; store task parameters from parameter bank
1737 .else
1738 XOUT BANK2, &MII_RCV, $sizeof(MII_RCV) ; store task parameters from parameter bank
1739 .endif
1741 .if $defined("TWO_PORT_CFG")
1743 .if $defined("PRU0")
1744 LDI R0.b0, SHIFT_R14_TO_R0
1745 XOUT BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT) ; store task parameters from parameter bank
1746 .else
1747 LDI R0.b0, SHIFT_R14_TO_R4
1748 XOUT BANK0, &MII_RCV_PORT, $sizeof(MII_RCV_PORT)
1749 .endif
1750 ; For Host Receive
1751 QBBC LB_UPDATE_CHECK_FWD_FLAG, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
1752 .endif ;TWO_PORT_CFG
1753 LDI R0.b0, SHIFT_R2_TO_R26
1754 .if $defined("PRU0")
1755 XIN BANK1, &RCV_CONTEXT, $sizeof(MII_RCV_PORT) ; store task parameters from parameter bank
1756 .else
1757 XIN BANK2, &RCV_CONTEXT, $sizeof(MII_RCV_PORT) ; store task parameters from parameter bank
1758 .endif
1759 .if $defined("TWO_PORT_CFG")
1760 CLR R6 , R6 , 0
1761 QBA LB_UPDATE_FOR_HOST_RECEIVE
1762 LB_UPDATE_CHECK_FWD_FLAG:
1764 QBBC LB_UPDATE_CHECK_DONE, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
1765 .if $defined("PRU0")
1766 LDI R0.b0, SHIFT_R2_TO_R0
1767 XIN BANK0, &RCV_CONTEXT, $sizeof(MII_RCV_PORT) ; store task parameters from parameter bank
1768 .else
1769 LDI R0.b0, SHIFT_R2_TO_R4
1770 XIN BANK0, &RCV_CONTEXT, $sizeof(MII_RCV_PORT) ; store task parameters from parameter bank
1771 .endif
1772 SET R6 , R6 , 0
1773 .else
1774 ;store the length of the packet for statistics
1775 LDI RCV_TEMP_REG_2 , RX_PKT_SIZE_OFFSET
1776 SBCO &RCV_CONTEXT.byte_cntr, PRU_DMEM_ADDR, RCV_TEMP_REG_2, 2 ; load the byte count in working register
1778 .endif ;TWO_PORT_CFG
1779 LB_UPDATE_FOR_HOST_RECEIVE:
1780 ; Update the Receive Buffer Descriptor
1781 ; Read the wr_ptr of first buffer descriptor
1782 .if $defined("TWO_PORT_CFG")
1783 LBCO &RCV_TEMP_REG_1, PRU1_DMEM_CONST, RCV_CONTEXT.rcv_queue_pointer, 4
1784 .else
1785 LBCO &RCV_TEMP_REG_1, ICSS_SHARED_CONST, RCV_CONTEXT.rcv_queue_pointer, 4
1786 .endif ;TWO_PORT_CFG
1787 ; clear length field (18..28) and update length with current received frame
1788 LDI RCV_TEMP_REG_2.w0, 0
1789 SUB RCV_TEMP_REG_2.w2, RCV_CONTEXT.byte_cntr, 4 ;4 byte of FCS
1790 LSL RCV_TEMP_REG_2.w2, RCV_TEMP_REG_2.w2, 2
1792 ;Set the Port number on which packet was received
1793 .if $defined("PRU0")
1794 SET RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 16 ; Port 1
1795 .else
1796 SET RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 17 ;Port 2
1797 .endif
1799 CLR RCV_TEMP_REG_2, RCV_TEMP_REG_2, 15 ;Clear PTP descriptor bit
1801 .if $defined(PTP) ;check if bit 15 needs to be set
1802 QBBC LB_SKIP_PTP_DESC_BIT_SET, R22, RX_IS_PTP_BIT
1803 CLR R22, R22, RX_IS_PTP_BIT
1804 SET RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 15 ;Indicate to the driver that this is a PTP frame
1805 LB_SKIP_PTP_DESC_BIT_SET:
1806 .endif ;PTP
1808 .if $defined("ICSS_STP_SWITCH")
1809 ; Set FDB Lookup Success bit if the FDB lookup was successful
1810 QBBC FDB_LOOKUP_FAIL, R22, FDB_LOOKUP_SUCCESS__R22_BIT
1811 SET RCV_TEMP_REG_2, RCV_TEMP_REG_2, FDB_LOOKUP_SUCCESS__BD_BIT
1812 FDB_LOOKUP_FAIL:
1814 ; Set Packet Flooded bit if the packet was indeed flooded
1815 QBBC PKT_NOT_FLOODED, R22, PKT_FLOODED__R22_BIT
1816 SET RCV_TEMP_REG_2, RCV_TEMP_REG_2, PKT_FLOODED__BD_BIT
1817 PKT_NOT_FLOODED:
1818 .endif ; ICSS_STP_SWITCH
1820 ; the first buffer descriptor of the frame has been updated with length and port information
1821 SBCO &RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w2, 4
1823 ;Update the queue max fill level
1824 QBGT LB_RCV_QUEUE_WRAP, RCV_CONTEXT.wrkng_wr_ptr, RCV_CONTEXT.rd_ptr
1825 SUB RCV_TEMP_REG_2.w0, RCV_CONTEXT.wrkng_wr_ptr, RCV_CONTEXT.rd_ptr
1826 JMP SKIP_LB_RCV_QUEUE_WRAP
1828 LB_RCV_QUEUE_WRAP:
1829 ; add queue size to rd_ptr and then subtract wr_ptr
1830 SUB RCV_TEMP_REG_2.w0, RCV_CONTEXT.top_most_buffer_desc_offset, RCV_CONTEXT.rd_ptr
1831 ADD RCV_TEMP_REG_2.w0, RCV_TEMP_REG_2.w0, 4
1832 SUB RCV_TEMP_REG_2.w2, RCV_CONTEXT.wrkng_wr_ptr, RCV_CONTEXT.base_buffer_desc_offset
1833 ADD RCV_TEMP_REG_2.w0, RCV_TEMP_REG_2.w0, RCV_TEMP_REG_2.w2
1835 SKIP_LB_RCV_QUEUE_WRAP:
1836 ;divide the queue fill level by 4
1837 LSR RCV_TEMP_REG_2.w0, RCV_TEMP_REG_2.w0, 2
1838 ;Read the queue max fill level
1839 ADD RCV_TEMP_REG_1.w0, RCV_CONTEXT.rcv_queue_pointer, Q_MAX_FILL_LEVEL_OFFSET
1840 .if $defined("TWO_PORT_CFG")
1841 LBCO &RCV_TEMP_REG_2.b2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 1 ;RCV_TEMP_REG_2.w2.b0
1842 .else
1843 LBCO &RCV_TEMP_REG_2.b2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 1
1845 .endif ;TWO_PORT_CFG
1846 ;compare the new queue fill level with max fill level
1847 QBGE LB_SKIP_NEW_FILL_LEVEL, RCV_TEMP_REG_2.b0, RCV_TEMP_REG_2.b2
1848 AND RCV_TEMP_REG_2.b2 , RCV_TEMP_REG_2.b0 , RCV_TEMP_REG_2.b0
1849 ; store the new max fill level
1850 .if $defined("TWO_PORT_CFG")
1851 SBCO &RCV_TEMP_REG_2.b2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 1 ;RCV_TEMP_REG_2.w2.b0
1852 .else
1853 SBCO &RCV_TEMP_REG_2.b2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 1
1855 .endif ;TWO_PORT_CFG
1856 LB_SKIP_NEW_FILL_LEVEL:
1857 LB_HOST_PORT_QUEUE_OVERFLOW_CHECK:
1858 LB_HOST_QUEUE_OVERFLOW:
1860 ADD RCV_TEMP_REG_1.w0, RCV_CONTEXT.rcv_queue_pointer, Q_OVERFLOW_CNT_OFFSET
1861 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
1862 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
1863 QBA HOST_QUEUE_OVERFLOW_STATS
1865 LB_PORT_QUEUE_OVERFLOW_CHECK:
1866 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
1868 HOST_QUEUE_OVERFLOW_STATS:
1869 PORT_QUEUE_OVERFLOW_STATS:
1871 .if $defined("TWO_PORT_CFG")
1872 LBCO &RCV_TEMP_REG_2.b2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 1
1873 .else
1874 LBCO &RCV_TEMP_REG_2.b2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 1
1875 .endif
1876 ADD RCV_TEMP_REG_2.b2, RCV_TEMP_REG_2.b2, 1
1877 .if $defined("TWO_PORT_CFG")
1878 SBCO &RCV_TEMP_REG_2.b2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 1
1879 .else
1880 SBCO &RCV_TEMP_REG_2.b2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 1
1881 .endif
1882 LB_HOST_PORT_QUEUE_OVERFLOW_CHECK_DONE:
1883 ; Update the Queue Descriptor with the new wr_ptr
1884 ADD RCV_TEMP_REG_1.w0, RCV_CONTEXT.rcv_queue_pointer, Q_RD_PTR_SIZE
1885 .if $defined("TWO_PORT_CFG")
1886 SBCO &RCV_CONTEXT.wrkng_wr_ptr, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, Q_WR_PTR_SIZE
1887 .else
1888 SBCO &RCV_CONTEXT.wrkng_wr_ptr, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, Q_WR_PTR_SIZE
1889 .endif ;TWO_PORT_CFG
1890 .if $defined("ICSS_SWITCH_BUILD")
1891 .if $defined("TWO_PORT_CFG")
1892 QBBS LB_CHECK_COLLISION_FOR_PORT, R6, 0 ;CODE_EXECUTING_FOR_PORT_RECEIVE
1893 ; Update the collision status register with info required by the collision task.
1894 QBBC LB_UPDATE_CHECK_FWD_FLAG, MII_RCV.rx_flags, host_collision_queue_selected_shift ;MII_RCV.rx_flags.host_collision_queue_selected
1895 QBA LB_UPDATE_COLLISION_STATUS
1896 .endif ;TWO_PORT_CFG
1897 LB_CHECK_COLLISION_FOR_PORT:
1898 .if $defined("TWO_PORT_CFG")
1899 ; Update the collision status register with info required by the collision task.
1900 QBBC LB_NO_COLLISIION_OCCURED, MII_RCV.rx_flags, port_collision_queue_selected_shift ;MII_RCV.rx_flags.port_collision_queue_selected
1901 LB_UPDATE_COLLISION_STATUS:
1902 LDI RCV_TEMP_REG_1.w0, COLLISION_STATUS_ADDR
1903 AND COLLISION_STATUS_REG.b2 , MII_RCV.qos_queue , MII_RCV.qos_queue ;Warning: converted from MOV
1904 LSL COLLISION_STATUS_REG.b2, COLLISION_STATUS_REG.b2, 1
1905 OR COLLISION_STATUS_REG.b2, COLLISION_STATUS_REG.b2, 0x01
1906 QBBC LB_COLLISION_SATUS_FOR_HOST_QUEUE, R6, 0 ;CODE_EXECUTING_FOR_PORT_RECEIVE
1907 .if $defined("PRU0")
1908 ADD RCV_TEMP_REG_1.w0, RCV_TEMP_REG_1.w0, 2
1909 .else
1910 ADD RCV_TEMP_REG_1.w0, RCV_TEMP_REG_1.w0, 1
1911 .endif
1913 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, port_collision_queue_selected_shift ; Clear the collision bit for port
1914 LB_COLLISION_SATUS_FOR_HOST_QUEUE:
1915 SBCO &COLLISION_STATUS_REG.b2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 1
1917 QBBC LB_UPDATE_CHECK_FWD_FLAG, R6, 0 ;CODE_EXECUTING_FOR_PORT_RECEIVE
1918 .endif ;TWO_PORT_CFG
1919 LB_NO_COLLISIION_OCCURED:
1920 LB_UPDATE_CHECK_DONE:
1921 .endif ;ICSS_SWITCH_BUILD
1922 LB_RELEASE_QUEUE:
1923 .if $defined("ICSS_SWITCH_BUILD")
1924 QBBS LB_RELEASE_HOST_QUEUE, MII_RCV.rx_flags_extended, host_queue_overflow_shift ;MII_RCV.rx_flags_extended.host_queue_overflow
1925 QBBC LB_RELEASE_QUEUE_CHECK_FWD_FLAG, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
1926 .endif ;ICSS_SWITCH_BUILD
1927 LB_RELEASE_HOST_QUEUE:
1928 ;Release the Receive Queue. De-assert the Queue busy bit
1929 ; PRU0 is master so it clear's only "busy_m" bit
1930 .if $defined("PRU0")
1931 ADD RCV_TEMP_REG_1.w0, MII_RCV.rcv_queue_pointer, Q_STATUS_OFFSET
1932 .if $defined("TWO_PORT_CFG")
1933 LBCO &RCV_TEMP_REG_2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 3
1934 .else
1935 LBCO &RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 3
1937 .endif ;TWO_PORT_CFG
1938 AND RCV_TEMP_REG_2.b0, RCV_TEMP_REG_2.b0, 0xFC ; !(1<<Q_BUSY_M_BIT | 1<<Q_COLLISION_BIT)
1939 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
1940 OR RCV_TEMP_REG_2.b0, RCV_TEMP_REG_2.b0, 0x04 ; set the overflow bit
1941 ADD RCV_TEMP_REG_2.b2, RCV_TEMP_REG_2.b2, 1 ; increment the overflow count by 1
1942 LB_NO_HOST_QUEUE_OVERFLOW_OCCURED:
1943 .if $defined("TWO_PORT_CFG")
1944 SBCO &RCV_TEMP_REG_2.b0, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 3
1945 .else
1946 SBCO &RCV_TEMP_REG_2.b0, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 3
1947 .endif ;TWO_PORT_CFG
1949 .else
1950 ; PRU1 is slave so it clear's only "busy_s" bit
1951 ADD RCV_TEMP_REG_1.w0, MII_RCV.rcv_queue_pointer, Q_BUSY_S_OFFSET
1952 .if $defined("TWO_PORT_CFG")
1953 LBCO &RCV_TEMP_REG_2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 4
1954 .else
1955 LBCO &RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 4
1956 .endif ;TWO_PORT_CFG
1957 LDI RCV_TEMP_REG_2.b0, 0
1958 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
1959 OR RCV_TEMP_REG_2.b1, RCV_TEMP_REG_2.b1, 0x04 ; set the overflow bit
1960 ADD RCV_TEMP_REG_2.b3, RCV_TEMP_REG_2.b3, 1 ; increment the overflow count by 1
1961 LB_NO_HOST_QUEUE_OVERFLOW_OCCURED_SLAVE:
1962 .if $defined("TWO_PORT_CFG")
1963 SBCO &RCV_TEMP_REG_2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 4
1964 .else
1965 SBCO &RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 4
1966 .endif ;TWO_PORT_CFG
1967 .endif
1969 LB_RELEASE_QUEUE_CHECK_FWD_FLAG:
1970 .if $defined("ICSS_SWITCH_BUILD")
1971 QBBS LB_RELEASE_PORT_QUEUE, MII_RCV.rx_flags_extended, port_queue_overflow_shift ;MII_RCV.rx_flags_extended.port_queue_overflow
1972 QBBC LB_RELEASE_QUEUE_CHECK_DONE, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
1974 LB_RELEASE_PORT_QUEUE:
1975 ;Release the Port Receive Queue. clear busy_m bit in status as PRU is master
1977 ADD RCV_TEMP_REG_1.w0, MII_RCV_PORT.rcv_queue_pointer, Q_STATUS_OFFSET
1978 .if $defined("TWO_PORT_CFG")
1979 LBCO &RCV_TEMP_REG_2, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 3
1980 .else
1981 LBCO &RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 3
1982 .endif ;TWO_PORT_CFG
1983 AND RCV_TEMP_REG_2.b0, RCV_TEMP_REG_2.b0, 0xFC ; !(1<<Q_BUSY_M_BIT | 1<<Q_COLLISION_BIT)
1984 QBBC LB_NO_PORT_QUEUE_OVERFLOW_OCCURED, MII_RCV.rx_flags_extended, port_queue_overflow_shift ;MII_RCV.rx_flags_extended.port_queue_overflow
1985 OR RCV_TEMP_REG_2.b0, RCV_TEMP_REG_2.b0, 0x04 ; set the overflow bit
1986 ADD RCV_TEMP_REG_2.b2, RCV_TEMP_REG_2.b2, 1 ; increment the overflow count by 1
1987 LB_NO_PORT_QUEUE_OVERFLOW_OCCURED:
1988 .if $defined("TWO_PORT_CFG")
1989 SBCO &RCV_TEMP_REG_2.b0, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w0, 3
1990 .else
1991 SBCO &RCV_TEMP_REG_2.b0, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 3
1992 .endif ;TWO_PORT_CFG
1993 .if $defined(PTP)
1994 QBBC LB_RELEASE_QUEUE_CHECK_DONE, R22, PTP_RELEASE_PORT_QUEUE_BIT
1995 CLR R22, R22, PTP_RELEASE_PORT_QUEUE_BIT
1996 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, fwd_flag_shift
1997 QBA PTP_PORT_QUEUE_RELEASE_DONE
1998 .endif
1999 LB_RELEASE_QUEUE_CHECK_DONE:
2000 LB_MAINTENANCE:
2001 .endif ;ICSS_SWITCH_BUILD
2003 CLR R23 , R23 , Rcv_active ; indicate that rcv has been completed
2004 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
2005 SET R23 , R23 , RX_STAT_PEND
2007 .if $defined("ICSS_SWITCH_BUILD")
2008 QBBC LB_DONE, MII_RCV.rx_flags, host_rcv_flag_shift ;MII_RCV.rx_flags.host_rcv_flag
2009 .if $defined("TWO_PORT_CFG")
2010 QBBS LB_DONE, MII_RCV.rx_flags, host_collision_queue_selected_shift ;MII_RCV.rx_flags.host_collision_queue_selected
2011 .endif ;TWO_PORT_CFG
2012 .endif ;ICSS_SWITCH_BUILD
2014 M_RCV_RX_EOF_INTERRUPT_RAISE_INTC ; raise RX interrupt on intc controller.
2016 .if $defined("ICSS_SWITCH_BUILD")
2017 LB_DONE:
2018 .if $defined("TWO_PORT_CFG")
2019 CLR MII_RCV.rx_flags, MII_RCV.rx_flags, host_collision_queue_selected_shift ;MII_RCV.rx_flags.host_collision_queue_selected
2020 .endif ;TWO_PORT_CFG
2021 QBBC DO_NOT_SET_RX_FWD, MII_RCV.rx_flags, fwd_flag_shift ;MII_RCV.rx_flags.fwd_flag
2022 .if $defined("TWO_PORT_CFG")
2023 SET R22, R22, RX_FWD_FLAG
2024 .endif ;TWO_PORT_CFG
2026 DO_NOT_SET_RX_FWD:
2027 .endif ;ICSS_SWITCH_BUILD
2029 LB_NO_RX_STAT:
2031 .if $defined("ICSS_REV1")
2032 M_RCV_RX_EOF_CLEAR_INTC_ICSS_REV1
2033 .endif ;ICSS_REV1
2035 .if $defined("ICSS_REV2")
2036 M_RCV_RX_EOF_CLEAR_INTC_ICSS_REV2
2037 .endif ;ICSS_REV2
2039 ; Execute the TX Task as next task
2040 QBBC TASK_EXECUTION_FINISHED_inter, R23, 0 ;replaced: QBBC TASK_EXECUTION_FINISHED_inter, Xmt_active
2041 LDI CURRENT_TASK_POINTER, BG_TASK_POINTER
2042 JMP XMT_QUEUE
2044 TASK_EXECUTION_FINISHED_inter:
2045 JMP TASK_EXECUTION_FINISHED
2047 .if $defined("TWO_PORT_CFG")
2048 ;/////////////////////////////// Experimenting Start /////////////////////////////////////////////////////
2050 ;-------------------------------------------------------------------------------------------
2051 ; Function: F_QUEUE_ARBITRATION
2052 ; Description: Function will aquire token for either queue or collision buffer
2053 ; Input: MII_RCV.qos_queue - contains the Qos queue number as been determined by the RX_FB function
2054 ; Input: RCV_TEMP_REG_3.w0 - contains the base address of host/port queue
2055 ; Input: RCV_TEMP_REG_3.w2 - contains the base address of the collision queue
2056 ; Input: RCV_TEMP_REG_1.b1 - contains information about whether called for host or port queue arbitration
2057 ; Output: RCV_TEMP_REG_1.b0 - returns value for caller, to indicate that the queue has been aquired
2058 ; successful ((0-failed to aquire; 1-queue; 2-collision)
2059 ; Output: RCV_TEMP_REG_2.w0 - returns the queue pointer after aquiring the queue
2060 ; Output: RCV_TEMP_REG_2.w2 - returns the current write pointer of the queue that has been aquired
2061 ; is used as wrkng_wr_ptr during the following packet processing
2062 ; RCV_TEMP_REG_1.w2 - temporayr use
2063 ;-------------------------------------------------------------------------------------------
2065 FN_QUEUE_ARBITRATION:
2066 LDI RCV_TEMP_REG_1.b0, 0x00
2067 QAM_CHECK:
2068 LSL RCV_TEMP_REG_1.w2, MII_RCV.qos_queue, 3 ; adjust queue-number offset to 8byte boundaries
2069 QBNE PICK_NORMAL_QUEUE, RCV_TEMP_REG_1.b0, COLLISION_AQUIRED
2070 LDI RCV_TEMP_REG_1.w2, 0x0
2071 PICK_NORMAL_QUEUE:
2072 ADD RCV_TEMP_REG_1.w2, RCV_TEMP_REG_3.w0, RCV_TEMP_REG_1.w2 ; adjust for queue base address
2073 ADD RCV_TEMP_REG_3.w0, RCV_TEMP_REG_1.w2, Q_BUSY_S_OFFSET ; .w2 points to Q_BUSY_S_OFFSET
2074 ADD RCV_TEMP_REG_1.w2, RCV_TEMP_REG_1.w2, Q_STATUS_OFFSET ; .w0 points to Q_STATUS_OFFSET
2075 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
2076 ; Check if it is called for the Port Arbitration
2077 QBBS PORT_QUEUE_ARBITRATION, RCV_TEMP_REG_1.b1, 0 ;RCV_TEMP_REG_1.b1.t0
2078 .if $defined("PRU0")
2079 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
2080 SET RCV_TEMP_REG_2.b3, RCV_TEMP_REG_2.b3, Q_BUSY_M_BIT ;RCV_TEMP_REG_2.w2.b1
2081 SBCO &RCV_TEMP_REG_2.b3, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w2, Q_STATUS_SIZE ; set busy_m into memory
2082 QBA QAM_CALC_QUEUE_POINTER
2083 .else
2084 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
2085 SET RCV_TEMP_REG_2.b2, RCV_TEMP_REG_2.b2, Q_BUSY_S_BIT ;RCV_TEMP_REG_2.w2.b0
2086 SBCO &RCV_TEMP_REG_2.b2, PRU1_DMEM_CONST, RCV_TEMP_REG_3.w0, Q_BUSY_S_SIZE ; set busy_s into memory
2087 ; load again busy_m ..only for Slave because it needs to check that master has not acquired the queue inbetween
2088 LBCO &RCV_TEMP_REG_2.b3, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w2, Q_STATUS_SIZE ;RCV_TEMP_REG_2.w2.b1
2089 QBBC QAM_CALC_QUEUE_POINTER, RCV_TEMP_REG_2.b3, Q_BUSY_M_BIT ; is queue already busy?
2090 ; Clear busy_s bit because busy_m bit is set
2091 CLR RCV_TEMP_REG_2.b2, RCV_TEMP_REG_2.b2, Q_BUSY_S_BIT ;RCV_TEMP_REG_2.w2.b0
2092 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
2093 QBA QAM_BUSY
2094 .endif
2096 PORT_QUEUE_ARBITRATION:
2097 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
2098 SET RCV_TEMP_REG_2.b3, RCV_TEMP_REG_2.b3, Q_BUSY_M_BIT ;RCV_TEMP_REG_2.w2.b1
2099 SBCO &RCV_TEMP_REG_2.b3, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w2, Q_STATUS_SIZE ; set busy_m into memory
2100 QBA QAM_CALC_QUEUE_POINTER
2102 QAM_BUSY: ; failed to aquire the queue, now try the colission
2103 QBEQ QAM_FAILED, RCV_TEMP_REG_1.b0, COLLISION_AQUIRED
2104 AND RCV_TEMP_REG_3.w0 , RCV_TEMP_REG_3.w2 , RCV_TEMP_REG_3.w2
2105 LDI RCV_TEMP_REG_1.b0, COLLISION_AQUIRED ; failed to aquire the queue, indicate this to macro caller by returing 0
2106 ;check that host has emptied the queue before acquiring it
2107 LDI RCV_TEMP_REG_1.w2, COLLISION_STATUS_ADDR
2108 ADD RCV_TEMP_REG_1.w2, RCV_TEMP_REG_1.w2, 3
2109 LBCO &RCV_TEMP_REG_1.b3, PRU1_DMEM_CONST, RCV_TEMP_REG_1.w2, 1
2110 QBBC QAM_CHECK, RCV_TEMP_REG_1, 3 ;replaced: QBBC QAM_CHECK, RCV_TEMP_REG_1.HOST_COLLISION_READ_PENDING
2112 QAM_FAILED:
2113 LDI RCV_TEMP_REG_1.b0, QUEUE_FAILED ; failed to aquire queue & collision
2114 LDI RCV_TEMP_REG_2.w2, 0
2115 QBA QAM_DONE
2116 QAM_CALC_QUEUE_POINTER:
2117 QBEQ PICK_COL_QUEUE, RCV_TEMP_REG_1.b0, COLLISION_AQUIRED
2118 ; return value that queue had been aquired OK.
2119 LDI RCV_TEMP_REG_1.b0, QUEUE_AQUIRED
2120 PICK_COL_QUEUE:
2121 ; adjust the pointer to the wr_ptr offset
2122 SUB RCV_TEMP_REG_2.w0, RCV_TEMP_REG_1.w2, Q_STATUS_OFFSET - Q_WR_PTR_OFFSET
2123 ; load wr_ptr from memory, and us it to init the wrkng_wr_ptr
2124 LBCO &RCV_TEMP_REG_2.w2, PRU1_DMEM_CONST, RCV_TEMP_REG_2.w0, Q_WR_PTR_SIZE
2125 ; ToDo: this can be optimized!
2126 SUB RCV_TEMP_REG_2.w0, RCV_TEMP_REG_2.w0, Q_WR_PTR_OFFSET
2127 QAM_DONE:
2128 JMP CALL_REG
2130 ;////////////////////////////// Experimenting End ////////////////////////////////////////////////////////////////////
2131 .endif ;TWO_PORT_CFG
2132 .endif ; e/o MII_Rcv_p