Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / obp / obp / dev / network / neptune / core.fth
CommitLineData
920dae64
AT
1\ ========== Copyright Header Begin ==========================================
2\
3\ Hypervisor Software File: core.fth
4\
5\ Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
6\
7\ - Do no alter or remove copyright notices
8\
9\ - Redistribution and use of this software in source and binary forms, with
10\ or without modification, are permitted provided that the following
11\ conditions are met:
12\
13\ - Redistribution of source code must retain the above copyright notice,
14\ this list of conditions and the following disclaimer.
15\
16\ - Redistribution in binary form must reproduce the above copyright notice,
17\ this list of conditions and the following disclaimer in the
18\ documentation and/or other materials provided with the distribution.
19\
20\ Neither the name of Sun Microsystems, Inc. or the names of contributors
21\ may be used to endorse or promote products derived from this software
22\ without specific prior written permission.
23\
24\ This software is provided "AS IS," without a warranty of any kind.
25\ ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
26\ INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
27\ PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
28\ MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
29\ ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
30\ DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
31\ OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
32\ FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
33\ DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
34\ ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
35\ SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
36\
37\ You acknowledge that this software is not designed, licensed or
38\ intended for use in the design, construction, operation or maintenance of
39\ any nuclear facility.
40\
41\ ========== Copyright Header End ============================================
42id: @(#)core.fth 1.2 07/03/13
43purpose:
44copyright: Copyright 2007 Sun Microsystems, Inc. All rights reserved.
45copyright: Use is subject to license terms.
46
47headerless
48
49\ Possible vables of PKTBUFSZ field of the Receive Completion Ring Entry
50b# 00 constant bufsz0
51b# 01 constant bufsz1
52b# 10 constant bufsz2
53b# 11 constant singleblk
54
55\ Neptune Tx packet descriptor structure. Flags occupies bits [63:44]
56h# 1 d# 63 lshift constant sof \ Start of Frame
57h# 1 d# 62 lshift constant mark \ Interrupt after pkt is transmitted
58h# 1 d# 58 lshift constant num-ptr=1 \ # of gather pointers of this pkt=1
59h# 1fff d# 44 lshift constant tr-len-mask \ Mask for TR_LEN (bits[56:44])
60
61\ SW must toggle this bit every time the tail wraps around the ring.
62h# 8.0000 constant wrap=1
630 constant wrap=0
64wrap=0 value wrap
65
660 value last-rmd-idx
67
68\ Get the HEAD field of register TX_RING_HDL to check which descriptor
69\ has been processed by the hardware
70\
71\ In Neptune, software appends packets to be transmitted to the tail
72\ of the TX descriptor ring; HW hammers the packet at the head of
73\ the TX ring to the medium. When we transmit one packet at a time,
74\ the head will follow the tail! Packets have been sent out when
75\ head matches tail.
76\
77: tx-head@ ( chan -- head ) tx-ring-hdl-i@ 3 xrshift h# ffff and ;
78: tx-hdr-wrap@ ( chan -- wrap ) tx-ring-hdl-i@ d# 44 lshift d# 63 xrshift ;
79: tx-tail@ ( chan -- tail ) tx-ring-kick-i@ 3 xrshift h# ffff and ;
80: tx-tail-wrap@ ( chan -- wrap ) tx-ring-kick-i@ d# 44 lshift d# 63 xrshift ;
81
82false instance value restart? \ To flag serious errors
83
84\ Words to access the 64-bit message descriptors.
85\ xbflip takes care of SPARC's big endianess
86\
87: descriptor64@ ( addr -- x ) x@ xbflip ;
88: descriptor64! ( x addr -- ) >r xbflip r> x! ;
89
90: descriptor32@ ( addr -- x ) l@ lbflip ;
91: descriptor32! ( x addr -- ) >r lbflip r> l! ;
92
93\ RX descriptor ring address calculations
94: rmd#>rmdaddr ( n -- addr ) /rmd * rmd0 + ;
95: rmdaddr>rmd# ( addr -- n ) rmd0 - /rmd / ;
96
97\ TX descriptor ring address calculations
98\ /tmd=8 (bytes), which is the size of tx descriptor
99: tmd#>tmdaddr ( n -- addr ) #tmds mod /tmd * tmd0 + ;
100: tmdaddr>tmd# ( addr -- n ) tmd0 - /tmd / #tmds mod ;
101
102\ RX completion ring address calculations
103: rcd#>rcdaddr ( n -- addr ) #rcds mod /rcd * rcd0 + ;
104: rcdaddr>rcd# ( addr -- n ) rcd0 - /rcd / #rcds mod ;
105
106\ RX buffer address calculations
107\ #rbufs is the total number of Rx buffers = 60 = 64-4
108\ /rbuf is the size of Rx data block, 8K each
109: rbuf#>rbuf-io-adr ( n -- addr ) #rbufs mod /rbuf * io-rbuf0 + ;
110
111\ Convert rcd-cpu-addr to rcd-io-addr
112: rcd-cpu-addr>rcd-io-addr ( rcd-cpu-addr -- rcd-io-addr )
113 rcd0 - io-rcd0 +
114;
115
116: tmdheader@ ( tmdaddr -- len )
117 descriptor64@
118 d# 44 xrshift d# 44 lshift \ Clear the lower 44 bits of
119; \ descriptor contents
120
121\ Pointer to the shared 4K Tx data buffer is the lower 44 bits
122\ of the descriptor. This word gets the contents of the descriptor
123\ then mask off the top 20 bits of the 64 bits descriptor.
124\
125: txbufptr@ ( tmdaddr -- addr )
126 descriptor64@
127 d# 20 lshift d# 20 xrshift
128;
129
130\ Get current tmd entry, clear bits 63:44, OR the addr of
131\ block buffer with new flags including len. Must use xrshift
132\ to avoid truncating.
133\
134: tmdheader! ( hdr tmdaddr -- )
135 dup ( hdr tmdaddr tmdaddr )
136 txbufptr@ ( hdr tmdaddr low44_cur_tmd )
137 rot ( tmdaddr low44_cur_tmd hdr )
138 or ( tmdaddr lenORlow44_cur_tmd )
139 swap ( new_tmd tmdaddr ) \ new_tmd = len OR low44bits_cur_tmd
140 descriptor64!
141;
142
143\ The TX descriptor has two parts, the leading 20 bits are flags and
144\ the length of data, the remaining 44 bits are address of the data
145\ buffer. This word only puts the address of a data buffer to the
146\ lower 44 bits of the descriptor without changing the leadring
147\ 20 bits, which are set by tmdheader!
148\
149: txbufptr! ( bufptr tmdaddr -- )
150 >r ( bufptr ) ( r: tmdaddr )
151 d# 20 lshift d# 20 xrshift \ Clear the top 20 bits of bufptr
152 r> ( low44_bufptr tmdaddr )
153 dup ( low44_bufptr tmdaddr tmdaddr )
154 tmdheader@ ( low44_bufptr tmdaddr top20bits_cur_tmd )
155 rot ( tmdaddr top20bits_cur_tmd low44_bufptr )
156 or ( tmdaddr top20bits_cur_tmd-OR-low44_bufptr )
157 swap ( new_tmd tmdaddr ) \ new_tmd=top20bits_cur_tmd OR low44_bufptr
158 descriptor64!
159;
160
161\ RX descriptor fields
162\
163: rxbufptr! ( bufptr rmdaddr -- )
164 swap ( rmdaddr bufptr )
165 d# 12 xrshift d# 12 lshift \ Clear the low 12 bits
166 swap
167 descriptor64!
168;
169
170: rxbufptr@ ( rmdaddr -- bufptr )
171 descriptor64@
172 \ What we read from the descriptor is bits[43:12] of addr
173 d# 12 lshift \ now append 12 0s to bits[43:12]
174;
175
176: synciopb ( cpu-addr size -- )
177 over ( cpu-addr size cpu-addr )
178 cpu>io-adr ( cpu-addr size dev-addr )
179 swap ( cpu-addr io-addr size )
180 dma-sync ( )
181;
182
183\ Set logic device group 0 to include Channel0 RxDMA (logic devie 0),
184\ Channel0 TxDMA (logic device 32) and port-th MAC (logic device 64,65,66,67).
185\ Set logic device group 63 for Device Error (logic device 68)
186\
187\ Notice that these registers are blocked off in NIU and must be accessed
188\ via Hypervisor APIs.
189\
190 0 constant ld-rx-dma0
191d# 32 constant ld-tx-dma0
192d# 64 constant ld-mac0
193d# 68 constant ld-sys-err
194
195: set-ldg ( -- )
196 ld-rx-dma0 ldg0 ldg-num-i!
197 ld-tx-dma0 ldg0 ldg-num-i!
198 ld-mac0 port + ldg0 ldg-num-i!
199 ld-sys-err ldg63 ldg-num-i!
200;
201
202
203\ RX descriptor Initialization
204\ rbuf-io-adr: io addr of a 8K data block buffer for hw to use.
205\ rmd-cpu-adr: cpu addr of a Rx descriptor entry for driver to use.
206\ Before lshift
207\ 63 43 0
208\ +-----------+------------------------+
209\ |xxxxxxxxxxx| high addr low-adr |
210\ +-----------+------------------------+
211\ After lshift 20 then xrshift 32
212\ 63 31 0
213\ +------------------+-----------------+
214\ |000000000000000000| high addr |000low-adr00
215\ +------------------+-----------------+
216\ 43 12 0
217\ After this word is called, we should see initialized rx
218\ descriptors at cpu memory location rmd-cpu-adr
219\ which is the result of
220\ i rmd#>rmdaddr
221\ where rmd#>rmdaddr ( n -- addr ) is defined as
222\ /rmd * rmd0 + ;
223\ Do dump rmd0 to see the contents
224
225: rmd-init ( rbuf-io-adr rmd-cpu-adr -- )
226 dup ( rbuf-io-adr rmd-cpu-adr rmd-cpu-adr )
227 rot ( rmd-cpu-adr rmd-cpu-adr rbuf-io-adr )
228 d# 20 lshift d# 32 xrshift \ Clear bits[63:44] & bits[11:0] of rbuf-io-adr
229 swap ( rmd-cpu-adr rbuf-io-adr' rmd-cpu-adr )
230 descriptor32! ( rmd-cpu-adr ) \ Store rbuf-io-adr' in cpu-rmaddr
231 \ rmd is 32 bits!
232 /rmd synciopb \ dma sync using a cpu address
233;
234
235\ RX completion descriptor initialization
236\ Fill deadbeef to rcd entry. HW will fill in meaningful values after
237\ receiving packets.
238\
239: rcd-init ( rcd-cpu-adr -- )
240 h# dead.beef over ( rcd-cpu-adr deadbeef rcd-cpu-adr )
241 descriptor64! ( rcd-cpu-adr )
242 /rcd synciopb \ sunc so that HW will get the newest data
243;
244
245\ TX descriptor initialization called by transmit.
246\ o "Transfer length" (TR_LEN, bits[56:44]) of Neptune Tx Packet
247\ descriptor is 13 bit long , so the TR_LEN mask is 0x1FFF.
248\ o Mark bit is never set, so we do not request interrust after Tx.
249\ o Here we store header with tmdheader! and store pointer to data
250\ buffer with txbufptr! We could have combined them into one. Actually
251\ we do not need to make Tx descriptor point to the shared Tx data
252\ buffer before each time we use it because doing it once at
253\ initialization is enough.
254\ o Although the MARK bit of the descriptor will cause an interrupt
255\ after the packet is transmitted only if interrupt is enabled,
256\ we still set it hoping that it will still cause the MK bit of
257\ the TX_CS register to be turned on. In send-wait we will
258\ check that bit to make sure that the packet has indeed been
259\ transmitted.
260\
261: tmd-init ( txbuf len tmdaddr -- )
262 swap ( txbuf tmdaddr len )
263
264 \ First Check len
265 dup tr-len-mask d# 44 xrshift ( txbuf tmdaddr len len 0x1fff)
266 > if cmn-error[ " Application data too long" ]cmn-end
267 true to restart? \ Set flag, will restart at the end of transmit
268 then
269 d# 44 lshift \ Shift TR_LEN(len) of appl data to bits[56:44]
270 tr-len-mask and ( txbuf tmdaddr len ) \ bits[56:44] is len
271 sof or ( txbuf tmdaddr len|SOF ) \ Every packet is sof
272 mark or ( txbuf tmdaddr len|SOF|MARK )
273 num-ptr=1 or ( txbuf tmdaddr len|SOF|MARK|NUM_PTR )
274 over ( txbuf tmdaddr value tmdaddr )
275 tmdheader! ( txbuf tmdaddr )
276 swap ( tmdaddr txbuf )
277 cpu>io-adr ( tmdaddr txbuf-io-adr )
278 over ( tmdaddr txbuf-io-adr tmdaddr )
279 txbufptr! \ store the txbuf-io-addr into the pointer part of tmd
280 /tmd synciopb \ dma sync the tmd entry
281;
282
283
284\ 14 bits L2_LEN is bit[53:40] of Rx completion ring entry.
285\ Do shifts so that the 64 bit values contains only the packet length
286\
287: rcdaddr>pkt-len ( rcdaddr -- pkt-len )
288 descriptor64@ d# 10 lshift d# 50 xrshift
289;
290
291\ With the cpu address of a Rx Completion Ring descriptor, read the
292\ contents of the descriptor with descriptor64@, then shift out
293\ PKTBUFSZ (bits[39:38] of the descriptor entry), which indicates the
294\ partition of the 8K block buffer. 00=BUFSZ0, b01=BUFSZ1, b10=BUFSZ2
295\ b11=single block=8K
296\
297: rcdaddr>pbuf-size ( rcdaddr -- pbuf-len )
298 descriptor64@ d# 24 lshift d# 63 xrshift
299;
300
301\ With the cpu address of a Rx Completion Ring descriptor, read the
302\ contents of the descriptor with descriptor64@, then shift out
303\ PKT_BUF_ADDR (bits[37:0] of the descriptor entry)
304\
305: rcdaddr>pbuf-addr ( rcdaddr -- pbuf-addr )
306 descriptor64@ d# 26 lshift d# 26 xrshift
307;
308
309
310\ It is easy to figure out rcd# from the (cpu) address of rcd.
311\ Inside rcd we can find the io-adr of the rx block buffer and
312\ the offset of the packet inside that block buffer. With
313\ these two pieces of info, we can find the io-addr of the packet.
314\ Finally we conver the io-adr of the packet to its cpu-adr
315\ 43 6 0 ( real io adr)
316\ RCR 63 37 0 ( RCR bits )
317\ | flags |<----- packet-io-addr----|----->|
318\ bits[5:0]=0 implied
319
320: rcdaddr>pkt-cpu-adr ( rcd-cpu-addr -- pkt-cpu-adr )
321 descriptor64@ d# 26 lshift d# 20 xrshift \ Get rid of flags
322 io>cpu-adr ( pkt-adr )
323;
324
325: rcd#>skip ( n -- #skip )
326 rcd#>rcdaddr descriptor64@ d# 55 xrshift 3 and
327;
328
329\ Sync buffer contents
330: sync-buf ( buf-cpu-adr len -- )
331 over ( buf-cpu-adr len buf-cpu-adr )
332 cpu>io-adr ( buf-cpu-adr len buf-io-adr )
333 swap ( buf-cpu-adr buf-io-adr len )
334 dma-sync ( )
335;
336
337variable nextrcd
338variable nexttmd
339
340\ Get current rx completion descriptor ring pointer in CPU address space.
341: nextrcd@ ( -- rcd-cpu-addr ) nextrcd x@ ;
342
343\ Get current tx message descriptor ring pointer in CPU address space.
344: nexttmd@ ( -- tmd-cpu-addr ) nexttmd x@ ;
345
346\ Save current rx completion/tx message descriptor ring pointer in
347\ CPU address space.
348\ Note that we write a rcd address to nextrcd variable, not contents of
349\ a rcd to nextrcd
350\
351: nextrcd! ( rcdaddr -- ) nextrcd x! ;
352
353: nexttmd! ( tmdaddr -- ) nexttmd x! ;
354
355: tx-config ( chan -- )
356 0 tx-addr-md! \ Use 64 bit addressing mode
357
358 niu? 0= if
359 \ Define only page0, page1 will not be checked.
360 \ Set the FUNC field (bits[3:2]) of register TX_LOG_PAGE_VLD to
361 \ port (it equals PCI function number) which will "be used when
362 \ sending request across PCI bus".
363 port 2 lshift page0 or ( chan# val ) \ val = FUNC|PAGE0
364 over tx-log-page-vld-i! \ Use only chan#-th Rx DMA channel
365
366 \ All mask bits are set to 0 so there is no relocation.
367 0 over tx-log-mask1-i!
368 0 over tx-log-value1-i!
369 0 over tx-log-mask2-i!
370 0 over tx-log-value2-i!
371 0 over tx-log-page-relo1-i! \ Since mask=0, this doesn't matter
372 0 over tx-log-page-relo2-i! \ Since mask=0, this doesn't matter
373 0 over tx-log-page-hdl-i! \ Assume no need to extend to 64 bits
374 then
375 drop
376
377 \ Weight of Deficit Round Robin for multiple Tx DMA chan to share a port.
378 h# 2710 chan# txc-dma-max-i!
379
380 \ Do not inject parity error to any of the 24 DMA
381 0 tdmc-inj-par-err!
382
383 \ Debug select register, set to initial value
384 0 tdmc-dbg-sel!
385
386 \ TDMC training vector register, set to default value
387 0 tdmc-training-vector!
388;
389
390
391: rx-config ( chan -- )
392 \ System clock divider, granularity for dma timeout.
393 h# 1d4c rx-dma-ck-div!
394
395 set-default-rdc-for-my-port
396
397 \ Use 64 bit addressing mode. But test shows that bit0 = 1 (MODE32)
398 \ also works.
399 0 rx-addr-md!
400
401 \ Weights of Deficit Round Robin (DRR) for 4 ports
402 h# 400 pt-drr-wt0!
403 h# 400 pt-drr-wt1!
404 h# 66 pt-drr-wt2!
405 h# 66 pt-drr-wt3!
406
407 niu? 0= if
408 \ Logic pages related registers. All mask bits are set to 0
409 \ so there is no relocation. Only page0 is defined so page1 will
410 \ not be checked. Bits[3:2] of register RX_LOG_PAGE_VLD (FUNC)
411 \ is set to the PCI function number (which is equal to the port
412 \ number). The FUNC field is used when we make PCI request
413 port 2 lshift page0 or ( chan x1 )
414 over rx-log-page-vld-i!
415
416 0 over rx-log-mask1-i!
417 0 over rx-log-val1-i!
418 0 over rx-log-mask2-i!
419 0 over rx-log-val2-i!
420 0 over rx-log-page-relo1-i! \ Since mask=0, this doesn't matter
421 0 over rx-log-page-relo2-i! \ Since mask=0, this doesn't matter
422 0 over rx-log-page-hdl-i! \ Assume no need for 64 bits
423
424 \ Set MBADDR_L=0, OFFSET=no, FULL_HDR
425 full-hdr over rxdma-cfig2-i!
426 else
427 io-rmbox xlsplit nip ( chan addr.lo )
428 over rxdma-cfig1-i! ( chan )
429
430 \ RXMAC configuration2
431 io-rmbox xlsplit drop ( chan addr.hi )
432 full-hdr or ( chan addr.hi' )
433 over rxdma-cfig2-i! ( chan )
434 then ( chan )
435
436 \ Disable mailbox
437 dup rx-dma-ctl-stat-i@ mex invert and ( chan x1 )
438 swap rx-dma-ctl-stat-i! ( )
439;
440
441: wait-sng-state ( -- flag )
442 chan# tx-cs-i@ sng-state and 0<> \ SNG_STATE=1 if reset is done
443;
444
445: wait-for-dma-engine-to-stop ( -- ok? )
446 d# 3000 ['] wait-sng-state wait-status
447 dup 0= if
448 cmn-error[ " SNG_STATE did not reset" ]cmn-end
449 then
450;
451
452\ Check if RST is cleared by HW and if QST is 1 which
453\ incidates all state machines are in initial state
454: wait-rx-dma-reset ( chan# -- flag )
455 dup rxdma-cfig1-i@ rxdma-rst and 0= \ RST = 0 ?
456 swap rxdma-cfig1-i@ rxdma-qst and 0<> and \ QST = 1 ?
457;
458
459\ PRM: "First set EN bit to zero, and then set RST bit to 1.
460\ After RST bit is cleared by hardware and the QST bit is set
461\ to 1, software may then start configuring the DMA channel.
462\ After configuration, software may then set the EN bit to 1
463\ to enable the DMA.
464\
465\ First disable Rx DMA by setting EN bit of RXDMA_CFG1 to 0
466\ then set RST bit and poll it until hardware clears it.
467\ After this call, we can start configuring the DMA channel.
468\ We will enable the Rx DMA in enable-tx-dma-channel which is
469\ called at the end of (setup-link).
470\
471: reset-rx-dma-channel ( chan# -- ok? )
472 dup dup
473 rxdma-cfig1-i@ ( chan# chan# val )
474 rxdma-en invert and swap ( chan# val&[~EN] chan# )
475 rxdma-cfig1-i! ( chan# )
476 dup ( chan# chan# )
477 \ Just set RST bit, do not read first
478 rxdma-rst swap ( chan# val|RST chan# )
479 rxdma-cfig1-i! ( chan# )
480 d# 100 swap ( 100 chan# )
481 ['] wait-rx-dma-reset wait-status-with-arg
482 dup 0= if ( ok? )
483 cmn-error[ " reset-rx-dmc-channel failed" ]cmn-end
484 then
485;
486
487\ The PRM states:
488\ "The DMA channel may be reset by writing a 1 to the RST bit. When
489\ reset is completed, hardware will set the RST_STATE bit to 1."
490\ In the description of the RST bit of the TX_CS register, PRM also
491\ mentions "Hardware will clear this bit after reset is completed."
492\ We check the completion of DMA reset by checking both RST=0 and
493\ RST_STATE=1.
494\
495: wait-tx-dma-reset ( chan# -- flag )
496 dup tx-cs-i@ rst and 0=
497 swap tx-cs-i@ rst-state and 0<> and
498;
499
500: cleanup-tx-dma-channel ( chan# -- )
501 \ Must clear TAIL because the HW will not clear it. If driver
502 \ does not clear TAIL, HEAD will follow TAIL to the non-zero value
503 \ when enable-tx-dma-channel is called and that will cause trouble.
504 0 swap ( 0 chan )
505 tx-ring-kick-i! ( )
506
507 \ Must clear WRAP so that both sw and hw start with WRAP=0
508 wrap=0 to wrap
509;
510
511\ First sets the RST bit of TX_CS to 1 and poll RST and RST_STATE
512\ until HW clears RST and sets RST_STATE. RST_STATE=1 indicates that
513\ the DMA channel is in a stall state and is waiting for the driver
514\ to do configuration. We will bring the DMA channel out of stall
515\ state later by clearing RST_STATE in word "enable-tdma" after DMA
516\ configuration is done.
517\
518: reset-tx-dma-channel ( chan -- ok? )
519 dup ( chan chan )
520 tx-cs-i@ ( chan val )
521 rst-state and if ( chan ) \ Already in reset state
522 true ( chan true )
523 else ( chan )
524 stop-n-go over ( chan STOP_N_GO chan )
525 tx-cs-i! ( chan )
526 wait-for-dma-engine-to-stop ( chan ok? )
527 0= if ( chan )
528 cmn-error[ " TX DMA engine did not stop" ]cmn-end
529 false ( chan false )
530 else
531 dup tx-cs-i@ ( chan val )
532 rst-state ( chan val RST_STATE )
533 and 0= if ( chan ) \ Reset if not in reset state
534 RST over ( chan RST chan )
535 tx-cs-i! ( chan )
536 then ( chan )
537 dup wait-tx-dma-reset ( chan ok? )
538 dup 0= if cmn-error[ " TX DMA engine did not reset" ]cmn-end then
539 then ( chan ok? )
540 then ( ok? )
541 swap cleanup-tx-dma-channel ( ok? )
542;
543
544: reset-dma-channel ( chan -- ok? )
545 niu? if
546 cleanup-tx-dma-channel true ( ok? )
547 else ( chan )
548 dup reset-tx-dma-channel ( chan ok1? )
549 swap reset-rx-dma-channel ( ok1? ok2? )
550 and
551 then
552;
553
554\ Initialize RX descriptor and completion rings for one DMA channel
555\
556: init-rxrings ( -- )
557 #rmds 4 - 0 do
558 \ Prepare args for rmd-init ( rbug-io-adr rmd-cpu-adr -- )
559 i rbuf#>rbuf-io-adr \ dev addr of ith 8K data block
560 i rmd#>rmdaddr \ cpu addr of ith Rx Descriptor
561 rmd-init
562 loop
563
564 #rcds 0 do
565 i rcd#>rcdaddr \ Prepare arg for rcd-init
566 rcd-init \ Fill 0 to each of 256 rcd entry
567 loop
568
569 rcd0 nextrcd!
570;
571
572\ Initialize a Tx descriptor ring for one DMA channel.
573\ Use only one Tx buffer.
574\ The address stored in the Tx packet descriptors is io address.
575\
576: init-txring ( -- )
577 #tmds 0 do
578 io-tbuf0 \ Addr of the 4K Tx data buffer
579 i tmd#>tmdaddr \ Starting addr of i-th descriptor
580 txbufptr! \ Store io-tbuf0 in the 2nd 8bytes of tmd
581 loop \ All 64 tmds point to the same 4K data buffer
582 tmd0 nexttmd!
583;
584
585
586\ These "cached" Rx errors are updated in update-rx-err-status.
587\ This word set fatal rx error flag if any of the cached error
588\ is non-zero.
589\
590: fatal-rx-errors? ( -- flag )
591 rx-dma-err-status
592 rdmc-pre-err-status or
593 rdmc-sha-err-status or
594 rx-ctl-dat-fifo-status or
595 ipp-int-err-status or
596;
597
598: fatal-tx-errors? ( -- glag )
599 tx-dma-err-status
600;
601
6020 value txerr-status \ TX MAC Error status bits
6030 value rxerr-status \ RX MAC Error status bits
604
605defer restart-net ( -- ok? )
606['] true to restart-net
607
608: update-tx-err-status ( -- )
609 \ Fatal Tx DMA errors
610 chan# tx-cs-i@ tx-dma-fatal-errs and
611 tx-dma-err-status or to tx-dma-err-status
612
613 \ MAC Tx errors
614 update-mac-tx-err-stat
615
616 \ XPCS, PCS also have error registers, but they
617 \ are not listed as fatal by the PRM.
618;
619
620: update-rx-err-status ( chan -- )
621 \ Fatal Rx DMA errors
622 rx-dma-ctl-stat-i@ rx-dma-fatal-errs-mask and ( stat )
623 rx-dma-err-status or dup 0<> if ( stat )
624 cmn-error[ dup " rx-dma-fatal-errs = %x" ]cmn-end then
625 to rx-dma-err-status ( )
626
627 rdmc-pre-par-err@ rdmc-pre-par-errs-mask and ( stat )
628 rdmc-pre-err-status or dup 0<> if ( stat )
629 cmn-error[ dup " rdmc-pre-par-errs = %x" ]cmn-end then
630 to rdmc-pre-err-status ( )
631
632 rdmc-sha-par-err@ rdmc-sha-par-errs-mask and ( stat )
633 rdmc-sha-err-status or dup 0<> if ( stat )
634 cmn-error[ " rdmc-sha-par-errs = %x" ]cmn-end then
635 to rdmc-sha-err-status ( )
636
637 \ bits[3:0] of RX_CTL_DAT_FIFO_STAT are IPP_EOP_ERR for port3:0
638 \ bits[7:4] of RX_CTL_DAT_FIFO_STAT are ZCP_EOP_ERR for port3:0
639 \ Since we do not initialize other ports, we should care about
640 \ our own port only. For example, if we are using port 1, we
641 \ should only care about bit1 and bit 4.
642 \ Bit 8 (h# 80) is for ID mismatch. Bits[63:9] are RSVD
643 h# 11 port lshift h# 80 or ( mask )
644 rx-ctl-dat-fifo-stat@ and ( stat )
645 rx-ctl-dat-fifo-errs-mask and ( stat' )
646 rx-ctl-dat-fifo-status or ( stat'' )
647 dup 0<> if ( stat'' )
648 cmn-error[ " rx-ctl-dat-fifo-errs = %x" ]cmn-end
649 then ( stat'' )
650 to rx-ctl-dat-fifo-status ( )
651
652 \ Fatal IPP errors
653 port ipp-int-stat-p@ ( stat )
654 ipp-int-stat-errs-mask and ( stat' )
655 ipp-int-err-status or dup 0<> if ( stat'' )
656 cmn-error[ " ipp-int-stat-errs = %x" ]cmn-end then
657 to ipp-int-err-status ( )
658
659 \ Serious XMAC or BMAC errors, but we do not set the restart? flag.
660 update-mac-rx-err-stat ( )
661
662 \ XPCS, PCS also have error registers, but
663 \ none of them are fatal so we do not count them
664;
665
666\ Display transmit errors.
667: .transmit-errors ( -- )
668 \ Fatal Tx DMA errors
669 tx-dma-err-status tx-ring-oflow and 0<> if ." TX_RING_OFLOW" cr then
670 tx-dma-err-status pref-buf-par-err and 0<> if ." PREF_BUF_PAR_ERR" cr then
671 tx-dma-err-status nack-pref and 0<> if ." NACK_PREF" cr then
672 tx-dma-err-status nack-pkt-rd and 0<> if ." NACK_PKT_RD" cr then
673 tx-dma-err-status conf-part-err and 0<> if ." CONF_PART_ERR" cr then
674 tx-dma-err-status pkt-prt-err and 0<> if ." PKT_PRT_ERR" cr then
675 .mac-tx-err
676;
677
678\ Display receive errors.
679: .receive-errors ( -- )
680 ." Rx Error: " cr
681 \ Fatal DMA Error
682 rx-dma-err-status rbr-tmout and 0<> if ." BR_TMOUT" cr then
683 rx-dma-err-status rsp-cnt-err and 0<> if ." RSP_CNT_ERR" cr then
684 rx-dma-err-status byte-en-bus and 0<> if ." BYTE_EN_BUS" cr then
685 rx-dma-err-status rsp-dat-err and 0<> if ." RSP_DAT_ERR" cr then
686 rx-dma-err-status rcr-ack-err and 0<> if ." RCR_ACK_ERR" cr then
687 rx-dma-err-status dc-fifo-err and 0<> if ." DC_FIFO_ERR" cr then
688 rx-dma-err-status rcr-sha-par and 0<> if ." RCR_SHA_PAR" cr then
689 rx-dma-err-status rbr-pre-par and 0<> if ." RBR_PRE_PAR" cr then
690 rx-dma-err-status config-err and 0<> if ." CONFIG_ERR" cr then
691 rx-dma-err-status rcrincon and 0<> if ." CRINCON" cr then
692 rx-dma-err-status rcrfull and 0<> if ." RCRFULL" cr then
693 rx-dma-err-status rbrfull and 0<> if ." RBRFULL" cr then
694 rx-dma-err-status rbrlogpage and 0<> if ." RBRLOGPAGE" cr then
695 rx-dma-err-status cfiglogpage and 0<> if ." CFIGLOGPAGE" cr then
696 rdmc-pre-err-status pre-par-err and 0<> if ." RDMC_PRE_PAR.ERR" cr then
697 rdmc-pre-err-status pre-par-merr and 0<> if ." RDMC_PRE_PAR.MERR" cr then
698 rdmc-sha-err-status sha-par-err and 0<> if ." RDMC_SHA_PAR.ERR" cr then
699 rdmc-sha-err-status sha-par-merr and 0<> if ." RDMC_SHA_PAR.MERR" cr then
700 rx-ctl-dat-fifo-status id-mismatch and 0<> if ." ID_MISMATCH" cr then
701 rx-ctl-dat-fifo-status zcp-eop-err and 0<> if ." ZCP_EOP_ERR" cr then
702 rx-ctl-dat-fifo-status ipp-eop-err and 0<> if ." IPP_EOP_ERR" cr then
703 \ Fatal IPP errors
704 ipp-int-err-status sop-miss and 0<> if ." SOP_MISS" cr then
705 ipp-int-err-status eop-miss and 0<> if ." EOP_MISS" cr then
706 ipp-int-err-status pfifo-und and 0<> if ." PFIFO_UND" cr then
707 \ Serious XMAC or BMAC errors
708 .mac-rx-err
709;
710
711: transmit-errors? ( -- flag )
712 update-tx-err-status
713
714 \ Set restart? flag if update-tx-err-status has detected fatal error
715 fatal-tx-errors? dup if
716 true to restart?
717 then
718
719 \ Following error does not trigger restart. Simply report to caller
720 mactype xmac = if
721 tx-xmac-err-status or
722 else
723 tx-bmac-err-status or
724 then
725;
726
727: receive-errors? ( chan -- err|0 )
728 update-rx-err-status ( -- )
729
730 \ fatal-rx-errors? returns true if update-rx-err-status has recorded
731 \ a fatal error
732 fatal-rx-errors? if
733 true to restart?
734 then
735
736 \ The following errors are also cached by update-rx-err-status
737 \ but we simply report them to the caller instead of treating them
738 \ as fatal.
739 mactype xmac = if
740 rx-xmac-err-status ( err ) \ 0 if no error
741 else
742 rx-bmac-err-status
743 then
744;
745
746\ Clear TX error bits in cached values.
747: clear-tx-errors ( -- )
748 tx-dma-err-status tx-dma-fatal-errs invert and
749 to tx-dma-err-status
750 clear-mac-tx-err
751;
752
753
754\ Clear RX error bits in cached values.
755: clear-rx-errors ( -- )
756 rx-dma-err-status rx-dma-fatal-errs-mask invert and to
757 rx-dma-err-status
758 rdmc-pre-err-status rdmc-pre-par-errs-mask invert and to
759 rdmc-pre-err-status
760 rdmc-sha-err-status rdmc-sha-par-errs-mask invert and to
761 rdmc-sha-err-status
762 rx-ctl-dat-fifo-status rx-ctl-dat-fifo-errs-mask invert and to
763 rx-ctl-dat-fifo-status
764 ipp-int-err-status ipp-int-stat-errs-mask invert and to
765 ipp-int-err-status
766 clear-mac-rx-err
767;
768
769\ Clear the rst-state bit to start
770\ the dma after we have done configuration.
771\
772: enable-tx-dma-channel ( chan -- )
773 dup tx-cs-i@ rst-state invert and ( chan mod_val )
774 swap tx-cs-i!
775;
776
777: enable-rx-dma-channel ( chan -- )
778 dup rxdma-cfig1-i@ rxdma-en or swap rxdma-cfig1-i!
779;
780
781
782\ We have a tx descriptor ring constructed already, now tell the
783\ Neptune about it.
784\
785: init-tx-regs ( chan -- )
786 \ Set length of ring to 64 and set STADDE_BASE:STADDR to the
787 \ the IO address of the Tx ring
788 len=64 io-tmd0 or ( chan x1 )
789 over tx-rng-cfig-i! ( chan )
790
791 \ Disable events that may trigger interrrups.
792 tx-dma-ent-dis-msk swap tx-ent-msk-i!
793;
794
795\ last-partition-of-rbuf? depends on how we partion the 8K
796\ Rx block buffer. We divide it into 4K and 2K
797\
798: init-rx-regs ( chan -- )
799 \ Initialize rmd related config registers. Tell Neptune that
800 \ rmd has #rmds entries. Its base addr is io-rmd0
801 #rmds d# 48 lshift io-rmd0 or ( chan x1 )
802 over rbr-cfig-a-i! ( chan )
803
804 \ Tell Neptune that each block is 8K, and it should partition
805 \ the blocks into 4K, 4K and 2K sub-blocks. 2K is always greater
806 \ than the size of non-jumbo Ethernet frames.
807 bksize=8k ( chan x2 )
808 vld2 or bufsz2=4k or ( chan x2' )
809 vld1 or bufsz1=2k or ( chan x2'' )
810 vld0 or bufsz0=2k or ( chan x2''' )
811 over rbr-cfig-b-i! ( chan )
812
813 \ Initialize rcd related config registers
814 \ Tell Neptune where the RCR is and the number of RCR entries
815 \ in the ring.
816
817 #rcds d# 48 lshift io-rcd0 or ( chan x3 )
818 over rcrcfig-a-i! ( chan )
819
820 pthres=1 entout or timeout=1 or ( chan x4 )
821 over rcrcfig-b-i! ( chan )
822
823 \ Disable events that may trigger interrups.
824 rx-dma-ent-disable-mask over rx-dma-ent-msk-i!
825
826 \ Enable Weighted Random Early Discard (WRED) to prevent the rings
827 \ from overflow when there is an attack targeting at the Neptune's
828 \ MAC address.
829 #rcds 2 / shift-thre-syn lshift ( chan x5 )
830 0 shift-win-syn lshift or ( chan x5' )
831 #rcds 2 / shift-thre lshift or ( chan x5'' )
832 0 shift-win lshift or ( chan x5''' )
833 chan# rdc-red-para-i! ( chan )
834
835 \ Set OPMODE bit to enable WRED for all DMA. But we have set
836 \ parameters for channel 0 only. other channel will not be able
837 \ to receive because the default value of RDC_RED_PARA causes
838 \ the WRED to drop all packets. Init value 0x3456 is an arbitrary
839 \ number that is known to have worked.
840 h# 3456 opmode=1 or red-ran-init! ( chan )
841
842 #rmds 4 - dup to last-rmd-idx ( chan x6 )
843 over rbr-kick-i! \ Kick some to begin
844
845 \ As advised by PRM, write to RX_DMA_CTL_STAT to clear bit 35
846 \ so that RBR_EMPTY is cleared.
847 over rx-dma-ctl-stat-i@ rbr-empty or over rx-dma-ctl-stat-i!
848
849 \ Disable mailbox update.
850 dup rx-dma-ctl-stat-i@ MEX invert and swap rx-dma-ctl-stat-i!
851;
852
853\ Neptune has 69 (LD) interrupt sources and 64 (LDG) logic groups for
854\ generating interrupts. set-ldg has set LDGs as follows,
855\ LDG0 for Rx DMA0 (LD0), Tx DMA0 (LD32) and port-th-MAC (LD64,65,66,67).
856\ LDG 63 LD68 Device Error. After calling this word, events from these
857\ two logic groups will not be able to trigger interrupt
858\
859: disable-all-intrs ( -- )
860 ldg0 ldgimgn-i@ arm invert and ldg0 ldgimgn-i!
861 ldg63 ldgimgn-i@ arm invert and ldg63 ldgimgn-i!
862
863 disable-mac-intr
864;
865
866: init-dma-channel ( chan -- )
867 dup tx-config ( chan )
868 dup rx-config ( chan )
869 init-txring ( chan )
870 init-rxrings ( chan )
871 dup init-tx-regs ( chan )
872 dup init-rx-regs ( chan )
873 dup enable-tx-dma-channel ( chan )
874 enable-rx-dma-channel ( )
875 disable-all-intrs ( )
876;
877
878
879\ Tell the HW that we have received a packet so that the HW will
880\ update its ring head. Update nextrcd which is a software copy
881\ of the addr of next rcd (Rx Completion-ring Descriptor)
882\
883: sync-and-update-nextrcd ( -- )
884 \ Free current completion descriptor
885 nextrcd@ rcd-init ( )
886
887 \ Update completion ring info, clear low 32 bits
888 chan# rx-dma-ctl-stat-i@ ( x1 )
889 d# 31 lshift d# 31 xrshift ( x1' )
890 ptrread=1 or pktread=1 or ( x1'' )
891 chan# rx-dma-ctl-stat-i! ( )
892
893 \ Update pointer to next completion descriptor
894 nextrcd@ rcdaddr>rcd# 1 + ( x2 )
895 rcd#>rcdaddr nextrcd! ( )
896;
897
898
899\ If an 8K block buffer has been used up, then we reclaim
900\ it kick it back to the Neptune. We can get the starting
901\ address of the 8K block buffer a pakcet belongs to by clearing
902\ the lower 13 bits of the the packet address (rcdaddr). Note that
903\ since the rmd omits the lower 12 bit for 4K boundary, bit 12
904\ is the LSB in rmd, which MUST be 0 in order to use 8K block buffers.
905\ Original content of rcd:
906\ 63 RCD 37 6 0
907\ +--------------------+-----------------+-------+
908\ | flags | bits[43:6] of pkt adr |
909\ +--------------------+-----------------+-------+
910\ actual addr: 43 12 6 (bits[5:0]=0 for
911\ 64B alignment)
912\ Above io address of the packet reported by the hardware via
913\ RCR may not be the same as the starting io address of the
914\ 8K block buffer (because the packet may not be the first
915\ partition in that block buffer). So we need to clear bits[12:6]
916\ in addition to the implied zero bits[5:0] to make a 8K aligned
917\ address. That is the starting address of the 8K block buffer
918\ to be reclaimed and kicked back to the hardware.
919\ We xrshift 7 bits then lshift 13 bits to clear the lowest 13 bits.
920
921\ 63 43 0
922\ +-------------+--------------------------------+
923\ | | addr bits[43:13] 0000000000000|
924\ +-------------+--------------------------------+
925\
926: reclaim-rx-buffer ( nextrcdaddr -- )
927 descriptor64@ \ Got contents of a Rx completion ring entry
928
929 \ Shift to get the starting address of the 8K block buffer
930 \ which the packet is in.
931 7 xrshift d# 13 lshift ( rbuf-io-adr )
932 last-rmd-idx ( rbuf-io-adr rmd# ) \ Get recorded kicked rmd
933 \ index (Its initial value
934 \ is #rmds - 4)
935 rmd#>rmdaddr ( rbuf-io-adr rmd-cpu-adr )
936 rmd-init ( ) \ Puts rbuf-io-adr in a rmd in cpu addr
937
938 \ Update soft kick state and kick register
939 last-rmd-idx 1+ \ New last-kicked-rmd-idx
940
941 1 chan# rbr-kick-i! \ Different from Cassini which kicks
942 \ the rmd index, here we kick BKADD, which
943 \ stands for "number of BlocK buffer ADDed.
944
945 \ If rmd index is greater than #rmds, wrap it back to 0
946 #rmds mod
947 to last-rmd-idx \ Even if we did not kick a rmd, still record it
948;
949
950
951\ last-partition-of-rbuf? checks if the packet just received
952\ took the last partition of the 8K block buffer. If yes,
953\ then we recycle the whole 8K block buffer; if not, then we
954\ wait until all the partitions in the 8K block buffer
955\ have been used by the hardware.
956\
957\ Neptune's Rx completion ring entry carries the addr of
958\ a packet buffer inside a 8K block buffer. We can figure out
959\ if a packet is the last packet in the block buffer by checking
960\ its address. For 8K block buffers, the address of the last
961\ packet has the following bits as 1s
962\ 8K block buffer
963\ If pkt uses size 0(1K) and if bits[12:10] ==111 --> last packet
964\ If pkt uses size 1(2K) and if bits[12:11] ==11 --> last packet
965\ If pkt uses size 2(4K) and if bits[12] ==1 --> last packet
966\
967\ For example, below is a Rx completion ring entry for a packet
968\ that uses a 1K partition inside the 8K buffer block. If bits[12:10]
969\ of a size0 partition are 111 (which are bits[8:6] of the RCR entry),
970\ then this packet has taken the last 1K sub-block of the 8K buffer.
971\ (Bits[5:0] of the packet address are outside of the RCR entry
972\ because the the address is 64B aligned)
973\
974\ 63 37 6 0
975\ +--------------------+-----------------+-------+
976\ | flags | high addr |111XXXX|xxxxxx
977\ +--------------------+-----------------+-------+
978\ 43 12 9 6 543210
979\
980: last-partition-of-rbuf? ( nextrcdaddr -- need-to-release? )
981 dup rcdaddr>pbuf-addr swap ( pktbuf-addr nextrcdaddr )
982 rcdaddr>pbuf-size \ return 0,1,2 represent size0,1,2
983
984 \ Switch based on the PKTBUFSZ field of the Receive
985 \ Completion Ring Entry
986 case
987 \ If bits[39:38] (PKTBUFSZ) are zero, it means this packet
988 \ was put in a BUFSZ0(set to 2K) partition. The partition
989 \ is the last one in the 8K block buffer if bits[12:10] of
990 \ the RCR descriptor are 11. Therefore we must release the
991 \ whole 8K buffer.
992 bufsz0 of
993 d# 57 lshift d# 62 xrshift b# 11 = \ bufsz0=2k
994 endof
995
996 \ If bits[39:38] (PKTBUFSZ) are b01, this packet was
997 \ put in a BUFSZ1(was also set to 2K) partition. The partition
998 \ is the last one in the 8K block buffer if bits[12:11]
999 \ of the RCD are 11.
1000 bufsz1 of
1001 d# 57 lshift d# 62 xrshift b# 11 =
1002 endof
1003
1004 \ If bits[39:38] (PKTBUFSZ) are b10, this packet was
1005 \ put in a BUFSZ2(set to 4K) partition. The partition
1006 \ is the last one in the 8K block buffer if bit12 of the
1007 \ RCD is 1.
1008 bufsz2 of
1009 d# 57 lshift d# 63 xrshift b# 1 =
1010 endof
1011
1012 singleblk of
1013 \ If packet takes whole 8K block, then set need-to-release? = true
1014 drop true
1015 endof
1016
1017 \ drop the contents of descriptor
1018 dup cmn-error[ " Bad packet size: 0x%x " ]cmn-end
1019 endcase
1020;
1021
1022: return-rx-buffer ( rcd-cpu-addr -- )
1023 dup last-partition-of-rbuf? ( rcd-cpu-addr last-partion-in-8K-block? )
1024 if ( rcd-cpu-addr )
1025 reclaim-rx-buffer ( ) \ Reclaim one 8K data block
1026 else
1027 drop
1028 then
1029 sync-and-update-nextrcd \ Clear curr rcd, syncronize with HW by
1030 \ telling HW the pkt and the rcd we just read
1031 \ and move to next rcd regardless reclaim or not
1032;
1033
1034
1035\ Do nothing if receive-errors? reports false
1036\
1037: process-receive-errors ( chan -- )
1038 receive-errors? if \ chan is consumed by receive-errors?
1039 .receive-errors
1040 restart? if \ restart? is set in receive-errors? if we
1041 restart-net drop \ see any fatal or serious error. Note that
1042 then \ MAC Rx overflow error does not set restart?
1043 clear-rx-errors \ flag, we only print and clear it here.
1044 then
1045;
1046
1047\ Before driver reads data received by the HW, it first polls to see
1048\ if there is any packet ready to be read by SW by checking the contents
1049\ of the next RCR, if its packet address is not the initialized value 0,
1050\ then HW has something for us. To check the contents of the next
1051\ RCR entry, we first call synciopb to make sure that device will do
1052\ a DMA sync to putback the latest data into the dma memory before we
1053\ read it. After synciopb, we can confidently read the contents of
1054\ the next RCR entry to check if there is any packet for us.
1055\
1056: rcr-has-pkt? ( -- pkt-waiting? )
1057 chan# process-receive-errors
1058
1059 1 chan# rcr-flsh-i! \ Force HW to flash latest info to DRAM
1060 \ But test shows that we do not have to flush.
1061
1062 chan# rcrstat-a-i@
1063;
1064
1065\ Check where the packet is and how long the packet is.
1066\
1067: get-pkt-addr&len-from-rcr ( -- nextrcdaddr pkt-cpu-adr pktlen )
1068 \ Get packet address and length
1069 nextrcd@ ( nextrcd-cpu-addr )
1070 dup dup
1071 \ In the rcd what we get is the RBR(pkt)'s io addr.
1072 \ rcdaddr>pkt-cpu-adr converts the io address to cpu address
1073 rcdaddr>pkt-cpu-adr ( nextrcd-cpu-addr nextrcd-cpu-addr pkt-cpu-adr )
1074 swap ( nextrcd-cpu-addr pkt-cpu-adr nextrcd-cpu-addr )
1075 rcdaddr>pkt-len ( nextrcd-cpu-addr pkt-cpu-adr pkt-len )
1076
1077 \ Sync contents of Rx packet buffer before looking at it
1078 \ Note that this DMA sync is for packet buffer (whose address was obtained
1079 \ from RCR entry) rather than for the RCR entry itself. rcr-has-pkt? has
1080 \ done DMA sync for RCR entry with synciopb.
1081 2dup ( nextrcd-cpu-addr pkt-cpu-adr pkt-len pkt-cpu-adr pkt-len )
1082 sync-buf ( nextrcd-cpu-addr pkt-cpu-adr pkt-len )
1083;
1084
1085: send-wait ( chan -- ok? )
1086 d# 4000 get-msecs + false ( chan out-time false )
1087 begin
1088 over ( chan out-time f out-time )
1089 timed-out? ( chan out-time f T/F )
1090 0= ( chan out-time f F/T )
1091 over ( chan out-time f F/T f )
1092 0= ( chan out-time f F/T t )
1093 and ( chan out-time f F/T ) \ F/T=F if TO
1094 \ Enter while only if true ( not TO and f has not been replace by T )
1095 while ( chan out-time f )
1096 >r over ( chan out-time chan ) ( r: false )
1097 r> swap ( chan out-time false chan )
1098 dup tx-head@ ( chan out-time false chan head )
1099 over tx-tail@ ( chan out-time false chan head tail )
1100 = if ( chan out-time false chan )
1101 dup tx-hdr-wrap@ over tx-tail-wrap@ = if ( same as above )
1102 \ Check the MK bit of TX_CS register to double
1103 \ check that the packet whose descriptor has the
1104 \ MARK bit on has really been transmitted. This
1105 \ read will set the MK bit to 0
1106 tx-cs-i@ mk and if ( chan out-time false )
1107 drop true ( chan out-time true )
1108 else
1109 ." MK bit is not on" cr ( chan out-time false )
1110 then
1111 else
1112 . " Wrap mismatch" cr
1113 drop \ Drop chan before going to begin
1114 then
1115 else ( chan out-time false chan )
1116 drop ( chan out-time false )
1117 then
1118 repeat ( chan out-time f/t )
1119 -rot 2drop ( f/t )
1120 dup 0= if ( f/t )
1121 cmn-warn[ " Timeout waiting for Tx completion" ]cmn-end
1122 true to restart?
1123 then
1124;
1125
1126
1127\ When this word is called, the application data has been copied
1128\ from application data buffer to the 4K Tx block buffer.
1129\
1130: transmit ( tbuf-cpu-adr len -- ok? )
1131 \ Sync contents of the TX buffer first
1132 2dup sync-buf ( tbuf-cpu-adr len )
1133
1134 \ Initialize TX message descriptor (tmd). The tmd has two
1135 \ parts, Bits above bit43 are for "header", which contain info
1136 \ such as the length of the application data, start-of-frame
1137 \ (SOF) indicator, etc. Bits[43:0] is for storing the io
1138 \ address of the 4K Tx block buffer. tmd-init constructs
1139 \ the tmd.
1140 nexttmd@ ( tbuf-cpu-adr len tmdaddr )
1141 tmd-init ( len )
1142
1143 \ Calculate TAIL for kick.
1144 \ in the PRM, TAIL of TX_RING_KICK register is specified as
1145 \ an offset, in number of entries, from the staring address.
1146 \ The following two lines figure out the offset.
1147 nexttmd@ tmdaddr>tmd# 1 + ( len tmd#+1 )
1148 #tmds mod ( len tail ) \ tail=(tmd#+1)mod64
1149
1150 \ Because TAIL occupies bits[18:3] of TX_RING_KICK, left
1151 \ shift the offset by 3.
1152 dup dup ( len tail tail tail )
1153 d# 3 lshift swap ( len tail tail<<3 tail )
1154
1155 \ PRM requires that if we wrap around Tx Ring, we should turn
1156 \ on the WRAP bit of TX_RING_KICK register
1157 0= ( len tail tail<<3 tail=0? )
1158 if ( len tail tail<<3 )
1159 wrap wrap=1 xor ( len tail tail<<3 WRAP )
1160 dup to wrap \ Save WRAP value for this round
1161 else
1162 wrap
1163 then
1164 or ( len tail WRAP||TAIL<<3 )
1165 \ Now kick the descriptor to chan#-th DMA channel to start
1166 \ transmission.
1167
1168 chan# tx-ring-kick-i! ( tail )
1169
1170 \ "tail" on top of the stack is actually the tmd index.
1171 \ Convert it to tmdaddr (in cpu space) and save it in
1172 \ nexttmd
1173 tmd#>tmdaddr nexttmd! ( Empty ) \ Update nexttmd
1174
1175 \ Wait for transmit completion
1176 chan# send-wait ( ok? )
1177
1178 \ Check for transmit errors
1179 transmit-errors? if
1180 .transmit-errors clear-tx-errors drop false
1181 then
1182
1183 restart? if restart-net 2drop false then
1184;
1185
1186\ ASIC group endorsed IPP init sequence:
1187\ o Set interrupt mask
1188\ o Configure IPP (Enable/Disable ECC Correct/CRC Drop/Cksum...)
1189\ o Set max packet size IPP can handle
1190\ o Initialize IPP counters
1191\ o Enble IPP
1192\
1193: init-ipp ( -- )
1194 soft-rst port ipp-cfig-p!
1195 \ ipp-intr-msk port ipp-msk-p! \ Mask off IPP interrupts
1196
1197 \ Clear IPP counters by reading them
1198 port ipp-pkt-dis-p@ drop
1199 port ipp-bad-cs-cnt-p@ drop
1200 port ipp-ecc-p@ drop
1201
1202 \ Enable IPP
1203 \ port ipp-cfig-p@
1204 ipp-max-pkt-default ipp-enable or
1205 \ dfifo-ecc-en or \ Enable ecc detection and correction
1206 \ drop-bad-crc or
1207 \ chksum-en or \ Enable tcp/ip udp checksum
1208 \ dfifo-pio-w or
1209 \ pfifo-pio-w or
1210 port ipp-cfig-p!
1211;
1212
1213: (setup-link) ( -- link-up? )
1214 chan# reset-dma-channel 0= if
1215 false exit ( flag )
1216 then
1217
1218 init-ipp \ IPP is between MAC and DMA, it is used by MAC loopback
1219
1220 portmode 1g-copper = if
1221 mac-mode normal = ( flag )
1222 mac-mode qgc-ext-loopback = or if ( )
1223 \ 1G copper has no serdes to init.
1224 \ ASIC engr said there is no need to setup xcvr for 1G copper
1225 setup-transceiver ( flag )
1226 0= if false exit then ( flag )
1227 link-up? 0= if ( )
1228 cmn-note[ " Link is down." ]cmn-end false exit
1229 then ( )
1230 then ( )
1231 then ( )
1232
1233 portmode 10g-fiber = if ( )
1234 mac-mode normal = ( flag )
1235 mac-mode 2xgf-ext-loopback = or if ( )
1236 init-internal-serdes ( )
1237 setup-transceiver 0= if ( )
1238 false exit ( flag )
1239 then ( )
1240 link-up? 0= if ( )
1241 cmn-note[ " Link is down." ]cmn-end false exit
1242 then ( )
1243 then ( )
1244 mac-mode serdes-ewrap-loopback = ( flag )
1245 mac-mode serdes-pad-loopback = or if ( )
1246 init-internal-serdes ( )
1247 then ( )
1248 then ( )
1249
1250 init-xif \ Set xmac mode (10G 1G, loopback etc)
1251 init-pcs 0= if cmn-error[ " PCS block init failed." ]cmn-end false exit then
1252
1253 \ PRM: "MAC software reset to clean up clock line glitches"
1254 reset-mac 0= if cmn-error[ " MAC block reset failed." ]cmn-end false exit then
1255 init-mac
1256
1257 \ classification must be called after reset-mac. Otherwise
1258 \ the hostinfo set by this function will be cleared by reset-mac.
1259 classification
1260
1261 chan# init-dma-channel
1262
1263 enable-mac
1264 enable-pcs
1265 true
1266;
1267
1268\ If (setup-link) does not throw, then ['] (setup-link) catch
1269\ returns a false (consider it as NO error) on top of the return value
1270\ of (setup-link), which is the link-up? flag.
1271\ If there is a throw (the only reason for (setup-link) to throw is
1272\ that the user has specified a parameter that is not supported by the
1273\ 1G-copper transceiver), then (setup-link) will gracefully abort
1274\ and put a non-zero error code on top of the stack. The caller will
1275\ quit after seeing a non-zero error code.
1276\
1277: setup-link ( -- [ link-status ] error? )
1278 ['] (setup-link) catch
1279;
1280
1281
1282: (restart-net) ( -- link-up? )
1283 false to restart?
1284 clear-tx-errors clear-rx-errors
1285 setup-link if \ A non-zero value returned by setup-link means it has
1286 false \ caught a throw from check-phy-capability. In that
1287 \ case, the link will never be up because the throw
1288 \ implies that the user desired speed or duplex
1289 \ is not supported.
1290 then \ If setup-link has returned a 0, then just forward
1291; \ the link-up? value (could be true or false)
1292 \ returned by (setup-link) to the caller.
1293
1294['] (restart-net) to restart-net
1295
1296: bringup-link ( -- ok? )
1297 d# 20000 get-msecs + false
1298 begin
1299 over timed-out? 0= over 0= and
1300 while
1301 setup-link if \ setup-link returns ( -- link-up? 0 ) if OK.
1302 2drop false exit \ If there is a throw, which implies that
1303 \ bringing up the link is impossible,
1304 \ then drop the top 2 data (which are the
1305 \ expire time and the false) put on the stack
1306 \ by this word and exit
1307 then ( link-up? )
1308
1309 \ Check the link-up? flag put on the stack by setup-link
1310 if
1311 drop true \ link-up? is true, so we are done.
1312 else \ link is not up yet, keep waiting
1313 cmn-type[ " Retrying network initialization" ]cmn-end
1314 then
1315 repeat nip \ Nip the timeout value.
1316;
1317
1318
1319\ Neptune does not have global reset. This word resets sub blocks one by one.
1320\
1321: resetall ( -- )
1322 reset-transceiver drop
1323 reset-mac drop
1324 chan# reset-dma-channel drop
1325 niu? if
1326 chan# reset-tx-dma-channel drop
1327 chan# reset-rx-dma-channel drop
1328 then
1329 disable-all-intrs
1330;
1331
1332headerless
1333
1334