2 Provides basic function upon network adapter card.
4 Copyright (c) 2006, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 static UINT8 basic_config_cmd
[22] = {
27 (UINT8
)0xf2, (UINT8
)0x80, // 0x40=Force full-duplex
32 // How to wait for the command unit to accept a command.
33 // Typically this takes 0 ticks.
35 #define wait_for_cmd_done(cmd_ioaddr) \
37 INT16 wait_count = 2000; \
38 while ((InByte (AdapterInfo, cmd_ioaddr) != 0) && --wait_count >= 0) \
39 DelayIt (AdapterInfo, 10); \
40 if (wait_count == 0) \
41 DelayIt (AdapterInfo, 50); \
46 This function calls the MemIo callback to read a byte from the device's
48 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
49 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
50 to make undi3.0 a special case
52 @param Port Which port to read from.
54 @retval Results The data read from the port.
57 // TODO: AdapterInfo - add argument and description to function comment
60 IN NIC_DATA_INSTANCE
*AdapterInfo
,
66 (*AdapterInfo
->Mem_Io
) (
67 AdapterInfo
->Unique_ID
,
71 (UINT64
) (UINTN
) &Results
78 This function calls the MemIo callback to read a word from the device's
80 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
81 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
82 to make undi3.0 a special case
84 @param Port Which port to read from.
86 @retval Results The data read from the port.
89 // TODO: AdapterInfo - add argument and description to function comment
92 IN NIC_DATA_INSTANCE
*AdapterInfo
,
98 (*AdapterInfo
->Mem_Io
) (
99 AdapterInfo
->Unique_ID
,
103 (UINT64
)(UINTN
)&Results
110 This function calls the MemIo callback to read a dword from the device's
112 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
113 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
114 to make undi3.0 a special case
116 @param Port Which port to read from.
118 @retval Results The data read from the port.
121 // TODO: AdapterInfo - add argument and description to function comment
124 IN NIC_DATA_INSTANCE
*AdapterInfo
,
130 (*AdapterInfo
->Mem_Io
) (
131 AdapterInfo
->Unique_ID
,
135 (UINT64
)(UINTN
)&Results
142 This function calls the MemIo callback to write a byte from the device's
144 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
145 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
146 to make undi3.0 a special case
148 @param Data Data to write to Port.
149 @param Port Which port to write to.
154 // TODO: AdapterInfo - add argument and description to function comment
157 IN NIC_DATA_INSTANCE
*AdapterInfo
,
165 (*AdapterInfo
->Mem_Io
) (
166 AdapterInfo
->Unique_ID
,
170 (UINT64
)(UINTN
)(UINTN
)&Val
177 This function calls the MemIo callback to write a word from the device's
179 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
180 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
181 to make undi3.0 a special case
183 @param Data Data to write to Port.
184 @param Port Which port to write to.
189 // TODO: AdapterInfo - add argument and description to function comment
192 IN NIC_DATA_INSTANCE
*AdapterInfo
,
200 (*AdapterInfo
->Mem_Io
) (
201 AdapterInfo
->Unique_ID
,
212 This function calls the MemIo callback to write a dword from the device's
214 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
215 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
216 to make undi3.0 a special case
218 @param Data Data to write to Port.
219 @param Port Which port to write to.
224 // TODO: AdapterInfo - add argument and description to function comment
227 IN NIC_DATA_INSTANCE
*AdapterInfo
,
235 (*AdapterInfo
->Mem_Io
) (
236 AdapterInfo
->Unique_ID
,
247 TODO: Add function description
249 @param AdapterInfo TODO: add argument description
250 @param MemAddr TODO: add argument description
251 @param Size TODO: add argument description
252 @param Direction TODO: add argument description
253 @param MappedAddr TODO: add argument description
255 @return TODO: add return values
261 IN NIC_DATA_INSTANCE
*AdapterInfo
,
265 OUT UINT64 MappedAddr
270 PhyAddr
= (UINT64
*) (UINTN
) MappedAddr
;
272 // mapping is different for theold and new NII protocols
274 if (AdapterInfo
->VersionFlag
== 0x30) {
275 if (AdapterInfo
->Virt2Phys_30
== (VOID
*) NULL
) {
276 *PhyAddr
= (UINT64
) AdapterInfo
->MemoryPtr
;
278 (*AdapterInfo
->Virt2Phys_30
) (MemAddr
, (UINT64
) (UINTN
) PhyAddr
);
281 if (*PhyAddr
> FOUR_GIGABYTE
) {
282 return PXE_STATCODE_INVALID_PARAMETER
;
285 if (AdapterInfo
->Map_Mem
== (VOID
*) NULL
) {
287 // this UNDI cannot handle addresses beyond 4 GB without a map routine
289 if (MemAddr
> FOUR_GIGABYTE
) {
290 return PXE_STATCODE_INVALID_PARAMETER
;
295 (*AdapterInfo
->Map_Mem
) (
296 AdapterInfo
->Unique_ID
,
305 return PXE_STATCODE_SUCCESS
;
310 TODO: Add function description
312 @param AdapterInfo TODO: add argument description
313 @param MemAddr TODO: add argument description
314 @param Size TODO: add argument description
315 @param Direction TODO: add argument description
316 @param MappedAddr TODO: add argument description
318 @return TODO: add return values
324 IN NIC_DATA_INSTANCE
*AdapterInfo
,
331 if (AdapterInfo
->VersionFlag
> 0x30) {
333 // no mapping service
335 if (AdapterInfo
->UnMap_Mem
!= (VOID
*) NULL
) {
336 (*AdapterInfo
->UnMap_Mem
) (
337 AdapterInfo
->Unique_ID
,
353 @param AdapterInfo Pointer to the NIC data structure
354 information which the UNDI driver is
359 // TODO: MicroSeconds - add argument and description to function comment
363 IN NIC_DATA_INSTANCE
*AdapterInfo
,
367 if (AdapterInfo
->VersionFlag
== 0x30) {
368 (*AdapterInfo
->Delay_30
) (MicroSeconds
);
370 (*AdapterInfo
->Delay
) (AdapterInfo
->Unique_ID
, MicroSeconds
);
377 @param AdapterInfo Pointer to the NIC data structure
378 information which the UNDI driver is
383 // TODO: flag - add argument and description to function comment
387 IN NIC_DATA_INSTANCE
*AdapterInfo
,
391 if (AdapterInfo
->VersionFlag
== 0x30) {
392 (*AdapterInfo
->Block_30
) (flag
);
394 (*AdapterInfo
->Block
) (AdapterInfo
->Unique_ID
, flag
);
400 TODO: Add function description
402 @param AdapterInfo TODO: add argument description
404 @return TODO: add return values
410 NIC_DATA_INSTANCE
*AdapterInfo
414 // we will use the linear (flat) memory model and fill our base registers
415 // with 0's so that the entire physical address is our offset
418 // we reset the statistics totals here because this is where we are loading stats addr
420 AdapterInfo
->RxTotals
= 0;
421 AdapterInfo
->TxTotals
= 0;
424 // Load the statistics block address.
426 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
427 OutLong (AdapterInfo
, (UINT32
) AdapterInfo
->stat_phy_addr
, AdapterInfo
->ioaddr
+ SCBPointer
);
428 OutByte (AdapterInfo
, CU_STATSADDR
, AdapterInfo
->ioaddr
+ SCBCmd
);
429 AdapterInfo
->statistics
->done_marker
= 0;
431 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
432 OutLong (AdapterInfo
, 0, AdapterInfo
->ioaddr
+ SCBPointer
);
433 OutByte (AdapterInfo
, RX_ADDR_LOAD
, AdapterInfo
->ioaddr
+ SCBCmd
);
435 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
436 OutLong (AdapterInfo
, 0, AdapterInfo
->ioaddr
+ SCBPointer
);
437 OutByte (AdapterInfo
, CU_CMD_BASE
, AdapterInfo
->ioaddr
+ SCBCmd
);
444 TODO: Add function description
446 @param AdapterInfo TODO: add argument description
447 @param cmd_ptr TODO: add argument description
449 @return TODO: add return values
455 NIC_DATA_INSTANCE
*AdapterInfo
,
461 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
464 // read the CU status, if it is idle, write the address of cb_ptr
465 // in the scbpointer and issue a cu_start,
466 // if it is suspended, remove the suspend bit in the previous command
467 // block and issue a resume
469 // Ensure that the CU Active Status bit is not on from previous CBs.
471 status
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBStatus
);
474 // Skip acknowledging the interrupt if it is not already set
478 // ack only the cna the integer
480 if ((status
& SCB_STATUS_CNA
) != 0) {
481 OutWord (AdapterInfo
, SCB_STATUS_CNA
, AdapterInfo
->ioaddr
+ SCBStatus
);
485 if ((status
& SCB_STATUS_CU_MASK
) == SCB_STATUS_CU_IDLE
) {
489 OutLong (AdapterInfo
, cmd_ptr
->PhysTCBAddress
, AdapterInfo
->ioaddr
+ SCBPointer
);
490 OutByte (AdapterInfo
, CU_START
, AdapterInfo
->ioaddr
+ SCBCmd
);
493 // either active or suspended, give a resume
496 cmd_ptr
->PrevTCBVirtualLinkPtr
->cb_header
.command
&= ~(CmdSuspend
| CmdIntr
);
497 OutByte (AdapterInfo
, CU_RESUME
, AdapterInfo
->ioaddr
+ SCBCmd
);
505 TODO: Add function description
507 @param AdapterInfo TODO: add argument description
509 @return TODO: add return values
515 NIC_DATA_INSTANCE
*AdapterInfo
519 // all command blocks are of TxCB format
523 volatile INT16 Index
;
526 cmd_ptr
= GetFreeCB (AdapterInfo
);
527 data_ptr
= (UINT8
*) (&cmd_ptr
->PhysTBDArrayAddres
);
530 // start the config data right after the command header
532 for (Index
= 0; Index
< sizeof (basic_config_cmd
); Index
++) {
533 data_ptr
[Index
] = basic_config_cmd
[Index
];
536 my_filter
= (UINT8
) ((AdapterInfo
->Rx_Filter
& PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS
) ? 1 : 0);
537 my_filter
= (UINT8
) (my_filter
| ((AdapterInfo
->Rx_Filter
& PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST
) ? 0 : 2));
539 data_ptr
[15] = (UINT8
) (data_ptr
[15] | my_filter
);
540 data_ptr
[19] = (UINT8
) (AdapterInfo
->Duplex
? 0xC0 : 0x80);
541 data_ptr
[21] = (UINT8
) ((AdapterInfo
->Rx_Filter
& PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST
) ? 0x0D : 0x05);
544 // check if we have to use the AUI port instead
546 if ((AdapterInfo
->PhyRecord
[0] & 0x8000) != 0) {
547 data_ptr
[15] |= 0x80;
551 BlockIt (AdapterInfo
, TRUE
);
552 cmd_ptr
->cb_header
.command
= CmdSuspend
| CmdConfigure
;
554 IssueCB (AdapterInfo
, cmd_ptr
);
555 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
557 BlockIt (AdapterInfo
, FALSE
);
559 CommandWaitForCompletion (cmd_ptr
, AdapterInfo
);
562 // restore the cb values for tx
564 cmd_ptr
->PhysTBDArrayAddres
= cmd_ptr
->PhysArrayAddr
;
565 cmd_ptr
->ByteCount
= cmd_ptr
->Threshold
= cmd_ptr
->TBDCount
= 0;
567 // fields beyond the immediatedata are assumed to be safe
568 // add the CB to the free list again
570 SetFreeCB (AdapterInfo
, cmd_ptr
);
576 TODO: Add function description
578 @param AdapterInfo TODO: add argument description
580 @return TODO: add return values
585 NIC_DATA_INSTANCE
*AdapterInfo
589 // all command blocks are of TxCB format
595 eaddrs
= (UINT16
*) AdapterInfo
->CurrentNodeAddress
;
597 cmd_ptr
= GetFreeCB (AdapterInfo
);
598 data_ptr
= (UINT16
*) (&cmd_ptr
->PhysTBDArrayAddres
);
601 // AVOID a bug (?!) here by marking the command already completed.
603 cmd_ptr
->cb_header
.command
= (CmdSuspend
| CmdIASetup
);
604 cmd_ptr
->cb_header
.status
= 0;
605 data_ptr
[0] = eaddrs
[0];
606 data_ptr
[1] = eaddrs
[1];
607 data_ptr
[2] = eaddrs
[2];
609 BlockIt (AdapterInfo
, TRUE
);
610 IssueCB (AdapterInfo
, cmd_ptr
);
611 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
612 BlockIt (AdapterInfo
, FALSE
);
614 CommandWaitForCompletion (cmd_ptr
, AdapterInfo
);
617 // restore the cb values for tx
619 cmd_ptr
->PhysTBDArrayAddres
= cmd_ptr
->PhysArrayAddr
;
620 cmd_ptr
->ByteCount
= cmd_ptr
->Threshold
= cmd_ptr
->TBDCount
= 0;
622 // fields beyond the immediatedata are assumed to be safe
623 // add the CB to the free list again
625 SetFreeCB (AdapterInfo
, cmd_ptr
);
631 Instructs the NIC to stop receiving packets.
633 @param AdapterInfo Pointer to the NIC data structure
634 information which the UNDI driver is
642 IN NIC_DATA_INSTANCE
*AdapterInfo
645 if (AdapterInfo
->Receive_Started
) {
648 // Todo: verify that we must wait for previous command completion.
650 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
653 // Disable interrupts, and stop the chip's Rx process.
655 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
656 OutWord (AdapterInfo
, INT_MASK
| RX_ABORT
, AdapterInfo
->ioaddr
+ SCBCmd
);
658 AdapterInfo
->Receive_Started
= FALSE
;
666 Instructs the NIC to start receiving packets.
668 @param AdapterInfo Pointer to the NIC data structure
669 information which the UNDI driver is
673 @retval -1 Already Started
679 NIC_DATA_INSTANCE
*AdapterInfo
683 if (AdapterInfo
->Receive_Started
) {
690 AdapterInfo
->cur_rx_ind
= 0;
691 AdapterInfo
->Int_Status
= 0;
693 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
695 OutLong (AdapterInfo
, (UINT32
) AdapterInfo
->rx_phy_addr
, AdapterInfo
->ioaddr
+ SCBPointer
);
696 OutByte (AdapterInfo
, RX_START
, AdapterInfo
->ioaddr
+ SCBCmd
);
698 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
700 AdapterInfo
->Receive_Started
= TRUE
;
706 Configures the chip. This routine expects the NIC_DATA_INSTANCE structure to be filled in.
708 @param AdapterInfo Pointer to the NIC data structure
709 information which the UNDI driver is
713 @retval PXE_STATCODE_NOT_ENOUGH_MEMORY Insufficient length of locked memory
714 @retval other Failure initializing chip
719 IN NIC_DATA_INSTANCE
*AdapterInfo
722 PCI_CONFIG_HEADER
*CfgHdr
;
727 if (AdapterInfo
->MemoryLength
< MEMORY_NEEDED
) {
728 return PXE_STATCODE_NOT_ENOUGH_MEMORY
;
733 AdapterInfo
->MemoryPtr
,
734 AdapterInfo
->MemoryLength
,
736 (UINT64
)(UINTN
) &AdapterInfo
->Mapped_MemoryPtr
743 CfgHdr
= (PCI_CONFIG_HEADER
*) &(AdapterInfo
->Config
[0]);
746 // fill in the ioaddr, int... from the config space
748 AdapterInfo
->int_num
= CfgHdr
->int_line
;
751 // we don't need to validate integer number, what if they don't want to assign one?
752 // if (AdapterInfo->int_num == 0 || AdapterInfo->int_num == 0xff)
753 // return PXE_STATCODE_DEVICE_FAILURE;
755 AdapterInfo
->ioaddr
= 0;
756 AdapterInfo
->VendorID
= CfgHdr
->VendorID
;
757 AdapterInfo
->DeviceID
= CfgHdr
->DeviceID
;
758 AdapterInfo
->RevID
= CfgHdr
->RevID
;
759 AdapterInfo
->SubVendorID
= CfgHdr
->SubVendorID
;
760 AdapterInfo
->SubSystemID
= CfgHdr
->SubSystemID
;
761 AdapterInfo
->flash_addr
= 0;
764 // Read the station address EEPROM before doing the reset.
765 // Perhaps this should even be done before accepting the device,
766 // then we wouldn't have a device name with which to report the error.
768 if (E100bReadEepromAndStationAddress (AdapterInfo
) != 0) {
769 return PXE_STATCODE_DEVICE_FAILURE
;
773 // ## calculate the buffer #s depending on memory given
774 // ## calculate the rx and tx ring pointers
777 AdapterInfo
->TxBufCnt
= TX_BUFFER_COUNT
;
778 AdapterInfo
->RxBufCnt
= RX_BUFFER_COUNT
;
779 rx_size
= (AdapterInfo
->RxBufCnt
* sizeof (RxFD
));
780 tx_size
= (AdapterInfo
->TxBufCnt
* sizeof (TxCB
));
781 AdapterInfo
->rx_ring
= (RxFD
*) (UINTN
) (AdapterInfo
->MemoryPtr
);
782 AdapterInfo
->tx_ring
= (TxCB
*) (UINTN
) (AdapterInfo
->MemoryPtr
+ rx_size
);
783 AdapterInfo
->statistics
= (struct speedo_stats
*) (UINTN
) (AdapterInfo
->MemoryPtr
+ rx_size
+ tx_size
);
785 AdapterInfo
->rx_phy_addr
= AdapterInfo
->Mapped_MemoryPtr
;
786 AdapterInfo
->tx_phy_addr
= AdapterInfo
->Mapped_MemoryPtr
+ rx_size
;
787 AdapterInfo
->stat_phy_addr
= AdapterInfo
->tx_phy_addr
+ tx_size
;
792 AdapterInfo
->PhyAddress
= 0xFF;
793 AdapterInfo
->Rx_Filter
= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST
;
794 AdapterInfo
->Receive_Started
= FALSE
;
795 AdapterInfo
->mcast_list
.list_len
= 0;
796 return InitializeChip (AdapterInfo
);
801 Sets the interrupt state for the NIC.
803 @param AdapterInfo Pointer to the NIC data structure
804 information which the UNDI driver is
811 E100bSetInterruptState (
812 IN NIC_DATA_INSTANCE
*AdapterInfo
816 // don't set receive interrupt if receiver is disabled...
820 if ((AdapterInfo
->int_mask
& PXE_OPFLAGS_INTERRUPT_RECEIVE
) != 0) {
821 cmd_word
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCmd
);
822 cmd_word
&= ~INT_MASK
;
823 OutWord (AdapterInfo
, cmd_word
, AdapterInfo
->ioaddr
+ SCBCmd
);
826 // disable ints, should not be given for SW Int.
828 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
831 if ((AdapterInfo
->int_mask
& PXE_OPFLAGS_INTERRUPT_SOFTWARE
) != 0) {
833 // reset the bit in our mask, it is only one time!!
835 AdapterInfo
->int_mask
&= ~(PXE_OPFLAGS_INTERRUPT_SOFTWARE
);
836 cmd_word
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCmd
);
837 cmd_word
|= DRVR_INT
;
838 OutWord (AdapterInfo
, cmd_word
, AdapterInfo
->ioaddr
+ SCBCmd
);
844 // we are not going to disable broadcast for the WOL's sake!
848 Instructs the NIC to start receiving packets.
850 @param AdapterInfo Pointer to the NIC data structure
851 information which the UNDI driver is
852 layering on.. new_filter
857 @retval -1 Already Started
862 NIC_DATA_INSTANCE
*AdapterInfo
,
868 PXE_CPB_RECEIVE_FILTERS
*mc_list
= (PXE_CPB_RECEIVE_FILTERS
*) (UINTN
)cpb
;
875 struct MC_CB_STRUCT
*data_ptr
;
878 old_filter
= AdapterInfo
->Rx_Filter
;
881 // only these bits need a change in the configuration
882 // actually change in bcast requires configure but we ignore that change
884 cfg_flt
= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS
|
885 PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST
;
887 if ((old_filter
& cfg_flt
) != (new_filter
& cfg_flt
)) {
888 XmitWaitForCompletion (AdapterInfo
);
890 if (AdapterInfo
->Receive_Started
) {
891 StopRU (AdapterInfo
);
894 AdapterInfo
->Rx_Filter
= (UINT8
) (new_filter
| PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST
);
895 Configure (AdapterInfo
);
899 // check if mcast setting changed
901 if ( ((new_filter
& PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
) !=
902 (old_filter
& PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
) ) ||
903 (mc_list
!= NULL
) ) {
906 if (mc_list
!= NULL
) {
907 mc_count
= AdapterInfo
->mcast_list
.list_len
= (UINT16
) (cpbsize
/ PXE_MAC_LENGTH
);
909 for (Index
= 0; (Index
< mc_count
&& Index
< MAX_MCAST_ADDRESS_CNT
); Index
++) {
910 for (Index2
= 0; Index2
< PXE_MAC_LENGTH
; Index2
++) {
911 AdapterInfo
->mcast_list
.mc_list
[Index
][Index2
] = mc_list
->MCastList
[Index
][Index2
];
917 // are we setting the list or resetting??
919 if ((new_filter
& PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
) != 0) {
921 // we are setting a new list!
923 mc_count
= AdapterInfo
->mcast_list
.list_len
;
925 // count should be the actual # of bytes in the list
926 // so multiply this with 6
928 mc_byte_cnt
= (UINT16
) ((mc_count
<< 2) + (mc_count
<< 1));
929 AdapterInfo
->Rx_Filter
|= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
;
932 // disabling the list in the NIC.
934 mc_byte_cnt
= mc_count
= 0;
935 AdapterInfo
->Rx_Filter
&= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
);
939 // before issuing any new command!
941 XmitWaitForCompletion (AdapterInfo
);
943 if (AdapterInfo
->Receive_Started
) {
944 StopRU (AdapterInfo
);
948 cmd_ptr
= GetFreeCB (AdapterInfo
);
949 if (cmd_ptr
== NULL
) {
950 return PXE_STATCODE_QUEUE_FULL
;
953 // fill the command structure and issue
955 data_ptr
= (struct MC_CB_STRUCT
*) (&cmd_ptr
->PhysTBDArrayAddres
);
957 // first 2 bytes are the count;
959 data_ptr
->count
= mc_byte_cnt
;
960 for (Index
= 0; Index
< mc_count
; Index
++) {
961 for (Index2
= 0; Index2
< PXE_HWADDR_LEN_ETHER
; Index2
++) {
962 data_ptr
->m_list
[Index
][Index2
] = AdapterInfo
->mcast_list
.mc_list
[Index
][Index2
];
966 cmd_ptr
->cb_header
.command
= CmdSuspend
| CmdMulticastList
;
967 cmd_ptr
->cb_header
.status
= 0;
969 BlockIt (AdapterInfo
, TRUE
);
970 IssueCB (AdapterInfo
, cmd_ptr
);
971 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
973 BlockIt (AdapterInfo
, FALSE
);
975 CommandWaitForCompletion (cmd_ptr
, AdapterInfo
);
977 cmd_ptr
->PhysTBDArrayAddres
= cmd_ptr
->PhysArrayAddr
;
978 cmd_ptr
->ByteCount
= cmd_ptr
->Threshold
= cmd_ptr
->TBDCount
= 0;
980 // fields beyond the immediatedata are assumed to be safe
981 // add the CB to the free list again
983 SetFreeCB (AdapterInfo
, cmd_ptr
);
986 if (new_filter
!= 0) {
988 // enable unicast and start the RU
990 AdapterInfo
->Rx_Filter
= (UINT8
) (AdapterInfo
->Rx_Filter
| (new_filter
| PXE_OPFLAGS_RECEIVE_FILTER_UNICAST
));
991 StartRU (AdapterInfo
);
994 // may be disabling everything!
996 if (AdapterInfo
->Receive_Started
) {
997 StopRU (AdapterInfo
);
1000 AdapterInfo
->Rx_Filter
|= (~PXE_OPFLAGS_RECEIVE_FILTER_UNICAST
);
1008 TODO: Add function description
1010 @param AdapterInfo TODO: add argument description
1011 @param cpb TODO: add argument description
1012 @param opflags TODO: add argument description
1014 @return TODO: add return values
1019 NIC_DATA_INSTANCE
*AdapterInfo
,
1024 PXE_CPB_TRANSMIT_FRAGMENTS
*tx_ptr_f
;
1025 PXE_CPB_TRANSMIT
*tx_ptr_1
;
1032 tx_ptr_1
= (PXE_CPB_TRANSMIT
*) (UINTN
) cpb
;
1033 tx_ptr_f
= (PXE_CPB_TRANSMIT_FRAGMENTS
*) (UINTN
) cpb
;
1036 // stop reentrancy here
1038 if (AdapterInfo
->in_transmit
) {
1039 return PXE_STATCODE_BUSY
;
1043 AdapterInfo
->in_transmit
= TRUE
;
1046 // Prevent interrupts from changing the Tx ring from underneath us.
1048 // Calculate the Tx descriptor entry.
1050 if ((tcb_ptr
= GetFreeCB (AdapterInfo
)) == NULL
) {
1051 AdapterInfo
->in_transmit
= FALSE
;
1052 return PXE_STATCODE_QUEUE_FULL
;
1055 AdapterInfo
->TxTotals
++;
1057 tcb_ptr
->cb_header
.command
= (CmdSuspend
| CmdTx
| CmdTxFlex
);
1058 tcb_ptr
->cb_header
.status
= 0;
1061 // no immediate data, set EOF in the ByteCount
1063 tcb_ptr
->ByteCount
= 0x8000;
1066 // The data region is always in one buffer descriptor, Tx FIFO
1067 // threshold of 256.
1068 // 82557 multiplies the threashold value by 8, so give 256/8
1070 tcb_ptr
->Threshold
= 32;
1071 if ((opflags
& PXE_OPFLAGS_TRANSMIT_FRAGMENTED
) != 0) {
1073 if (tx_ptr_f
->FragCnt
> MAX_XMIT_FRAGMENTS
) {
1074 SetFreeCB (AdapterInfo
, tcb_ptr
);
1075 AdapterInfo
->in_transmit
= FALSE
;
1076 return PXE_STATCODE_INVALID_PARAMETER
;
1079 tcb_ptr
->TBDCount
= (UINT8
) tx_ptr_f
->FragCnt
;
1081 for (Index
= 0; Index
< tx_ptr_f
->FragCnt
; Index
++) {
1084 tx_ptr_f
->FragDesc
[Index
].FragAddr
,
1085 tx_ptr_f
->FragDesc
[Index
].FragLen
,
1087 (UINT64
)(UINTN
) &Tmp_ptr
1090 SetFreeCB (AdapterInfo
, tcb_ptr
);
1091 AdapterInfo
->in_transmit
= FALSE
;
1092 return PXE_STATCODE_INVALID_PARAMETER
;
1095 tcb_ptr
->TBDArray
[Index
].phys_buf_addr
= (UINT32
) Tmp_ptr
;
1096 tcb_ptr
->TBDArray
[Index
].buf_len
= tx_ptr_f
->FragDesc
[Index
].FragLen
;
1099 tcb_ptr
->free_data_ptr
= tx_ptr_f
->FragDesc
[0].FragAddr
;
1103 // non fragmented case
1105 tcb_ptr
->TBDCount
= 1;
1108 tx_ptr_1
->FrameAddr
,
1109 tx_ptr_1
->DataLen
+ tx_ptr_1
->MediaheaderLen
,
1111 (UINT64
)(UINTN
) &Tmp_ptr
1114 SetFreeCB (AdapterInfo
, tcb_ptr
);
1115 AdapterInfo
->in_transmit
= FALSE
;
1116 return PXE_STATCODE_INVALID_PARAMETER
;
1119 tcb_ptr
->TBDArray
[0].phys_buf_addr
= (UINT32
) (Tmp_ptr
);
1120 tcb_ptr
->TBDArray
[0].buf_len
= tx_ptr_1
->DataLen
+ tx_ptr_1
->MediaheaderLen
;
1121 tcb_ptr
->free_data_ptr
= tx_ptr_1
->FrameAddr
;
1125 // must wait for previous command completion only if it was a non-transmit
1127 BlockIt (AdapterInfo
, TRUE
);
1128 IssueCB (AdapterInfo
, tcb_ptr
);
1129 BlockIt (AdapterInfo
, FALSE
);
1132 // see if we need to wait for completion here
1134 if ((opflags
& PXE_OPFLAGS_TRANSMIT_BLOCK
) != 0) {
1136 // don't wait for more than 1 second!!!
1139 while (tcb_ptr
->cb_header
.status
== 0) {
1140 DelayIt (AdapterInfo
, 10);
1142 if (wait_sec
== 0) {
1147 // we need to un-map any mapped buffers here
1149 if ((opflags
& PXE_OPFLAGS_TRANSMIT_FRAGMENTED
) != 0) {
1151 for (Index
= 0; Index
< tx_ptr_f
->FragCnt
; Index
++) {
1152 Tmp_ptr
= tcb_ptr
->TBDArray
[Index
].phys_buf_addr
;
1155 tx_ptr_f
->FragDesc
[Index
].FragAddr
,
1156 tx_ptr_f
->FragDesc
[Index
].FragLen
,
1162 Tmp_ptr
= tcb_ptr
->TBDArray
[0].phys_buf_addr
;
1165 tx_ptr_1
->FrameAddr
,
1166 tx_ptr_1
->DataLen
+ tx_ptr_1
->MediaheaderLen
,
1172 if (tcb_ptr
->cb_header
.status
== 0) {
1173 SetFreeCB (AdapterInfo
, tcb_ptr
);
1174 AdapterInfo
->in_transmit
= FALSE
;
1175 return PXE_STATCODE_DEVICE_FAILURE
;
1178 SetFreeCB (AdapterInfo
, tcb_ptr
);
1181 // CB will be set free later in get_status (or when we run out of xmit buffers
1183 AdapterInfo
->in_transmit
= FALSE
;
1190 TODO: Add function description
1192 @param AdapterInfo TODO: add argument description
1193 @param cpb TODO: add argument description
1194 @param db TODO: add argument description
1196 @return TODO: add return values
1201 NIC_DATA_INSTANCE
*AdapterInfo
,
1206 PXE_CPB_RECEIVE
*rx_cpbptr
;
1207 PXE_DB_RECEIVE
*rx_dbptr
;
1213 PXE_FRAME_TYPE pkt_type
;
1215 EtherHeader
*hdr_ptr
;
1216 ret_code
= PXE_STATCODE_NO_DATA
;
1217 pkt_type
= PXE_FRAME_TYPE_NONE
;
1218 status
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBStatus
);
1219 AdapterInfo
->Int_Status
= (UINT16
) (AdapterInfo
->Int_Status
| status
);
1221 // acknoledge the interrupts
1223 OutWord (AdapterInfo
, (UINT16
) (status
& 0xfc00), (UINT32
) (AdapterInfo
->ioaddr
+ SCBStatus
));
1226 // include the prev ints as well
1228 status
= AdapterInfo
->Int_Status
;
1229 rx_cpbptr
= (PXE_CPB_RECEIVE
*) (UINTN
) cpb
;
1230 rx_dbptr
= (PXE_DB_RECEIVE
*) (UINTN
) db
;
1232 rx_ptr
= &AdapterInfo
->rx_ring
[AdapterInfo
->cur_rx_ind
];
1235 // be in a loop just in case (we may drop a pkt)
1237 while ((status
= rx_ptr
->cb_header
.status
) & RX_COMPLETE
) {
1239 AdapterInfo
->RxTotals
++;
1241 // If we own the next entry, it's a new packet. Send it up.
1243 if (rx_ptr
->forwarded
) {
1249 // discard bad frames
1253 // crc, align, dma overrun, too short, receive error (v22 no coll)
1255 if ((status
& 0x0D90) != 0) {
1261 // make sure the status is OK
1263 if ((status
& 0x02000) == 0) {
1267 pkt_len
= (UINT16
) (rx_ptr
->ActualCount
& 0x3fff);
1272 if (pkt_len
> rx_cpbptr
->BufferLen
) {
1273 Tmp_len
= (UINT16
) rx_cpbptr
->BufferLen
;
1276 CopyMem ((INT8
*) (UINTN
) rx_cpbptr
->BufferAddr
, (INT8
*) &rx_ptr
->RFDBuffer
, Tmp_len
);
1278 hdr_ptr
= (EtherHeader
*) &rx_ptr
->RFDBuffer
;
1280 // fill the CDB and break the loop
1286 rx_dbptr
->FrameLen
= pkt_len
;
1287 rx_dbptr
->MediaHeaderLen
= PXE_MAC_HEADER_LEN_ETHER
;
1289 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1290 if (hdr_ptr
->dest_addr
[Index
] != AdapterInfo
->CurrentNodeAddress
[Index
]) {
1295 if (Index
>= PXE_HWADDR_LEN_ETHER
) {
1296 pkt_type
= PXE_FRAME_TYPE_UNICAST
;
1298 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1299 if (hdr_ptr
->dest_addr
[Index
] != AdapterInfo
->BroadcastNodeAddress
[Index
]) {
1304 if (Index
>= PXE_HWADDR_LEN_ETHER
) {
1305 pkt_type
= PXE_FRAME_TYPE_BROADCAST
;
1307 if ((hdr_ptr
->dest_addr
[0] & 1) == 1) {
1312 pkt_type
= PXE_FRAME_TYPE_FILTERED_MULTICAST
;
1314 pkt_type
= PXE_FRAME_TYPE_PROMISCUOUS
;
1319 rx_dbptr
->Type
= pkt_type
;
1320 rx_dbptr
->Protocol
= hdr_ptr
->type
;
1322 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1323 rx_dbptr
->SrcAddr
[Index
] = hdr_ptr
->src_addr
[Index
];
1324 rx_dbptr
->DestAddr
[Index
] = hdr_ptr
->dest_addr
[Index
];
1327 rx_ptr
->forwarded
= TRUE
;
1332 Recycle_RFD (AdapterInfo
, AdapterInfo
->cur_rx_ind
);
1333 AdapterInfo
->cur_rx_ind
++;
1334 if (AdapterInfo
->cur_rx_ind
== AdapterInfo
->RxBufCnt
) {
1335 AdapterInfo
->cur_rx_ind
= 0;
1341 Recycle_RFD (AdapterInfo
, AdapterInfo
->cur_rx_ind
);
1342 AdapterInfo
->cur_rx_ind
++;
1343 if (AdapterInfo
->cur_rx_ind
== AdapterInfo
->RxBufCnt
) {
1344 AdapterInfo
->cur_rx_ind
= 0;
1347 rx_ptr
= &AdapterInfo
->rx_ring
[AdapterInfo
->cur_rx_ind
];
1350 if (pkt_type
== PXE_FRAME_TYPE_NONE
) {
1351 AdapterInfo
->Int_Status
&= (~SCB_STATUS_FR
);
1354 status
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBStatus
);
1355 if ((status
& SCB_RUS_NO_RESOURCES
) != 0) {
1357 // start the receive unit here!
1358 // leave all the filled frames,
1360 SetupReceiveQueues (AdapterInfo
);
1361 OutLong (AdapterInfo
, (UINT32
) AdapterInfo
->rx_phy_addr
, AdapterInfo
->ioaddr
+ SCBPointer
);
1362 OutWord (AdapterInfo
, RX_START
, AdapterInfo
->ioaddr
+ SCBCmd
);
1363 AdapterInfo
->cur_rx_ind
= 0;
1371 TODO: Add function description
1373 @param AdapterInfo TODO: add argument description
1375 @return TODO: add return values
1379 E100bReadEepromAndStationAddress (
1380 NIC_DATA_INSTANCE
*AdapterInfo
1390 eedata
= (UINT16
*) (&AdapterInfo
->NVData
[0]);
1393 addr_len
= E100bGetEepromAddrLen (AdapterInfo
);
1398 AdapterInfo
->NVData_Len
= eeprom_len
= (UINT16
) (1 << addr_len
);
1399 for (Index2
= 0, Index
= 0; Index
< eeprom_len
; Index
++) {
1401 value
= E100bReadEeprom (AdapterInfo
, Index
, addr_len
);
1402 eedata
[Index
] = value
;
1403 sum
= (UINT16
) (sum
+ value
);
1405 AdapterInfo
->PermNodeAddress
[Index2
++] = (UINT8
) value
;
1406 AdapterInfo
->PermNodeAddress
[Index2
++] = (UINT8
) (value
>> 8);
1410 if (sum
!= 0xBABA) {
1414 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1415 AdapterInfo
->CurrentNodeAddress
[Index
] = AdapterInfo
->PermNodeAddress
[Index
];
1418 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1419 AdapterInfo
->BroadcastNodeAddress
[Index
] = 0xff;
1422 for (Index
= PXE_HWADDR_LEN_ETHER
; Index
< PXE_MAC_LENGTH
; Index
++) {
1423 AdapterInfo
->CurrentNodeAddress
[Index
] = 0;
1424 AdapterInfo
->PermNodeAddress
[Index
] = 0;
1425 AdapterInfo
->BroadcastNodeAddress
[Index
] = 0;
1432 // CBList is a circular linked list
1433 // 1) When all are free, Tail->next == Head and FreeCount == # allocated
1434 // 2) When none are free, Tail == Head and FreeCount == 0
1435 // 3) when one is free, Tail == Head and Freecount == 1
1436 // 4) First non-Free frame is always at Tail->next
1440 TODO: Add function description
1442 @param AdapterInfo TODO: add argument description
1444 @return TODO: add return values
1449 NIC_DATA_INSTANCE
*AdapterInfo
1458 cur_ptr
= &(AdapterInfo
->tx_ring
[0]);
1459 array_off
= (UINTN
) (&cur_ptr
->TBDArray
) - (UINTN
) cur_ptr
;
1460 for (Index
= 0; Index
< AdapterInfo
->TxBufCnt
; Index
++) {
1461 cur_ptr
[Index
].cb_header
.status
= 0;
1462 cur_ptr
[Index
].cb_header
.command
= 0;
1464 cur_ptr
[Index
].PhysTCBAddress
=
1465 (UINT32
) AdapterInfo
->tx_phy_addr
+ (Index
* sizeof (TxCB
));
1467 cur_ptr
[Index
].PhysArrayAddr
= (UINT32
)(cur_ptr
[Index
].PhysTCBAddress
+ array_off
);
1468 cur_ptr
[Index
].PhysTBDArrayAddres
= (UINT32
)(cur_ptr
[Index
].PhysTCBAddress
+ array_off
);
1470 cur_ptr
->free_data_ptr
= (UINT64
) 0;
1472 if (Index
< AdapterInfo
->TxBufCnt
- 1) {
1473 cur_ptr
[Index
].cb_header
.link
= cur_ptr
[Index
].PhysTCBAddress
+ sizeof (TxCB
);
1474 cur_ptr
[Index
].NextTCBVirtualLinkPtr
= &cur_ptr
[Index
+ 1];
1475 cur_ptr
[Index
+ 1].PrevTCBVirtualLinkPtr
= &cur_ptr
[Index
];
1479 head_ptr
= &cur_ptr
[0];
1480 tail_ptr
= &cur_ptr
[AdapterInfo
->TxBufCnt
- 1];
1481 tail_ptr
->cb_header
.link
= head_ptr
->PhysTCBAddress
;
1482 tail_ptr
->NextTCBVirtualLinkPtr
= head_ptr
;
1483 head_ptr
->PrevTCBVirtualLinkPtr
= tail_ptr
;
1485 AdapterInfo
->FreeCBCount
= AdapterInfo
->TxBufCnt
;
1486 AdapterInfo
->FreeTxHeadPtr
= head_ptr
;
1488 // set tail of the free list, next to this would be either in use
1489 // or the head itself
1491 AdapterInfo
->FreeTxTailPtr
= tail_ptr
;
1493 AdapterInfo
->xmit_done_head
= AdapterInfo
->xmit_done_tail
= 0;
1500 TODO: Add function description
1502 @param AdapterInfo TODO: add argument description
1504 @return TODO: add return values
1509 NIC_DATA_INSTANCE
*AdapterInfo
1515 // claim any hanging free CBs
1517 if (AdapterInfo
->FreeCBCount
<= 1) {
1518 CheckCBList (AdapterInfo
);
1522 // don't use up the last CB problem if the previous CB that the CU used
1523 // becomes the last CB we submit because of the SUSPEND bit we set.
1524 // the CU thinks it was never cleared.
1527 if (AdapterInfo
->FreeCBCount
<= 1) {
1531 BlockIt (AdapterInfo
, TRUE
);
1532 free_cb_ptr
= AdapterInfo
->FreeTxHeadPtr
;
1533 AdapterInfo
->FreeTxHeadPtr
= free_cb_ptr
->NextTCBVirtualLinkPtr
;
1534 --AdapterInfo
->FreeCBCount
;
1535 BlockIt (AdapterInfo
, FALSE
);
1541 TODO: Add function description
1543 @param AdapterInfo TODO: add argument description
1544 @param cb_ptr TODO: add argument description
1546 @return TODO: add return values
1551 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1556 // here we assume cb are returned in the order they are taken out
1557 // and we link the newly freed cb at the tail of free cb list
1559 cb_ptr
->cb_header
.status
= 0;
1560 cb_ptr
->free_data_ptr
= (UINT64
) 0;
1562 AdapterInfo
->FreeTxTailPtr
= cb_ptr
;
1563 ++AdapterInfo
->FreeCBCount
;
1569 TODO: Add function description
1571 @param ind TODO: add argument description
1573 @return TODO: add return values
1583 Tmp
= (UINT16
) (ind
+ 1);
1584 if (Tmp
>= (TX_BUFFER_COUNT
<< 1)) {
1593 TODO: Add function description
1595 @param AdapterInfo TODO: add argument description
1597 @return TODO: add return values
1602 IN NIC_DATA_INSTANCE
*AdapterInfo
1610 Tmp_ptr
= AdapterInfo
->FreeTxTailPtr
->NextTCBVirtualLinkPtr
;
1611 if ((Tmp_ptr
->cb_header
.status
& CMD_STATUS_MASK
) != 0) {
1613 // check if Q is full
1615 if (next (AdapterInfo
->xmit_done_tail
) != AdapterInfo
->xmit_done_head
) {
1616 AdapterInfo
->xmit_done
[AdapterInfo
->xmit_done_tail
] = Tmp_ptr
->free_data_ptr
;
1620 Tmp_ptr
->free_data_ptr
,
1621 Tmp_ptr
->TBDArray
[0].buf_len
,
1623 (UINT64
) Tmp_ptr
->TBDArray
[0].phys_buf_addr
1626 AdapterInfo
->xmit_done_tail
= next (AdapterInfo
->xmit_done_tail
);
1629 SetFreeCB (AdapterInfo
, Tmp_ptr
);
1638 // Description : Initialize the RFD list list by linking each element together
1639 // in a circular list. The simplified memory model is used.
1640 // All data is in the RFD. The RFDs are linked together and the
1641 // last one points back to the first one. When the current RFD
1642 // is processed (frame received), its EL bit is set and the EL
1643 // bit in the previous RXFD is cleared.
1644 // Allocation done during INIT, this is making linked list.
1648 TODO: Add function description
1650 @param AdapterInfo TODO: add argument description
1652 @return TODO: add return values
1656 SetupReceiveQueues (
1657 IN NIC_DATA_INSTANCE
*AdapterInfo
1664 AdapterInfo
->cur_rx_ind
= 0;
1665 rx_ptr
= (&AdapterInfo
->rx_ring
[0]);
1667 for (Index
= 0; Index
< AdapterInfo
->RxBufCnt
; Index
++) {
1668 rx_ptr
[Index
].cb_header
.status
= 0;
1669 rx_ptr
[Index
].cb_header
.command
= 0;
1670 rx_ptr
[Index
].RFDSize
= RX_BUFFER_SIZE
;
1671 rx_ptr
[Index
].ActualCount
= 0;
1673 // RBDs not used, simple memory model
1675 rx_ptr
[Index
].rx_buf_addr
= (UINT32
) (-1);
1678 // RBDs not used, simple memory model
1680 rx_ptr
[Index
].forwarded
= FALSE
;
1683 // don't use Tmp_ptr if it is beyond the last one
1685 if (Index
< AdapterInfo
->RxBufCnt
- 1) {
1686 rx_ptr
[Index
].cb_header
.link
= (UINT32
) AdapterInfo
->rx_phy_addr
+ ((Index
+ 1) * sizeof (RxFD
));
1690 tail_ptr
= (&AdapterInfo
->rx_ring
[AdapterInfo
->RxBufCnt
- 1]);
1691 tail_ptr
->cb_header
.link
= (UINT32
) AdapterInfo
->rx_phy_addr
;
1696 tail_ptr
->cb_header
.command
= 0xC000;
1697 AdapterInfo
->RFDTailPtr
= tail_ptr
;
1703 TODO: Add function description
1705 @param AdapterInfo TODO: add argument description
1706 @param rx_index TODO: add argument description
1708 @return TODO: add return values
1713 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1720 // change the EL bit and change the AdapterInfo->RxTailPtr
1721 // rx_ptr is assumed to be the head of the Q
1722 // AdapterInfo->rx_forwarded[rx_index] = FALSE;
1724 rx_ptr
= &AdapterInfo
->rx_ring
[rx_index
];
1725 tail_ptr
= AdapterInfo
->RFDTailPtr
;
1727 // set el_bit and suspend bit
1729 rx_ptr
->cb_header
.command
= 0xc000;
1730 rx_ptr
->cb_header
.status
= 0;
1731 rx_ptr
->ActualCount
= 0;
1732 rx_ptr
->forwarded
= FALSE
;
1733 AdapterInfo
->RFDTailPtr
= rx_ptr
;
1735 // resetting the el_bit.
1737 tail_ptr
->cb_header
.command
= 0;
1739 // check the receive unit, fix if there is any problem
1744 // Serial EEPROM section.
1746 // EEPROM_Ctrl bits.
1748 #define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */
1749 #define EE_CS 0x02 /* EEPROM chip select. */
1750 #define EE_DI 0x04 /* EEPROM chip data in. */
1751 #define EE_WRITE_0 0x01
1752 #define EE_WRITE_1 0x05
1753 #define EE_DO 0x08 /* EEPROM chip data out. */
1754 #define EE_ENB (0x4800 | EE_CS)
1757 // Delay between EEPROM clock transitions.
1758 // This will actually work with no delay on 33Mhz PCI.
1760 #define eeprom_delay(nanosec) DelayIt (AdapterInfo, nanosec);
1763 // The EEPROM commands include the alway-set leading bit.
1765 #define EE_WRITE_CMD 5 // 101b
1766 #define EE_READ_CMD 6 // 110b
1767 #define EE_ERASE_CMD (7 << 6)
1772 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1778 Routine Description:
1780 TODO: Add function description
1784 AdapterInfo - TODO: add argument description
1785 val - TODO: add argument description
1786 num_bits - TODO: add argument description
1790 TODO: add return values
1798 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
1800 for (Index
= num_bits
; Index
>= 0; Index
--) {
1806 dataval
= (INT16
) ((val
& (1 << Index
)) ? EE_DI
: 0);
1809 // mask off the data_in bit
1811 Tmp
= (UINT8
) (InByte (AdapterInfo
, EEAddr
) &~EE_DI
);
1812 Tmp
= (UINT8
) (Tmp
| dataval
);
1813 OutByte (AdapterInfo
, Tmp
, EEAddr
);
1816 // raise the eeprom clock
1818 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
1821 // lower the eeprom clock
1823 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
1830 TODO: Add function description
1832 @param AdapterInfo TODO: add argument description
1834 @return TODO: add return values
1840 IN NIC_DATA_INSTANCE
*AdapterInfo
1848 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
1851 for (Index
= 15; Index
>= 0; Index
--) {
1857 // mask off the data_in bit
1859 Tmp
= InByte (AdapterInfo
, EEAddr
);
1860 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
1862 Tmp
= InByte (AdapterInfo
, EEAddr
);
1863 retval
= (UINT16
) ((retval
<< 1) | ((Tmp
& EE_DO
) ? 1 : 0));
1867 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
1876 This routine sets the EEPROM lockout bit to gain exclusive access to the
1877 eeprom. the access bit is the most significant bit in the General Control
1878 Register 2 in the SCB space.
1880 @param AdapterInfo Pointer to the NIC data structure
1881 information which the UNDI driver is
1884 @retval TRUE if it got the access
1885 @retval FALSE if it fails to get the exclusive access
1890 E100bSetEepromLockOut (
1891 IN NIC_DATA_INSTANCE
*AdapterInfo
1897 if ((AdapterInfo
->DeviceID
== D102_DEVICE_ID
) ||
1898 (AdapterInfo
->RevID
>= D102_REVID
)) {
1904 tmp
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1905 tmp
|= GCR2_EEPROM_ACCESS_SEMAPHORE
;
1906 OutByte (AdapterInfo
, tmp
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1908 DelayIt (AdapterInfo
, 50);
1909 tmp
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1911 if (tmp
& GCR2_EEPROM_ACCESS_SEMAPHORE
) {
1924 This routine Resets the EEPROM lockout bit to giveup access to the
1925 eeprom. the access bit is the most significant bit in the General Control
1926 Register 2 in the SCB space.
1928 @param AdapterInfo Pointer to the NIC data structure
1929 information which the UNDI driver is
1937 E100bReSetEepromLockOut (
1938 IN NIC_DATA_INSTANCE
*AdapterInfo
1943 if ((AdapterInfo
->DeviceID
== D102_DEVICE_ID
) ||
1944 (AdapterInfo
->RevID
>= D102_REVID
)) {
1946 tmp
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1947 tmp
&= ~(GCR2_EEPROM_ACCESS_SEMAPHORE
);
1948 OutByte (AdapterInfo
, tmp
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1950 DelayIt (AdapterInfo
, 50);
1956 Using the NIC data structure information, read the EEPROM to get a Word of data for the MAC address.
1958 @param AdapterInfo Pointer to the NIC data structure
1959 information which the UNDI driver is
1961 @param Location Word offset into the MAC address to read.
1962 @param AddrLen Number of bits of address length.
1964 @retval RetVal The word read from the EEPROM.
1969 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1980 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
1981 ReadCmd
= (UINT16
) (Location
| (EE_READ_CMD
<< AddrLen
));
1986 // get exclusive access to the eeprom first!
1988 E100bSetEepromLockOut (AdapterInfo
);
1991 // eeprom control reg bits: x,x,x,x,DO,DI,CS,SK
1992 // to write the opcode+data value out one bit at a time in DI starting at msb
1993 // and then out a 1 to sk, wait, out 0 to SK and wait
1994 // repeat this for all the bits to be written
2000 Tmp
= (UINT8
) (InByte (AdapterInfo
, EEAddr
) & 0xF2);
2001 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_CS
), EEAddr
);
2004 // 3 for the read opcode 110b
2006 shift_bits_out (AdapterInfo
, ReadCmd
, (UINT8
) (3 + AddrLen
));
2009 // read the eeprom word one bit at a time
2011 RetVal
= shift_bits_in (AdapterInfo
);
2014 // Terminate the EEPROM access and leave eeprom in a clean state.
2016 Tmp
= InByte (AdapterInfo
, EEAddr
);
2017 Tmp
&= ~(EE_CS
| EE_DI
);
2018 OutByte (AdapterInfo
, Tmp
, EEAddr
);
2021 // raise the clock and lower the eeprom shift clock
2023 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
2026 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
2030 // giveup access to the eeprom
2032 E100bReSetEepromLockOut (AdapterInfo
);
2039 Using the NIC data structure information, read the EEPROM to determine how many bits of address length
2040 this EEPROM is in Words.
2042 @param AdapterInfo Pointer to the NIC data structure
2043 information which the UNDI driver is
2046 @retval RetVal The word read from the EEPROM.
2050 E100bGetEepromAddrLen (
2051 IN NIC_DATA_INSTANCE
*AdapterInfo
2058 // assume 64word eeprom (so,6 bits of address_length)
2062 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
2063 ReadCmd
= (EE_READ_CMD
<< 6);
2066 // get exclusive access to the eeprom first!
2068 E100bSetEepromLockOut (AdapterInfo
);
2071 // address we are trying to read is 0
2072 // eeprom control reg bits: x,x,x,x,DO,,DI,,CS,SK
2073 // to write the opcode+data value out one bit at a time in DI starting at msb
2074 // and then out a 1 to sk, wait, out 0 to SK and wait
2075 // repeat this for all the bits to be written
2077 Tmp
= (UINT8
) (InByte (AdapterInfo
, EEAddr
) & 0xF2);
2080 // enable eeprom access
2082 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_CS
), EEAddr
);
2085 // 3 for opcode, 6 for the default address len
2087 shift_bits_out (AdapterInfo
, ReadCmd
, (UINT8
) (3 + 6));
2090 // (in case of a 64 word eeprom).
2091 // read the "dummy zero" from EE_DO to say that the address we wrote
2092 // (six 0s) is accepted, write more zeros (until 8) to get a "dummy zero"
2096 // assume the smallest
2099 Tmp
= InByte (AdapterInfo
, EEAddr
);
2100 while ((AddrLen
< 8) && ((Tmp
& EE_DO
) != 0)) {
2101 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_DI
), EEAddr
);
2105 // raise the eeprom clock
2107 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
2111 // lower the eeprom clock
2113 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
2115 Tmp
= InByte (AdapterInfo
, EEAddr
);
2120 // read the eeprom word, even though we don't need this
2122 shift_bits_in (AdapterInfo
);
2125 // Terminate the EEPROM access.
2127 Tmp
= InByte (AdapterInfo
, EEAddr
);
2128 Tmp
&= ~(EE_CS
| EE_DI
);
2129 OutByte (AdapterInfo
, Tmp
, EEAddr
);
2132 // raise the clock and lower the eeprom shift clock
2134 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
2137 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
2141 // giveup access to the eeprom!
2143 E100bReSetEepromLockOut (AdapterInfo
);
2150 TODO: Add function description
2152 @param AdapterInfo TODO: add argument description
2153 @param DBaddr TODO: add argument description
2154 @param DBsize TODO: add argument description
2156 @return TODO: add return values
2161 NIC_DATA_INSTANCE
*AdapterInfo
,
2166 PXE_DB_STATISTICS db
;
2168 // wait upto one second (each wait is 100 micro s)
2172 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
2175 // Clear statistics done marker.
2177 AdapterInfo
->statistics
->done_marker
= 0;
2180 // Issue statistics dump (or dump w/ reset) command.
2184 (UINT8
) (DBsize
? CU_SHOWSTATS
: CU_DUMPSTATS
),
2185 (UINT32
) (AdapterInfo
->ioaddr
+ SCBCmd
)
2189 // Wait for command to complete.
2191 // zero the db here just to chew up a little more time.
2194 ZeroMem ((VOID
*) &db
, sizeof db
);
2198 // Wait a bit before checking.
2201 DelayIt (AdapterInfo
, 100);
2204 // Look for done marker at end of statistics.
2207 switch (AdapterInfo
->statistics
->done_marker
) {
2218 // if we did not "continue" from the above switch, we are done,
2224 // If this is a reset, we are out of here!
2227 return PXE_STATCODE_SUCCESS
;
2231 // Convert NIC statistics counter format to EFI/UNDI
2232 // specification statistics counter format.
2236 // 54 3210 fedc ba98 7654 3210
2237 // db.Supported = 01 0000 0100 1101 0001 0111;
2239 db
.Supported
= 0x104D17;
2242 // Statistics from the NIC
2245 db
.Data
[0x01] = AdapterInfo
->statistics
->rx_good_frames
;
2247 db
.Data
[0x02] = AdapterInfo
->statistics
->rx_runt_errs
;
2249 db
.Data
[0x08] = AdapterInfo
->statistics
->rx_crc_errs
+
2250 AdapterInfo
->statistics
->rx_align_errs
;
2252 db
.Data
[0x04] = db
.Data
[0x02] +
2254 AdapterInfo
->statistics
->rx_resource_errs
+
2255 AdapterInfo
->statistics
->rx_overrun_errs
;
2257 db
.Data
[0x00] = db
.Data
[0x01] + db
.Data
[0x04];
2259 db
.Data
[0x0B] = AdapterInfo
->statistics
->tx_good_frames
;
2261 db
.Data
[0x0E] = AdapterInfo
->statistics
->tx_coll16_errs
+
2262 AdapterInfo
->statistics
->tx_late_colls
+
2263 AdapterInfo
->statistics
->tx_underruns
+
2264 AdapterInfo
->statistics
->tx_one_colls
+
2265 AdapterInfo
->statistics
->tx_multi_colls
;
2267 db
.Data
[0x14] = AdapterInfo
->statistics
->tx_total_colls
;
2269 db
.Data
[0x0A] = db
.Data
[0x0B] +
2271 AdapterInfo
->statistics
->tx_lost_carrier
;
2273 if (DBsize
> sizeof db
) {
2277 CopyMem ((VOID
*) (UINTN
) DBaddr
, (VOID
*) &db
, (UINTN
) DBsize
);
2279 return PXE_STATCODE_SUCCESS
;
2284 TODO: Add function description
2286 @param AdapterInfo TODO: add argument description
2287 @param OpFlags TODO: add argument description
2289 @return TODO: add return values
2294 IN NIC_DATA_INSTANCE
*AdapterInfo
,
2301 // disable the interrupts
2303 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
2306 // wait for the tx queue to complete
2308 CheckCBList (AdapterInfo
);
2310 XmitWaitForCompletion (AdapterInfo
);
2312 if (AdapterInfo
->Receive_Started
) {
2313 StopRU (AdapterInfo
);
2316 InitializeChip (AdapterInfo
);
2319 // check the opflags and restart receive filters
2321 if ((OpFlags
& PXE_OPFLAGS_RESET_DISABLE_FILTERS
) == 0) {
2323 save_filter
= AdapterInfo
->Rx_Filter
;
2325 // if we give the filter same as Rx_Filter,
2326 // this routine will not set mcast list (it thinks there is no change)
2327 // to force it, we will reset that flag in the Rx_Filter
2329 AdapterInfo
->Rx_Filter
&= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
);
2330 E100bSetfilter (AdapterInfo
, save_filter
, (UINT64
) 0, (UINT32
) 0);
2333 if ((OpFlags
& PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS
) != 0) {
2335 // disable the interrupts
2337 AdapterInfo
->int_mask
= 0;
2340 // else leave the interrupt in the pre-set state!!!
2342 E100bSetInterruptState (AdapterInfo
);
2349 TODO: Add function description
2351 @param AdapterInfo TODO: add argument description
2353 @return TODO: add return values
2358 IN NIC_DATA_INSTANCE
*AdapterInfo
2362 // disable the interrupts
2364 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
2367 // stop the receive unit
2369 if (AdapterInfo
->Receive_Started
) {
2370 StopRU (AdapterInfo
);
2374 // wait for the tx queue to complete
2376 CheckCBList (AdapterInfo
);
2377 if (AdapterInfo
->FreeCBCount
!= AdapterInfo
->TxBufCnt
) {
2378 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
2382 // we do not want to reset the phy, it takes a long time to renegotiate the
2383 // link after that (3-4 seconds)
2385 InitializeChip (AdapterInfo
);
2386 SelectiveReset (AdapterInfo
);
2392 This routine will write a value to the specified MII register
2393 of an external MDI compliant device (e.g. PHY 100). The command will
2394 execute in polled mode.
2396 @param AdapterInfo pointer to the structure that contains
2398 @param RegAddress The MII register that we are writing to
2399 @param PhyAddress The MDI address of the Phy component.
2400 @param DataValue The value that we are writing to the MII
2408 IN NIC_DATA_INSTANCE
*AdapterInfo
,
2409 IN UINT8 RegAddress
,
2410 IN UINT8 PhyAddress
,
2414 UINT32 WriteCommand
;
2416 WriteCommand
= ((UINT32
) DataValue
) |
2417 ((UINT32
)(RegAddress
<< 16)) |
2418 ((UINT32
)(PhyAddress
<< 21)) |
2419 ((UINT32
)(MDI_WRITE
<< 26));
2422 // Issue the write command to the MDI control register.
2424 OutLong (AdapterInfo
, WriteCommand
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
);
2427 // wait 20usec before checking status
2429 DelayIt (AdapterInfo
, 20);
2432 // poll for the mdi write to complete
2433 while ((InLong (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
) &
2434 MDI_PHY_READY
) == 0){
2435 DelayIt (AdapterInfo
, 20);
2441 This routine will read a value from the specified MII register
2442 of an external MDI compliant device (e.g. PHY 100), and return
2443 it to the calling routine. The command will execute in polled mode.
2445 @param AdapterInfo pointer to the structure that contains
2447 @param RegAddress The MII register that we are reading from
2448 @param PhyAddress The MDI address of the Phy component.
2449 @param DataValue pointer to the value that we read from
2456 IN NIC_DATA_INSTANCE
*AdapterInfo
,
2457 IN UINT8 RegAddress
,
2458 IN UINT8 PhyAddress
,
2459 IN OUT UINT16
*DataValue
2464 ReadCommand
= ((UINT32
) (RegAddress
<< 16)) |
2465 ((UINT32
) (PhyAddress
<< 21)) |
2466 ((UINT32
) (MDI_READ
<< 26));
2469 // Issue the read command to the MDI control register.
2471 OutLong (AdapterInfo
, ReadCommand
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
);
2474 // wait 20usec before checking status
2476 DelayIt (AdapterInfo
, 20);
2479 // poll for the mdi read to complete
2481 while ((InLong (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
) &
2482 MDI_PHY_READY
) == 0) {
2483 DelayIt (AdapterInfo
, 20);
2487 *DataValue
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
);
2492 This routine will reset the PHY that the adapter is currently
2495 @param AdapterInfo pointer to the structure that contains
2502 NIC_DATA_INSTANCE
*AdapterInfo
2505 UINT16 MdiControlReg
;
2507 MdiControlReg
= (MDI_CR_AUTO_SELECT
|
2508 MDI_CR_RESTART_AUTO_NEG
|
2512 // Write the MDI control register with our new Phy configuration
2517 AdapterInfo
->PhyAddress
,
2526 This routine will detect what phy we are using, set the line
2527 speed, FDX or HDX, and configure the phy if necessary.
2528 The following combinations are supported:
2529 - TX or T4 PHY alone at PHY address 1
2530 - T4 or TX PHY at address 1 and MII PHY at address 0
2531 - 82503 alone (10Base-T mode, no full duplex support)
2532 - 82503 and MII PHY (TX or T4) at address 0
2533 The sequence / priority of detection is as follows:
2534 - PHY 1 with cable termination
2535 - PHY 0 with cable termination
2536 - PHY 1 (if found) without cable termination
2538 Additionally auto-negotiation capable (NWAY) and parallel
2539 detection PHYs are supported. The flow-chart is described in
2540 the 82557 software writer's manual.
2541 NOTE: 1. All PHY MDI registers are read in polled mode.
2542 2. The routines assume that the 82557 has been RESET and we have
2543 obtained the virtual memory address of the CSR.
2544 3. PhyDetect will not RESET the PHY.
2545 4. If FORCEFDX is set, SPEED should also be set. The driver will
2546 check the values for inconsistency with the detected PHY
2548 5. PHY 1 (the PHY on the adapter) may have an address in the range
2549 1 through 31 inclusive. The driver will accept addresses in
2551 6. Driver ignores FORCEFDX and SPEED overrides if a 503 interface
2554 @param AdapterInfo pointer to the structure that contains
2557 @retval TRUE If a Phy was detected, and configured
2559 @retval FALSE If a valid phy could not be detected and
2565 NIC_DATA_INSTANCE
*AdapterInfo
2569 UINT16 MdiControlReg
;
2570 UINT16 MdiStatusReg
;
2572 UINT8 ReNegotiateTime
;
2574 eedata
= (UINT16
*) (&AdapterInfo
->NVData
[0]);
2577 ReNegotiateTime
= 35;
2579 // EEPROM word [6] contains the Primary PHY record in which the least 3 bits
2580 // indicate the PHY address
2581 // and word [7] contains the secondary PHY record
2583 AdapterInfo
->PhyRecord
[0] = eedata
[6];
2584 AdapterInfo
->PhyRecord
[1] = eedata
[7];
2585 AdapterInfo
->PhyAddress
= (UINT8
) (AdapterInfo
->PhyRecord
[0] & 7);
2588 // Check for a phy address over-ride of 32 which indicates force use of 82503
2589 // not detecting the link in this case
2591 if (AdapterInfo
->PhyAddress
== 32) {
2593 // 503 interface over-ride
2594 // Record the current speed and duplex. We will be in half duplex
2595 // mode unless the user used the force full duplex over-ride.
2597 AdapterInfo
->LinkSpeed
= 10;
2602 // If the Phy Address is between 1-31 then we must first look for phy 1,
2605 if ((AdapterInfo
->PhyAddress
> 0) && (AdapterInfo
->PhyAddress
< 32)) {
2608 // Read the MDI control and status registers at phy 1
2609 // and check if we found a valid phy
2614 AdapterInfo
->PhyAddress
,
2621 AdapterInfo
->PhyAddress
,
2625 if (!((MdiControlReg
== 0xffff) ||
2626 ((MdiStatusReg
== 0) && (MdiControlReg
== 0)))) {
2629 // we have a valid phy1
2630 // Read the status register again because of sticky bits
2636 AdapterInfo
->PhyAddress
,
2641 // If there is a valid link then use this Phy.
2643 if (MdiStatusReg
& MDI_SR_LINK_STATUS
) {
2644 return (SetupPhy(AdapterInfo
));
2650 // Next try to detect a PHY at address 0x00 because there was no Phy 1,
2651 // or Phy 1 didn't have link, or we had a phy 0 over-ride
2655 // Read the MDI control and status registers at phy 0
2657 MdiRead (AdapterInfo
, MDI_CONTROL_REG
, 0, &MdiControlReg
);
2658 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2661 // check if we found a valid phy 0
2663 if (((MdiControlReg
== 0xffff) ||
2664 ((MdiStatusReg
== 0) && (MdiControlReg
== 0)))) {
2667 // we don't have a valid phy at address 0
2668 // if phy address was forced to 0, then error out because we
2669 // didn't find a phy at that address
2671 if (AdapterInfo
->PhyAddress
== 0x0000) {
2675 // at this point phy1 does not have link and there is no phy 0 at all
2676 // if we are forced to detect the cable, error out here!
2678 if (AdapterInfo
->CableDetect
!= 0) {
2685 // no phy 0, but there is a phy 1 (no link I guess), so use phy 1
2687 return SetupPhy (AdapterInfo
);
2690 // didn't find phy 0 or phy 1, so assume a 503 interface
2692 AdapterInfo
->PhyAddress
= 32;
2695 // Record the current speed and duplex. We'll be in half duplex
2696 // mode unless the user used the force full duplex over-ride.
2698 AdapterInfo
->LinkSpeed
= 10;
2704 // We have a valid phy at address 0. If phy 0 has a link then we use
2705 // phy 0. If Phy 0 doesn't have a link then we use Phy 1 (no link)
2706 // if phy 1 is present, or phy 0 if phy 1 is not present
2707 // If phy 1 was present, then we must isolate phy 1 before we enable
2708 // phy 0 to see if Phy 0 has a link.
2717 AdapterInfo
->PhyAddress
,
2722 // wait 100 microseconds for the phy to isolate.
2724 DelayIt (AdapterInfo
, 100);
2728 // Since this Phy is at address 0, we must enable it. So clear
2729 // the isolate bit, and set the auto-speed select bit
2739 // wait 100 microseconds for the phy to be enabled.
2741 DelayIt (AdapterInfo
, 100);
2744 // restart the auto-negotion process
2750 MDI_CR_RESTART_AUTO_NEG
| MDI_CR_AUTO_SELECT
2754 // wait no more than 3.5 seconds for auto-negotiation to complete
2756 while (ReNegotiateTime
) {
2758 // Read the status register twice because of sticky bits
2760 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2761 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2763 if (MdiStatusReg
& MDI_SR_AUTO_NEG_COMPLETE
) {
2767 DelayIt (AdapterInfo
, 100);
2772 // Read the status register again because of sticky bits
2774 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2777 // If the link was not set
2779 if ((MdiStatusReg
& MDI_SR_LINK_STATUS
) == 0) {
2781 // PHY1 does not have a link and phy 0 does not have a link
2782 // do not proceed if we need to detect the link!
2784 if (AdapterInfo
->CableDetect
!= 0) {
2789 // the link wasn't set, so use phy 1 if phy 1 was present
2795 MdiWrite (AdapterInfo
, MDI_CONTROL_REG
, 0, MDI_CR_ISOLATE
);
2798 // wait 100 microseconds for the phy to isolate.
2800 DelayIt (AdapterInfo
, 100);
2803 // Now re-enable PHY 1
2808 AdapterInfo
->PhyAddress
,
2813 // wait 100 microseconds for the phy to be enabled
2815 DelayIt (AdapterInfo
, 100);
2818 // restart the auto-negotion process
2823 AdapterInfo
->PhyAddress
,
2824 MDI_CR_RESTART_AUTO_NEG
| MDI_CR_AUTO_SELECT
2828 // Don't wait for it to complete (we didn't have link earlier)
2830 return (SetupPhy (AdapterInfo
));
2835 // Definitely using Phy 0
2837 AdapterInfo
->PhyAddress
= 0;
2838 return (SetupPhy(AdapterInfo
));
2844 This routine will setup phy 1 or phy 0 so that it is configured
2845 to match a speed and duplex over-ride option. If speed or
2846 duplex mode is not explicitly specified in the registry, the
2847 driver will skip the speed and duplex over-ride code, and
2848 assume the adapter is automatically setting the line speed, and
2849 the duplex mode. At the end of this routine, any truly Phy
2850 specific code will be executed (each Phy has its own quirks,
2851 and some require that certain special bits are set).
2852 NOTE: The driver assumes that SPEED and FORCEFDX are specified at the
2853 same time. If FORCEDPX is set without speed being set, the driver
2854 will encouter a fatal error and log a message into the event viewer.
2856 @param AdapterInfo pointer to the structure that contains
2859 @retval TRUE If the phy could be configured correctly
2860 @retval FALSE If the phy couldn't be configured
2861 correctly, because an unsupported
2862 over-ride option was used
2867 IN NIC_DATA_INSTANCE
*AdapterInfo
2870 UINT16 MdiControlReg
;
2871 UINT16 MdiStatusReg
;
2873 UINT16 MdiIdHighReg
;
2876 BOOLEAN ForcePhySetting
;
2878 ForcePhySetting
= FALSE
;
2881 // If we are NOT forcing a setting for line speed or full duplex, then
2882 // we won't force a link setting, and we'll jump down to the phy
2885 if (((AdapterInfo
->LinkSpeedReq
) || (AdapterInfo
->DuplexReq
))) {
2887 // Find out what kind of technology this Phy is capable of.
2892 AdapterInfo
->PhyAddress
,
2897 // Read the MDI control register at our phy
2902 AdapterInfo
->PhyAddress
,
2907 // Now check the validity of our forced option. If the force option is
2908 // valid, then force the setting. If the force option is not valid,
2909 // we'll set a flag indicating that we should error out.
2913 // If speed is forced to 10mb
2915 if (AdapterInfo
->LinkSpeedReq
== 10) {
2917 // If half duplex is forced
2919 if ((AdapterInfo
->DuplexReq
& PXE_FORCE_HALF_DUPLEX
) != 0) {
2920 if (MdiStatusReg
& MDI_SR_10T_HALF_DPX
) {
2922 MdiControlReg
&= ~(MDI_CR_10_100
| MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
2923 ForcePhySetting
= TRUE
;
2925 } else if ((AdapterInfo
->DuplexReq
& PXE_FORCE_FULL_DUPLEX
) != 0) {
2928 // If full duplex is forced
2930 if (MdiStatusReg
& MDI_SR_10T_FULL_DPX
) {
2932 MdiControlReg
&= ~(MDI_CR_10_100
| MDI_CR_AUTO_SELECT
);
2933 MdiControlReg
|= MDI_CR_FULL_HALF
;
2934 ForcePhySetting
= TRUE
;
2938 // If auto duplex (we actually set phy to 1/2)
2940 if (MdiStatusReg
& (MDI_SR_10T_FULL_DPX
| MDI_SR_10T_HALF_DPX
)) {
2942 MdiControlReg
&= ~(MDI_CR_10_100
| MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
2943 ForcePhySetting
= TRUE
;
2949 // If speed is forced to 100mb
2951 else if (AdapterInfo
->LinkSpeedReq
== 100) {
2953 // If half duplex is forced
2955 if ((AdapterInfo
->DuplexReq
& PXE_FORCE_HALF_DUPLEX
) != 0) {
2956 if (MdiStatusReg
& (MDI_SR_TX_HALF_DPX
| MDI_SR_T4_CAPABLE
)) {
2958 MdiControlReg
&= ~(MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
2959 MdiControlReg
|= MDI_CR_10_100
;
2960 ForcePhySetting
= TRUE
;
2962 } else if ((AdapterInfo
->DuplexReq
& PXE_FORCE_FULL_DUPLEX
) != 0) {
2964 // If full duplex is forced
2966 if (MdiStatusReg
& MDI_SR_TX_FULL_DPX
) {
2967 MdiControlReg
&= ~MDI_CR_AUTO_SELECT
;
2968 MdiControlReg
|= (MDI_CR_10_100
| MDI_CR_FULL_HALF
);
2969 ForcePhySetting
= TRUE
;
2973 // If auto duplex (we set phy to 1/2)
2975 if (MdiStatusReg
& (MDI_SR_TX_HALF_DPX
| MDI_SR_T4_CAPABLE
)) {
2977 MdiControlReg
&= ~(MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
2978 MdiControlReg
|= MDI_CR_10_100
;
2979 ForcePhySetting
= TRUE
;
2984 if (!ForcePhySetting
) {
2989 // Write the MDI control register with our new Phy configuration
2994 AdapterInfo
->PhyAddress
,
2999 // wait 100 milliseconds for auto-negotiation to complete
3001 DelayIt (AdapterInfo
, 100);
3005 // Find out specifically what Phy this is. We do this because for certain
3006 // phys there are specific bits that must be set so that the phy and the
3007 // 82557 work together properly.
3013 AdapterInfo
->PhyAddress
,
3019 AdapterInfo
->PhyAddress
,
3023 PhyId
= ((UINT32
) MdiIdLowReg
| ((UINT32
) MdiIdHighReg
<< 16));
3026 // And out the revsion field of the Phy ID so that we'll be able to detect
3027 // future revs of the same Phy.
3029 PhyId
&= PHY_MODEL_REV_ID_MASK
;
3032 // Handle the National TX
3034 if (PhyId
== PHY_NSC_TX
) {
3038 NSC_CONG_CONTROL_REG
,
3039 AdapterInfo
->PhyAddress
,
3043 MdiMiscReg
|= (NSC_TX_CONG_TXREADY
| NSC_TX_CONG_F_CONNECT
);
3047 NSC_CONG_CONTROL_REG
,
3048 AdapterInfo
->PhyAddress
,
3053 FindPhySpeedAndDpx (AdapterInfo
, PhyId
);
3056 // We put a hardware fix on to our adapters to work-around the PHY_100 errata
3057 // described below. The following code is only compiled in, if we wanted
3058 // to attempt a software workaround to the PHY_100 A/B step problem.
3066 This routine will figure out what line speed and duplex mode
3067 the PHY is currently using.
3069 @param AdapterInfo pointer to the structure that contains
3071 @param PhyId The ID of the PHY in question.
3077 FindPhySpeedAndDpx (
3078 IN NIC_DATA_INSTANCE
*AdapterInfo
,
3082 UINT16 MdiStatusReg
;
3085 UINT16 MdiLinkPartnerAdReg
;
3088 // If there was a speed and/or duplex override, then set our current
3089 // value accordingly
3091 AdapterInfo
->LinkSpeed
= AdapterInfo
->LinkSpeedReq
;
3092 AdapterInfo
->Duplex
= (UINT8
) ((AdapterInfo
->DuplexReq
& PXE_FORCE_FULL_DUPLEX
) ?
3093 FULL_DUPLEX
: HALF_DUPLEX
);
3096 // If speed and duplex were forced, then we know our current settings, so
3097 // we'll just return. Otherwise, we'll need to figure out what NWAY set
3100 if (AdapterInfo
->LinkSpeed
&& AdapterInfo
->Duplex
) {
3105 // If we didn't have a valid link, then we'll assume that our current
3106 // speed is 10mb half-duplex.
3110 // Read the status register twice because of sticky bits
3115 AdapterInfo
->PhyAddress
,
3121 AdapterInfo
->PhyAddress
,
3126 // If there wasn't a valid link then use default speed & duplex
3128 if (!(MdiStatusReg
& MDI_SR_LINK_STATUS
)) {
3130 AdapterInfo
->LinkSpeed
= 10;
3131 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3136 // If this is an Intel PHY (a T4 PHY_100 or a TX PHY_TX), then read bits
3137 // 1 and 0 of extended register 0, to get the current speed and duplex
3140 if ((PhyId
== PHY_100_A
) || (PhyId
== PHY_100_C
) || (PhyId
== PHY_TX_ID
)) {
3142 // Read extended register 0
3147 AdapterInfo
->PhyAddress
,
3152 // Get current speed setting
3154 if (MdiMiscReg
& PHY_100_ER0_SPEED_INDIC
) {
3155 AdapterInfo
->LinkSpeed
= 100;
3157 AdapterInfo
->LinkSpeed
= 10;
3161 // Get current duplex setting -- if bit is set then FDX is enabled
3163 if (MdiMiscReg
& PHY_100_ER0_FDX_INDIC
) {
3164 AdapterInfo
->Duplex
= FULL_DUPLEX
;
3166 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3172 // Read our link partner's advertisement register
3176 AUTO_NEG_LINK_PARTNER_REG
,
3177 AdapterInfo
->PhyAddress
,
3178 &MdiLinkPartnerAdReg
3182 // See if Auto-Negotiation was complete (bit 5, reg 1)
3187 AdapterInfo
->PhyAddress
,
3192 // If a True NWAY connection was made, then we can detect speed/duplex by
3193 // ANDing our adapter's advertised abilities with our link partner's
3194 // advertised ablilities, and then assuming that the highest common
3195 // denominator was chosed by NWAY.
3197 if ((MdiLinkPartnerAdReg
& NWAY_LP_ABILITY
) &&
3198 (MdiStatusReg
& MDI_SR_AUTO_NEG_COMPLETE
)) {
3201 // Read our advertisement register
3205 AUTO_NEG_ADVERTISE_REG
,
3206 AdapterInfo
->PhyAddress
,
3211 // AND the two advertisement registers together, and get rid of any
3214 MdiOwnAdReg
= (UINT16
) (MdiOwnAdReg
& (MdiLinkPartnerAdReg
& NWAY_LP_ABILITY
));
3217 // Get speed setting
3219 if (MdiOwnAdReg
& (NWAY_AD_TX_HALF_DPX
| NWAY_AD_TX_FULL_DPX
| NWAY_AD_T4_CAPABLE
)) {
3220 AdapterInfo
->LinkSpeed
= 100;
3222 AdapterInfo
->LinkSpeed
= 10;
3226 // Get duplex setting -- use priority resolution algorithm
3228 if (MdiOwnAdReg
& (NWAY_AD_T4_CAPABLE
)) {
3229 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3231 } else if (MdiOwnAdReg
& (NWAY_AD_TX_FULL_DPX
)) {
3232 AdapterInfo
->Duplex
= FULL_DUPLEX
;
3234 } else if (MdiOwnAdReg
& (NWAY_AD_TX_HALF_DPX
)) {
3235 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3237 } else if (MdiOwnAdReg
& (NWAY_AD_10T_FULL_DPX
)) {
3238 AdapterInfo
->Duplex
= FULL_DUPLEX
;
3241 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3247 // If we are connected to a dumb (non-NWAY) repeater or hub, and the line
3248 // speed was determined automatically by parallel detection, then we have
3249 // no way of knowing exactly what speed the PHY is set to unless that PHY
3250 // has a propietary register which indicates speed in this situation. The
3251 // NSC TX PHY does have such a register. Also, since NWAY didn't establish
3252 // the connection, the duplex setting should HALF duplex.
3254 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3256 if (PhyId
== PHY_NSC_TX
) {
3258 // Read register 25 to get the SPEED_10 bit
3263 AdapterInfo
->PhyAddress
,
3268 // If bit 6 was set then we're at 10mb
3270 if (MdiMiscReg
& NSC_TX_SPD_INDC_SPEED
) {
3271 AdapterInfo
->LinkSpeed
= 10;
3273 AdapterInfo
->LinkSpeed
= 100;
3278 // If we don't know what line speed we are set at, then we'll default to
3282 AdapterInfo
->LinkSpeed
= 10;
3288 TODO: Add function description
3290 @param AdapterInfo TODO: add argument description
3292 @return TODO: add return values
3296 XmitWaitForCompletion (
3297 NIC_DATA_INSTANCE
*AdapterInfo
3302 if (AdapterInfo
->FreeCBCount
== AdapterInfo
->TxBufCnt
) {
3307 // used xmit cb list starts right after the free tail (ends before the
3310 TxPtr
= AdapterInfo
->FreeTxTailPtr
->NextTCBVirtualLinkPtr
;
3311 while (TxPtr
!= AdapterInfo
->FreeTxHeadPtr
) {
3312 CommandWaitForCompletion (TxPtr
, AdapterInfo
);
3313 SetFreeCB (AdapterInfo
, TxPtr
);
3314 TxPtr
= TxPtr
->NextTCBVirtualLinkPtr
;
3320 TODO: Add function description
3322 @param cmd_ptr TODO: add argument description
3323 @param AdapterInfo TODO: add argument description
3325 @return TODO: add return values
3329 CommandWaitForCompletion (
3331 NIC_DATA_INSTANCE
*AdapterInfo
3336 while ((cmd_ptr
->cb_header
.status
== 0) && (--wait
> 0)) {
3337 DelayIt (AdapterInfo
, 10);
3340 if (cmd_ptr
->cb_header
.status
== 0) {
3349 TODO: Add function description
3351 @param AdapterInfo TODO: add argument description
3353 @return TODO: add return values
3359 NIC_DATA_INSTANCE
*AdapterInfo
3368 // Reset the chip: stop Tx and Rx processes and clear counters.
3369 // This takes less than 10usec and will easily finish before the next
3373 OutLong (AdapterInfo
, PORT_RESET
, AdapterInfo
->ioaddr
+ SCBPort
);
3375 // wait for 5 milli seconds here!
3377 DelayIt (AdapterInfo
, 5000);
3379 // TCO Errata work around for 559s only
3380 // -----------------------------------------------------------------------------------
3381 // TCO Workaround Code
3383 // -----------------------------------------------------------------------------------
3384 // 1. Issue SW-RST ^^^ (already done above)
3385 // 2. Issue a redundant Set CU Base CMD immediately
3386 // Do not set the General Pointer before the Set CU Base cycle
3387 // Do not check the SCB CMD before the Set CU Base cycle
3388 // 3. Wait for the SCB-CMD to be cleared
3389 // this indicates the transition to post-driver
3390 // 4. Poll the TCO-Req bit in the PMDR to be cleared
3391 // this indicates the tco activity has stopped for real
3392 // 5. Proceed with the nominal Driver Init:
3393 // Actual Set CU & RU Base ...
3395 // Check for ICH2 device ID. If this is an ICH2,
3396 // do the TCO workaround code.
3398 if (AdapterInfo
->VendorID
== D102_DEVICE_ID
||
3399 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_1
||
3400 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_2
||
3401 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_3
||
3402 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_4
||
3403 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_5
||
3404 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_6
||
3405 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_7
||
3406 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_8
||
3407 AdapterInfo
->RevID
>= 8) { // do the TCO fix
3409 // donot load the scb pointer but just give load_cu cmd.
3411 OutByte (AdapterInfo
, CU_CMD_BASE
, AdapterInfo
->ioaddr
+ SCBCmd
);
3413 // wait for command to be accepted.
3415 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
3417 // read PMDR register and check bit 1 in it to see if TCO is active
3421 // wait for 5 milli seconds
3425 tco_stat
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ 0x1b);
3426 if ((tco_stat
& 2) == 0) {
3428 // is the activity bit clear??
3434 DelayIt (AdapterInfo
, 1);
3437 if ((tco_stat
& 2) != 0) {
3450 TODO: Add function description
3452 @param AdapterInfo TODO: add argument description
3454 @return TODO: add return values
3459 IN NIC_DATA_INSTANCE
*AdapterInfo
3467 OutLong (AdapterInfo
, POR_SELECTIVE_RESET
, AdapterInfo
->ioaddr
+ SCBPort
);
3469 // wait for this to complete
3473 // wait for 2 milli seconds here!
3475 DelayIt (AdapterInfo
, 2000);
3478 stat
= InLong (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBPort
);
3484 // wait for 1 milli second
3486 DelayIt (AdapterInfo
, 1000);
3490 return PXE_STATCODE_DEVICE_FAILURE
;
3498 TODO: Add function description
3500 @param AdapterInfo TODO: add argument description
3502 @return TODO: add return values
3507 IN NIC_DATA_INSTANCE
*AdapterInfo
3511 if (SoftwareReset (AdapterInfo
) != 0) {
3512 return PXE_STATCODE_DEVICE_FAILURE
;
3516 // disable interrupts
3518 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
3521 // Load the base registers with 0s (we will give the complete address as
3522 // offset later when we issue any command
3524 if ((ret_val
= Load_Base_Regs (AdapterInfo
)) != 0) {
3528 if ((ret_val
= SetupCBlink (AdapterInfo
)) != 0) {
3532 if ((ret_val
= SetupReceiveQueues (AdapterInfo
)) != 0) {
3537 // detect the PHY only if we need to detect the cable as requested by the
3538 // initialize parameters
3540 AdapterInfo
->PhyAddress
= 0xFF;
3542 if (AdapterInfo
->CableDetect
!= 0) {
3543 if (!PhyDetect (AdapterInfo
)) {
3544 return PXE_STATCODE_DEVICE_FAILURE
;
3548 if ((ret_val
= E100bSetupIAAddr (AdapterInfo
)) != 0) {
3552 if ((ret_val
= Configure (AdapterInfo
)) != 0) {