-
Notifications
You must be signed in to change notification settings - Fork 1
/
fei82557End.c
4837 lines (3669 loc) · 142 KB
/
fei82557End.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* fei82557End.c - END style Intel 82557 Ethernet network interface driver */
/* Copyright 1989-2003 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01l,21mar03,rcs removed #include "endNetBufLib.c" SPR# 87039
01k,21mar03,rcs unmasked interrupt after netJobAdd() failed SPR# 87038
01j,28feb03,rcs fixed polled mode. SPR#86433
01i,24feb03,rcs corrected for using pre-allocated memory SPR# 86352
01h,13feb03,rcs consolidated CFD writes in fei82557Encap.
01g,13feb03,rcs consolidated descriptor cachDmaMalloc s in fei82557InitMem().
01f,07feb03,rcs fixed diab compiler warnings.
01e,05feb03,rcs fixed RFD_LONG_WR double swap SPR# 86037 and added
documentation for fei82557ShowRxRing and fei82557GetRUStatus
01d,04feb03,pmr fixed doc build error.
01c,31jan03,m_h IPv6 support
01b,31jan03,jkf removed logMsg() of pDrvCtrl value.
01a,23jan03,rcs created from target/src/drv/end/fei82557End.c, version 02r
*/
/*
DESCRIPTION
This module implements an Intel 82557 and 82559 Ethernet network interface
driver. (For the sake of brevity this document will only refer to the 82557.)
This is a fast Ethernet PCI bus controller, IEEE 802.3 10Base-T and
100Base-T compatible. It also features a glueless 32-bit PCI bus master
interface, fully compliant with PCI Spec version 2.1. An interface to
MII compliant physical layer devices is built-in to the card. The 82557
Ethernet PCI bus controller also includes Flash support up to 1 MByte
and EEPROM support, altough these features are not dealt with in this
driver.
The 82557 establishes a shared memory communication system with the CPU,
which is divided into three parts: the Control/Status Registers (CSR),
the Command Block List (CBL) and the Receive Frame Area (RFA). The CSR
is on chip and is either accessible with I/O or memory cycles, whereas the
other structures reside on the host.
The CSR is the main means of communication between the device and the
host, meaning that the host issues commands through these registers
while the chip posts status changes in it, occurred as a result of those
commands. Pointers to both the CBL and RFA are also stored in the CSR.
The CBL consists of a linked list of frame descriptors through which
individual action commands can be performed. These may be transmit
commands as well as non-transmit commands, e.g. Configure or Multicast
setup commands. While the CBL list may function in two different modes,
only the simplified memory mode is implemented in the driver.
The RFA consists of a pair of linked list rings. The Receive Frame Descriptor
(RFD) ring and the Receive Buffer Descriptor (RBD) ring. The RFDs hold the
status of completed DMAs. The RBDs hold the pointers to the DMA buffers,
refered to as clusters.
When the device is initialized or restarted it is passed a pointer to an RFD.
This RFD is considered to be the "first" RFD. This RFD holds a pointer to
one of the RBDs. This RBD is then considered the "first" RBD. All other RFDs
only have a NULL RBD pointer, actually 0xffffffff. Once the device is started
the rings are traversed by the device independently.
Either descriptor type RFD or RBD can have a bit set in it to indicate that
it is the End of the List (EL). This is initially set in the RBD descriptor
immediately before the first RBD. This acts as a stop which prevents the DMA
engine from wrapping around the ring and encountering a used descriptor.
This is an unallowed condition and results in the device stopping operation
without an interupt or and indication of failure. When the EL RBD is
encountered the the device goes into the receive stall state. The driver must
then restart the device. To reduce, if not eliminate, the occurence of this
costly, time consuming operation, the driver continually advances the EL to
the last cleared RBD. Then when the driver services an incomming frame it
clears the RFD RBD pair and advances the EL. If the driver is not able to
service an incomming frame, because of a shortage of resources such as
clusters, the driver will throw that frame away and clear the RFD RBD pair
and advance EL.
Because the rings are independently traversed by the device it is imperative
that they be kept in sync. Unfortunately, there is no indication from one
or the other as to which descriptor it is pared with. It is left to the driver
to keep track of which discriptor goes with its counter part. If this
syncronization is lost then the performance of the driver will be greatly
impared or worse. To keep this syncronization this driver imbeds the
RBD descriptors in tags. To do this it utilizes memory that would otherwise
have been wasted. The DMA engine purportedly works most efficiently when the
descriptors are on a 32 byte boundry. The descriptors are only 16 bytes so
there are 16 bytes to work with. The RBD_TAG s have as their first 16 bytes
the RBD itself, then it holds the RFD pointer to its counter part, a pointer
to itself, a 16 bit index, a 16 bit next index, and 4 bytes of spare. This
arrangement allows the driver to traverse only the RBD ring and discover the
corresponding RFD through the RBD_TAG and guaranteeing sycronization.
The driver is designed to be moderately generic, operating unmodified
across the range of architectures and targets supported by VxWorks.
To achieve this, this driver must be given several target-specific
parameters, and some external support routines must be provided. These
parameters, and the mechanisms used to communicate them to the driver,
are detailed below.
BOARD LAYOUT
This device is on-board. No jumpering diagram is necessary.
EXTERNAL INTERFACE
The driver provides the standard external interface, fei82557EndLoad(), which
takes a string of colon separated parameters. The parameters should be
specified in hexadecimal, optionally preceeded by "0x" or a minus sign "-".
The parameter string is parsed using strtok_r() and each parameter is
converted from a string representation to binary by a call to
strtoul(parameter, NULL, 16).
The format of the parameter string is:
"<memBase>:<memSize>:<nTfds>:<nRfds>:<flags>:<offset>:<maxRxFrames>:
<clToRfdRatio>:<nClusters>"
In addition, the two global variables 'feiEndIntConnect' and
'feiEndIntDisconnect' specify respectively the interrupt connect routine
and the interrupt disconnect routine to be used depending on the BSP.
The former defaults to intConnect() and the user can override this to use
any other interrupt connect routine (say pciIntConnect()) in sysHwInit()
or any device specific initialization routine called in sysHwInit().
Likewise, the latter is set by default to NULL, but it may be overridden
in the BSP in the same way.
TARGET-SPECIFIC PARAMETERS
.IP <memBase>
This parameter is passed to the driver via fei82557EndLoad().
The Intel 82557 device is a DMA-type device and typically shares
access to some region of memory with the CPU. This driver is designed
for systems that directly share memory between the CPU and the 82557.
This parameter can be used to specify an explicit memory region for use
by the 82557. This should be done on targets that restrict the 82557
to a particular memory region. Since use of this parameter indicates that
the device has limited access to this specific memory region all buffers
and descriptors directly accessed by the device (RFDs, RBDs, CFDs, and
clusters) must be carved from this region. Since the transmit buffers must
reside in this region the driver will revert to using simple mode buffering
for transmit meaning that zero copy transmit is not supported. This then
requires that there be enough space for clusters to be attached to the CFDs.
The minimum memory requirement is for 32 bytes for all descriptors plus
at lease two 1536 byte clusters for each RFD and one 1536 byte cluster for
each CFD. Also, it should be noted that this memory must be non-cached.
The constant `NONE' can be used to indicate that there are no memory
limitations, in which case the driver will allocate cache aligned memory
for its use using memalign().
.IP <memSize>
The memory size parameter specifies the size of the pre-allocated memory
region. If memory base is specified as NONE (-1), the driver ignores this
parameter. Otherwise, the driver checks the size of the provided memory
region is adequate with respect to the given number of descriptors and
clusters specified. The amount of memory allocated must be enough to hold
the RFDs, RBDs, CFDs and clusters. The minimum memory requirement is for
32 bytes each for all descriptors, 32 bytes each for alignment of the
descriptor types (RFDs, RBDs, and CFDs), plus at least two 1536 byte
clusters for each RFD and one 1536 byte cluster for each CFD. Otherwise the
End Load routine will return ERROR. The number of clusters can be specified
by either passing a value in the nCluster parameter, in which case the
nCluster value must be at least nRFDs * 2, or by setting the cluster to RFD
ratio (clToRfdRatio) to a number equal or greater than 2.
.IP <nTfds>
This parameter specifies the number of transmit descriptor/buffers to be
allocated. If this parameter is less than two, a default of 64 is used.
.IP <nRfds>
This parameter specifies the number of receive descriptors to be
allocated. If this parameter is less than two, a default of 128 is used.
.IP <flags>
User flags may control the run-time characteristics of the Ethernet
chip. Not implemented.
.IP <offset>
Offset used to align IP header on word boundary for CPUs that need long word
aligned access to the IP packet (this will normally be zero or two). This
parameter is optional, the default value is zero.
.IP <deviceId>
This parameter is used to indicate the specific type of device being used,
the 82557 or subsequent. This is used to determine if features which were
introduced after the 82557 can be used. The default is the 82557. If this is
set to any value other than ZERO (0), NONE (-1), or FEI82557_DEVICE_ID (0x1229)
it is assumed that the device will support features not in the 82557.
.IP <maxRxFrames>
This parameter limits the number of frames the receive handler will service
in one pass. It is intended to prevent the tNetTask from hoging the CPU and
starving applications. This parameter is optional, the default value is
nRFDs * 2.
.IP <clToRfdRatio>
Cluster To RFD Ratio sets the number of clusters as a ratio of nRFDs. The
minimum setting for this parameter is 2. This parameter is optional, the
default value is 5.
.IP <nClusters>
Number of clusters to allocate. This value must be at least nRFD * 2.
If this value is set then the <clToRfdRatio> is ignored. This parameter is
optional, the default is nRFDs * clToRfdRatio.
.LP
EXTERNAL SUPPORT REQUIREMENTS
This driver requires one external support function:
.CS
STATUS sys557Init (int unit, FEI_BOARD_INFO *pBoard)
.CE
This routine performs any target-specific initialization
required before the 82557 device is initialized by the driver.
The driver calls this routine every time it wants to [re]initialize
the device. This routine returns OK, or ERROR if it fails.
.LP
SYSTEM RESOURCE USAGE
The driver uses cacheDmaMalloc() to allocate memory to share with the 82557.
The size of this area is affected by the configuration parameters specified
in the fei82557EndLoad() call.
Either the shared memory region must be non-cacheable, or else
the hardware must implement bus snooping. The driver cannot maintain
cache coherency for the device because fields within the command
structures are asynchronously modified by both the driver and the device,
and these fields may share the same cache line.
TUNING HINTS
The adjustable parameters are:
The number of TFDs and RFDs that will be created at run-time. These
parameters are given to the driver when fei82557EndLoad() is called. There
is one TFD and one RFD associated with each transmitted frame and each
received frame respectively. For memory-limited applications, decreasing
the number of TFDs and RFDs may be desirable. Increasing the number of TFDs
will provide no performance benefit after a certain point. Increasing the
number of RFDs will provide more buffering before packets are dropped. This
can be useful if there are tasks running at a higher priority than tNetTask.
The maximum receive frames <maxRxFrames>. This parameter will allow the
driver to service fixed amount of in comming traffic before forcing the
receive handler to relenquish the CPU. This prevents the possible scenerio
of the receive handler starving the application.
The parameters <clToRfdRatio> and <nClusters> control the number of
clusters created which is the major portion of the memory allocated by the
driver. For memory-limited applications, decreasing the number clusters
may be desirable. However, this also will probably result in performance
degradation.
ALIGNMENT
Some architectures do not support unaligned access to 32-bit data items. On
these architectures (eg ARM and MIPs), it will be necessary to adjust the
offset parameter in the load string to realign the packet. Failure to do so
will result in received packets being absorbed by the network stack, although
transmit functions should work OK. Also, some architectures do not support
SNOOPING, for these architectures the utilities FLUSH and INVALIDATE are
used for cache coherency of DMA buffers (clusters). These utilities depend
on the buffers being cache line aligned and being cache line multiple.
Therefore, if memory for these buffers is pre-allocated then it is imperitive
that this memory be cache line aligned and being cache line multiple.
SEE ALSO: ifLib,
.I "Intel 82557 User's Manual,"
.I "Intel 32-bit Local Area Network (LAN) Component User's Manual"
*/
#include "vxWorks.h"
#include "wdLib.h"
#include "iv.h"
#include "vme.h"
#include "lstLib.h"
#include "semLib.h"
#include "sys/times.h"
#include "net/mbuf.h"
#include "net/unixLib.h"
#include "net/protosw.h"
#include "sys/socket.h"
#include "sys/ioctl.h"
#include "errno.h"
#include "memLib.h"
#include "intLib.h"
#include "net/route.h"
#include "iosLib.h"
#include "errnoLib.h"
#include "vxLib.h" /* from if_fei.c */
#include "private/funcBindP.h"
#include "cacheLib.h"
#include "logLib.h"
#include "netLib.h"
#include "stdio.h"
#include "stdlib.h"
#include "sysLib.h"
#include "taskLib.h"
#include "msgQLib.h"
#include "net/systm.h"
#include "net/if_subr.h"
#include "drv/end/fei82557End.h"
#include "drv/pci/pciIntLib.h"
#undef ETHER_MAP_IP_MULTICAST
#include "etherMultiLib.h"
#include "end.h"
#define END_MACROS
#include "endLib.h"
#ifdef WR_IPV6
#include "adv_net.h"
#endif /*WR_IPV6*/
/* defines */
/* Driver debug control */
#if 0
#define DRV_DEBUG557 /*wangfq*/
#else
#undef DRV_DEBUG557
#endif
/* Driver debug control */
#ifdef DRV_DEBUG557
#define DRV_DEBUG_OFF 0x0000
#define DRV_DEBUG_RX 0x0001
#define DRV_DEBUG_TX 0x0002
#define DRV_DEBUG_POLL (DRV_DEBUG_POLL_RX | DRV_DEBUG_POLL_TX)
#define DRV_DEBUG_POLL_RX 0x0004
#define DRV_DEBUG_POLL_TX 0x0008
#define DRV_DEBUG_LOAD 0x0010
#define DRV_DEBUG_IOCTL 0x0020
#define DRV_DEBUG_INT 0x0040
#define DRV_DEBUG_START 0x0080
#define DRV_DEBUG_DUMP 0x0100
#define DRV_DEBUG_PHY 0x0200
#define DRV_DEBUG_ALL 0xffff
int fei82557Debug = DRV_DEBUG_ALL;
#define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) \
do { \
if (fei82557Debug & FLG) \
if (_func_logMsg != NULL) \
_func_logMsg (X0, (int)X1, (int)X2, (int)X3, (int)X4, \
(int)X5, (int)X6); \
} while (0)
#else /* DRV_DEBUG557 */
#define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)
#define DRV_PRINT(FLG, X)
#endif /* DRV_DEBUG557 */
/* general macros for reading/writing from/to specified locations */
#if (_BYTE_ORDER == _BIG_ENDIAN)
#define FEI_SWAP_LONG(x) LONGSWAP(x)
#define FEI_SWAP_WORD(x) (MSB(x) | LSB(x) << 8)
#else
#define FEI_SWAP_LONG(x) (x)
#define FEI_SWAP_WORD(x) (x)
#endif /* _BYTE_ORDER == _BIG_ENDIAN */
/* Cache and PCI-bus related macros */
#define FEI_VIRT_TO_SYS(virtAddr) \
(FEI_LOCAL_TO_SYS (((UINT32) FEI_VIRT_TO_PHYS (virtAddr))))
#define FEI_VIRT_TO_PHYS(virtAddr) \
CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheDmaFuncs, (char *)(virtAddr))
#define FEI_LOCAL_TO_SYS(physAddr) \
LOCAL_TO_SYS_ADDR (pDrvCtrl->unit, (physAddr))
#define FEI_SYS_TO_VIRT(physAddr) \
(FEI_SYS_TO_LOCAL (((UINT32) FEI_PHYS_TO_VIRT (physAddr))))
#define FEI_PHYS_TO_VIRT(physAddr) \
CACHE_DRV_PHYS_TO_VIRT (&pDrvCtrl->cacheDmaFuncs, (char *)(physAddr))
#define FEI_SYS_TO_LOCAL(virtAddr) \
SYS_TO_LOCAL_ADDR (pDrvCtrl->unit, (virtAddr))
#define FEI_CACHE_INVALIDATE(address, len) \
CACHE_DRV_INVALIDATE (&pDrvCtrl->cacheFuncs, (address), (len))
#define FEI_CACHE_FLUSH(address, len) \
CACHE_DRV_FLUSH (&pDrvCtrl->cacheFuncs, (address), (len))
/* driver flags */
#define FEI_OWN_MEM 0x01 /* internally provided memory */
#define FEI_INV_NCFD 0x02 /* invalid nCFDs provided */
#define FEI_INV_NRFD 0x04 /* invalid nRFDs provided */
#define FEI_POLLING 0x08 /* polling mode */
#define FEI_PROMISC 0x20 /* promiscuous mode */
#define FEI_MCAST 0x40 /* multicast addressing mode */
#define FEI_MCASTALL 0x80 /* all multicast addressing mode */
#define FEI_MEMOWN 0x10 /* device mem allocated by driver */
#define FEI_FLAG_CLEAR(clearBits) \
(pDrvCtrl->flags &= ~(clearBits))
#define FEI_FLAG_SET(setBits) \
(pDrvCtrl->flags |= (setBits))
#define FEI_FLAG_GET() \
(pDrvCtrl->flags)
#define FEI_FLAG_ISSET(setBits) \
(pDrvCtrl->flags & (setBits))
/* shortcuts */
#define END_FLAGS_ISSET(setBits) \
((&pDrvCtrl->endObj)->flags & (setBits))
#define FEI_VECTOR(pDrvCtrl) \
((pDrvCtrl)->board.vector)
#define FEI_INT_ENABLE(pDrvCtrl) \
((int)(pDrvCtrl)->board.intEnable)
#define FEI_INT_DISABLE(pDrvCtrl) \
((int)(pDrvCtrl)->board.intDisable)
#define FEI_INT_ACK(pDrvCtrl) \
((int)(pDrvCtrl)->board.intAck)
#define RFD_SLUSH 8
#define CL_OVERHEAD 4 /* prepended cluster header */
#define CL_RFD_SIZE (RFD_DESC_SIZE + CL_OVERHEAD + RFD_SLUSH)
#define FEI_SAFE_MEM(pDrvCtrl) \
((pDrvCtrl)->memSize)
#define FEI_RFD_MEM(pDrvCtrl) \
(CL_RFD_SIZE * (pDrvCtrl)->nRFDs)
#define FEI_CFD_MEM(pDrvCtrl) \
(CFD_SIZE * (pDrvCtrl)->nCFDs)
#ifdef INCLUDE_RFC_2233
#define FEI_HADDR(pEnd) \
((pEnd)->pMib2Tbl->m2Data.mibIfTbl.ifPhysAddress.phyAddress)
#define FEI_HADDR_LEN(pEnd) \
((pEnd)->pMib2Tbl->m2Data.mibIfTbl.ifPhysAddress.addrLength)
#else
/* Old RFC 1213 mib2 interface */
#define FEI_HADDR(pEnd) \
((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
#define FEI_HADDR_LEN(pEnd) \
((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
#endif /* INCLUDE_RFC_2233 */
/* Control Status Register definitions, some of them came from if_fei.h */
#define CSR_STAT_OFFSET SCB_STATUS /* CSR status byte */
#define CSR_ACK_OFFSET 0x01 /* CSR acknowledge byte */
#define CSR_COMM_OFFSET SCB_CMD /* CSR command byte */
#define CSR_INT_OFFSET 0x03 /* CSR Interrupt byte */
#define CSR_GP_OFFSET SCB_POINTER /* CSR General Pointer */
#define CSR_PORT_OFFSET SCB_PORT /* CSR PORT Register */
#define CSR_FLASH_OFFSET SCB_FLASH /* CSR FLASH Register */
#define CSR_EEPROM_OFFSET SCB_EEPROM /* CSR EEPROM Register */
#define CSR_MDI_OFFSET SCB_MDI /* CSR MDI Register */
#define CSR_RXBC_OFFSET SCB_EARLYRX /* CSR early RCV Byte Count */
/* Control Status Registers read/write macros */
/* Control Status Registers write macros */
/*
* CSR_BYTE_WR, CSR_WORD_WR, and CSR_LONG_WR have a CACHE_PIPE_FLUSH()
* and CSR_BYTE_RD (CSR_INT_OFFSET, (UINT8) tmp) embedded in them.
* The CSR_BYTE_RD is to force the write data through any write posting queues
* it may be stuck while crossing the pci. The CACHE_PIPE_FLUSH() is necessary
* to ensure the proper order of execution. The choice of reading the interrupt
* mask register is not significant except that it is a convient location
* which has no side effects when read.
*/
#define CSR_BYTE_WR(offset, value) \
{ \
UINT8 tmp; \
FEI_BYTE_WR (((UINT32) (pDrvCtrl->pCSR) + (offset)), (value)); \
CACHE_PIPE_FLUSH(); \
CSR_BYTE_RD (CSR_INT_OFFSET, tmp); \
}
#define CSR_WORD_WR(offset, value) \
{ \
UINT8 tmp; \
FEI_WORD_WR (((UINT32) (pDrvCtrl->pCSR) + (offset)), (value)); \
CACHE_PIPE_FLUSH(); \
CSR_BYTE_RD (CSR_INT_OFFSET, tmp); \
}
#define CSR_LONG_WR(offset, value) \
{ \
UINT8 tmp; \
FEI_LONG_WR (((UINT32) (pDrvCtrl->pCSR) + (offset)), (value)); \
CACHE_PIPE_FLUSH(); \
CSR_BYTE_RD (CSR_INT_OFFSET, tmp); \
}
/* this is a special case, as the device will read it as an address */
#define CSR_GP_WR(value) \
do { \
volatile UINT32 temp = FEI_VIRT_TO_SYS (value); \
\
CSR_LONG_WR (CSR_GP_OFFSET, (temp)); \
} while (0)
/* Control Status Registers read macros */
#define CSR_BYTE_RD(offset, value) \
FEI_BYTE_RD ((UINT32 *) ((UINT32) (pDrvCtrl->pCSR) + (offset)), \
(value))
#define CSR_WORD_RD(offset, value) \
FEI_WORD_RD ((UINT32 *) ((UINT32) (pDrvCtrl->pCSR) + (offset)), \
(value))
#define CSR_LONG_RD(offset, value) \
FEI_LONG_RD ((UINT32 *) ((UINT32) (pDrvCtrl->pCSR) + (offset)), \
(value))
/* FD rings available */
#define CFD_FREE 0x01 /* CFD free ring */
#define CFD_USED 0x02 /* CFD used ring */
#define RFD_FREE 0x04 /* RFD free ring */
#define CFD_COMM_WORD 0x01 /* CFD command word */
#define CFD_STAT_WORD 0x02 /* CFD status word */
#define RFD_COMM_WORD 0x04 /* RFD command word */
#define RFD_STAT_WORD 0x08 /* RFD status word */
#define CFD_ACTION 0x01 /* generic action command */
#define CFD_TX 0x02 /* transmit command */
/* frame descriptors macros: these are generic among RFDs and CFDs */
#define FD_FLAG_ISSET(fdStat, bits) \
(((UINT16) (fdStat)) & ((UINT16) (bits)))
/* get the pointer to the appropriate frame descriptor ring */
#define FREE_CFD_GET(pCurrFD) \
((pCurrFD) = pDrvCtrl->pFreeCFD)
#define USED_CFD_GET(pCurrFD) \
((pCurrFD) = pDrvCtrl->pUsedCFD)
/* command frame descriptors write macros */
#define CFD_BYTE_WR(base, offset, value) \
FEI_BYTE_WR ((UINT32 *) ((UINT32) (base) + (offset)), \
(value))
#define CFD_WORD_WR(base, offset, value) \
FEI_WORD_WR ((UINT32 *) ((UINT32) (base) + (offset)), \
(value))
#define CFD_LONG_WR(base, offset, value) \
FEI_LONG_WR ((UINT32 *) ((UINT32) (base) + (offset)), \
(value))
/* this is a special case, as the device will read as an address */
#define CFD_NEXT_WR(base, value) \
do { \
volatile UINT32 temp = (UINT32) FEI_VIRT_TO_SYS (value); \
\
CFD_LONG_WR ((UINT32) (base), CFD_NEXT_OFFSET, (temp)); \
} while (0)
/* this is a special case, as the device will read as an address */
#define CFD_TBD_WR(base, value) \
do { \
volatile UINT32 temp; \
temp = (value == TBD_NOT_USED) ? value : \
((UINT32) FEI_VIRT_TO_SYS ((UINT32) (value))); \
CFD_LONG_WR ((UINT32) (base), CFD_TBD_ADDR_OFFSET, (temp)); \
} while (0)
/* receive frame descriptors write macros */
#define RFD_BYTE_WR(base, offset, value) \
FEI_BYTE_WR ((UINT32 *) ((UINT32) (base) + (offset)), \
(value))
#define RFD_WORD_WR(base, offset, value) \
FEI_WORD_WR ((UINT32 *) ((UINT32) (base) + (offset)), \
(value))
#define RFD_LONG_WR(base, offset, value) \
FEI_LONG_WR ((UINT32 *) ((UINT32) (base) + (offset)), \
(value))
/* this is a special case, as the device will read as an address */
#define RFD_NEXT_WR(base, value) \
do { \
volatile UINT32 temp = (UINT32) FEI_VIRT_TO_SYS ((UINT32) (value)); \
\
RFD_LONG_WR ((UINT32) (base), RFD_NEXT_OFFSET, (temp)); \
} while (0)
/* this is a special case, as the device will read as an address */
#define RFD_RBD_WR(base, value) \
do { \
volatile UINT32 temp; \
temp = (value == RBD_NULL_ADDR) ? value : \
((UINT32) FEI_VIRT_TO_SYS ((UINT32) (value))); \
RFD_LONG_WR ((UINT32) (base), RFD_RBD_OFFSET, (temp)); \
} while (0)
/* receive buffer descriptors write macros */
#define RBD_BYTE_WR(base, offset, value) \
FEI_BYTE_WR ((UINT32 *) ((UINT32) (base) + (offset)), \
(value))
#define RBD_WORD_WR(base, offset, value) \
FEI_WORD_WR ((UINT32 *) ((UINT32) (base) + (offset)), \
(value))
#define RBD_LONG_WR(base, offset, value) \
FEI_LONG_WR ((UINT32 *) ((UINT32) (base) + (offset)), \
(value))
#ifdef notdef
#define RBD_LONG_WR(base, offset, value) \
do { \
volatile UINT32 myVal = value; \
volatile UINT16 *tempVal; \
\
tempVal = (UINT16 *)&myVal; \
FEI_WORD_WR ((UINT32 *) ((UINT32) (base) + (offset)), \
(tempVal[0])); \
FEI_WORD_WR ((UINT32 *) ((UINT32) (base) + (offset) + 2), \
(tempVal[1])); \
} while (0)
#endif
/* these are special cases, as the device will read an address */
#define RBD_NEXT_WR(base, value) \
do { \
volatile UINT32 temp = (UINT32) FEI_VIRT_TO_SYS ((UINT32) (value)); \
\
RBD_LONG_WR ((UINT32) (base), RBD_NEXT_OFFSET, (temp)); \
} while (0)
#define RBD_BUF_WR(base, value) \
do { \
volatile UINT32 temp = (UINT32) FEI_VIRT_TO_SYS ((UINT32) (value)); \
\
RBD_LONG_WR ((UINT32) (base), RBD_BUFFER_OFFSET, (temp)); \
} while (0)
#define RBD_BUF_RD(base, value) \
do { \
volatile UINT32 temp; \
RBD_LONG_RD ((UINT32) (base), RBD_BUFFER_OFFSET, (temp)); \
value = (CL_BUF_ID) FEI_SYS_TO_VIRT ((UINT32) (temp)); \
} while (0)
/* command frame descriptors read macros */
#define CFD_BYTE_RD(base, offset, value) \
FEI_BYTE_RD ((UINT32 *) ((UINT32) (base) + (offset)), (value))
#define CFD_WORD_RD(base, offset, value) \
FEI_WORD_RD ((UINT32 *) ((UINT32) (base) + (offset)), (value))
#define CFD_LONG_RD(base, offset, value) \
FEI_LONG_RD ((UINT32 *) ((UINT32) (base) + (offset)), (value))
#define CFD_POINT_RD(base, offset, value, type) \
{ \
volatile UINT32 temp; \
FEI_LONG_RD ((UINT32 *) ((UINT32) (base) + (offset)),(temp)); \
value = (type)temp; \
}
/* this is a special case, as the device will read as an address */
#define CFD_NEXT_RD(base, value) \
CFD_LONG_RD ((UINT32) (base), CFD_SW_NEXT_OFFSET, (value))
/* receive frame descriptors read macros */
#define RFD_BYTE_RD(base, offset, value) \
FEI_BYTE_RD ((UINT32 *) ((UINT32) (base) + (offset)), (value))
#define RFD_WORD_RD(base, offset, value) \
FEI_WORD_RD ((UINT32 *) ((UINT32) (base) + (offset)), (value))
#define RFD_LONG_RD(base, offset, value) \
FEI_LONG_RD ((UINT32 *) ((UINT32) (base) + (offset)), (value))
/* receive buffer descriptors read macros */
#define RBD_BYTE_RD(base, offset, value) \
FEI_BYTE_RD ((UINT32 *) ((UINT32) (base) + (offset)), (value))
#define RBD_WORD_RD(base, offset, value) \
FEI_WORD_RD ((UINT32 *) ((UINT32) (base) + (offset)), (value))
#define RBD_LONG_RD(base, offset, value) \
FEI_LONG_RD ((UINT32 *) ((UINT32) (base) + (offset)), (value))
/* various command frame descriptors macros */
#define CFD_PKT_ADDR(cfdBase) \
((UINT32 *) ((UINT32) cfdBase + CFD_PKT_OFFSET))
#define RFD_PKT_ADDR(cfdBase) \
((UINT32 *) ((UINT32) cfdBase + RFD_PKT_OFFSET))
#define CFD_IA_ADDR(cfdBase) \
((UINT32 *) ((UINT32) (cfdBase) + CFD_IA_OFFSET))
#define CFD_MC_ADDR(cfdBase) \
((UINT32 *) ((UINT32) (cfdBase) + CFD_MC_OFFSET))
#define CFD_CONFIG_WR(address, value) \
FEI_BYTE_WR ((UINT32 *) ((UINT32) (address)), \
(value))
#define I82557_INT_ENABLE(value) \
{ \
UINT8 temp; \
CACHE_PIPE_FLUSH(); \
CSR_BYTE_RD (CSR_INT_OFFSET, temp); \
CSR_BYTE_WR (CSR_INT_OFFSET, (temp & ~value)); \
}
#define I82557_INT_DISABLE(value) \
{ \
UINT8 temp; \
CACHE_PIPE_FLUSH(); \
CSR_BYTE_RD (CSR_INT_OFFSET, temp); \
CSR_BYTE_WR (CSR_INT_OFFSET, (temp | value)); \
}
/* extern */
IMPORT POOL_FUNC * _pEndNetPoolFuncTbl;
IMPORT int ffsMsb ();
FUNCPTR feiEndIntConnect = (FUNCPTR) intConnect;
FUNCPTR feiEndIntDisconnect = (FUNCPTR) NULL;
/* locals */
/* The definition of the driver control structure */
typedef struct drv_ctrl
{
END_OBJ endObj; /* base class */
int unit; /* unit number */
FUNCPTR pSendRtn;
int nRFDs; /* number of RFDs on DMA ring */
int nRBDs; /* number of RBDs on DMA ring */
int nCFDs; /* how many CFDs to create */
char * pRfdBase; /* RFD allocation base */
char * pRbdBase; /* RBD allocation base */
char * pCfdBase; /* CFD allocation base */
char * pClusterBase; /* cluster pool base */
int nClusters; /* number of clusters to create */
int clToRfdRatio; /* Ratio of clusters to RFDs */
ULONG clMemSize; /* cluster pool size */
char * pMclBlkMemArea; /* clBlk mBlk memory area pointer */
volatile CSR_ID pCSR; /* pointer to CSR base */
volatile CFD_ID pFreeCFD; /* current free CFD */
volatile CFD_ID pUsedCFD; /* first used CFD */
volatile RFD_ID pRFD; /* current Receive Frame Descriptor */
volatile RBD_ID pRBD; /* current Receive Buffer Descriptor */
RFD_TAG * rfdTags; /* Array of RFD_TAGs */
RBD_TAG * rbdTags; /* Array of RBD_TAGs */
int rbdIndex; /* current RX index */
int rfdIndex; /* current RX index */
RBD_TAG * eLRbdTag; /* RBD that currently has EL bit set */
RBD_TAG * startRbdTag; /* RBD that RU was last started at */
INT8 flags; /* driver state */
BOOL attached; /* interface has been attached */
volatile BOOL rxHandle; /* rx handler scheduled */
BOOL txHandle; /* tx handler scheduled */
BOOL txStall; /* tx handler stalled - no CFDs */
UINT maxRxFrames; /* max frames to Receive in one job */
BOOL rxJobQued; /* fei82557RecvHandler() queing flag */
CACHE_FUNCS cacheFuncs; /* cache descriptor */
CACHE_FUNCS cacheDmaFuncs; /* cache descriptor */
CACHE_FUNCS cacheUserFuncs; /* cache descriptor */
FEI_BOARD_INFO board; /* board specific info */
CL_POOL_ID pClPoolId; /* cluster pool identifier */
int offset; /* Alignment offset */
UINT deviceId; /* PCI device ID */
END_ERR lastError; /* Last error passed to muxError */
UINT errorNoBufs; /* cluster exhaustion */
WDOG_ID txRetryWDId; /* Tx restart watchdog */
UINT16 event; /* storage for interrupt events */
} DRV_CTRL;
#ifdef DRV_DEBUG557
void feiPoolShow
(
int unit
)
{
DRV_CTRL *pDrvCtrl = (DRV_CTRL *)endFindByName ("fei", unit);
netPoolShow (pDrvCtrl->endObj.pNetPool);
}
#endif /* DRV_DEBUG557 */
/* Function declarations not in any header files */
IMPORT STATUS sys557Init (int unit, FEI_BOARD_INFO *pBoard);
/* forward function declarations */
LOCAL int fei82557ClkRate = 0;
LOCAL STATUS fei82557InitParse (DRV_CTRL *pDrvCtrl, char *initString);
LOCAL STATUS fei82557InitMem (DRV_CTRL *pDrvCtrl);
LOCAL STATUS fei82557Encap (DRV_CTRL *pDrvCtrl, CFD_ID pCFD,
M_BLK *pMblkHead);
LOCAL STATUS fei82557Send (DRV_CTRL *pDrvCtrl, M_BLK *pMblk);
LOCAL STATUS fei82557GatherSend (DRV_CTRL *pDrvCtrl, M_BLK *pMblk);
LOCAL STATUS fei82557CopySend (DRV_CTRL *pDrvCtrl, M_BLK *pMblk);
LOCAL UINT16 fei82557Action (DRV_CTRL *pDrvCtrl, UINT16 action);
LOCAL STATUS fei82557PhyInit (DRV_CTRL *pDrvCtrl);
LOCAL STATUS fei82557Stop (DRV_CTRL *pDrvCtrl);
LOCAL STATUS fei82557Reset (DRV_CTRL *pDrvCtrl);
LOCAL STATUS fei82557SCBCommand (DRV_CTRL *pDrvCtrl, UINT8 cmd,
BOOL addrValid, UINT32 *addr);
LOCAL STATUS fei82557Diag (DRV_CTRL *pDrvCtrl);
LOCAL STATUS fei82557IASetup (DRV_CTRL *pDrvCtrl);
LOCAL STATUS fei82557Config (DRV_CTRL *pDrvCtrl);
LOCAL void fei82557MCastListForm (DRV_CTRL *pDrvCtrl, CFD_ID pCFD);
LOCAL void fei82557ConfigForm (DRV_CTRL *pDrvCtrl, CFD_ID pCFD);
LOCAL int fei82557MDIPhyLinkSet (DRV_CTRL *pDrvCtrl, int phyAddr);
LOCAL STATUS fei82557NOP (DRV_CTRL *pDrvCtrl);
LOCAL void fei82557CFDFree ( DRV_CTRL *pDrvCtrl);
LOCAL void fei82557FDUpdate (DRV_CTRL *pDrvCtrl, UINT8 fdList);
LOCAL STATUS fei82557MDIPhyConfig (DRV_CTRL *pDrvCtrl, int phyAddr);
LOCAL void fei82557Int (DRV_CTRL *pDrvCtrl);
LOCAL void fei82557NoResource(DRV_CTRL *pDrvCtrl);
LOCAL void fei82557MuxTxRestart( END_OBJ *pEndObj);
LOCAL void fei82557RecvHandler (DRV_CTRL *pDrvCtrl);
LOCAL STATUS fei82557Restart (DRV_CTRL * pDrvCtrl);
LOCAL int fei82557MDIRead (DRV_CTRL *pDrvCtrl, int regAddr,
int phyAddr, UINT16 *retVal);
LOCAL int fei82557MDIWrite (DRV_CTRL *pDrvCtrl, int regAddr,
int phyAddr, UINT16 writeData);
/* debug routines, not normally compiled */
STATUS fei82557ErrCounterDump (DRV_CTRL *pDrvCtrl, UINT32 *memAddr);
STATUS fei82557DumpPrint (int unit);
LOCAL void fei82557TxRestart (END_OBJ *pEndObj);
/* END Specific interfaces. */
END_OBJ * fei82557EndLoad (char *initString);
LOCAL STATUS fei82557Start (DRV_CTRL *pDrvCtrl);
LOCAL STATUS fei82557Unload (DRV_CTRL *pDrvCtrl);
LOCAL STATUS fei82557Stop (DRV_CTRL *pDrvCtrl);
LOCAL int fei82557Ioctl (DRV_CTRL *pDrvCtrl, UINT32 cmd, caddr_t data);
LOCAL STATUS fei82557Send (DRV_CTRL *pDrvCtrl, M_BLK_ID pMblk);
LOCAL STATUS fei82557MCastAddrAdd (DRV_CTRL *pDrvCtrl, char* pAddress);
LOCAL STATUS fei82557MCastAddrDel (DRV_CTRL *pDrvCtrl, char* pAddress);
LOCAL STATUS fei82557MCastAddrGet (DRV_CTRL *pDrvCtrl,
MULTI_TABLE *pTable);
LOCAL STATUS fei82557PollSend (DRV_CTRL *pDrvCtrl, M_BLK_ID pMblk);
LOCAL STATUS fei82557PollReceive (DRV_CTRL *pDrvCtrl, M_BLK_ID pMblk);
LOCAL STATUS fei82557PollStart (DRV_CTRL *pDrvCtrl);
LOCAL STATUS fei82557PollStop (DRV_CTRL *pDrvCtrl);
/*
* Define the device function table. This is static across all driver
* instances.
*/
LOCAL NET_FUNCS netFuncs =
{
(FUNCPTR)fei82557Start, /* start func. */
(FUNCPTR)fei82557Stop, /* stop func. */
(FUNCPTR)fei82557Unload, /* unload func. */
(FUNCPTR)fei82557Ioctl, /* ioctl func. */
(FUNCPTR)fei82557Send, /* send func. */
(FUNCPTR)fei82557MCastAddrAdd, /* multicast add func. */
(FUNCPTR)fei82557MCastAddrDel, /* multicast delete func. */
(FUNCPTR)fei82557MCastAddrGet, /* multicast get fun. */
(FUNCPTR)fei82557PollSend, /* polling send func. */
(FUNCPTR)fei82557PollReceive, /* polling receive func. */
endEtherAddressForm, /* put address info into a NET_BUFFER. */
endEtherPacketDataGet, /* get pointer to data in NET_BUFFER. */
endEtherPacketAddrGet /* Get packet addresses. */
};
/*******************************************************************************
*
* fei82557EndLoad - initialize the driver and device
*
* This routine initializes both, driver and device to an operational state
* using device specific parameters specified by <initString>.
*
* The parameter string, <initString>, is an ordered list of parameters each
* separated by a colon. The format of <initString> is,
* "<unit>:<memBase>:<memSize>:<nCFDs>:<nRFDs>:<flags>:<offset>:<deviceId>:
* <maxRxFrames>:<clToRfdRatio>:<nClusters>"
*
*
* The 82557 shares a region of memory with the driver. The caller of this
* routine can specify the address of this memory region, or can specify that
* the driver must obtain this memory region from the system resources.
*
* A default number of transmit/receive frames of 32 and 128 respectively and
* can be selected by passing zero in the parameters <nTfds> and <nRfds>. In
* other cases, the number of frames selected should be greater than two.
*
* All optional parameters can be set to their default value by specifing
* NONE (-1) as their value.
*
* The <memBase> parameter is used to inform the driver about the shared
* memory region. If this parameter is set to the constant "NONE," then this
* routine will attempt to allocate the shared memory from the system. Any
* other value for this parameter is interpreted by this routine as the address
* of the shared memory region to be used. The <memSize> parameter is used
* to check that this region is large enough with respect to the provided
* values of both transmit/receive frames.
*
* If the caller provides the shared memory region, then the driver assumes
* that this region is non-cached.
*
* If the caller indicates that this routine must allocate the shared memory
* region, then this routine will use memalign() to allocate some cache aligned
* memory.
*
* The <memSize> parameter specifies the size of the pre-allocated memory
* region. If memory base is specified as NONE (-1), the driver ignores this
* parameter. Otherwise, the driver checks the size of the provided memory
* region is adequate with respect to the given number of RFDs, RBDs, CFDs, and
* clusters specified. The number of clusters required will be at least equal
* to (nRFDs * 2) + nCFDs. Otherwise the End Load routine will return ERROR.
* The number of clusters can be specified by either passing a value in the
* nCluster parameter, in which case the nCluster value must be at least
* nRFDs * 2, or by setting the cluster to RFD ratio (clToRfdRatio) to a number
* equal or greater than 2.
*
*
* The <nTfds> parameter specifies the number of transmit descriptor/buffers
* to be allocated. If this parameter is less than two, a default of 64 is used.
*
* The <nRfds> parameter specifies the number of receive descriptors to be
* allocated. If this parameter is less than two or NONE (-1) a default of
* 128 is used.
*
* The <flags> parameter specifies the user flags may control the run-time
* characteristics of the Ethernet chip. Not implemented.
*
* The <offset> parameter is used to align IP header on word boundary for CPUs
* that need long word aligned access to the IP packet (this will normally be
* zero or two). This parameter is optional, the default value is zero.
*
* The <deviceId> parameter is used to indicate the specific type of device
* being used, the 82557 or subsequent. This is used to determine if features
* which were introduced after the 82557 can be used. The default is the 82557.