3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
26 static UINT8 basic_config_cmd
[22] = {
36 (UINT8
)0xf2, (UINT8
)0x80, // 0x40=Force full-duplex
41 // How to wait for the command unit to accept a command.
42 // Typically this takes 0 ticks.
44 #define wait_for_cmd_done(cmd_ioaddr) \
47 while ((InByte (AdapterInfo, cmd_ioaddr) != 0) && --wait >= 0) \
48 DelayIt (AdapterInfo, 10); \
50 DelayIt (AdapterInfo, 50); \
55 IN NIC_DATA_INSTANCE
*AdapterInfo
,
61 This function calls the MemIo callback to read a byte from the device's
63 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
64 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
65 to make undi3.0 a special case
68 Port - Which port to read from.
71 Results - The data read from the port.
74 // TODO: AdapterInfo - add argument and description to function comment
78 (*AdapterInfo
->Mem_Io
) (
79 AdapterInfo
->Unique_ID
,
83 (UINT64
) (UINTN
) &Results
90 IN NIC_DATA_INSTANCE
*AdapterInfo
,
96 This function calls the MemIo callback to read a word from the device's
98 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
99 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
100 to make undi3.0 a special case
103 Port - Which port to read from.
106 Results - The data read from the port.
109 // TODO: AdapterInfo - add argument and description to function comment
113 (*AdapterInfo
->Mem_Io
) (
114 AdapterInfo
->Unique_ID
,
118 (UINT64
)(UINTN
)&Results
125 IN NIC_DATA_INSTANCE
*AdapterInfo
,
131 This function calls the MemIo callback to read a dword from the device's
133 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
134 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
135 to make undi3.0 a special case
138 Port - Which port to read from.
141 Results - The data read from the port.
144 // TODO: AdapterInfo - add argument and description to function comment
148 (*AdapterInfo
->Mem_Io
) (
149 AdapterInfo
->Unique_ID
,
153 (UINT64
)(UINTN
)&Results
160 IN NIC_DATA_INSTANCE
*AdapterInfo
,
167 This function calls the MemIo callback to write a byte from the device's
169 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
170 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
171 to make undi3.0 a special case
174 Data - Data to write to Port.
175 Port - Which port to write to.
181 // TODO: AdapterInfo - add argument and description to function comment
186 (*AdapterInfo
->Mem_Io
) (
187 AdapterInfo
->Unique_ID
,
191 (UINT64
)(UINTN
)(UINTN
)&Val
198 IN NIC_DATA_INSTANCE
*AdapterInfo
,
205 This function calls the MemIo callback to write a word from the device's
207 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
208 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
209 to make undi3.0 a special case
212 Data - Data to write to Port.
213 Port - Which port to write to.
219 // TODO: AdapterInfo - add argument and description to function comment
224 (*AdapterInfo
->Mem_Io
) (
225 AdapterInfo
->Unique_ID
,
236 IN NIC_DATA_INSTANCE
*AdapterInfo
,
243 This function calls the MemIo callback to write a dword from the device's
245 Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)
246 which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have
247 to make undi3.0 a special case
250 Data - Data to write to Port.
251 Port - Which port to write to.
257 // TODO: AdapterInfo - add argument and description to function comment
262 (*AdapterInfo
->Mem_Io
) (
263 AdapterInfo
->Unique_ID
,
274 IN NIC_DATA_INSTANCE
*AdapterInfo
,
278 OUT UINT64 MappedAddr
284 TODO: Add function description
288 AdapterInfo - TODO: add argument description
289 MemAddr - TODO: add argument description
290 Size - TODO: add argument description
291 Direction - TODO: add argument description
292 MappedAddr - TODO: add argument description
296 TODO: add return values
302 PhyAddr
= (UINT64
*) (UINTN
) MappedAddr
;
304 // mapping is different for theold and new NII protocols
306 if (AdapterInfo
->VersionFlag
== 0x30) {
307 if (AdapterInfo
->Virt2Phys_30
== (VOID
*) NULL
) {
308 *PhyAddr
= (UINT64
) AdapterInfo
->MemoryPtr
;
310 (*AdapterInfo
->Virt2Phys_30
) (MemAddr
, (UINT64
) (UINTN
) PhyAddr
);
313 if (*PhyAddr
> FOUR_GIGABYTE
) {
314 return PXE_STATCODE_INVALID_PARAMETER
;
317 if (AdapterInfo
->Map_Mem
== (VOID
*) NULL
) {
319 // this UNDI cannot handle addresses beyond 4 GB without a map routine
321 if (MemAddr
> FOUR_GIGABYTE
) {
322 return PXE_STATCODE_INVALID_PARAMETER
;
327 (*AdapterInfo
->Map_Mem
) (
328 AdapterInfo
->Unique_ID
,
337 return PXE_STATCODE_SUCCESS
;
342 IN NIC_DATA_INSTANCE
*AdapterInfo
,
352 TODO: Add function description
356 AdapterInfo - TODO: add argument description
357 MemAddr - TODO: add argument description
358 Size - TODO: add argument description
359 Direction - TODO: add argument description
360 MappedAddr - TODO: add argument description
364 TODO: add return values
368 if (AdapterInfo
->VersionFlag
> 0x30) {
370 // no mapping service
372 if (AdapterInfo
->UnMap_Mem
!= (VOID
*) NULL
) {
373 (*AdapterInfo
->UnMap_Mem
) (
374 AdapterInfo
->Unique_ID
,
389 IN NIC_DATA_INSTANCE
*AdapterInfo
,
397 AdapterInfo - Pointer to the NIC data structure information
398 which the UNDI driver is layering on..
403 // TODO: MicroSeconds - add argument and description to function comment
405 if (AdapterInfo
->VersionFlag
== 0x30) {
406 (*AdapterInfo
->Delay_30
) (MicroSeconds
);
408 (*AdapterInfo
->Delay
) (AdapterInfo
->Unique_ID
, MicroSeconds
);
414 IN NIC_DATA_INSTANCE
*AdapterInfo
,
422 AdapterInfo - Pointer to the NIC data structure information
423 which the UNDI driver is layering on..
428 // TODO: flag - add argument and description to function comment
430 if (AdapterInfo
->VersionFlag
== 0x30) {
431 (*AdapterInfo
->Block_30
) (flag
);
433 (*AdapterInfo
->Block
) (AdapterInfo
->Unique_ID
, flag
);
439 NIC_DATA_INSTANCE
*AdapterInfo
445 TODO: Add function description
449 AdapterInfo - TODO: add argument description
453 TODO: add return values
458 // we will use the linear (flat) memory model and fill our base registers
459 // with 0's so that the entire physical address is our offset
462 // we reset the statistics totals here because this is where we are loading stats addr
464 AdapterInfo
->RxTotals
= 0;
465 AdapterInfo
->TxTotals
= 0;
468 // Load the statistics block address.
470 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
471 OutLong (AdapterInfo
, (UINT32
) AdapterInfo
->stat_phy_addr
, AdapterInfo
->ioaddr
+ SCBPointer
);
472 OutByte (AdapterInfo
, CU_STATSADDR
, AdapterInfo
->ioaddr
+ SCBCmd
);
473 AdapterInfo
->statistics
->done_marker
= 0;
475 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
476 OutLong (AdapterInfo
, 0, AdapterInfo
->ioaddr
+ SCBPointer
);
477 OutByte (AdapterInfo
, RX_ADDR_LOAD
, AdapterInfo
->ioaddr
+ SCBCmd
);
479 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
480 OutLong (AdapterInfo
, 0, AdapterInfo
->ioaddr
+ SCBPointer
);
481 OutByte (AdapterInfo
, CU_CMD_BASE
, AdapterInfo
->ioaddr
+ SCBCmd
);
488 NIC_DATA_INSTANCE
*AdapterInfo
,
495 TODO: Add function description
499 AdapterInfo - TODO: add argument description
500 cmd_ptr - TODO: add argument description
504 TODO: add return values
510 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
513 // read the CU status, if it is idle, write the address of cb_ptr
514 // in the scbpointer and issue a cu_start,
515 // if it is suspended, remove the suspend bit in the previous command
516 // block and issue a resume
518 // Ensure that the CU Active Status bit is not on from previous CBs.
520 status
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBStatus
);
523 // Skip acknowledging the interrupt if it is not already set
527 // ack only the cna the integer
529 if ((status
& SCB_STATUS_CNA
) != 0) {
530 OutWord (AdapterInfo
, SCB_STATUS_CNA
, AdapterInfo
->ioaddr
+ SCBStatus
);
534 if ((status
& SCB_STATUS_CU_MASK
) == SCB_STATUS_CU_IDLE
) {
538 OutLong (AdapterInfo
, cmd_ptr
->PhysTCBAddress
, AdapterInfo
->ioaddr
+ SCBPointer
);
539 OutByte (AdapterInfo
, CU_START
, AdapterInfo
->ioaddr
+ SCBCmd
);
542 // either active or suspended, give a resume
545 cmd_ptr
->PrevTCBVirtualLinkPtr
->cb_header
.command
&= ~(CmdSuspend
| CmdIntr
);
546 OutByte (AdapterInfo
, CU_RESUME
, AdapterInfo
->ioaddr
+ SCBCmd
);
554 NIC_DATA_INSTANCE
*AdapterInfo
560 TODO: Add function description
564 AdapterInfo - TODO: add argument description
568 TODO: add return values
573 // all command blocks are of TxCB format
580 cmd_ptr
= GetFreeCB (AdapterInfo
);
581 data_ptr
= (UINT8
*) (&cmd_ptr
->PhysTBDArrayAddres
);
584 // start the config data right after the command header
586 for (Index
= 0; Index
< sizeof (basic_config_cmd
); Index
++) {
587 data_ptr
[Index
] = basic_config_cmd
[Index
];
590 my_filter
= (UINT8
) ((AdapterInfo
->Rx_Filter
& PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS
) ? 1 : 0);
591 my_filter
|= (AdapterInfo
->Rx_Filter
& PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST
) ? 0 : 2;
593 data_ptr
[15] |= my_filter
;
594 data_ptr
[19] = (UINT8
) (AdapterInfo
->Duplex
? 0xC0 : 0x80);
595 data_ptr
[21] = (UINT8
) ((AdapterInfo
->Rx_Filter
& PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST
) ? 0x0D : 0x05);
598 // check if we have to use the AUI port instead
600 if ((AdapterInfo
->PhyRecord
[0] & 0x8000) != 0) {
601 data_ptr
[15] |= 0x80;
605 BlockIt (AdapterInfo
, TRUE
);
606 cmd_ptr
->cb_header
.command
= CmdSuspend
| CmdConfigure
;
608 IssueCB (AdapterInfo
, cmd_ptr
);
609 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
611 BlockIt (AdapterInfo
, FALSE
);
613 CommandWaitForCompletion (cmd_ptr
, AdapterInfo
);
616 // restore the cb values for tx
618 cmd_ptr
->PhysTBDArrayAddres
= cmd_ptr
->PhysArrayAddr
;
619 cmd_ptr
->ByteCount
= cmd_ptr
->Threshold
= cmd_ptr
->TBDCount
= 0;
621 // fields beyond the immediatedata are assumed to be safe
622 // add the CB to the free list again
624 SetFreeCB (AdapterInfo
, cmd_ptr
);
630 NIC_DATA_INSTANCE
*AdapterInfo
636 TODO: Add function description
640 AdapterInfo - TODO: add argument description
644 TODO: add return values
649 // all command blocks are of TxCB format
655 eaddrs
= (UINT16
*) AdapterInfo
->CurrentNodeAddress
;
657 cmd_ptr
= GetFreeCB (AdapterInfo
);
658 data_ptr
= (UINT16
*) (&cmd_ptr
->PhysTBDArrayAddres
);
661 // AVOID a bug (?!) here by marking the command already completed.
663 cmd_ptr
->cb_header
.command
= (CmdSuspend
| CmdIASetup
);
664 cmd_ptr
->cb_header
.status
= 0;
665 data_ptr
[0] = eaddrs
[0];
666 data_ptr
[1] = eaddrs
[1];
667 data_ptr
[2] = eaddrs
[2];
669 BlockIt (AdapterInfo
, TRUE
);
670 IssueCB (AdapterInfo
, cmd_ptr
);
671 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
672 BlockIt (AdapterInfo
, FALSE
);
674 CommandWaitForCompletion (cmd_ptr
, AdapterInfo
);
677 // restore the cb values for tx
679 cmd_ptr
->PhysTBDArrayAddres
= cmd_ptr
->PhysArrayAddr
;
680 cmd_ptr
->ByteCount
= cmd_ptr
->Threshold
= cmd_ptr
->TBDCount
= 0;
682 // fields beyond the immediatedata are assumed to be safe
683 // add the CB to the free list again
685 SetFreeCB (AdapterInfo
, cmd_ptr
);
691 IN NIC_DATA_INSTANCE
*AdapterInfo
696 Instructs the NIC to stop receiving packets.
699 AdapterInfo - Pointer to the NIC data structure information
700 which the UNDI driver is layering on..
705 if (AdapterInfo
->Receive_Started
) {
708 // Todo: verify that we must wait for previous command completion.
710 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
713 // Disable interrupts, and stop the chip's Rx process.
715 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
716 OutWord (AdapterInfo
, INT_MASK
| RX_ABORT
, AdapterInfo
->ioaddr
+ SCBCmd
);
718 AdapterInfo
->Receive_Started
= FALSE
;
726 NIC_DATA_INSTANCE
*AdapterInfo
731 Instructs the NIC to start receiving packets.
734 AdapterInfo - Pointer to the NIC data structure information
735 which the UNDI driver is layering on..
742 if (AdapterInfo
->Receive_Started
) {
749 AdapterInfo
->cur_rx_ind
= 0;
750 AdapterInfo
->Int_Status
= 0;
752 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
754 OutLong (AdapterInfo
, (UINT32
) AdapterInfo
->rx_phy_addr
, AdapterInfo
->ioaddr
+ SCBPointer
);
755 OutByte (AdapterInfo
, RX_START
, AdapterInfo
->ioaddr
+ SCBCmd
);
757 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
759 AdapterInfo
->Receive_Started
= TRUE
;
765 IN NIC_DATA_INSTANCE
*AdapterInfo
770 Configures the chip. This routine expects the NIC_DATA_INSTANCE structure to be filled in.
773 AdapterInfo - Pointer to the NIC data structure information
774 which the UNDI driver is layering on..
778 PXE_STATCODE_NOT_ENOUGH_MEMORY - Insufficient length of locked memory
779 other - Failure initializing chip
782 PCI_CONFIG_HEADER
*CfgHdr
;
787 if (AdapterInfo
->MemoryLength
< MEMORY_NEEDED
) {
788 return PXE_STATCODE_NOT_ENOUGH_MEMORY
;
793 AdapterInfo
->MemoryPtr
,
794 AdapterInfo
->MemoryLength
,
796 (UINT64
)(UINTN
) &AdapterInfo
->Mapped_MemoryPtr
803 CfgHdr
= (PCI_CONFIG_HEADER
*) &(AdapterInfo
->Config
[0]);
806 // fill in the ioaddr, int... from the config space
808 AdapterInfo
->int_num
= CfgHdr
->int_line
;
811 // we don't need to validate integer number, what if they don't want to assign one?
812 // if (AdapterInfo->int_num == 0 || AdapterInfo->int_num == 0xff)
813 // return PXE_STATCODE_DEVICE_FAILURE;
815 AdapterInfo
->ioaddr
= 0;
816 AdapterInfo
->VendorID
= CfgHdr
->VendorID
;
817 AdapterInfo
->DeviceID
= CfgHdr
->DeviceID
;
818 AdapterInfo
->RevID
= CfgHdr
->RevID
;
819 AdapterInfo
->SubVendorID
= CfgHdr
->SubVendorID
;
820 AdapterInfo
->SubSystemID
= CfgHdr
->SubSystemID
;
821 AdapterInfo
->flash_addr
= 0;
824 // Read the station address EEPROM before doing the reset.
825 // Perhaps this should even be done before accepting the device,
826 // then we wouldn't have a device name with which to report the error.
828 if (E100bReadEepromAndStationAddress (AdapterInfo
) != 0) {
829 return PXE_STATCODE_DEVICE_FAILURE
;
833 // ## calculate the buffer #s depending on memory given
834 // ## calculate the rx and tx ring pointers
837 AdapterInfo
->TxBufCnt
= TX_BUFFER_COUNT
;
838 AdapterInfo
->RxBufCnt
= RX_BUFFER_COUNT
;
839 rx_size
= (AdapterInfo
->RxBufCnt
* sizeof (RxFD
));
840 tx_size
= (AdapterInfo
->TxBufCnt
* sizeof (TxCB
));
841 AdapterInfo
->rx_ring
= (RxFD
*) (UINTN
) (AdapterInfo
->MemoryPtr
);
842 AdapterInfo
->tx_ring
= (TxCB
*) (UINTN
) (AdapterInfo
->MemoryPtr
+ rx_size
);
843 AdapterInfo
->statistics
= (struct speedo_stats
*) (UINTN
) (AdapterInfo
->MemoryPtr
+ rx_size
+ tx_size
);
845 AdapterInfo
->rx_phy_addr
= AdapterInfo
->Mapped_MemoryPtr
;
846 AdapterInfo
->tx_phy_addr
= AdapterInfo
->Mapped_MemoryPtr
+ rx_size
;
847 AdapterInfo
->stat_phy_addr
= AdapterInfo
->tx_phy_addr
+ tx_size
;
852 AdapterInfo
->PhyAddress
= 0xFF;
853 AdapterInfo
->Rx_Filter
= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST
;
854 AdapterInfo
->Receive_Started
= FALSE
;
855 AdapterInfo
->mcast_list
.list_len
= 0;
856 return InitializeChip (AdapterInfo
);
860 E100bSetInterruptState (
861 IN NIC_DATA_INSTANCE
*AdapterInfo
866 Sets the interrupt state for the NIC.
869 AdapterInfo - Pointer to the NIC data structure information
870 which the UNDI driver is layering on..
876 // don't set receive interrupt if receiver is disabled...
880 if ((AdapterInfo
->int_mask
& PXE_OPFLAGS_INTERRUPT_RECEIVE
) != 0) {
881 cmd_word
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCmd
);
882 cmd_word
&= ~INT_MASK
;
883 OutWord (AdapterInfo
, cmd_word
, AdapterInfo
->ioaddr
+ SCBCmd
);
886 // disable ints, should not be given for SW Int.
888 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
891 if ((AdapterInfo
->int_mask
& PXE_OPFLAGS_INTERRUPT_SOFTWARE
) != 0) {
893 // reset the bit in our mask, it is only one time!!
895 AdapterInfo
->int_mask
&= ~(PXE_OPFLAGS_INTERRUPT_SOFTWARE
);
896 cmd_word
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCmd
);
897 cmd_word
|= DRVR_INT
;
898 OutWord (AdapterInfo
, cmd_word
, AdapterInfo
->ioaddr
+ SCBCmd
);
904 // we are not going to disable broadcast for the WOL's sake!
908 NIC_DATA_INSTANCE
*AdapterInfo
,
916 Instructs the NIC to start receiving packets.
919 AdapterInfo - Pointer to the NIC data structure information
920 which the UNDI driver is layering on..
930 PXE_CPB_RECEIVE_FILTERS
*mc_list
= (PXE_CPB_RECEIVE_FILTERS
*) (UINTN
)cpb
;
937 struct MC_CB_STRUCT
*data_ptr
;
940 old_filter
= AdapterInfo
->Rx_Filter
;
943 // only these bits need a change in the configuration
944 // actually change in bcast requires configure but we ignore that change
946 cfg_flt
= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS
|
947 PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST
;
949 if ((old_filter
& cfg_flt
) != (new_filter
& cfg_flt
)) {
950 XmitWaitForCompletion (AdapterInfo
);
952 if (AdapterInfo
->Receive_Started
) {
953 StopRU (AdapterInfo
);
956 AdapterInfo
->Rx_Filter
= (UINT8
) (new_filter
| PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST
);
957 Configure (AdapterInfo
);
961 // check if mcast setting changed
963 if ( ((new_filter
& PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
) !=
964 (old_filter
& PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
) ) ||
965 (mc_list
!= NULL
) ) {
968 if (mc_list
!= NULL
) {
969 mc_count
= AdapterInfo
->mcast_list
.list_len
= (UINT16
) (cpbsize
/ PXE_MAC_LENGTH
);
971 for (Index
= 0; (Index
< mc_count
&& Index
< MAX_MCAST_ADDRESS_CNT
); Index
++) {
972 for (Index2
= 0; Index2
< PXE_MAC_LENGTH
; Index2
++) {
973 AdapterInfo
->mcast_list
.mc_list
[Index
][Index2
] = mc_list
->MCastList
[Index
][Index2
];
979 // are we setting the list or resetting??
981 if ((new_filter
& PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
) != 0) {
983 // we are setting a new list!
985 mc_count
= AdapterInfo
->mcast_list
.list_len
;
987 // count should be the actual # of bytes in the list
988 // so multiply this with 6
990 mc_byte_cnt
= (UINT16
) ((mc_count
<< 2) + (mc_count
<< 1));
991 AdapterInfo
->Rx_Filter
|= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
;
994 // disabling the list in the NIC.
996 mc_byte_cnt
= mc_count
= 0;
997 AdapterInfo
->Rx_Filter
&= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
);
1001 // before issuing any new command!
1003 XmitWaitForCompletion (AdapterInfo
);
1005 if (AdapterInfo
->Receive_Started
) {
1006 StopRU (AdapterInfo
);
1010 cmd_ptr
= GetFreeCB (AdapterInfo
);
1011 if (cmd_ptr
== NULL
) {
1012 return PXE_STATCODE_QUEUE_FULL
;
1015 // fill the command structure and issue
1017 data_ptr
= (struct MC_CB_STRUCT
*) (&cmd_ptr
->PhysTBDArrayAddres
);
1019 // first 2 bytes are the count;
1021 data_ptr
->count
= mc_byte_cnt
;
1022 for (Index
= 0; Index
< mc_count
; Index
++) {
1023 for (Index2
= 0; Index2
< PXE_HWADDR_LEN_ETHER
; Index2
++) {
1024 data_ptr
->m_list
[Index
][Index2
] = AdapterInfo
->mcast_list
.mc_list
[Index
][Index2
];
1028 cmd_ptr
->cb_header
.command
= CmdSuspend
| CmdMulticastList
;
1029 cmd_ptr
->cb_header
.status
= 0;
1031 BlockIt (AdapterInfo
, TRUE
);
1032 IssueCB (AdapterInfo
, cmd_ptr
);
1033 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
1035 BlockIt (AdapterInfo
, FALSE
);
1037 CommandWaitForCompletion (cmd_ptr
, AdapterInfo
);
1039 cmd_ptr
->PhysTBDArrayAddres
= cmd_ptr
->PhysArrayAddr
;
1040 cmd_ptr
->ByteCount
= cmd_ptr
->Threshold
= cmd_ptr
->TBDCount
= 0;
1042 // fields beyond the immediatedata are assumed to be safe
1043 // add the CB to the free list again
1045 SetFreeCB (AdapterInfo
, cmd_ptr
);
1048 if (new_filter
!= 0) {
1050 // enable unicast and start the RU
1052 AdapterInfo
->Rx_Filter
|= (new_filter
| PXE_OPFLAGS_RECEIVE_FILTER_UNICAST
);
1053 StartRU (AdapterInfo
);
1056 // may be disabling everything!
1058 if (AdapterInfo
->Receive_Started
) {
1059 StopRU (AdapterInfo
);
1062 AdapterInfo
->Rx_Filter
|= (~PXE_OPFLAGS_RECEIVE_FILTER_UNICAST
);
1070 NIC_DATA_INSTANCE
*AdapterInfo
,
1076 Routine Description:
1078 TODO: Add function description
1082 AdapterInfo - TODO: add argument description
1083 cpb - TODO: add argument description
1084 opflags - TODO: add argument description
1088 TODO: add return values
1092 PXE_CPB_TRANSMIT_FRAGMENTS
*tx_ptr_f
;
1093 PXE_CPB_TRANSMIT
*tx_ptr_1
;
1100 tx_ptr_1
= (PXE_CPB_TRANSMIT
*) (UINTN
) cpb
;
1101 tx_ptr_f
= (PXE_CPB_TRANSMIT_FRAGMENTS
*) (UINTN
) cpb
;
1104 // stop reentrancy here
1106 if (AdapterInfo
->in_transmit
) {
1107 return PXE_STATCODE_BUSY
;
1111 AdapterInfo
->in_transmit
= TRUE
;
1114 // Prevent interrupts from changing the Tx ring from underneath us.
1116 // Calculate the Tx descriptor entry.
1118 if ((tcb_ptr
= GetFreeCB (AdapterInfo
)) == NULL
) {
1119 AdapterInfo
->in_transmit
= FALSE
;
1120 return PXE_STATCODE_QUEUE_FULL
;
1123 AdapterInfo
->TxTotals
++;
1125 tcb_ptr
->cb_header
.command
= (CmdSuspend
| CmdTx
| CmdTxFlex
);
1126 tcb_ptr
->cb_header
.status
= 0;
1129 // no immediate data, set EOF in the ByteCount
1131 tcb_ptr
->ByteCount
= 0x8000;
1134 // The data region is always in one buffer descriptor, Tx FIFO
1135 // threshold of 256.
1136 // 82557 multiplies the threashold value by 8, so give 256/8
1138 tcb_ptr
->Threshold
= 32;
1139 if ((opflags
& PXE_OPFLAGS_TRANSMIT_FRAGMENTED
) != 0) {
1141 if (tx_ptr_f
->FragCnt
> MAX_XMIT_FRAGMENTS
) {
1142 SetFreeCB (AdapterInfo
, tcb_ptr
);
1143 AdapterInfo
->in_transmit
= FALSE
;
1144 return PXE_STATCODE_INVALID_PARAMETER
;
1147 tcb_ptr
->TBDCount
= (UINT8
) tx_ptr_f
->FragCnt
;
1149 for (Index
= 0; Index
< tx_ptr_f
->FragCnt
; Index
++) {
1152 tx_ptr_f
->FragDesc
[Index
].FragAddr
,
1153 tx_ptr_f
->FragDesc
[Index
].FragLen
,
1155 (UINT64
)(UINTN
) &Tmp_ptr
1158 SetFreeCB (AdapterInfo
, tcb_ptr
);
1159 AdapterInfo
->in_transmit
= FALSE
;
1160 return PXE_STATCODE_INVALID_PARAMETER
;
1163 tcb_ptr
->TBDArray
[Index
].phys_buf_addr
= (UINT32
) Tmp_ptr
;
1164 tcb_ptr
->TBDArray
[Index
].buf_len
= tx_ptr_f
->FragDesc
[Index
].FragLen
;
1167 tcb_ptr
->free_data_ptr
= tx_ptr_f
->FragDesc
[0].FragAddr
;
1171 // non fragmented case
1173 tcb_ptr
->TBDCount
= 1;
1176 tx_ptr_1
->FrameAddr
,
1177 tx_ptr_1
->DataLen
+ tx_ptr_1
->MediaheaderLen
,
1179 (UINT64
)(UINTN
) &Tmp_ptr
1182 SetFreeCB (AdapterInfo
, tcb_ptr
);
1183 AdapterInfo
->in_transmit
= FALSE
;
1184 return PXE_STATCODE_INVALID_PARAMETER
;
1187 tcb_ptr
->TBDArray
[0].phys_buf_addr
= (UINT32
) (Tmp_ptr
);
1188 tcb_ptr
->TBDArray
[0].buf_len
= tx_ptr_1
->DataLen
+ tx_ptr_1
->MediaheaderLen
;
1189 tcb_ptr
->free_data_ptr
= tx_ptr_1
->FrameAddr
;
1193 // must wait for previous command completion only if it was a non-transmit
1195 BlockIt (AdapterInfo
, TRUE
);
1196 IssueCB (AdapterInfo
, tcb_ptr
);
1197 BlockIt (AdapterInfo
, FALSE
);
1200 // see if we need to wait for completion here
1202 if ((opflags
& PXE_OPFLAGS_TRANSMIT_BLOCK
) != 0) {
1204 // don't wait for more than 1 second!!!
1207 while (tcb_ptr
->cb_header
.status
== 0) {
1208 DelayIt (AdapterInfo
, 10);
1210 if (wait_sec
== 0) {
1215 // we need to un-map any mapped buffers here
1217 if ((opflags
& PXE_OPFLAGS_TRANSMIT_FRAGMENTED
) != 0) {
1219 for (Index
= 0; Index
< tx_ptr_f
->FragCnt
; Index
++) {
1220 Tmp_ptr
= tcb_ptr
->TBDArray
[Index
].phys_buf_addr
;
1223 tx_ptr_f
->FragDesc
[Index
].FragAddr
,
1224 tx_ptr_f
->FragDesc
[Index
].FragLen
,
1230 Tmp_ptr
= tcb_ptr
->TBDArray
[0].phys_buf_addr
;
1233 tx_ptr_1
->FrameAddr
,
1234 tx_ptr_1
->DataLen
+ tx_ptr_1
->MediaheaderLen
,
1240 if (tcb_ptr
->cb_header
.status
== 0) {
1241 SetFreeCB (AdapterInfo
, tcb_ptr
);
1242 AdapterInfo
->in_transmit
= FALSE
;
1243 return PXE_STATCODE_DEVICE_FAILURE
;
1246 SetFreeCB (AdapterInfo
, tcb_ptr
);
1249 // CB will be set free later in get_status (or when we run out of xmit buffers
1251 AdapterInfo
->in_transmit
= FALSE
;
1258 NIC_DATA_INSTANCE
*AdapterInfo
,
1264 Routine Description:
1266 TODO: Add function description
1270 AdapterInfo - TODO: add argument description
1271 cpb - TODO: add argument description
1272 db - TODO: add argument description
1276 TODO: add return values
1280 PXE_CPB_RECEIVE
*rx_cpbptr
;
1281 PXE_DB_RECEIVE
*rx_dbptr
;
1287 PXE_FRAME_TYPE pkt_type
;
1289 EtherHeader
*hdr_ptr
;
1290 ret_code
= PXE_STATCODE_NO_DATA
;
1291 pkt_type
= PXE_FRAME_TYPE_NONE
;
1292 status
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBStatus
);
1293 AdapterInfo
->Int_Status
|= status
;
1295 // acknoledge the interrupts
1297 OutWord (AdapterInfo
, (UINT16
) (status
& 0xfc00), (UINT32
) (AdapterInfo
->ioaddr
+ SCBStatus
));
1300 // include the prev ints as well
1302 status
= AdapterInfo
->Int_Status
;
1303 rx_cpbptr
= (PXE_CPB_RECEIVE
*) (UINTN
) cpb
;
1304 rx_dbptr
= (PXE_DB_RECEIVE
*) (UINTN
) db
;
1306 rx_ptr
= &AdapterInfo
->rx_ring
[AdapterInfo
->cur_rx_ind
];
1309 // be in a loop just in case (we may drop a pkt)
1311 while ((status
= rx_ptr
->cb_header
.status
) & RX_COMPLETE
) {
1313 AdapterInfo
->RxTotals
++;
1315 // If we own the next entry, it's a new packet. Send it up.
1317 if (rx_ptr
->forwarded
) {
1323 // discard bad frames
1327 // crc, align, dma overrun, too short, receive error (v22 no coll)
1329 if ((status
& 0x0D90) != 0) {
1335 // make sure the status is OK
1337 if ((status
& 0x02000) == 0) {
1341 pkt_len
= (UINT16
) (rx_ptr
->ActualCount
& 0x3fff);
1346 if (pkt_len
> rx_cpbptr
->BufferLen
) {
1347 Tmp_len
= (UINT16
) rx_cpbptr
->BufferLen
;
1350 CopyMem ((INT8
*) (UINTN
) rx_cpbptr
->BufferAddr
, (INT8
*) &rx_ptr
->RFDBuffer
, Tmp_len
);
1352 hdr_ptr
= (EtherHeader
*) &rx_ptr
->RFDBuffer
;
1354 // fill the CDB and break the loop
1360 rx_dbptr
->FrameLen
= pkt_len
;
1361 rx_dbptr
->MediaHeaderLen
= PXE_MAC_HEADER_LEN_ETHER
;
1363 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1364 if (hdr_ptr
->dest_addr
[Index
] != AdapterInfo
->CurrentNodeAddress
[Index
]) {
1369 if (Index
>= PXE_HWADDR_LEN_ETHER
) {
1370 pkt_type
= PXE_FRAME_TYPE_UNICAST
;
1372 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1373 if (hdr_ptr
->dest_addr
[Index
] != AdapterInfo
->BroadcastNodeAddress
[Index
]) {
1378 if (Index
>= PXE_HWADDR_LEN_ETHER
) {
1379 pkt_type
= PXE_FRAME_TYPE_BROADCAST
;
1381 if ((hdr_ptr
->dest_addr
[0] & 1) == 1) {
1386 pkt_type
= PXE_FRAME_TYPE_MULTICAST
;
1388 pkt_type
= PXE_FRAME_TYPE_PROMISCUOUS
;
1393 rx_dbptr
->Type
= pkt_type
;
1394 rx_dbptr
->Protocol
= hdr_ptr
->type
;
1396 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1397 rx_dbptr
->SrcAddr
[Index
] = hdr_ptr
->src_addr
[Index
];
1398 rx_dbptr
->DestAddr
[Index
] = hdr_ptr
->dest_addr
[Index
];
1401 rx_ptr
->forwarded
= TRUE
;
1406 Recycle_RFD (AdapterInfo
, AdapterInfo
->cur_rx_ind
);
1407 AdapterInfo
->cur_rx_ind
++;
1408 if (AdapterInfo
->cur_rx_ind
== AdapterInfo
->RxBufCnt
) {
1409 AdapterInfo
->cur_rx_ind
= 0;
1415 Recycle_RFD (AdapterInfo
, AdapterInfo
->cur_rx_ind
);
1416 AdapterInfo
->cur_rx_ind
++;
1417 if (AdapterInfo
->cur_rx_ind
== AdapterInfo
->RxBufCnt
) {
1418 AdapterInfo
->cur_rx_ind
= 0;
1421 rx_ptr
= &AdapterInfo
->rx_ring
[AdapterInfo
->cur_rx_ind
];
1424 if (pkt_type
== PXE_FRAME_TYPE_NONE
) {
1425 AdapterInfo
->Int_Status
&= (~SCB_STATUS_FR
);
1428 status
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBStatus
);
1429 if ((status
& SCB_RUS_NO_RESOURCES
) != 0) {
1431 // start the receive unit here!
1432 // leave all the filled frames,
1434 SetupReceiveQueues (AdapterInfo
);
1435 OutLong (AdapterInfo
, (UINT32
) AdapterInfo
->rx_phy_addr
, AdapterInfo
->ioaddr
+ SCBPointer
);
1436 OutWord (AdapterInfo
, RX_START
, AdapterInfo
->ioaddr
+ SCBCmd
);
1437 AdapterInfo
->cur_rx_ind
= 0;
1444 E100bReadEepromAndStationAddress (
1445 NIC_DATA_INSTANCE
*AdapterInfo
1449 Routine Description:
1451 TODO: Add function description
1455 AdapterInfo - TODO: add argument description
1459 TODO: add return values
1470 eedata
= (UINT16
*) (&AdapterInfo
->NVData
[0]);
1473 addr_len
= E100bGetEepromAddrLen (AdapterInfo
);
1478 AdapterInfo
->NVData_Len
= eeprom_len
= (UINT16
) (1 << addr_len
);
1479 for (Index2
= 0, Index
= 0; Index
< eeprom_len
; Index
++) {
1481 value
= E100bReadEeprom (AdapterInfo
, Index
, addr_len
);
1482 eedata
[Index
] = value
;
1483 sum
= (UINT16
) (sum
+ value
);
1485 AdapterInfo
->PermNodeAddress
[Index2
++] = (UINT8
) value
;
1486 AdapterInfo
->PermNodeAddress
[Index2
++] = (UINT8
) (value
>> 8);
1490 if (sum
!= 0xBABA) {
1494 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1495 AdapterInfo
->CurrentNodeAddress
[Index
] = AdapterInfo
->PermNodeAddress
[Index
];
1498 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1499 AdapterInfo
->BroadcastNodeAddress
[Index
] = 0xff;
1502 for (Index
= PXE_HWADDR_LEN_ETHER
; Index
< PXE_MAC_LENGTH
; Index
++) {
1503 AdapterInfo
->CurrentNodeAddress
[Index
] = 0;
1504 AdapterInfo
->PermNodeAddress
[Index
] = 0;
1505 AdapterInfo
->BroadcastNodeAddress
[Index
] = 0;
1512 // CBList is a circular linked list
1513 // 1) When all are free, Tail->next == Head and FreeCount == # allocated
1514 // 2) When none are free, Tail == Head and FreeCount == 0
1515 // 3) when one is free, Tail == Head and Freecount == 1
1516 // 4) First non-Free frame is always at Tail->next
1520 NIC_DATA_INSTANCE
*AdapterInfo
1524 Routine Description:
1526 TODO: Add function description
1530 AdapterInfo - TODO: add argument description
1534 TODO: add return values
1544 cur_ptr
= &(AdapterInfo
->tx_ring
[0]);
1545 array_off
= (UINTN
) (&cur_ptr
->TBDArray
) - (UINTN
) cur_ptr
;
1546 for (Index
= 0; Index
< AdapterInfo
->TxBufCnt
; Index
++) {
1547 cur_ptr
[Index
].cb_header
.status
= 0;
1548 cur_ptr
[Index
].cb_header
.command
= 0;
1550 cur_ptr
[Index
].PhysTCBAddress
=
1551 (UINT32
) AdapterInfo
->tx_phy_addr
+ (Index
* sizeof (TxCB
));
1553 cur_ptr
[Index
].PhysArrayAddr
= (UINT32
)(cur_ptr
[Index
].PhysTCBAddress
+ array_off
);
1554 cur_ptr
[Index
].PhysTBDArrayAddres
= (UINT32
)(cur_ptr
[Index
].PhysTCBAddress
+ array_off
);
1556 cur_ptr
->free_data_ptr
= (UINT64
) 0;
1558 if (Index
< AdapterInfo
->TxBufCnt
- 1) {
1559 cur_ptr
[Index
].cb_header
.link
= cur_ptr
[Index
].PhysTCBAddress
+ sizeof (TxCB
);
1560 cur_ptr
[Index
].NextTCBVirtualLinkPtr
= &cur_ptr
[Index
+ 1];
1561 cur_ptr
[Index
+ 1].PrevTCBVirtualLinkPtr
= &cur_ptr
[Index
];
1565 head_ptr
= &cur_ptr
[0];
1566 tail_ptr
= &cur_ptr
[AdapterInfo
->TxBufCnt
- 1];
1567 tail_ptr
->cb_header
.link
= head_ptr
->PhysTCBAddress
;
1568 tail_ptr
->NextTCBVirtualLinkPtr
= head_ptr
;
1569 head_ptr
->PrevTCBVirtualLinkPtr
= tail_ptr
;
1571 AdapterInfo
->FreeCBCount
= AdapterInfo
->TxBufCnt
;
1572 AdapterInfo
->FreeTxHeadPtr
= head_ptr
;
1574 // set tail of the free list, next to this would be either in use
1575 // or the head itself
1577 AdapterInfo
->FreeTxTailPtr
= tail_ptr
;
1579 AdapterInfo
->xmit_done_head
= AdapterInfo
->xmit_done_tail
= 0;
1586 NIC_DATA_INSTANCE
*AdapterInfo
1590 Routine Description:
1592 TODO: Add function description
1596 AdapterInfo - TODO: add argument description
1600 TODO: add return values
1607 // claim any hanging free CBs
1609 if (AdapterInfo
->FreeCBCount
<= 1) {
1610 CheckCBList (AdapterInfo
);
1614 // don't use up the last CB problem if the previous CB that the CU used
1615 // becomes the last CB we submit because of the SUSPEND bit we set.
1616 // the CU thinks it was never cleared.
1619 if (AdapterInfo
->FreeCBCount
<= 1) {
1623 BlockIt (AdapterInfo
, TRUE
);
1624 free_cb_ptr
= AdapterInfo
->FreeTxHeadPtr
;
1625 AdapterInfo
->FreeTxHeadPtr
= free_cb_ptr
->NextTCBVirtualLinkPtr
;
1626 --AdapterInfo
->FreeCBCount
;
1627 BlockIt (AdapterInfo
, FALSE
);
1633 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1638 Routine Description:
1640 TODO: Add function description
1644 AdapterInfo - TODO: add argument description
1645 cb_ptr - TODO: add argument description
1649 TODO: add return values
1654 // here we assume cb are returned in the order they are taken out
1655 // and we link the newly freed cb at the tail of free cb list
1657 cb_ptr
->cb_header
.status
= 0;
1658 cb_ptr
->free_data_ptr
= (UINT64
) 0;
1660 AdapterInfo
->FreeTxTailPtr
= cb_ptr
;
1661 ++AdapterInfo
->FreeCBCount
;
1671 Routine Description:
1673 TODO: Add function description
1677 ind - TODO: add argument description
1681 TODO: add return values
1687 Tmp
= (UINT16
) (ind
+ 1);
1688 if (Tmp
>= (TX_BUFFER_COUNT
<< 1)) {
1697 IN NIC_DATA_INSTANCE
*AdapterInfo
1701 Routine Description:
1703 TODO: Add function description
1707 AdapterInfo - TODO: add argument description
1711 TODO: add return values
1720 Tmp_ptr
= AdapterInfo
->FreeTxTailPtr
->NextTCBVirtualLinkPtr
;
1721 if ((Tmp_ptr
->cb_header
.status
& CMD_STATUS_MASK
) != 0) {
1723 // check if Q is full
1725 if (next (AdapterInfo
->xmit_done_tail
) != AdapterInfo
->xmit_done_head
) {
1726 AdapterInfo
->xmit_done
[AdapterInfo
->xmit_done_tail
] = Tmp_ptr
->free_data_ptr
;
1730 Tmp_ptr
->free_data_ptr
,
1731 Tmp_ptr
->TBDArray
[0].buf_len
,
1733 (UINT64
) Tmp_ptr
->TBDArray
[0].phys_buf_addr
1736 AdapterInfo
->xmit_done_tail
= next (AdapterInfo
->xmit_done_tail
);
1739 SetFreeCB (AdapterInfo
, Tmp_ptr
);
1748 // Description : Initialize the RFD list list by linking each element together
1749 // in a circular list. The simplified memory model is used.
1750 // All data is in the RFD. The RFDs are linked together and the
1751 // last one points back to the first one. When the current RFD
1752 // is processed (frame received), its EL bit is set and the EL
1753 // bit in the previous RXFD is cleared.
1754 // Allocation done during INIT, this is making linked list.
1757 SetupReceiveQueues (
1758 IN NIC_DATA_INSTANCE
*AdapterInfo
1762 Routine Description:
1764 TODO: Add function description
1768 AdapterInfo - TODO: add argument description
1772 TODO: add return values
1781 AdapterInfo
->cur_rx_ind
= 0;
1782 rx_ptr
= (&AdapterInfo
->rx_ring
[0]);
1784 for (Index
= 0; Index
< AdapterInfo
->RxBufCnt
; Index
++) {
1785 rx_ptr
[Index
].cb_header
.status
= 0;
1786 rx_ptr
[Index
].cb_header
.command
= 0;
1787 rx_ptr
[Index
].RFDSize
= RX_BUFFER_SIZE
;
1788 rx_ptr
[Index
].ActualCount
= 0;
1790 // RBDs not used, simple memory model
1792 rx_ptr
[Index
].rx_buf_addr
= (UINT32
) (-1);
1795 // RBDs not used, simple memory model
1797 rx_ptr
[Index
].forwarded
= FALSE
;
1800 // don't use Tmp_ptr if it is beyond the last one
1802 if (Index
< AdapterInfo
->RxBufCnt
- 1) {
1803 rx_ptr
[Index
].cb_header
.link
= (UINT32
) AdapterInfo
->rx_phy_addr
+ ((Index
+ 1) * sizeof (RxFD
));
1807 head_ptr
= (&AdapterInfo
->rx_ring
[0]);
1808 tail_ptr
= (&AdapterInfo
->rx_ring
[AdapterInfo
->RxBufCnt
- 1]);
1809 tail_ptr
->cb_header
.link
= (UINT32
) AdapterInfo
->rx_phy_addr
;
1814 tail_ptr
->cb_header
.command
= 0xC000;
1815 AdapterInfo
->RFDTailPtr
= tail_ptr
;
1821 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1826 Routine Description:
1828 TODO: Add function description
1832 AdapterInfo - TODO: add argument description
1833 rx_index - TODO: add argument description
1837 TODO: add return values
1844 // change the EL bit and change the AdapterInfo->RxTailPtr
1845 // rx_ptr is assumed to be the head of the Q
1846 // AdapterInfo->rx_forwarded[rx_index] = FALSE;
1848 rx_ptr
= &AdapterInfo
->rx_ring
[rx_index
];
1849 tail_ptr
= AdapterInfo
->RFDTailPtr
;
1851 // set el_bit and suspend bit
1853 rx_ptr
->cb_header
.command
= 0xc000;
1854 rx_ptr
->cb_header
.status
= 0;
1855 rx_ptr
->ActualCount
= 0;
1856 rx_ptr
->forwarded
= FALSE
;
1857 AdapterInfo
->RFDTailPtr
= rx_ptr
;
1859 // resetting the el_bit.
1861 tail_ptr
->cb_header
.command
= 0;
1863 // check the receive unit, fix if there is any problem
1868 // Serial EEPROM section.
1870 // EEPROM_Ctrl bits.
1872 #define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */
1873 #define EE_CS 0x02 /* EEPROM chip select. */
1874 #define EE_DI 0x04 /* EEPROM chip data in. */
1875 #define EE_WRITE_0 0x01
1876 #define EE_WRITE_1 0x05
1877 #define EE_DO 0x08 /* EEPROM chip data out. */
1878 #define EE_ENB (0x4800 | EE_CS)
1881 // Delay between EEPROM clock transitions.
1882 // This will actually work with no delay on 33Mhz PCI.
1884 #define eeprom_delay(nanosec) DelayIt (AdapterInfo, nanosec);
1887 // The EEPROM commands include the alway-set leading bit.
1889 #define EE_WRITE_CMD 5 // 101b
1890 #define EE_READ_CMD 6 // 110b
1891 #define EE_ERASE_CMD (7 << 6)
1895 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1901 Routine Description:
1903 TODO: Add function description
1907 AdapterInfo - TODO: add argument description
1908 val - TODO: add argument description
1909 num_bits - TODO: add argument description
1913 TODO: add return values
1921 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
1923 for (Index
= num_bits
; Index
>= 0; Index
--) {
1929 dataval
= (INT16
) ((val
& (1 << Index
)) ? EE_DI
: 0);
1932 // mask off the data_in bit
1934 Tmp
= (UINT8
) (InByte (AdapterInfo
, EEAddr
) &~EE_DI
);
1936 OutByte (AdapterInfo
, Tmp
, EEAddr
);
1939 // raise the eeprom clock
1941 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
1944 // lower the eeprom clock
1946 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
1953 IN NIC_DATA_INSTANCE
*AdapterInfo
1957 Routine Description:
1959 TODO: Add function description
1963 AdapterInfo - TODO: add argument description
1967 TODO: add return values
1976 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
1979 for (Index
= 15; Index
>= 0; Index
--) {
1985 // mask off the data_in bit
1987 Tmp
= InByte (AdapterInfo
, EEAddr
);
1988 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
1990 Tmp
= InByte (AdapterInfo
, EEAddr
);
1991 retval
= (UINT16
) ((retval
<< 1) | ((Tmp
& EE_DO
) ? 1 : 0));
1995 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
2003 E100bSetEepromLockOut (
2004 IN NIC_DATA_INSTANCE
*AdapterInfo
2008 Routine Description:
2009 This routine sets the EEPROM lockout bit to gain exclusive access to the
2010 eeprom. the access bit is the most significant bit in the General Control
2011 Register 2 in the SCB space.
2014 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
2017 TRUE - if it got the access
2018 FALSE - if it fails to get the exclusive access
2025 if ((AdapterInfo
->DeviceID
== D102_DEVICE_ID
) ||
2026 (AdapterInfo
->RevID
>= D102_REVID
)) {
2032 tmp
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
2033 tmp
|= GCR2_EEPROM_ACCESS_SEMAPHORE
;
2034 OutByte (AdapterInfo
, tmp
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
2036 DelayIt (AdapterInfo
, 50);
2037 tmp
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
2039 if (tmp
& GCR2_EEPROM_ACCESS_SEMAPHORE
) {
2051 E100bReSetEepromLockOut (
2052 IN NIC_DATA_INSTANCE
*AdapterInfo
2056 Routine Description:
2057 This routine Resets the EEPROM lockout bit to giveup access to the
2058 eeprom. the access bit is the most significant bit in the General Control
2059 Register 2 in the SCB space.
2062 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
2071 if ((AdapterInfo
->DeviceID
== D102_DEVICE_ID
) ||
2072 (AdapterInfo
->RevID
>= D102_REVID
)) {
2074 tmp
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
2075 tmp
&= ~(GCR2_EEPROM_ACCESS_SEMAPHORE
);
2076 OutByte (AdapterInfo
, tmp
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
2078 DelayIt (AdapterInfo
, 50);
2084 IN NIC_DATA_INSTANCE
*AdapterInfo
,
2090 Routine Description:
2091 Using the NIC data structure information, read the EEPROM to get a Word of data for the MAC address.
2094 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
2095 Location - Word offset into the MAC address to read.
2096 AddrLen - Number of bits of address length.
2099 RetVal - The word read from the EEPROM.
2109 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
2110 ReadCmd
= (UINT16
) (Location
| (EE_READ_CMD
<< AddrLen
));
2115 // get exclusive access to the eeprom first!
2117 E100bSetEepromLockOut (AdapterInfo
);
2120 // eeprom control reg bits: x,x,x,x,DO,DI,CS,SK
2121 // to write the opcode+data value out one bit at a time in DI starting at msb
2122 // and then out a 1 to sk, wait, out 0 to SK and wait
2123 // repeat this for all the bits to be written
2129 Tmp
= (UINT8
) (InByte (AdapterInfo
, EEAddr
) & 0xF2);
2130 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_CS
), EEAddr
);
2133 // 3 for the read opcode 110b
2135 shift_bits_out (AdapterInfo
, ReadCmd
, (UINT8
) (3 + AddrLen
));
2138 // read the eeprom word one bit at a time
2140 RetVal
= shift_bits_in (AdapterInfo
);
2143 // Terminate the EEPROM access and leave eeprom in a clean state.
2145 Tmp
= InByte (AdapterInfo
, EEAddr
);
2146 Tmp
&= ~(EE_CS
| EE_DI
);
2147 OutByte (AdapterInfo
, Tmp
, EEAddr
);
2150 // raise the clock and lower the eeprom shift clock
2152 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
2155 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
2159 // giveup access to the eeprom
2161 E100bReSetEepromLockOut (AdapterInfo
);
2167 E100bGetEepromAddrLen (
2168 IN NIC_DATA_INSTANCE
*AdapterInfo
2172 Routine Description:
2173 Using the NIC data structure information, read the EEPROM to determine how many bits of address length
2174 this EEPROM is in Words.
2177 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
2180 RetVal - The word read from the EEPROM.
2188 // assume 64word eeprom (so,6 bits of address_length)
2192 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
2193 ReadCmd
= (EE_READ_CMD
<< 6);
2196 // get exclusive access to the eeprom first!
2198 E100bSetEepromLockOut (AdapterInfo
);
2201 // address we are trying to read is 0
2202 // eeprom control reg bits: x,x,x,x,DO,,DI,,CS,SK
2203 // to write the opcode+data value out one bit at a time in DI starting at msb
2204 // and then out a 1 to sk, wait, out 0 to SK and wait
2205 // repeat this for all the bits to be written
2207 Tmp
= (UINT8
) (InByte (AdapterInfo
, EEAddr
) & 0xF2);
2210 // enable eeprom access
2212 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_CS
), EEAddr
);
2215 // 3 for opcode, 6 for the default address len
2217 shift_bits_out (AdapterInfo
, ReadCmd
, (UINT8
) (3 + 6));
2220 // (in case of a 64 word eeprom).
2221 // read the "dummy zero" from EE_DO to say that the address we wrote
2222 // (six 0s) is accepted, write more zeros (until 8) to get a "dummy zero"
2226 // assume the smallest
2229 Tmp
= InByte (AdapterInfo
, EEAddr
);
2230 while ((AddrLen
< 8) && ((Tmp
& EE_DO
) != 0)) {
2231 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_DI
), EEAddr
);
2235 // raise the eeprom clock
2237 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
2241 // lower the eeprom clock
2243 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
2245 Tmp
= InByte (AdapterInfo
, EEAddr
);
2250 // read the eeprom word, even though we don't need this
2252 shift_bits_in (AdapterInfo
);
2255 // Terminate the EEPROM access.
2257 Tmp
= InByte (AdapterInfo
, EEAddr
);
2258 Tmp
&= ~(EE_CS
| EE_DI
);
2259 OutByte (AdapterInfo
, Tmp
, EEAddr
);
2262 // raise the clock and lower the eeprom shift clock
2264 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
2267 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
2271 // giveup access to the eeprom!
2273 E100bReSetEepromLockOut (AdapterInfo
);
2280 NIC_DATA_INSTANCE
*AdapterInfo
,
2286 Routine Description:
2288 TODO: Add function description
2292 AdapterInfo - TODO: add argument description
2293 DBaddr - TODO: add argument description
2294 DBsize - TODO: add argument description
2298 TODO: add return values
2302 PXE_DB_STATISTICS db
;
2304 // wait upto one second (each wait is 100 micro s)
2308 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
2311 // Clear statistics done marker.
2313 AdapterInfo
->statistics
->done_marker
= 0;
2316 // Issue statistics dump (or dump w/ reset) command.
2320 (UINT8
) (DBsize
? CU_SHOWSTATS
: CU_DUMPSTATS
),
2321 (UINT32
) (AdapterInfo
->ioaddr
+ SCBCmd
)
2325 // Wait for command to complete.
2327 // zero the db here just to chew up a little more time.
2330 ZeroMem ((VOID
*) &db
, sizeof db
);
2334 // Wait a bit before checking.
2337 DelayIt (AdapterInfo
, 100);
2340 // Look for done marker at end of statistics.
2343 switch (AdapterInfo
->statistics
->done_marker
) {
2354 // if we did not "continue" from the above switch, we are done,
2360 // If this is a reset, we are out of here!
2363 return PXE_STATCODE_SUCCESS
;
2367 // Convert NIC statistics counter format to EFI/UNDI
2368 // specification statistics counter format.
2372 // 54 3210 fedc ba98 7654 3210
2373 // db.Supported = 01 0000 0100 1101 0001 0111;
2375 db
.Supported
= 0x104D17;
2378 // Statistics from the NIC
2381 db
.Data
[0x01] = AdapterInfo
->statistics
->rx_good_frames
;
2383 db
.Data
[0x02] = AdapterInfo
->statistics
->rx_runt_errs
;
2385 db
.Data
[0x08] = AdapterInfo
->statistics
->rx_crc_errs
+
2386 AdapterInfo
->statistics
->rx_align_errs
;
2388 db
.Data
[0x04] = db
.Data
[0x02] +
2390 AdapterInfo
->statistics
->rx_resource_errs
+
2391 AdapterInfo
->statistics
->rx_overrun_errs
;
2393 db
.Data
[0x00] = db
.Data
[0x01] + db
.Data
[0x04];
2395 db
.Data
[0x0B] = AdapterInfo
->statistics
->tx_good_frames
;
2397 db
.Data
[0x0E] = AdapterInfo
->statistics
->tx_coll16_errs
+
2398 AdapterInfo
->statistics
->tx_late_colls
+
2399 AdapterInfo
->statistics
->tx_underruns
+
2400 AdapterInfo
->statistics
->tx_one_colls
+
2401 AdapterInfo
->statistics
->tx_multi_colls
;
2403 db
.Data
[0x14] = AdapterInfo
->statistics
->tx_total_colls
;
2405 db
.Data
[0x0A] = db
.Data
[0x0B] +
2407 AdapterInfo
->statistics
->tx_lost_carrier
;
2409 if (DBsize
> sizeof db
) {
2413 CopyMem ((VOID
*) (UINTN
) DBaddr
, (VOID
*) &db
, (UINTN
) DBsize
);
2415 return PXE_STATCODE_SUCCESS
;
2420 IN NIC_DATA_INSTANCE
*AdapterInfo
,
2425 Routine Description:
2427 TODO: Add function description
2431 AdapterInfo - TODO: add argument description
2432 OpFlags - TODO: add argument description
2436 TODO: add return values
2443 // disable the interrupts
2445 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
2448 // wait for the tx queue to complete
2450 CheckCBList (AdapterInfo
);
2452 XmitWaitForCompletion (AdapterInfo
);
2454 if (AdapterInfo
->Receive_Started
) {
2455 StopRU (AdapterInfo
);
2458 InitializeChip (AdapterInfo
);
2461 // check the opflags and restart receive filters
2463 if ((OpFlags
& PXE_OPFLAGS_RESET_DISABLE_FILTERS
) == 0) {
2465 save_filter
= AdapterInfo
->Rx_Filter
;
2467 // if we give the filter same as Rx_Filter,
2468 // this routine will not set mcast list (it thinks there is no change)
2469 // to force it, we will reset that flag in the Rx_Filter
2471 AdapterInfo
->Rx_Filter
&= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
);
2472 E100bSetfilter (AdapterInfo
, save_filter
, (UINT64
) 0, (UINT32
) 0);
2475 if ((OpFlags
& PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS
) != 0) {
2477 // disable the interrupts
2479 AdapterInfo
->int_mask
= 0;
2482 // else leave the interrupt in the pre-set state!!!
2484 E100bSetInterruptState (AdapterInfo
);
2491 IN NIC_DATA_INSTANCE
*AdapterInfo
2495 Routine Description:
2497 TODO: Add function description
2501 AdapterInfo - TODO: add argument description
2505 TODO: add return values
2510 // disable the interrupts
2512 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
2515 // stop the receive unit
2517 if (AdapterInfo
->Receive_Started
) {
2518 StopRU (AdapterInfo
);
2522 // wait for the tx queue to complete
2524 CheckCBList (AdapterInfo
);
2525 if (AdapterInfo
->FreeCBCount
!= AdapterInfo
->TxBufCnt
) {
2526 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
2530 // we do not want to reset the phy, it takes a long time to renegotiate the
2531 // link after that (3-4 seconds)
2533 InitializeChip (AdapterInfo
);
2534 SelectiveReset (AdapterInfo
);
2540 IN NIC_DATA_INSTANCE
*AdapterInfo
,
2541 IN UINT8 RegAddress
,
2542 IN UINT8 PhyAddress
,
2547 Routine Description:
2548 This routine will write a value to the specified MII register
2549 of an external MDI compliant device (e.g. PHY 100). The command will
2550 execute in polled mode.
2553 AdapterInfo - pointer to the structure that contains the NIC's context.
2554 RegAddress - The MII register that we are writing to
2555 PhyAddress - The MDI address of the Phy component.
2556 DataValue - The value that we are writing to the MII register.
2562 UINT32 WriteCommand
;
2564 WriteCommand
= ((UINT32
) DataValue
) |
2565 ((UINT32
)(RegAddress
<< 16)) |
2566 ((UINT32
)(PhyAddress
<< 21)) |
2567 ((UINT32
)(MDI_WRITE
<< 26));
2570 // Issue the write command to the MDI control register.
2572 OutLong (AdapterInfo
, WriteCommand
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
);
2575 // wait 20usec before checking status
2577 DelayIt (AdapterInfo
, 20);
2580 // poll for the mdi write to complete
2581 while ((InLong (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
) &
2582 MDI_PHY_READY
) == 0){
2583 DelayIt (AdapterInfo
, 20);
2589 IN NIC_DATA_INSTANCE
*AdapterInfo
,
2590 IN UINT8 RegAddress
,
2591 IN UINT8 PhyAddress
,
2592 IN OUT UINT16
*DataValue
2596 Routine Description:
2597 This routine will read a value from the specified MII register
2598 of an external MDI compliant device (e.g. PHY 100), and return
2599 it to the calling routine. The command will execute in polled mode.
2602 AdapterInfo - pointer to the structure that contains the NIC's context.
2603 RegAddress - The MII register that we are reading from
2604 PhyAddress - The MDI address of the Phy component.
2605 DataValue - pointer to the value that we read from the MII register.
2613 ReadCommand
= ((UINT32
) (RegAddress
<< 16)) |
2614 ((UINT32
) (PhyAddress
<< 21)) |
2615 ((UINT32
) (MDI_READ
<< 26));
2618 // Issue the read command to the MDI control register.
2620 OutLong (AdapterInfo
, ReadCommand
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
);
2623 // wait 20usec before checking status
2625 DelayIt (AdapterInfo
, 20);
2628 // poll for the mdi read to complete
2630 while ((InLong (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
) &
2631 MDI_PHY_READY
) == 0) {
2632 DelayIt (AdapterInfo
, 20);
2636 *DataValue
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
);
2641 NIC_DATA_INSTANCE
*AdapterInfo
2645 Routine Description:
2646 This routine will reset the PHY that the adapter is currently
2650 AdapterInfo - pointer to the structure that contains the NIC's context.
2656 UINT16 MdiControlReg
;
2658 MdiControlReg
= (MDI_CR_AUTO_SELECT
|
2659 MDI_CR_RESTART_AUTO_NEG
|
2663 // Write the MDI control register with our new Phy configuration
2668 AdapterInfo
->PhyAddress
,
2677 NIC_DATA_INSTANCE
*AdapterInfo
2681 Routine Description:
2682 This routine will detect what phy we are using, set the line
2683 speed, FDX or HDX, and configure the phy if necessary.
2685 The following combinations are supported:
2686 - TX or T4 PHY alone at PHY address 1
2687 - T4 or TX PHY at address 1 and MII PHY at address 0
2688 - 82503 alone (10Base-T mode, no full duplex support)
2689 - 82503 and MII PHY (TX or T4) at address 0
2691 The sequence / priority of detection is as follows:
2692 - PHY 1 with cable termination
2693 - PHY 0 with cable termination
2694 - PHY 1 (if found) without cable termination
2697 Additionally auto-negotiation capable (NWAY) and parallel
2698 detection PHYs are supported. The flow-chart is described in
2699 the 82557 software writer's manual.
2701 NOTE: 1. All PHY MDI registers are read in polled mode.
2702 2. The routines assume that the 82557 has been RESET and we have
2703 obtained the virtual memory address of the CSR.
2704 3. PhyDetect will not RESET the PHY.
2705 4. If FORCEFDX is set, SPEED should also be set. The driver will
2706 check the values for inconsistency with the detected PHY
2708 5. PHY 1 (the PHY on the adapter) may have an address in the range
2709 1 through 31 inclusive. The driver will accept addresses in
2711 6. Driver ignores FORCEFDX and SPEED overrides if a 503 interface
2715 AdapterInfo - pointer to the structure that contains the NIC's context.
2718 TRUE - If a Phy was detected, and configured correctly.
2719 FALSE - If a valid phy could not be detected and configured.
2724 UINT16 MdiControlReg
;
2725 UINT16 MdiStatusReg
;
2727 UINT8 ReNegotiateTime
;
2729 eedata
= (UINT16
*) (&AdapterInfo
->NVData
[0]);
2732 ReNegotiateTime
= 35;
2734 // EEPROM word [6] contains the Primary PHY record in which the least 3 bits
2735 // indicate the PHY address
2736 // and word [7] contains the secondary PHY record
2738 AdapterInfo
->PhyRecord
[0] = eedata
[6];
2739 AdapterInfo
->PhyRecord
[1] = eedata
[7];
2740 AdapterInfo
->PhyAddress
= (UINT8
) (AdapterInfo
->PhyRecord
[0] & 7);
2743 // Check for a phy address over-ride of 32 which indicates force use of 82503
2744 // not detecting the link in this case
2746 if (AdapterInfo
->PhyAddress
== 32) {
2748 // 503 interface over-ride
2749 // Record the current speed and duplex. We will be in half duplex
2750 // mode unless the user used the force full duplex over-ride.
2752 AdapterInfo
->LinkSpeed
= 10;
2757 // If the Phy Address is between 1-31 then we must first look for phy 1,
2760 if ((AdapterInfo
->PhyAddress
> 0) && (AdapterInfo
->PhyAddress
< 32)) {
2763 // Read the MDI control and status registers at phy 1
2764 // and check if we found a valid phy
2769 AdapterInfo
->PhyAddress
,
2776 AdapterInfo
->PhyAddress
,
2780 if (!((MdiControlReg
== 0xffff) ||
2781 ((MdiStatusReg
== 0) && (MdiControlReg
== 0)))) {
2784 // we have a valid phy1
2785 // Read the status register again because of sticky bits
2791 AdapterInfo
->PhyAddress
,
2796 // If there is a valid link then use this Phy.
2798 if (MdiStatusReg
& MDI_SR_LINK_STATUS
) {
2799 return (SetupPhy(AdapterInfo
));
2805 // Next try to detect a PHY at address 0x00 because there was no Phy 1,
2806 // or Phy 1 didn't have link, or we had a phy 0 over-ride
2810 // Read the MDI control and status registers at phy 0
2812 MdiRead (AdapterInfo
, MDI_CONTROL_REG
, 0, &MdiControlReg
);
2813 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2816 // check if we found a valid phy 0
2818 if (((MdiControlReg
== 0xffff) ||
2819 ((MdiStatusReg
== 0) && (MdiControlReg
== 0)))) {
2822 // we don't have a valid phy at address 0
2823 // if phy address was forced to 0, then error out because we
2824 // didn't find a phy at that address
2826 if (AdapterInfo
->PhyAddress
== 0x0000) {
2830 // at this point phy1 does not have link and there is no phy 0 at all
2831 // if we are forced to detect the cable, error out here!
2833 if (AdapterInfo
->CableDetect
!= 0) {
2840 // no phy 0, but there is a phy 1 (no link I guess), so use phy 1
2842 return SetupPhy (AdapterInfo
);
2845 // didn't find phy 0 or phy 1, so assume a 503 interface
2847 AdapterInfo
->PhyAddress
= 32;
2850 // Record the current speed and duplex. We'll be in half duplex
2851 // mode unless the user used the force full duplex over-ride.
2853 AdapterInfo
->LinkSpeed
= 10;
2859 // We have a valid phy at address 0. If phy 0 has a link then we use
2860 // phy 0. If Phy 0 doesn't have a link then we use Phy 1 (no link)
2861 // if phy 1 is present, or phy 0 if phy 1 is not present
2862 // If phy 1 was present, then we must isolate phy 1 before we enable
2863 // phy 0 to see if Phy 0 has a link.
2872 AdapterInfo
->PhyAddress
,
2877 // wait 100 microseconds for the phy to isolate.
2879 DelayIt (AdapterInfo
, 100);
2883 // Since this Phy is at address 0, we must enable it. So clear
2884 // the isolate bit, and set the auto-speed select bit
2894 // wait 100 microseconds for the phy to be enabled.
2896 DelayIt (AdapterInfo
, 100);
2899 // restart the auto-negotion process
2905 MDI_CR_RESTART_AUTO_NEG
| MDI_CR_AUTO_SELECT
2909 // wait no more than 3.5 seconds for auto-negotiation to complete
2911 while (ReNegotiateTime
) {
2913 // Read the status register twice because of sticky bits
2915 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2916 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2918 if (MdiStatusReg
& MDI_SR_AUTO_NEG_COMPLETE
) {
2922 DelayIt (AdapterInfo
, 100);
2927 // Read the status register again because of sticky bits
2929 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2932 // If the link was not set
2934 if ((MdiStatusReg
& MDI_SR_LINK_STATUS
) == 0) {
2936 // PHY1 does not have a link and phy 0 does not have a link
2937 // do not proceed if we need to detect the link!
2939 if (AdapterInfo
->CableDetect
!= 0) {
2944 // the link wasn't set, so use phy 1 if phy 1 was present
2950 MdiWrite (AdapterInfo
, MDI_CONTROL_REG
, 0, MDI_CR_ISOLATE
);
2953 // wait 100 microseconds for the phy to isolate.
2955 DelayIt (AdapterInfo
, 100);
2958 // Now re-enable PHY 1
2963 AdapterInfo
->PhyAddress
,
2968 // wait 100 microseconds for the phy to be enabled
2970 DelayIt (AdapterInfo
, 100);
2973 // restart the auto-negotion process
2978 AdapterInfo
->PhyAddress
,
2979 MDI_CR_RESTART_AUTO_NEG
| MDI_CR_AUTO_SELECT
2983 // Don't wait for it to complete (we didn't have link earlier)
2985 return (SetupPhy (AdapterInfo
));
2990 // Definitely using Phy 0
2992 AdapterInfo
->PhyAddress
= 0;
2993 return (SetupPhy(AdapterInfo
));
2999 IN NIC_DATA_INSTANCE
*AdapterInfo
3003 Routine Description:
3004 This routine will setup phy 1 or phy 0 so that it is configured
3005 to match a speed and duplex over-ride option. If speed or
3006 duplex mode is not explicitly specified in the registry, the
3007 driver will skip the speed and duplex over-ride code, and
3008 assume the adapter is automatically setting the line speed, and
3009 the duplex mode. At the end of this routine, any truly Phy
3010 specific code will be executed (each Phy has its own quirks,
3011 and some require that certain special bits are set).
3013 NOTE: The driver assumes that SPEED and FORCEFDX are specified at the
3014 same time. If FORCEDPX is set without speed being set, the driver
3015 will encouter a fatal error and log a message into the event viewer.
3018 AdapterInfo - pointer to the structure that contains the NIC's context.
3021 TRUE - If the phy could be configured correctly
3022 FALSE - If the phy couldn't be configured correctly, because an
3023 unsupported over-ride option was used
3027 UINT16 MdiControlReg
;
3028 UINT16 MdiStatusReg
;
3030 UINT16 MdiIdHighReg
;
3033 BOOLEAN ForcePhySetting
;
3035 ForcePhySetting
= FALSE
;
3038 // If we are NOT forcing a setting for line speed or full duplex, then
3039 // we won't force a link setting, and we'll jump down to the phy
3042 if (((AdapterInfo
->LinkSpeedReq
) || (AdapterInfo
->DuplexReq
))) {
3044 // Find out what kind of technology this Phy is capable of.
3049 AdapterInfo
->PhyAddress
,
3054 // Read the MDI control register at our phy
3059 AdapterInfo
->PhyAddress
,
3064 // Now check the validity of our forced option. If the force option is
3065 // valid, then force the setting. If the force option is not valid,
3066 // we'll set a flag indicating that we should error out.
3070 // If speed is forced to 10mb
3072 if (AdapterInfo
->LinkSpeedReq
== 10) {
3074 // If half duplex is forced
3076 if ((AdapterInfo
->DuplexReq
& PXE_FORCE_HALF_DUPLEX
) != 0) {
3077 if (MdiStatusReg
& MDI_SR_10T_HALF_DPX
) {
3079 MdiControlReg
&= ~(MDI_CR_10_100
| MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
3080 ForcePhySetting
= TRUE
;
3082 } else if ((AdapterInfo
->DuplexReq
& PXE_FORCE_FULL_DUPLEX
) != 0) {
3085 // If full duplex is forced
3087 if (MdiStatusReg
& MDI_SR_10T_FULL_DPX
) {
3089 MdiControlReg
&= ~(MDI_CR_10_100
| MDI_CR_AUTO_SELECT
);
3090 MdiControlReg
|= MDI_CR_FULL_HALF
;
3091 ForcePhySetting
= TRUE
;
3095 // If auto duplex (we actually set phy to 1/2)
3097 if (MdiStatusReg
& (MDI_SR_10T_FULL_DPX
| MDI_SR_10T_HALF_DPX
)) {
3099 MdiControlReg
&= ~(MDI_CR_10_100
| MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
3100 ForcePhySetting
= TRUE
;
3106 // If speed is forced to 100mb
3108 else if (AdapterInfo
->LinkSpeedReq
== 100) {
3110 // If half duplex is forced
3112 if ((AdapterInfo
->DuplexReq
& PXE_FORCE_HALF_DUPLEX
) != 0) {
3113 if (MdiStatusReg
& (MDI_SR_TX_HALF_DPX
| MDI_SR_T4_CAPABLE
)) {
3115 MdiControlReg
&= ~(MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
3116 MdiControlReg
|= MDI_CR_10_100
;
3117 ForcePhySetting
= TRUE
;
3119 } else if ((AdapterInfo
->DuplexReq
& PXE_FORCE_FULL_DUPLEX
) != 0) {
3121 // If full duplex is forced
3123 if (MdiStatusReg
& MDI_SR_TX_FULL_DPX
) {
3124 MdiControlReg
&= ~MDI_CR_AUTO_SELECT
;
3125 MdiControlReg
|= (MDI_CR_10_100
| MDI_CR_FULL_HALF
);
3126 ForcePhySetting
= TRUE
;
3130 // If auto duplex (we set phy to 1/2)
3132 if (MdiStatusReg
& (MDI_SR_TX_HALF_DPX
| MDI_SR_T4_CAPABLE
)) {
3134 MdiControlReg
&= ~(MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
3135 MdiControlReg
|= MDI_CR_10_100
;
3136 ForcePhySetting
= TRUE
;
3141 if (!ForcePhySetting
) {
3146 // Write the MDI control register with our new Phy configuration
3151 AdapterInfo
->PhyAddress
,
3156 // wait 100 milliseconds for auto-negotiation to complete
3158 DelayIt (AdapterInfo
, 100);
3162 // Find out specifically what Phy this is. We do this because for certain
3163 // phys there are specific bits that must be set so that the phy and the
3164 // 82557 work together properly.
3170 AdapterInfo
->PhyAddress
,
3176 AdapterInfo
->PhyAddress
,
3180 PhyId
= ((UINT32
) MdiIdLowReg
| ((UINT32
) MdiIdHighReg
<< 16));
3183 // And out the revsion field of the Phy ID so that we'll be able to detect
3184 // future revs of the same Phy.
3186 PhyId
&= PHY_MODEL_REV_ID_MASK
;
3189 // Handle the National TX
3191 if (PhyId
== PHY_NSC_TX
) {
3195 NSC_CONG_CONTROL_REG
,
3196 AdapterInfo
->PhyAddress
,
3200 MdiMiscReg
|= (NSC_TX_CONG_TXREADY
| NSC_TX_CONG_F_CONNECT
);
3202 #if CONGESTION_CONTROL
3204 // If we are configured to do congestion control, then enable the
3205 // congestion control bit in the National Phy
3207 if (AdapterInfo
->Congest
) {
3208 MdiMiscReg
|= NSC_TX_CONG_ENABLE
;
3210 MdiMiscReg
&= ~NSC_TX_CONG_ENABLE
;
3215 NSC_CONG_CONTROL_REG
,
3216 AdapterInfo
->PhyAddress
,
3221 FindPhySpeedAndDpx (AdapterInfo
, PhyId
);
3224 // We put a hardware fix on to our adapters to work-around the PHY_100 errata
3225 // described below. The following code is only compiled in, if we wanted
3226 // to attempt a software workaround to the PHY_100 A/B step problem.
3229 #if DO_PHY_100B_SOFTWARE_FIX
3231 // Handle the Intel PHY_100 (A and B steps)
3233 if ((PhyId
== PHY_100_A
) && (AdapterInfo
->LinkSpeed
== 100)) {
3235 // The PHY_100 is very sensitive to collisions at 100mb, so increase
3236 // the Adaptive IFS value with the intention of reducing the number of
3237 // collisions that the adapter generates.
3239 AdapterInfo
->CurrentIFSValue
= 0x18;
3240 AdapterInfo
->AdaptiveIFS
= 0;
3248 FindPhySpeedAndDpx (
3249 IN NIC_DATA_INSTANCE
*AdapterInfo
,
3254 Routine Description:
3255 This routine will figure out what line speed and duplex mode
3256 the PHY is currently using.
3259 AdapterInfo - pointer to the structure that contains the NIC's context.
3260 PhyId - The ID of the PHY in question.
3266 UINT16 MdiStatusReg
;
3269 UINT16 MdiLinkPartnerAdReg
;
3272 // If there was a speed and/or duplex override, then set our current
3273 // value accordingly
3275 AdapterInfo
->LinkSpeed
= AdapterInfo
->LinkSpeedReq
;
3276 AdapterInfo
->Duplex
= (UINT8
) ((AdapterInfo
->DuplexReq
& PXE_FORCE_FULL_DUPLEX
) ?
3277 FULL_DUPLEX
: HALF_DUPLEX
);
3280 // If speed and duplex were forced, then we know our current settings, so
3281 // we'll just return. Otherwise, we'll need to figure out what NWAY set
3284 if (AdapterInfo
->LinkSpeed
&& AdapterInfo
->Duplex
) {
3289 // If we didn't have a valid link, then we'll assume that our current
3290 // speed is 10mb half-duplex.
3294 // Read the status register twice because of sticky bits
3299 AdapterInfo
->PhyAddress
,
3305 AdapterInfo
->PhyAddress
,
3310 // If there wasn't a valid link then use default speed & duplex
3312 if (!(MdiStatusReg
& MDI_SR_LINK_STATUS
)) {
3314 AdapterInfo
->LinkSpeed
= 10;
3315 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3320 // If this is an Intel PHY (a T4 PHY_100 or a TX PHY_TX), then read bits
3321 // 1 and 0 of extended register 0, to get the current speed and duplex
3324 if ((PhyId
== PHY_100_A
) || (PhyId
== PHY_100_C
) || (PhyId
== PHY_TX_ID
)) {
3326 // Read extended register 0
3331 AdapterInfo
->PhyAddress
,
3336 // Get current speed setting
3338 if (MdiMiscReg
& PHY_100_ER0_SPEED_INDIC
) {
3339 AdapterInfo
->LinkSpeed
= 100;
3341 AdapterInfo
->LinkSpeed
= 10;
3345 // Get current duplex setting -- if bit is set then FDX is enabled
3347 if (MdiMiscReg
& PHY_100_ER0_FDX_INDIC
) {
3348 AdapterInfo
->Duplex
= FULL_DUPLEX
;
3350 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3356 // Read our link partner's advertisement register
3360 AUTO_NEG_LINK_PARTNER_REG
,
3361 AdapterInfo
->PhyAddress
,
3362 &MdiLinkPartnerAdReg
3366 // See if Auto-Negotiation was complete (bit 5, reg 1)
3371 AdapterInfo
->PhyAddress
,
3376 // If a True NWAY connection was made, then we can detect speed/duplex by
3377 // ANDing our adapter's advertised abilities with our link partner's
3378 // advertised ablilities, and then assuming that the highest common
3379 // denominator was chosed by NWAY.
3381 if ((MdiLinkPartnerAdReg
& NWAY_LP_ABILITY
) &&
3382 (MdiStatusReg
& MDI_SR_AUTO_NEG_COMPLETE
)) {
3385 // Read our advertisement register
3389 AUTO_NEG_ADVERTISE_REG
,
3390 AdapterInfo
->PhyAddress
,