2 Provides basic function upon network adapter card.
4 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
5 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 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
260 IN NIC_DATA_INSTANCE
*AdapterInfo
,
264 OUT UINT64 MappedAddr
269 PhyAddr
= (UINT64
*) (UINTN
) MappedAddr
;
271 // mapping is different for theold and new NII protocols
273 if (AdapterInfo
->VersionFlag
== 0x30) {
274 if (AdapterInfo
->Virt2Phys_30
== (VOID
*) NULL
) {
275 *PhyAddr
= (UINT64
) AdapterInfo
->MemoryPtr
;
277 (*AdapterInfo
->Virt2Phys_30
) (MemAddr
, (UINT64
) (UINTN
) PhyAddr
);
280 if (*PhyAddr
> FOUR_GIGABYTE
) {
281 return PXE_STATCODE_INVALID_PARAMETER
;
284 if (AdapterInfo
->Map_Mem
== (VOID
*) NULL
) {
286 // this UNDI cannot handle addresses beyond 4 GB without a map routine
288 if (MemAddr
> FOUR_GIGABYTE
) {
289 return PXE_STATCODE_INVALID_PARAMETER
;
294 (*AdapterInfo
->Map_Mem
) (
295 AdapterInfo
->Unique_ID
,
304 return PXE_STATCODE_SUCCESS
;
309 TODO: Add function description
311 @param AdapterInfo TODO: add argument description
312 @param MemAddr TODO: add argument description
313 @param Size TODO: add argument description
314 @param Direction TODO: add argument description
315 @param MappedAddr TODO: add argument description
317 @return TODO: add return values
322 IN NIC_DATA_INSTANCE
*AdapterInfo
,
329 if (AdapterInfo
->VersionFlag
> 0x30) {
331 // no mapping service
333 if (AdapterInfo
->UnMap_Mem
!= (VOID
*) NULL
) {
334 (*AdapterInfo
->UnMap_Mem
) (
335 AdapterInfo
->Unique_ID
,
351 @param AdapterInfo Pointer to the NIC data structure
352 information which the UNDI driver is
357 // TODO: MicroSeconds - add argument and description to function comment
360 IN NIC_DATA_INSTANCE
*AdapterInfo
,
364 if (AdapterInfo
->VersionFlag
== 0x30) {
365 (*AdapterInfo
->Delay_30
) (MicroSeconds
);
367 (*AdapterInfo
->Delay
) (AdapterInfo
->Unique_ID
, MicroSeconds
);
374 @param AdapterInfo Pointer to the NIC data structure
375 information which the UNDI driver is
380 // TODO: flag - add argument and description to function comment
383 IN NIC_DATA_INSTANCE
*AdapterInfo
,
387 if (AdapterInfo
->VersionFlag
== 0x30) {
388 (*AdapterInfo
->Block_30
) (flag
);
390 (*AdapterInfo
->Block
) (AdapterInfo
->Unique_ID
, flag
);
396 TODO: Add function description
398 @param AdapterInfo TODO: add argument description
400 @return TODO: add return values
405 NIC_DATA_INSTANCE
*AdapterInfo
409 // we will use the linear (flat) memory model and fill our base registers
410 // with 0's so that the entire physical address is our offset
413 // we reset the statistics totals here because this is where we are loading stats addr
415 AdapterInfo
->RxTotals
= 0;
416 AdapterInfo
->TxTotals
= 0;
419 // Load the statistics block address.
421 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
422 OutLong (AdapterInfo
, (UINT32
) AdapterInfo
->stat_phy_addr
, AdapterInfo
->ioaddr
+ SCBPointer
);
423 OutByte (AdapterInfo
, CU_STATSADDR
, AdapterInfo
->ioaddr
+ SCBCmd
);
424 AdapterInfo
->statistics
->done_marker
= 0;
426 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
427 OutLong (AdapterInfo
, 0, AdapterInfo
->ioaddr
+ SCBPointer
);
428 OutByte (AdapterInfo
, RX_ADDR_LOAD
, AdapterInfo
->ioaddr
+ SCBCmd
);
430 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
431 OutLong (AdapterInfo
, 0, AdapterInfo
->ioaddr
+ SCBPointer
);
432 OutByte (AdapterInfo
, CU_CMD_BASE
, AdapterInfo
->ioaddr
+ SCBCmd
);
439 TODO: Add function description
441 @param AdapterInfo TODO: add argument description
442 @param cmd_ptr TODO: add argument description
444 @return TODO: add return values
449 NIC_DATA_INSTANCE
*AdapterInfo
,
455 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
458 // read the CU status, if it is idle, write the address of cb_ptr
459 // in the scbpointer and issue a cu_start,
460 // if it is suspended, remove the suspend bit in the previous command
461 // block and issue a resume
463 // Ensure that the CU Active Status bit is not on from previous CBs.
465 status
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBStatus
);
468 // Skip acknowledging the interrupt if it is not already set
472 // ack only the cna the integer
474 if ((status
& SCB_STATUS_CNA
) != 0) {
475 OutWord (AdapterInfo
, SCB_STATUS_CNA
, AdapterInfo
->ioaddr
+ SCBStatus
);
479 if ((status
& SCB_STATUS_CU_MASK
) == SCB_STATUS_CU_IDLE
) {
483 OutLong (AdapterInfo
, cmd_ptr
->PhysTCBAddress
, AdapterInfo
->ioaddr
+ SCBPointer
);
484 OutByte (AdapterInfo
, CU_START
, AdapterInfo
->ioaddr
+ SCBCmd
);
487 // either active or suspended, give a resume
490 cmd_ptr
->PrevTCBVirtualLinkPtr
->cb_header
.command
&= ~(CmdSuspend
| CmdIntr
);
491 OutByte (AdapterInfo
, CU_RESUME
, AdapterInfo
->ioaddr
+ SCBCmd
);
499 TODO: Add function description
501 @param AdapterInfo TODO: add argument description
503 @return TODO: add return values
508 NIC_DATA_INSTANCE
*AdapterInfo
512 // all command blocks are of TxCB format
516 volatile INT16 Index
;
519 cmd_ptr
= GetFreeCB (AdapterInfo
);
520 ASSERT (cmd_ptr
!= NULL
);
521 data_ptr
= (UINT8
*) cmd_ptr
+ sizeof (struct CB_Header
);
524 // start the config data right after the command header
526 for (Index
= 0; Index
< sizeof (basic_config_cmd
); Index
++) {
527 data_ptr
[Index
] = basic_config_cmd
[Index
];
530 my_filter
= (UINT8
) ((AdapterInfo
->Rx_Filter
& PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS
) ? 1 : 0);
531 my_filter
= (UINT8
) (my_filter
| ((AdapterInfo
->Rx_Filter
& PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST
) ? 0 : 2));
533 data_ptr
[15] = (UINT8
) (data_ptr
[15] | my_filter
);
534 data_ptr
[19] = (UINT8
) (AdapterInfo
->Duplex
? 0xC0 : 0x80);
535 data_ptr
[21] = (UINT8
) ((AdapterInfo
->Rx_Filter
& PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST
) ? 0x0D : 0x05);
538 // check if we have to use the AUI port instead
540 if ((AdapterInfo
->PhyRecord
[0] & 0x8000) != 0) {
541 data_ptr
[15] |= 0x80;
545 BlockIt (AdapterInfo
, TRUE
);
546 cmd_ptr
->cb_header
.command
= CmdSuspend
| CmdConfigure
;
548 IssueCB (AdapterInfo
, cmd_ptr
);
549 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
551 BlockIt (AdapterInfo
, FALSE
);
553 CommandWaitForCompletion (cmd_ptr
, AdapterInfo
);
556 // restore the cb values for tx
558 cmd_ptr
->PhysTBDArrayAddres
= cmd_ptr
->PhysArrayAddr
;
559 cmd_ptr
->ByteCount
= cmd_ptr
->Threshold
= cmd_ptr
->TBDCount
= 0;
561 // fields beyond the immediatedata are assumed to be safe
562 // add the CB to the free list again
564 SetFreeCB (AdapterInfo
, cmd_ptr
);
570 TODO: Add function description
572 @param AdapterInfo TODO: add argument description
574 @return TODO: add return values
579 NIC_DATA_INSTANCE
*AdapterInfo
583 // all command blocks are of TxCB format
589 eaddrs
= (UINT16
*) AdapterInfo
->CurrentNodeAddress
;
591 cmd_ptr
= GetFreeCB (AdapterInfo
);
592 ASSERT (cmd_ptr
!= NULL
);
593 data_ptr
= (UINT16
*) ((UINT8
*) cmd_ptr
+sizeof (struct CB_Header
));
596 // AVOID a bug (?!) here by marking the command already completed.
598 cmd_ptr
->cb_header
.command
= (CmdSuspend
| CmdIASetup
);
599 cmd_ptr
->cb_header
.status
= 0;
600 data_ptr
[0] = eaddrs
[0];
601 data_ptr
[1] = eaddrs
[1];
602 data_ptr
[2] = eaddrs
[2];
604 BlockIt (AdapterInfo
, TRUE
);
605 IssueCB (AdapterInfo
, cmd_ptr
);
606 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
607 BlockIt (AdapterInfo
, FALSE
);
609 CommandWaitForCompletion (cmd_ptr
, AdapterInfo
);
612 // restore the cb values for tx
614 cmd_ptr
->PhysTBDArrayAddres
= cmd_ptr
->PhysArrayAddr
;
615 cmd_ptr
->ByteCount
= cmd_ptr
->Threshold
= cmd_ptr
->TBDCount
= 0;
617 // fields beyond the immediatedata are assumed to be safe
618 // add the CB to the free list again
620 SetFreeCB (AdapterInfo
, cmd_ptr
);
626 Instructs the NIC to stop receiving packets.
628 @param AdapterInfo Pointer to the NIC data structure
629 information which the UNDI driver is
636 IN NIC_DATA_INSTANCE
*AdapterInfo
639 if (AdapterInfo
->Receive_Started
) {
642 // Todo: verify that we must wait for previous command completion.
644 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
647 // Disable interrupts, and stop the chip's Rx process.
649 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
650 OutWord (AdapterInfo
, INT_MASK
| RX_ABORT
, AdapterInfo
->ioaddr
+ SCBCmd
);
652 AdapterInfo
->Receive_Started
= FALSE
;
660 Instructs the NIC to start receiving packets.
662 @param AdapterInfo Pointer to the NIC data structure
663 information which the UNDI driver is
667 @retval -1 Already Started
672 NIC_DATA_INSTANCE
*AdapterInfo
676 if (AdapterInfo
->Receive_Started
) {
683 AdapterInfo
->cur_rx_ind
= 0;
684 AdapterInfo
->Int_Status
= 0;
686 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
688 OutLong (AdapterInfo
, (UINT32
) AdapterInfo
->rx_phy_addr
, AdapterInfo
->ioaddr
+ SCBPointer
);
689 OutByte (AdapterInfo
, RX_START
, AdapterInfo
->ioaddr
+ SCBCmd
);
691 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
693 AdapterInfo
->Receive_Started
= TRUE
;
699 Configures the chip. This routine expects the NIC_DATA_INSTANCE structure to be filled in.
701 @param AdapterInfo Pointer to the NIC data structure
702 information which the UNDI driver is
706 @retval PXE_STATCODE_NOT_ENOUGH_MEMORY Insufficient length of locked memory
707 @retval other Failure initializing chip
712 IN NIC_DATA_INSTANCE
*AdapterInfo
715 PCI_CONFIG_HEADER
*CfgHdr
;
720 if (AdapterInfo
->MemoryLength
< MEMORY_NEEDED
) {
721 return PXE_STATCODE_NOT_ENOUGH_MEMORY
;
726 AdapterInfo
->MemoryPtr
,
727 AdapterInfo
->MemoryLength
,
729 (UINT64
)(UINTN
) &AdapterInfo
->Mapped_MemoryPtr
736 CfgHdr
= (PCI_CONFIG_HEADER
*) &(AdapterInfo
->Config
[0]);
739 // fill in the ioaddr, int... from the config space
741 AdapterInfo
->int_num
= CfgHdr
->int_line
;
744 // we don't need to validate integer number, what if they don't want to assign one?
745 // if (AdapterInfo->int_num == 0 || AdapterInfo->int_num == 0xff)
746 // return PXE_STATCODE_DEVICE_FAILURE;
748 AdapterInfo
->ioaddr
= 0;
749 AdapterInfo
->VendorID
= CfgHdr
->VendorID
;
750 AdapterInfo
->DeviceID
= CfgHdr
->DeviceID
;
751 AdapterInfo
->RevID
= CfgHdr
->RevID
;
752 AdapterInfo
->SubVendorID
= CfgHdr
->SubVendorID
;
753 AdapterInfo
->SubSystemID
= CfgHdr
->SubSystemID
;
754 AdapterInfo
->flash_addr
= 0;
757 // Read the station address EEPROM before doing the reset.
758 // Perhaps this should even be done before accepting the device,
759 // then we wouldn't have a device name with which to report the error.
761 if (E100bReadEepromAndStationAddress (AdapterInfo
) != 0) {
762 return PXE_STATCODE_DEVICE_FAILURE
;
766 // ## calculate the buffer #s depending on memory given
767 // ## calculate the rx and tx ring pointers
770 AdapterInfo
->TxBufCnt
= TX_BUFFER_COUNT
;
771 AdapterInfo
->RxBufCnt
= RX_BUFFER_COUNT
;
772 rx_size
= (AdapterInfo
->RxBufCnt
* sizeof (RxFD
));
773 tx_size
= (AdapterInfo
->TxBufCnt
* sizeof (TxCB
));
774 AdapterInfo
->rx_ring
= (RxFD
*) (UINTN
) (AdapterInfo
->MemoryPtr
);
775 AdapterInfo
->tx_ring
= (TxCB
*) (UINTN
) (AdapterInfo
->MemoryPtr
+ rx_size
);
776 AdapterInfo
->statistics
= (struct speedo_stats
*) (UINTN
) (AdapterInfo
->MemoryPtr
+ rx_size
+ tx_size
);
778 AdapterInfo
->rx_phy_addr
= AdapterInfo
->Mapped_MemoryPtr
;
779 AdapterInfo
->tx_phy_addr
= AdapterInfo
->Mapped_MemoryPtr
+ rx_size
;
780 AdapterInfo
->stat_phy_addr
= AdapterInfo
->tx_phy_addr
+ tx_size
;
785 AdapterInfo
->PhyAddress
= 0xFF;
786 AdapterInfo
->Rx_Filter
= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST
;
787 AdapterInfo
->Receive_Started
= FALSE
;
788 AdapterInfo
->mcast_list
.list_len
= 0;
789 return InitializeChip (AdapterInfo
);
794 Sets the interrupt state for the NIC.
796 @param AdapterInfo Pointer to the NIC data structure
797 information which the UNDI driver is
804 E100bSetInterruptState (
805 IN NIC_DATA_INSTANCE
*AdapterInfo
809 // don't set receive interrupt if receiver is disabled...
813 if ((AdapterInfo
->int_mask
& PXE_OPFLAGS_INTERRUPT_RECEIVE
) != 0) {
814 cmd_word
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCmd
);
815 cmd_word
&= ~INT_MASK
;
816 OutWord (AdapterInfo
, cmd_word
, AdapterInfo
->ioaddr
+ SCBCmd
);
819 // disable ints, should not be given for SW Int.
821 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
824 if ((AdapterInfo
->int_mask
& PXE_OPFLAGS_INTERRUPT_SOFTWARE
) != 0) {
826 // reset the bit in our mask, it is only one time!!
828 AdapterInfo
->int_mask
&= ~(PXE_OPFLAGS_INTERRUPT_SOFTWARE
);
829 cmd_word
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCmd
);
830 cmd_word
|= DRVR_INT
;
831 OutWord (AdapterInfo
, cmd_word
, AdapterInfo
->ioaddr
+ SCBCmd
);
837 // we are not going to disable broadcast for the WOL's sake!
841 Instructs the NIC to start receiving packets.
843 @param AdapterInfo Pointer to the NIC data structure
844 information which the UNDI driver is
845 layering on.. new_filter
850 @retval -1 Already Started
855 NIC_DATA_INSTANCE
*AdapterInfo
,
861 PXE_CPB_RECEIVE_FILTERS
*mc_list
= (PXE_CPB_RECEIVE_FILTERS
*) (UINTN
)cpb
;
868 struct MC_CB_STRUCT
*data_ptr
;
871 old_filter
= AdapterInfo
->Rx_Filter
;
874 // only these bits need a change in the configuration
875 // actually change in bcast requires configure but we ignore that change
877 cfg_flt
= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS
|
878 PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST
;
880 if ((old_filter
& cfg_flt
) != (new_filter
& cfg_flt
)) {
881 XmitWaitForCompletion (AdapterInfo
);
883 if (AdapterInfo
->Receive_Started
) {
884 StopRU (AdapterInfo
);
887 AdapterInfo
->Rx_Filter
= (UINT8
) (new_filter
| PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST
);
888 Configure (AdapterInfo
);
892 // check if mcast setting changed
894 if ( ((new_filter
& PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
) !=
895 (old_filter
& PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
) ) ||
896 (mc_list
!= NULL
) ) {
899 if (mc_list
!= NULL
) {
900 mc_count
= AdapterInfo
->mcast_list
.list_len
= (UINT16
) (cpbsize
/ PXE_MAC_LENGTH
);
902 for (Index
= 0; (Index
< mc_count
&& Index
< MAX_MCAST_ADDRESS_CNT
); Index
++) {
903 for (Index2
= 0; Index2
< PXE_MAC_LENGTH
; Index2
++) {
904 AdapterInfo
->mcast_list
.mc_list
[Index
][Index2
] = mc_list
->MCastList
[Index
][Index2
];
910 // are we setting the list or resetting??
912 if ((new_filter
& PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
) != 0) {
914 // we are setting a new list!
916 mc_count
= AdapterInfo
->mcast_list
.list_len
;
918 // count should be the actual # of bytes in the list
919 // so multiply this with 6
921 mc_byte_cnt
= (UINT16
) ((mc_count
<< 2) + (mc_count
<< 1));
922 AdapterInfo
->Rx_Filter
|= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
;
925 // disabling the list in the NIC.
927 mc_byte_cnt
= mc_count
= 0;
928 AdapterInfo
->Rx_Filter
&= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
);
932 // before issuing any new command!
934 XmitWaitForCompletion (AdapterInfo
);
936 if (AdapterInfo
->Receive_Started
) {
937 StopRU (AdapterInfo
);
941 cmd_ptr
= GetFreeCB (AdapterInfo
);
942 if (cmd_ptr
== NULL
) {
943 return PXE_STATCODE_QUEUE_FULL
;
946 // fill the command structure and issue
948 data_ptr
= (struct MC_CB_STRUCT
*) (&cmd_ptr
->PhysTBDArrayAddres
);
950 // first 2 bytes are the count;
952 data_ptr
->count
= mc_byte_cnt
;
953 for (Index
= 0; Index
< mc_count
; Index
++) {
954 for (Index2
= 0; Index2
< PXE_HWADDR_LEN_ETHER
; Index2
++) {
955 data_ptr
->m_list
[Index
][Index2
] = AdapterInfo
->mcast_list
.mc_list
[Index
][Index2
];
959 cmd_ptr
->cb_header
.command
= CmdSuspend
| CmdMulticastList
;
960 cmd_ptr
->cb_header
.status
= 0;
962 BlockIt (AdapterInfo
, TRUE
);
963 IssueCB (AdapterInfo
, cmd_ptr
);
964 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
966 BlockIt (AdapterInfo
, FALSE
);
968 CommandWaitForCompletion (cmd_ptr
, AdapterInfo
);
970 cmd_ptr
->PhysTBDArrayAddres
= cmd_ptr
->PhysArrayAddr
;
971 cmd_ptr
->ByteCount
= cmd_ptr
->Threshold
= cmd_ptr
->TBDCount
= 0;
973 // fields beyond the immediatedata are assumed to be safe
974 // add the CB to the free list again
976 SetFreeCB (AdapterInfo
, cmd_ptr
);
979 if (new_filter
!= 0) {
981 // enable unicast and start the RU
983 AdapterInfo
->Rx_Filter
= (UINT8
) (AdapterInfo
->Rx_Filter
| (new_filter
| PXE_OPFLAGS_RECEIVE_FILTER_UNICAST
));
984 StartRU (AdapterInfo
);
987 // may be disabling everything!
989 if (AdapterInfo
->Receive_Started
) {
990 StopRU (AdapterInfo
);
993 AdapterInfo
->Rx_Filter
|= (~PXE_OPFLAGS_RECEIVE_FILTER_UNICAST
);
1001 TODO: Add function description
1003 @param AdapterInfo TODO: add argument description
1004 @param cpb TODO: add argument description
1005 @param opflags TODO: add argument description
1007 @return TODO: add return values
1012 NIC_DATA_INSTANCE
*AdapterInfo
,
1017 PXE_CPB_TRANSMIT_FRAGMENTS
*tx_ptr_f
;
1018 PXE_CPB_TRANSMIT
*tx_ptr_1
;
1025 tx_ptr_1
= (PXE_CPB_TRANSMIT
*) (UINTN
) cpb
;
1026 tx_ptr_f
= (PXE_CPB_TRANSMIT_FRAGMENTS
*) (UINTN
) cpb
;
1030 // stop reentrancy here
1032 if (AdapterInfo
->in_transmit
) {
1033 return PXE_STATCODE_BUSY
;
1037 AdapterInfo
->in_transmit
= TRUE
;
1040 // Prevent interrupts from changing the Tx ring from underneath us.
1042 // Calculate the Tx descriptor entry.
1044 if ((tcb_ptr
= GetFreeCB (AdapterInfo
)) == NULL
) {
1045 AdapterInfo
->in_transmit
= FALSE
;
1046 return PXE_STATCODE_QUEUE_FULL
;
1049 AdapterInfo
->TxTotals
++;
1051 tcb_ptr
->cb_header
.command
= (CmdSuspend
| CmdTx
| CmdTxFlex
);
1052 tcb_ptr
->cb_header
.status
= 0;
1055 // no immediate data, set EOF in the ByteCount
1057 tcb_ptr
->ByteCount
= 0x8000;
1060 // The data region is always in one buffer descriptor, Tx FIFO
1061 // threshold of 256.
1062 // 82557 multiplies the threashold value by 8, so give 256/8
1064 tcb_ptr
->Threshold
= 32;
1065 if ((opflags
& PXE_OPFLAGS_TRANSMIT_FRAGMENTED
) != 0) {
1067 if (tx_ptr_f
->FragCnt
> MAX_XMIT_FRAGMENTS
) {
1068 SetFreeCB (AdapterInfo
, tcb_ptr
);
1069 AdapterInfo
->in_transmit
= FALSE
;
1070 return PXE_STATCODE_INVALID_PARAMETER
;
1073 tcb_ptr
->TBDCount
= (UINT8
) tx_ptr_f
->FragCnt
;
1075 for (Index
= 0; Index
< tx_ptr_f
->FragCnt
; Index
++) {
1078 tx_ptr_f
->FragDesc
[Index
].FragAddr
,
1079 tx_ptr_f
->FragDesc
[Index
].FragLen
,
1081 (UINT64
)(UINTN
) &Tmp_ptr
1084 SetFreeCB (AdapterInfo
, tcb_ptr
);
1085 AdapterInfo
->in_transmit
= FALSE
;
1086 return PXE_STATCODE_INVALID_PARAMETER
;
1089 tcb_ptr
->TBDArray
[Index
].phys_buf_addr
= (UINT32
) Tmp_ptr
;
1090 tcb_ptr
->TBDArray
[Index
].buf_len
= tx_ptr_f
->FragDesc
[Index
].FragLen
;
1093 tcb_ptr
->free_data_ptr
= tx_ptr_f
->FragDesc
[0].FragAddr
;
1097 // non fragmented case
1099 tcb_ptr
->TBDCount
= 1;
1102 tx_ptr_1
->FrameAddr
,
1103 tx_ptr_1
->DataLen
+ tx_ptr_1
->MediaheaderLen
,
1105 (UINT64
)(UINTN
) &Tmp_ptr
1108 SetFreeCB (AdapterInfo
, tcb_ptr
);
1109 AdapterInfo
->in_transmit
= FALSE
;
1110 return PXE_STATCODE_INVALID_PARAMETER
;
1113 tcb_ptr
->TBDArray
[0].phys_buf_addr
= (UINT32
) (Tmp_ptr
);
1114 tcb_ptr
->TBDArray
[0].buf_len
= tx_ptr_1
->DataLen
+ tx_ptr_1
->MediaheaderLen
;
1115 tcb_ptr
->free_data_ptr
= tx_ptr_1
->FrameAddr
;
1119 // must wait for previous command completion only if it was a non-transmit
1121 BlockIt (AdapterInfo
, TRUE
);
1122 IssueCB (AdapterInfo
, tcb_ptr
);
1123 BlockIt (AdapterInfo
, FALSE
);
1126 // see if we need to wait for completion here
1128 if ((opflags
& PXE_OPFLAGS_TRANSMIT_BLOCK
) != 0) {
1130 // don't wait for more than 1 second!!!
1133 while (tcb_ptr
->cb_header
.status
== 0) {
1134 DelayIt (AdapterInfo
, 10);
1136 if (wait_sec
== 0) {
1141 // we need to un-map any mapped buffers here
1143 if ((opflags
& PXE_OPFLAGS_TRANSMIT_FRAGMENTED
) != 0) {
1145 for (Index
= 0; Index
< tx_ptr_f
->FragCnt
; Index
++) {
1146 Tmp_ptr
= tcb_ptr
->TBDArray
[Index
].phys_buf_addr
;
1149 tx_ptr_f
->FragDesc
[Index
].FragAddr
,
1150 tx_ptr_f
->FragDesc
[Index
].FragLen
,
1156 Tmp_ptr
= tcb_ptr
->TBDArray
[0].phys_buf_addr
;
1159 tx_ptr_1
->FrameAddr
,
1160 tx_ptr_1
->DataLen
+ tx_ptr_1
->MediaheaderLen
,
1166 if (tcb_ptr
->cb_header
.status
== 0) {
1167 SetFreeCB (AdapterInfo
, tcb_ptr
);
1168 AdapterInfo
->in_transmit
= FALSE
;
1169 return PXE_STATCODE_DEVICE_FAILURE
;
1172 SetFreeCB (AdapterInfo
, tcb_ptr
);
1175 // CB will be set free later in get_status (or when we run out of xmit buffers
1177 AdapterInfo
->in_transmit
= FALSE
;
1184 TODO: Add function description
1186 @param AdapterInfo TODO: add argument description
1187 @param cpb TODO: add argument description
1188 @param db TODO: add argument description
1190 @return TODO: add return values
1195 NIC_DATA_INSTANCE
*AdapterInfo
,
1200 PXE_CPB_RECEIVE
*rx_cpbptr
;
1201 PXE_DB_RECEIVE
*rx_dbptr
;
1207 PXE_FRAME_TYPE pkt_type
;
1209 EtherHeader
*hdr_ptr
;
1210 ret_code
= PXE_STATCODE_NO_DATA
;
1211 pkt_type
= PXE_FRAME_TYPE_NONE
;
1212 status
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBStatus
);
1213 AdapterInfo
->Int_Status
= (UINT16
) (AdapterInfo
->Int_Status
| status
);
1215 // acknoledge the interrupts
1217 OutWord (AdapterInfo
, (UINT16
) (status
& 0xfc00), (UINT32
) (AdapterInfo
->ioaddr
+ SCBStatus
));
1220 // include the prev ints as well
1222 status
= AdapterInfo
->Int_Status
;
1223 rx_cpbptr
= (PXE_CPB_RECEIVE
*) (UINTN
) cpb
;
1224 rx_dbptr
= (PXE_DB_RECEIVE
*) (UINTN
) db
;
1226 rx_ptr
= &AdapterInfo
->rx_ring
[AdapterInfo
->cur_rx_ind
];
1229 // be in a loop just in case (we may drop a pkt)
1231 while ((status
= rx_ptr
->cb_header
.status
) & RX_COMPLETE
) {
1233 AdapterInfo
->RxTotals
++;
1235 // If we own the next entry, it's a new packet. Send it up.
1237 if (rx_ptr
->forwarded
) {
1243 // discard bad frames
1247 // crc, align, dma overrun, too short, receive error (v22 no coll)
1249 if ((status
& 0x0D90) != 0) {
1255 // make sure the status is OK
1257 if ((status
& 0x02000) == 0) {
1261 pkt_len
= (UINT16
) (rx_ptr
->ActualCount
& 0x3fff);
1266 if (pkt_len
> rx_cpbptr
->BufferLen
) {
1267 Tmp_len
= (UINT16
) rx_cpbptr
->BufferLen
;
1270 CopyMem ((INT8
*) (UINTN
) rx_cpbptr
->BufferAddr
, (INT8
*) &rx_ptr
->RFDBuffer
, Tmp_len
);
1272 hdr_ptr
= (EtherHeader
*) &rx_ptr
->RFDBuffer
;
1274 // fill the CDB and break the loop
1280 rx_dbptr
->FrameLen
= pkt_len
;
1281 rx_dbptr
->MediaHeaderLen
= PXE_MAC_HEADER_LEN_ETHER
;
1283 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1284 if (hdr_ptr
->dest_addr
[Index
] != AdapterInfo
->CurrentNodeAddress
[Index
]) {
1289 if (Index
>= PXE_HWADDR_LEN_ETHER
) {
1290 pkt_type
= PXE_FRAME_TYPE_UNICAST
;
1292 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1293 if (hdr_ptr
->dest_addr
[Index
] != AdapterInfo
->BroadcastNodeAddress
[Index
]) {
1298 if (Index
>= PXE_HWADDR_LEN_ETHER
) {
1299 pkt_type
= PXE_FRAME_TYPE_BROADCAST
;
1301 if ((hdr_ptr
->dest_addr
[0] & 1) == 1) {
1306 pkt_type
= PXE_FRAME_TYPE_FILTERED_MULTICAST
;
1308 pkt_type
= PXE_FRAME_TYPE_PROMISCUOUS
;
1313 rx_dbptr
->Type
= pkt_type
;
1314 rx_dbptr
->Protocol
= hdr_ptr
->type
;
1316 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1317 rx_dbptr
->SrcAddr
[Index
] = hdr_ptr
->src_addr
[Index
];
1318 rx_dbptr
->DestAddr
[Index
] = hdr_ptr
->dest_addr
[Index
];
1321 rx_ptr
->forwarded
= TRUE
;
1326 Recycle_RFD (AdapterInfo
, AdapterInfo
->cur_rx_ind
);
1327 AdapterInfo
->cur_rx_ind
++;
1328 if (AdapterInfo
->cur_rx_ind
== AdapterInfo
->RxBufCnt
) {
1329 AdapterInfo
->cur_rx_ind
= 0;
1335 Recycle_RFD (AdapterInfo
, AdapterInfo
->cur_rx_ind
);
1336 AdapterInfo
->cur_rx_ind
++;
1337 if (AdapterInfo
->cur_rx_ind
== AdapterInfo
->RxBufCnt
) {
1338 AdapterInfo
->cur_rx_ind
= 0;
1341 rx_ptr
= &AdapterInfo
->rx_ring
[AdapterInfo
->cur_rx_ind
];
1344 if (pkt_type
== PXE_FRAME_TYPE_NONE
) {
1345 AdapterInfo
->Int_Status
&= (~SCB_STATUS_FR
);
1348 status
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBStatus
);
1349 if ((status
& SCB_RUS_NO_RESOURCES
) != 0) {
1351 // start the receive unit here!
1352 // leave all the filled frames,
1354 SetupReceiveQueues (AdapterInfo
);
1355 OutLong (AdapterInfo
, (UINT32
) AdapterInfo
->rx_phy_addr
, AdapterInfo
->ioaddr
+ SCBPointer
);
1356 OutWord (AdapterInfo
, RX_START
, AdapterInfo
->ioaddr
+ SCBCmd
);
1357 AdapterInfo
->cur_rx_ind
= 0;
1365 TODO: Add function description
1367 @param AdapterInfo TODO: add argument description
1369 @return TODO: add return values
1373 E100bReadEepromAndStationAddress (
1374 NIC_DATA_INSTANCE
*AdapterInfo
1384 eedata
= (UINT16
*) (&AdapterInfo
->NVData
[0]);
1387 addr_len
= E100bGetEepromAddrLen (AdapterInfo
);
1392 AdapterInfo
->NVData_Len
= eeprom_len
= (UINT16
) (1 << addr_len
);
1393 for (Index2
= 0, Index
= 0; ((Index2
< PXE_MAC_LENGTH
- 1) && (Index
< eeprom_len
)); Index
++) {
1395 value
= E100bReadEeprom (AdapterInfo
, Index
, addr_len
);
1396 eedata
[Index
] = value
;
1397 sum
= (UINT16
) (sum
+ value
);
1399 AdapterInfo
->PermNodeAddress
[Index2
++] = (UINT8
) value
;
1400 AdapterInfo
->PermNodeAddress
[Index2
++] = (UINT8
) (value
>> 8);
1404 if (sum
!= 0xBABA) {
1408 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1409 AdapterInfo
->CurrentNodeAddress
[Index
] = AdapterInfo
->PermNodeAddress
[Index
];
1412 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1413 AdapterInfo
->BroadcastNodeAddress
[Index
] = 0xff;
1416 for (Index
= PXE_HWADDR_LEN_ETHER
; Index
< PXE_MAC_LENGTH
; Index
++) {
1417 AdapterInfo
->CurrentNodeAddress
[Index
] = 0;
1418 AdapterInfo
->PermNodeAddress
[Index
] = 0;
1419 AdapterInfo
->BroadcastNodeAddress
[Index
] = 0;
1426 // CBList is a circular linked list
1427 // 1) When all are free, Tail->next == Head and FreeCount == # allocated
1428 // 2) When none are free, Tail == Head and FreeCount == 0
1429 // 3) when one is free, Tail == Head and Freecount == 1
1430 // 4) First non-Free frame is always at Tail->next
1434 TODO: Add function description
1436 @param AdapterInfo TODO: add argument description
1438 @return TODO: add return values
1443 NIC_DATA_INSTANCE
*AdapterInfo
1452 cur_ptr
= &(AdapterInfo
->tx_ring
[0]);
1453 array_off
= (UINTN
) (&cur_ptr
->TBDArray
) - (UINTN
) cur_ptr
;
1454 for (Index
= 0; Index
< AdapterInfo
->TxBufCnt
; Index
++) {
1455 cur_ptr
[Index
].cb_header
.status
= 0;
1456 cur_ptr
[Index
].cb_header
.command
= 0;
1458 cur_ptr
[Index
].PhysTCBAddress
=
1459 (UINT32
) AdapterInfo
->tx_phy_addr
+ (Index
* sizeof (TxCB
));
1461 cur_ptr
[Index
].PhysArrayAddr
= (UINT32
)(cur_ptr
[Index
].PhysTCBAddress
+ array_off
);
1462 cur_ptr
[Index
].PhysTBDArrayAddres
= (UINT32
)(cur_ptr
[Index
].PhysTCBAddress
+ array_off
);
1464 cur_ptr
->free_data_ptr
= (UINT64
) 0;
1466 if (Index
< AdapterInfo
->TxBufCnt
- 1) {
1467 cur_ptr
[Index
].cb_header
.link
= cur_ptr
[Index
].PhysTCBAddress
+ sizeof (TxCB
);
1468 cur_ptr
[Index
].NextTCBVirtualLinkPtr
= &cur_ptr
[Index
+ 1];
1469 cur_ptr
[Index
+ 1].PrevTCBVirtualLinkPtr
= &cur_ptr
[Index
];
1473 head_ptr
= &cur_ptr
[0];
1474 tail_ptr
= &cur_ptr
[AdapterInfo
->TxBufCnt
- 1];
1475 tail_ptr
->cb_header
.link
= head_ptr
->PhysTCBAddress
;
1476 tail_ptr
->NextTCBVirtualLinkPtr
= head_ptr
;
1477 head_ptr
->PrevTCBVirtualLinkPtr
= tail_ptr
;
1479 AdapterInfo
->FreeCBCount
= AdapterInfo
->TxBufCnt
;
1480 AdapterInfo
->FreeTxHeadPtr
= head_ptr
;
1482 // set tail of the free list, next to this would be either in use
1483 // or the head itself
1485 AdapterInfo
->FreeTxTailPtr
= tail_ptr
;
1487 AdapterInfo
->xmit_done_head
= AdapterInfo
->xmit_done_tail
= 0;
1494 TODO: Add function description
1496 @param AdapterInfo TODO: add argument description
1498 @return TODO: add return values
1503 NIC_DATA_INSTANCE
*AdapterInfo
1509 // claim any hanging free CBs
1511 if (AdapterInfo
->FreeCBCount
<= 1) {
1512 CheckCBList (AdapterInfo
);
1516 // don't use up the last CB problem if the previous CB that the CU used
1517 // becomes the last CB we submit because of the SUSPEND bit we set.
1518 // the CU thinks it was never cleared.
1521 if (AdapterInfo
->FreeCBCount
<= 1) {
1525 BlockIt (AdapterInfo
, TRUE
);
1526 free_cb_ptr
= AdapterInfo
->FreeTxHeadPtr
;
1527 AdapterInfo
->FreeTxHeadPtr
= free_cb_ptr
->NextTCBVirtualLinkPtr
;
1528 --AdapterInfo
->FreeCBCount
;
1529 BlockIt (AdapterInfo
, FALSE
);
1535 TODO: Add function description
1537 @param AdapterInfo TODO: add argument description
1538 @param cb_ptr TODO: add argument description
1540 @return TODO: add return values
1545 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1550 // here we assume cb are returned in the order they are taken out
1551 // and we link the newly freed cb at the tail of free cb list
1553 cb_ptr
->cb_header
.status
= 0;
1554 cb_ptr
->free_data_ptr
= (UINT64
) 0;
1556 AdapterInfo
->FreeTxTailPtr
= cb_ptr
;
1557 ++AdapterInfo
->FreeCBCount
;
1563 TODO: Add function description
1565 @param ind TODO: add argument description
1567 @return TODO: add return values
1577 Tmp
= (UINT16
) (ind
+ 1);
1578 if (Tmp
>= (TX_BUFFER_COUNT
<< 1)) {
1587 TODO: Add function description
1589 @param AdapterInfo TODO: add argument description
1591 @return TODO: add return values
1596 IN NIC_DATA_INSTANCE
*AdapterInfo
1604 Tmp_ptr
= AdapterInfo
->FreeTxTailPtr
->NextTCBVirtualLinkPtr
;
1605 if ((Tmp_ptr
->cb_header
.status
& CMD_STATUS_MASK
) != 0) {
1607 // check if Q is full
1609 if (next (AdapterInfo
->xmit_done_tail
) != AdapterInfo
->xmit_done_head
) {
1610 ASSERT (AdapterInfo
->xmit_done_tail
< TX_BUFFER_COUNT
<< 1);
1611 AdapterInfo
->xmit_done
[AdapterInfo
->xmit_done_tail
] = Tmp_ptr
->free_data_ptr
;
1615 Tmp_ptr
->free_data_ptr
,
1616 Tmp_ptr
->TBDArray
[0].buf_len
,
1618 (UINT64
) Tmp_ptr
->TBDArray
[0].phys_buf_addr
1621 AdapterInfo
->xmit_done_tail
= next (AdapterInfo
->xmit_done_tail
);
1624 SetFreeCB (AdapterInfo
, Tmp_ptr
);
1633 // Description : Initialize the RFD list list by linking each element together
1634 // in a circular list. The simplified memory model is used.
1635 // All data is in the RFD. The RFDs are linked together and the
1636 // last one points back to the first one. When the current RFD
1637 // is processed (frame received), its EL bit is set and the EL
1638 // bit in the previous RXFD is cleared.
1639 // Allocation done during INIT, this is making linked list.
1643 TODO: Add function description
1645 @param AdapterInfo TODO: add argument description
1647 @return TODO: add return values
1651 SetupReceiveQueues (
1652 IN NIC_DATA_INSTANCE
*AdapterInfo
1659 AdapterInfo
->cur_rx_ind
= 0;
1660 rx_ptr
= (&AdapterInfo
->rx_ring
[0]);
1662 for (Index
= 0; Index
< AdapterInfo
->RxBufCnt
; Index
++) {
1663 rx_ptr
[Index
].cb_header
.status
= 0;
1664 rx_ptr
[Index
].cb_header
.command
= 0;
1665 rx_ptr
[Index
].RFDSize
= RX_BUFFER_SIZE
;
1666 rx_ptr
[Index
].ActualCount
= 0;
1668 // RBDs not used, simple memory model
1670 rx_ptr
[Index
].rx_buf_addr
= (UINT32
) (-1);
1673 // RBDs not used, simple memory model
1675 rx_ptr
[Index
].forwarded
= FALSE
;
1678 // don't use Tmp_ptr if it is beyond the last one
1680 if (Index
< AdapterInfo
->RxBufCnt
- 1) {
1681 rx_ptr
[Index
].cb_header
.link
= (UINT32
) AdapterInfo
->rx_phy_addr
+ ((Index
+ 1) * sizeof (RxFD
));
1685 tail_ptr
= (&AdapterInfo
->rx_ring
[AdapterInfo
->RxBufCnt
- 1]);
1686 tail_ptr
->cb_header
.link
= (UINT32
) AdapterInfo
->rx_phy_addr
;
1691 tail_ptr
->cb_header
.command
= 0xC000;
1692 AdapterInfo
->RFDTailPtr
= tail_ptr
;
1698 TODO: Add function description
1700 @param AdapterInfo TODO: add argument description
1701 @param rx_index TODO: add argument description
1703 @return TODO: add return values
1708 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1715 // change the EL bit and change the AdapterInfo->RxTailPtr
1716 // rx_ptr is assumed to be the head of the Q
1717 // AdapterInfo->rx_forwarded[rx_index] = FALSE;
1719 rx_ptr
= &AdapterInfo
->rx_ring
[rx_index
];
1720 tail_ptr
= AdapterInfo
->RFDTailPtr
;
1722 // set el_bit and suspend bit
1724 rx_ptr
->cb_header
.command
= 0xc000;
1725 rx_ptr
->cb_header
.status
= 0;
1726 rx_ptr
->ActualCount
= 0;
1727 rx_ptr
->forwarded
= FALSE
;
1728 AdapterInfo
->RFDTailPtr
= rx_ptr
;
1730 // resetting the el_bit.
1732 tail_ptr
->cb_header
.command
= 0;
1734 // check the receive unit, fix if there is any problem
1739 // Serial EEPROM section.
1741 // EEPROM_Ctrl bits.
1743 #define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */
1744 #define EE_CS 0x02 /* EEPROM chip select. */
1745 #define EE_DI 0x04 /* EEPROM chip data in. */
1746 #define EE_WRITE_0 0x01
1747 #define EE_WRITE_1 0x05
1748 #define EE_DO 0x08 /* EEPROM chip data out. */
1749 #define EE_ENB (0x4800 | EE_CS)
1752 // Delay between EEPROM clock transitions.
1753 // This will actually work with no delay on 33Mhz PCI.
1755 #define eeprom_delay(nanosec) DelayIt (AdapterInfo, nanosec);
1758 // The EEPROM commands include the alway-set leading bit.
1760 #define EE_WRITE_CMD 5 // 101b
1761 #define EE_READ_CMD 6 // 110b
1762 #define EE_ERASE_CMD (7 << 6)
1766 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1772 Routine Description:
1774 TODO: Add function description
1778 AdapterInfo - TODO: add argument description
1779 val - TODO: add argument description
1780 num_bits - TODO: add argument description
1784 TODO: add return values
1792 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
1794 for (Index
= num_bits
; Index
>= 0; Index
--) {
1800 dataval
= (INT16
) ((val
& (1 << Index
)) ? EE_DI
: 0);
1803 // mask off the data_in bit
1805 Tmp
= (UINT8
) (InByte (AdapterInfo
, EEAddr
) &~EE_DI
);
1806 Tmp
= (UINT8
) (Tmp
| dataval
);
1807 OutByte (AdapterInfo
, Tmp
, EEAddr
);
1810 // raise the eeprom clock
1812 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
1815 // lower the eeprom clock
1817 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
1824 TODO: Add function description
1826 @param AdapterInfo TODO: add argument description
1828 @return TODO: add return values
1833 IN NIC_DATA_INSTANCE
*AdapterInfo
1841 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
1844 for (Index
= 15; Index
>= 0; Index
--) {
1850 // mask off the data_in bit
1852 Tmp
= InByte (AdapterInfo
, EEAddr
);
1853 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
1855 Tmp
= InByte (AdapterInfo
, EEAddr
);
1856 retval
= (UINT16
) ((retval
<< 1) | ((Tmp
& EE_DO
) ? 1 : 0));
1860 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
1869 This routine sets the EEPROM lockout bit to gain exclusive access to the
1870 eeprom. the access bit is the most significant bit in the General Control
1871 Register 2 in the SCB space.
1873 @param AdapterInfo Pointer to the NIC data structure
1874 information which the UNDI driver is
1877 @retval TRUE if it got the access
1878 @retval FALSE if it fails to get the exclusive access
1882 E100bSetEepromLockOut (
1883 IN NIC_DATA_INSTANCE
*AdapterInfo
1889 if ((AdapterInfo
->DeviceID
== D102_DEVICE_ID
) ||
1890 (AdapterInfo
->RevID
>= D102_REVID
)) {
1896 tmp
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1897 tmp
|= GCR2_EEPROM_ACCESS_SEMAPHORE
;
1898 OutByte (AdapterInfo
, tmp
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1900 DelayIt (AdapterInfo
, 50);
1901 tmp
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1903 if (tmp
& GCR2_EEPROM_ACCESS_SEMAPHORE
) {
1916 This routine Resets the EEPROM lockout bit to giveup access to the
1917 eeprom. the access bit is the most significant bit in the General Control
1918 Register 2 in the SCB space.
1920 @param AdapterInfo Pointer to the NIC data structure
1921 information which the UNDI driver is
1928 E100bReSetEepromLockOut (
1929 IN NIC_DATA_INSTANCE
*AdapterInfo
1934 if ((AdapterInfo
->DeviceID
== D102_DEVICE_ID
) ||
1935 (AdapterInfo
->RevID
>= D102_REVID
)) {
1937 tmp
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1938 tmp
&= ~(GCR2_EEPROM_ACCESS_SEMAPHORE
);
1939 OutByte (AdapterInfo
, tmp
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1941 DelayIt (AdapterInfo
, 50);
1947 Using the NIC data structure information, read the EEPROM to get a Word of data for the MAC address.
1949 @param AdapterInfo Pointer to the NIC data structure
1950 information which the UNDI driver is
1952 @param Location Word offset into the MAC address to read.
1953 @param AddrLen Number of bits of address length.
1955 @retval RetVal The word read from the EEPROM.
1960 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1971 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
1972 ReadCmd
= (UINT16
) (Location
| (EE_READ_CMD
<< AddrLen
));
1977 // get exclusive access to the eeprom first!
1979 E100bSetEepromLockOut (AdapterInfo
);
1982 // eeprom control reg bits: x,x,x,x,DO,DI,CS,SK
1983 // to write the opcode+data value out one bit at a time in DI starting at msb
1984 // and then out a 1 to sk, wait, out 0 to SK and wait
1985 // repeat this for all the bits to be written
1991 Tmp
= (UINT8
) (InByte (AdapterInfo
, EEAddr
) & 0xF2);
1992 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_CS
), EEAddr
);
1995 // 3 for the read opcode 110b
1997 shift_bits_out (AdapterInfo
, ReadCmd
, (UINT8
) (3 + AddrLen
));
2000 // read the eeprom word one bit at a time
2002 RetVal
= shift_bits_in (AdapterInfo
);
2005 // Terminate the EEPROM access and leave eeprom in a clean state.
2007 Tmp
= InByte (AdapterInfo
, EEAddr
);
2008 Tmp
&= ~(EE_CS
| EE_DI
);
2009 OutByte (AdapterInfo
, Tmp
, EEAddr
);
2012 // raise the clock and lower the eeprom shift clock
2014 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
2017 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
2021 // giveup access to the eeprom
2023 E100bReSetEepromLockOut (AdapterInfo
);
2030 Using the NIC data structure information, read the EEPROM to determine how many bits of address length
2031 this EEPROM is in Words.
2033 @param AdapterInfo Pointer to the NIC data structure
2034 information which the UNDI driver is
2037 @retval RetVal The word read from the EEPROM.
2041 E100bGetEepromAddrLen (
2042 IN NIC_DATA_INSTANCE
*AdapterInfo
2049 // assume 64word eeprom (so,6 bits of address_length)
2053 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
2054 ReadCmd
= (EE_READ_CMD
<< 6);
2057 // get exclusive access to the eeprom first!
2059 E100bSetEepromLockOut (AdapterInfo
);
2062 // address we are trying to read is 0
2063 // eeprom control reg bits: x,x,x,x,DO,,DI,,CS,SK
2064 // to write the opcode+data value out one bit at a time in DI starting at msb
2065 // and then out a 1 to sk, wait, out 0 to SK and wait
2066 // repeat this for all the bits to be written
2068 Tmp
= (UINT8
) (InByte (AdapterInfo
, EEAddr
) & 0xF2);
2071 // enable eeprom access
2073 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_CS
), EEAddr
);
2076 // 3 for opcode, 6 for the default address len
2078 shift_bits_out (AdapterInfo
, ReadCmd
, (UINT8
) (3 + 6));
2081 // (in case of a 64 word eeprom).
2082 // read the "dummy zero" from EE_DO to say that the address we wrote
2083 // (six 0s) is accepted, write more zeros (until 8) to get a "dummy zero"
2087 // assume the smallest
2090 Tmp
= InByte (AdapterInfo
, EEAddr
);
2091 while ((AddrLen
< 8) && ((Tmp
& EE_DO
) != 0)) {
2092 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_DI
), EEAddr
);
2096 // raise the eeprom clock
2098 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
2102 // lower the eeprom clock
2104 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
2106 Tmp
= InByte (AdapterInfo
, EEAddr
);
2111 // read the eeprom word, even though we don't need this
2113 shift_bits_in (AdapterInfo
);
2116 // Terminate the EEPROM access.
2118 Tmp
= InByte (AdapterInfo
, EEAddr
);
2119 Tmp
&= ~(EE_CS
| EE_DI
);
2120 OutByte (AdapterInfo
, Tmp
, EEAddr
);
2123 // raise the clock and lower the eeprom shift clock
2125 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
2128 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
2132 // giveup access to the eeprom!
2134 E100bReSetEepromLockOut (AdapterInfo
);
2141 TODO: Add function description
2143 @param AdapterInfo TODO: add argument description
2144 @param DBaddr TODO: add argument description
2145 @param DBsize TODO: add argument description
2147 @return TODO: add return values
2152 NIC_DATA_INSTANCE
*AdapterInfo
,
2157 PXE_DB_STATISTICS db
;
2159 // wait upto one second (each wait is 100 micro s)
2163 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
2166 // Clear statistics done marker.
2168 AdapterInfo
->statistics
->done_marker
= 0;
2171 // Issue statistics dump (or dump w/ reset) command.
2175 (UINT8
) (DBsize
? CU_SHOWSTATS
: CU_DUMPSTATS
),
2176 (UINT32
) (AdapterInfo
->ioaddr
+ SCBCmd
)
2180 // Wait for command to complete.
2182 // zero the db here just to chew up a little more time.
2185 ZeroMem ((VOID
*) &db
, sizeof db
);
2189 // Wait a bit before checking.
2192 DelayIt (AdapterInfo
, 100);
2195 // Look for done marker at end of statistics.
2198 switch (AdapterInfo
->statistics
->done_marker
) {
2209 // if we did not "continue" from the above switch, we are done,
2215 // If this is a reset, we are out of here!
2218 return PXE_STATCODE_SUCCESS
;
2222 // Convert NIC statistics counter format to EFI/UNDI
2223 // specification statistics counter format.
2227 // 54 3210 fedc ba98 7654 3210
2228 // db.Supported = 01 0000 0100 1101 0001 0111;
2230 db
.Supported
= 0x104D17;
2233 // Statistics from the NIC
2236 db
.Data
[0x01] = AdapterInfo
->statistics
->rx_good_frames
;
2238 db
.Data
[0x02] = AdapterInfo
->statistics
->rx_runt_errs
;
2240 db
.Data
[0x08] = AdapterInfo
->statistics
->rx_crc_errs
+
2241 AdapterInfo
->statistics
->rx_align_errs
;
2243 db
.Data
[0x04] = db
.Data
[0x02] +
2245 AdapterInfo
->statistics
->rx_resource_errs
+
2246 AdapterInfo
->statistics
->rx_overrun_errs
;
2248 db
.Data
[0x00] = db
.Data
[0x01] + db
.Data
[0x04];
2250 db
.Data
[0x0B] = AdapterInfo
->statistics
->tx_good_frames
;
2252 db
.Data
[0x0E] = AdapterInfo
->statistics
->tx_coll16_errs
+
2253 AdapterInfo
->statistics
->tx_late_colls
+
2254 AdapterInfo
->statistics
->tx_underruns
+
2255 AdapterInfo
->statistics
->tx_one_colls
+
2256 AdapterInfo
->statistics
->tx_multi_colls
;
2258 db
.Data
[0x14] = AdapterInfo
->statistics
->tx_total_colls
;
2260 db
.Data
[0x0A] = db
.Data
[0x0B] +
2262 AdapterInfo
->statistics
->tx_lost_carrier
;
2264 if (DBsize
> sizeof db
) {
2265 DBsize
= (UINT16
) sizeof (db
);
2268 CopyMem ((VOID
*) (UINTN
) DBaddr
, (VOID
*) &db
, (UINTN
) DBsize
);
2270 return PXE_STATCODE_SUCCESS
;
2275 TODO: Add function description
2277 @param AdapterInfo TODO: add argument description
2278 @param OpFlags TODO: add argument description
2280 @return TODO: add return values
2285 IN NIC_DATA_INSTANCE
*AdapterInfo
,
2292 // disable the interrupts
2294 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
2297 // wait for the tx queue to complete
2299 CheckCBList (AdapterInfo
);
2301 XmitWaitForCompletion (AdapterInfo
);
2303 if (AdapterInfo
->Receive_Started
) {
2304 StopRU (AdapterInfo
);
2307 InitializeChip (AdapterInfo
);
2310 // check the opflags and restart receive filters
2312 if ((OpFlags
& PXE_OPFLAGS_RESET_DISABLE_FILTERS
) == 0) {
2314 save_filter
= AdapterInfo
->Rx_Filter
;
2316 // if we give the filter same as Rx_Filter,
2317 // this routine will not set mcast list (it thinks there is no change)
2318 // to force it, we will reset that flag in the Rx_Filter
2320 AdapterInfo
->Rx_Filter
&= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
);
2321 E100bSetfilter (AdapterInfo
, save_filter
, (UINT64
) 0, (UINT32
) 0);
2324 if ((OpFlags
& PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS
) != 0) {
2326 // disable the interrupts
2328 AdapterInfo
->int_mask
= 0;
2331 // else leave the interrupt in the pre-set state!!!
2333 E100bSetInterruptState (AdapterInfo
);
2340 TODO: Add function description
2342 @param AdapterInfo TODO: add argument description
2344 @return TODO: add return values
2349 IN NIC_DATA_INSTANCE
*AdapterInfo
2353 // disable the interrupts
2355 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
2358 // stop the receive unit
2360 if (AdapterInfo
->Receive_Started
) {
2361 StopRU (AdapterInfo
);
2365 // wait for the tx queue to complete
2367 CheckCBList (AdapterInfo
);
2368 if (AdapterInfo
->FreeCBCount
!= AdapterInfo
->TxBufCnt
) {
2369 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
2373 // we do not want to reset the phy, it takes a long time to renegotiate the
2374 // link after that (3-4 seconds)
2376 InitializeChip (AdapterInfo
);
2377 SelectiveReset (AdapterInfo
);
2383 This routine will write a value to the specified MII register
2384 of an external MDI compliant device (e.g. PHY 100). The command will
2385 execute in polled mode.
2387 @param AdapterInfo pointer to the structure that contains
2389 @param RegAddress The MII register that we are writing to
2390 @param PhyAddress The MDI address of the Phy component.
2391 @param DataValue The value that we are writing to the MII
2399 IN NIC_DATA_INSTANCE
*AdapterInfo
,
2400 IN UINT8 RegAddress
,
2401 IN UINT8 PhyAddress
,
2405 UINT32 WriteCommand
;
2407 WriteCommand
= ((UINT32
) DataValue
) |
2408 ((UINT32
)(RegAddress
<< 16)) |
2409 ((UINT32
)(PhyAddress
<< 21)) |
2410 ((UINT32
)(MDI_WRITE
<< 26));
2413 // Issue the write command to the MDI control register.
2415 OutLong (AdapterInfo
, WriteCommand
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
);
2418 // wait 20usec before checking status
2420 DelayIt (AdapterInfo
, 20);
2423 // poll for the mdi write to complete
2424 while ((InLong (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
) &
2425 MDI_PHY_READY
) == 0){
2426 DelayIt (AdapterInfo
, 20);
2432 This routine will read a value from the specified MII register
2433 of an external MDI compliant device (e.g. PHY 100), and return
2434 it to the calling routine. The command will execute in polled mode.
2436 @param AdapterInfo pointer to the structure that contains
2438 @param RegAddress The MII register that we are reading from
2439 @param PhyAddress The MDI address of the Phy component.
2440 @param DataValue pointer to the value that we read from
2447 IN NIC_DATA_INSTANCE
*AdapterInfo
,
2448 IN UINT8 RegAddress
,
2449 IN UINT8 PhyAddress
,
2450 IN OUT UINT16
*DataValue
2455 ReadCommand
= ((UINT32
) (RegAddress
<< 16)) |
2456 ((UINT32
) (PhyAddress
<< 21)) |
2457 ((UINT32
) (MDI_READ
<< 26));
2460 // Issue the read command to the MDI control register.
2462 OutLong (AdapterInfo
, ReadCommand
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
);
2465 // wait 20usec before checking status
2467 DelayIt (AdapterInfo
, 20);
2470 // poll for the mdi read to complete
2472 while ((InLong (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
) &
2473 MDI_PHY_READY
) == 0) {
2474 DelayIt (AdapterInfo
, 20);
2478 *DataValue
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
);
2483 This routine will reset the PHY that the adapter is currently
2486 @param AdapterInfo pointer to the structure that contains
2493 NIC_DATA_INSTANCE
*AdapterInfo
2496 UINT16 MdiControlReg
;
2498 MdiControlReg
= (MDI_CR_AUTO_SELECT
|
2499 MDI_CR_RESTART_AUTO_NEG
|
2503 // Write the MDI control register with our new Phy configuration
2508 AdapterInfo
->PhyAddress
,
2517 This routine will detect what phy we are using, set the line
2518 speed, FDX or HDX, and configure the phy if necessary.
2519 The following combinations are supported:
2520 - TX or T4 PHY alone at PHY address 1
2521 - T4 or TX PHY at address 1 and MII PHY at address 0
2522 - 82503 alone (10Base-T mode, no full duplex support)
2523 - 82503 and MII PHY (TX or T4) at address 0
2524 The sequence / priority of detection is as follows:
2525 - PHY 1 with cable termination
2526 - PHY 0 with cable termination
2527 - PHY 1 (if found) without cable termination
2529 Additionally auto-negotiation capable (NWAY) and parallel
2530 detection PHYs are supported. The flow-chart is described in
2531 the 82557 software writer's manual.
2532 NOTE: 1. All PHY MDI registers are read in polled mode.
2533 2. The routines assume that the 82557 has been RESET and we have
2534 obtained the virtual memory address of the CSR.
2535 3. PhyDetect will not RESET the PHY.
2536 4. If FORCEFDX is set, SPEED should also be set. The driver will
2537 check the values for inconsistency with the detected PHY
2539 5. PHY 1 (the PHY on the adapter) may have an address in the range
2540 1 through 31 inclusive. The driver will accept addresses in
2542 6. Driver ignores FORCEFDX and SPEED overrides if a 503 interface
2545 @param AdapterInfo pointer to the structure that contains
2548 @retval TRUE If a Phy was detected, and configured
2550 @retval FALSE If a valid phy could not be detected and
2556 NIC_DATA_INSTANCE
*AdapterInfo
2560 UINT16 MdiControlReg
;
2561 UINT16 MdiStatusReg
;
2563 UINT8 ReNegotiateTime
;
2565 eedata
= (UINT16
*) (&AdapterInfo
->NVData
[0]);
2568 ReNegotiateTime
= 35;
2570 // EEPROM word [6] contains the Primary PHY record in which the least 3 bits
2571 // indicate the PHY address
2572 // and word [7] contains the secondary PHY record
2574 AdapterInfo
->PhyRecord
[0] = eedata
[6];
2575 AdapterInfo
->PhyRecord
[1] = eedata
[7];
2576 AdapterInfo
->PhyAddress
= (UINT8
) (AdapterInfo
->PhyRecord
[0] & 7);
2579 // Check for a phy address over-ride of 32 which indicates force use of 82503
2580 // not detecting the link in this case
2582 if (AdapterInfo
->PhyAddress
== 32) {
2584 // 503 interface over-ride
2585 // Record the current speed and duplex. We will be in half duplex
2586 // mode unless the user used the force full duplex over-ride.
2588 AdapterInfo
->LinkSpeed
= 10;
2593 // If the Phy Address is between 1-31 then we must first look for phy 1,
2596 if ((AdapterInfo
->PhyAddress
> 0) && (AdapterInfo
->PhyAddress
< 32)) {
2599 // Read the MDI control and status registers at phy 1
2600 // and check if we found a valid phy
2605 AdapterInfo
->PhyAddress
,
2612 AdapterInfo
->PhyAddress
,
2616 if (!((MdiControlReg
== 0xffff) ||
2617 ((MdiStatusReg
== 0) && (MdiControlReg
== 0)))) {
2620 // we have a valid phy1
2621 // Read the status register again because of sticky bits
2627 AdapterInfo
->PhyAddress
,
2632 // If there is a valid link then use this Phy.
2634 if (MdiStatusReg
& MDI_SR_LINK_STATUS
) {
2635 return (SetupPhy(AdapterInfo
));
2641 // Next try to detect a PHY at address 0x00 because there was no Phy 1,
2642 // or Phy 1 didn't have link, or we had a phy 0 over-ride
2646 // Read the MDI control and status registers at phy 0
2648 MdiRead (AdapterInfo
, MDI_CONTROL_REG
, 0, &MdiControlReg
);
2649 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2652 // check if we found a valid phy 0
2654 if (((MdiControlReg
== 0xffff) ||
2655 ((MdiStatusReg
== 0) && (MdiControlReg
== 0)))) {
2658 // we don't have a valid phy at address 0
2659 // if phy address was forced to 0, then error out because we
2660 // didn't find a phy at that address
2662 if (AdapterInfo
->PhyAddress
== 0x0000) {
2666 // at this point phy1 does not have link and there is no phy 0 at all
2667 // if we are forced to detect the cable, error out here!
2669 if (AdapterInfo
->CableDetect
!= 0) {
2676 // no phy 0, but there is a phy 1 (no link I guess), so use phy 1
2678 return SetupPhy (AdapterInfo
);
2681 // didn't find phy 0 or phy 1, so assume a 503 interface
2683 AdapterInfo
->PhyAddress
= 32;
2686 // Record the current speed and duplex. We'll be in half duplex
2687 // mode unless the user used the force full duplex over-ride.
2689 AdapterInfo
->LinkSpeed
= 10;
2695 // We have a valid phy at address 0. If phy 0 has a link then we use
2696 // phy 0. If Phy 0 doesn't have a link then we use Phy 1 (no link)
2697 // if phy 1 is present, or phy 0 if phy 1 is not present
2698 // If phy 1 was present, then we must isolate phy 1 before we enable
2699 // phy 0 to see if Phy 0 has a link.
2708 AdapterInfo
->PhyAddress
,
2713 // wait 100 microseconds for the phy to isolate.
2715 DelayIt (AdapterInfo
, 100);
2719 // Since this Phy is at address 0, we must enable it. So clear
2720 // the isolate bit, and set the auto-speed select bit
2730 // wait 100 microseconds for the phy to be enabled.
2732 DelayIt (AdapterInfo
, 100);
2735 // restart the auto-negotion process
2741 MDI_CR_RESTART_AUTO_NEG
| MDI_CR_AUTO_SELECT
2745 // wait no more than 3.5 seconds for auto-negotiation to complete
2747 while (ReNegotiateTime
) {
2749 // Read the status register twice because of sticky bits
2751 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2752 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2754 if (MdiStatusReg
& MDI_SR_AUTO_NEG_COMPLETE
) {
2758 DelayIt (AdapterInfo
, 100);
2763 // Read the status register again because of sticky bits
2765 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2768 // If the link was not set
2770 if ((MdiStatusReg
& MDI_SR_LINK_STATUS
) == 0) {
2772 // PHY1 does not have a link and phy 0 does not have a link
2773 // do not proceed if we need to detect the link!
2775 if (AdapterInfo
->CableDetect
!= 0) {
2780 // the link wasn't set, so use phy 1 if phy 1 was present
2786 MdiWrite (AdapterInfo
, MDI_CONTROL_REG
, 0, MDI_CR_ISOLATE
);
2789 // wait 100 microseconds for the phy to isolate.
2791 DelayIt (AdapterInfo
, 100);
2794 // Now re-enable PHY 1
2799 AdapterInfo
->PhyAddress
,
2804 // wait 100 microseconds for the phy to be enabled
2806 DelayIt (AdapterInfo
, 100);
2809 // restart the auto-negotion process
2814 AdapterInfo
->PhyAddress
,
2815 MDI_CR_RESTART_AUTO_NEG
| MDI_CR_AUTO_SELECT
2819 // Don't wait for it to complete (we didn't have link earlier)
2821 return (SetupPhy (AdapterInfo
));
2826 // Definitely using Phy 0
2828 AdapterInfo
->PhyAddress
= 0;
2829 return (SetupPhy(AdapterInfo
));
2835 This routine will setup phy 1 or phy 0 so that it is configured
2836 to match a speed and duplex over-ride option. If speed or
2837 duplex mode is not explicitly specified in the registry, the
2838 driver will skip the speed and duplex over-ride code, and
2839 assume the adapter is automatically setting the line speed, and
2840 the duplex mode. At the end of this routine, any truly Phy
2841 specific code will be executed (each Phy has its own quirks,
2842 and some require that certain special bits are set).
2843 NOTE: The driver assumes that SPEED and FORCEFDX are specified at the
2844 same time. If FORCEDPX is set without speed being set, the driver
2845 will encouter a fatal error and log a message into the event viewer.
2847 @param AdapterInfo pointer to the structure that contains
2850 @retval TRUE If the phy could be configured correctly
2851 @retval FALSE If the phy couldn't be configured
2852 correctly, because an unsupported
2853 over-ride option was used
2858 IN NIC_DATA_INSTANCE
*AdapterInfo
2861 UINT16 MdiControlReg
;
2862 UINT16 MdiStatusReg
;
2864 UINT16 MdiIdHighReg
;
2867 BOOLEAN ForcePhySetting
;
2869 ForcePhySetting
= FALSE
;
2872 // If we are NOT forcing a setting for line speed or full duplex, then
2873 // we won't force a link setting, and we'll jump down to the phy
2876 if (((AdapterInfo
->LinkSpeedReq
) || (AdapterInfo
->DuplexReq
))) {
2878 // Find out what kind of technology this Phy is capable of.
2883 AdapterInfo
->PhyAddress
,
2888 // Read the MDI control register at our phy
2893 AdapterInfo
->PhyAddress
,
2898 // Now check the validity of our forced option. If the force option is
2899 // valid, then force the setting. If the force option is not valid,
2900 // we'll set a flag indicating that we should error out.
2904 // If speed is forced to 10mb
2906 if (AdapterInfo
->LinkSpeedReq
== 10) {
2908 // If half duplex is forced
2910 if ((AdapterInfo
->DuplexReq
& PXE_FORCE_HALF_DUPLEX
) != 0) {
2911 if (MdiStatusReg
& MDI_SR_10T_HALF_DPX
) {
2913 MdiControlReg
&= ~(MDI_CR_10_100
| MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
2914 ForcePhySetting
= TRUE
;
2916 } else if ((AdapterInfo
->DuplexReq
& PXE_FORCE_FULL_DUPLEX
) != 0) {
2919 // If full duplex is forced
2921 if (MdiStatusReg
& MDI_SR_10T_FULL_DPX
) {
2923 MdiControlReg
&= ~(MDI_CR_10_100
| MDI_CR_AUTO_SELECT
);
2924 MdiControlReg
|= MDI_CR_FULL_HALF
;
2925 ForcePhySetting
= TRUE
;
2929 // If auto duplex (we actually set phy to 1/2)
2931 if (MdiStatusReg
& (MDI_SR_10T_FULL_DPX
| MDI_SR_10T_HALF_DPX
)) {
2933 MdiControlReg
&= ~(MDI_CR_10_100
| MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
2934 ForcePhySetting
= TRUE
;
2940 // If speed is forced to 100mb
2942 else if (AdapterInfo
->LinkSpeedReq
== 100) {
2944 // If half duplex is forced
2946 if ((AdapterInfo
->DuplexReq
& PXE_FORCE_HALF_DUPLEX
) != 0) {
2947 if (MdiStatusReg
& (MDI_SR_TX_HALF_DPX
| MDI_SR_T4_CAPABLE
)) {
2949 MdiControlReg
&= ~(MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
2950 MdiControlReg
|= MDI_CR_10_100
;
2951 ForcePhySetting
= TRUE
;
2953 } else if ((AdapterInfo
->DuplexReq
& PXE_FORCE_FULL_DUPLEX
) != 0) {
2955 // If full duplex is forced
2957 if (MdiStatusReg
& MDI_SR_TX_FULL_DPX
) {
2958 MdiControlReg
&= ~MDI_CR_AUTO_SELECT
;
2959 MdiControlReg
|= (MDI_CR_10_100
| MDI_CR_FULL_HALF
);
2960 ForcePhySetting
= TRUE
;
2964 // If auto duplex (we set phy to 1/2)
2966 if (MdiStatusReg
& (MDI_SR_TX_HALF_DPX
| MDI_SR_T4_CAPABLE
)) {
2968 MdiControlReg
&= ~(MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
2969 MdiControlReg
|= MDI_CR_10_100
;
2970 ForcePhySetting
= TRUE
;
2975 if (!ForcePhySetting
) {
2980 // Write the MDI control register with our new Phy configuration
2985 AdapterInfo
->PhyAddress
,
2990 // wait 100 milliseconds for auto-negotiation to complete
2992 DelayIt (AdapterInfo
, 100);
2996 // Find out specifically what Phy this is. We do this because for certain
2997 // phys there are specific bits that must be set so that the phy and the
2998 // 82557 work together properly.
3004 AdapterInfo
->PhyAddress
,
3010 AdapterInfo
->PhyAddress
,
3014 PhyId
= ((UINT32
) MdiIdLowReg
| ((UINT32
) MdiIdHighReg
<< 16));
3017 // And out the revsion field of the Phy ID so that we'll be able to detect
3018 // future revs of the same Phy.
3020 PhyId
&= PHY_MODEL_REV_ID_MASK
;
3023 // Handle the National TX
3025 if (PhyId
== PHY_NSC_TX
) {
3029 NSC_CONG_CONTROL_REG
,
3030 AdapterInfo
->PhyAddress
,
3034 MdiMiscReg
|= (NSC_TX_CONG_TXREADY
| NSC_TX_CONG_F_CONNECT
);
3038 NSC_CONG_CONTROL_REG
,
3039 AdapterInfo
->PhyAddress
,
3044 FindPhySpeedAndDpx (AdapterInfo
, PhyId
);
3047 // We put a hardware fix on to our adapters to work-around the PHY_100 errata
3048 // described below. The following code is only compiled in, if we wanted
3049 // to attempt a software workaround to the PHY_100 A/B step problem.
3057 This routine will figure out what line speed and duplex mode
3058 the PHY is currently using.
3060 @param AdapterInfo pointer to the structure that contains
3062 @param PhyId The ID of the PHY in question.
3068 FindPhySpeedAndDpx (
3069 IN NIC_DATA_INSTANCE
*AdapterInfo
,
3073 UINT16 MdiStatusReg
;
3076 UINT16 MdiLinkPartnerAdReg
;
3079 // If there was a speed and/or duplex override, then set our current
3080 // value accordingly
3082 AdapterInfo
->LinkSpeed
= AdapterInfo
->LinkSpeedReq
;
3083 AdapterInfo
->Duplex
= (UINT8
) ((AdapterInfo
->DuplexReq
& PXE_FORCE_FULL_DUPLEX
) ?
3084 FULL_DUPLEX
: HALF_DUPLEX
);
3087 // If speed and duplex were forced, then we know our current settings, so
3088 // we'll just return. Otherwise, we'll need to figure out what NWAY set
3091 if (AdapterInfo
->LinkSpeed
&& AdapterInfo
->Duplex
) {
3096 // If we didn't have a valid link, then we'll assume that our current
3097 // speed is 10mb half-duplex.
3101 // Read the status register twice because of sticky bits
3106 AdapterInfo
->PhyAddress
,
3112 AdapterInfo
->PhyAddress
,
3117 // If there wasn't a valid link then use default speed & duplex
3119 if (!(MdiStatusReg
& MDI_SR_LINK_STATUS
)) {
3121 AdapterInfo
->LinkSpeed
= 10;
3122 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3127 // If this is an Intel PHY (a T4 PHY_100 or a TX PHY_TX), then read bits
3128 // 1 and 0 of extended register 0, to get the current speed and duplex
3131 if ((PhyId
== PHY_100_A
) || (PhyId
== PHY_100_C
) || (PhyId
== PHY_TX_ID
)) {
3133 // Read extended register 0
3138 AdapterInfo
->PhyAddress
,
3143 // Get current speed setting
3145 if (MdiMiscReg
& PHY_100_ER0_SPEED_INDIC
) {
3146 AdapterInfo
->LinkSpeed
= 100;
3148 AdapterInfo
->LinkSpeed
= 10;
3152 // Get current duplex setting -- if bit is set then FDX is enabled
3154 if (MdiMiscReg
& PHY_100_ER0_FDX_INDIC
) {
3155 AdapterInfo
->Duplex
= FULL_DUPLEX
;
3157 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3163 // Read our link partner's advertisement register
3167 AUTO_NEG_LINK_PARTNER_REG
,
3168 AdapterInfo
->PhyAddress
,
3169 &MdiLinkPartnerAdReg
3173 // See if Auto-Negotiation was complete (bit 5, reg 1)
3178 AdapterInfo
->PhyAddress
,
3183 // If a True NWAY connection was made, then we can detect speed/duplex by
3184 // ANDing our adapter's advertised abilities with our link partner's
3185 // advertised ablilities, and then assuming that the highest common
3186 // denominator was chosed by NWAY.
3188 if ((MdiLinkPartnerAdReg
& NWAY_LP_ABILITY
) &&
3189 (MdiStatusReg
& MDI_SR_AUTO_NEG_COMPLETE
)) {
3192 // Read our advertisement register
3196 AUTO_NEG_ADVERTISE_REG
,
3197 AdapterInfo
->PhyAddress
,
3202 // AND the two advertisement registers together, and get rid of any
3205 MdiOwnAdReg
= (UINT16
) (MdiOwnAdReg
& (MdiLinkPartnerAdReg
& NWAY_LP_ABILITY
));
3208 // Get speed setting
3210 if (MdiOwnAdReg
& (NWAY_AD_TX_HALF_DPX
| NWAY_AD_TX_FULL_DPX
| NWAY_AD_T4_CAPABLE
)) {
3211 AdapterInfo
->LinkSpeed
= 100;
3213 AdapterInfo
->LinkSpeed
= 10;
3217 // Get duplex setting -- use priority resolution algorithm
3219 if (MdiOwnAdReg
& (NWAY_AD_T4_CAPABLE
)) {
3220 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3222 } else if (MdiOwnAdReg
& (NWAY_AD_TX_FULL_DPX
)) {
3223 AdapterInfo
->Duplex
= FULL_DUPLEX
;
3225 } else if (MdiOwnAdReg
& (NWAY_AD_TX_HALF_DPX
)) {
3226 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3228 } else if (MdiOwnAdReg
& (NWAY_AD_10T_FULL_DPX
)) {
3229 AdapterInfo
->Duplex
= FULL_DUPLEX
;
3232 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3238 // If we are connected to a dumb (non-NWAY) repeater or hub, and the line
3239 // speed was determined automatically by parallel detection, then we have
3240 // no way of knowing exactly what speed the PHY is set to unless that PHY
3241 // has a propietary register which indicates speed in this situation. The
3242 // NSC TX PHY does have such a register. Also, since NWAY didn't establish
3243 // the connection, the duplex setting should HALF duplex.
3245 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3247 if (PhyId
== PHY_NSC_TX
) {
3249 // Read register 25 to get the SPEED_10 bit
3254 AdapterInfo
->PhyAddress
,
3259 // If bit 6 was set then we're at 10mb
3261 if (MdiMiscReg
& NSC_TX_SPD_INDC_SPEED
) {
3262 AdapterInfo
->LinkSpeed
= 10;
3264 AdapterInfo
->LinkSpeed
= 100;
3269 // If we don't know what line speed we are set at, then we'll default to
3273 AdapterInfo
->LinkSpeed
= 10;
3279 TODO: Add function description
3281 @param AdapterInfo TODO: add argument description
3283 @return TODO: add return values
3287 XmitWaitForCompletion (
3288 NIC_DATA_INSTANCE
*AdapterInfo
3293 if (AdapterInfo
->FreeCBCount
== AdapterInfo
->TxBufCnt
) {
3298 // used xmit cb list starts right after the free tail (ends before the
3301 TxPtr
= AdapterInfo
->FreeTxTailPtr
->NextTCBVirtualLinkPtr
;
3302 while (TxPtr
!= AdapterInfo
->FreeTxHeadPtr
) {
3303 CommandWaitForCompletion (TxPtr
, AdapterInfo
);
3304 SetFreeCB (AdapterInfo
, TxPtr
);
3305 TxPtr
= TxPtr
->NextTCBVirtualLinkPtr
;
3311 TODO: Add function description
3313 @param cmd_ptr TODO: add argument description
3314 @param AdapterInfo TODO: add argument description
3316 @return TODO: add return values
3320 CommandWaitForCompletion (
3322 NIC_DATA_INSTANCE
*AdapterInfo
3327 while ((cmd_ptr
->cb_header
.status
== 0) && (--wait
> 0)) {
3328 DelayIt (AdapterInfo
, 10);
3331 if (cmd_ptr
->cb_header
.status
== 0) {
3340 TODO: Add function description
3342 @param AdapterInfo TODO: add argument description
3344 @return TODO: add return values
3349 NIC_DATA_INSTANCE
*AdapterInfo
3358 // Reset the chip: stop Tx and Rx processes and clear counters.
3359 // This takes less than 10usec and will easily finish before the next
3363 OutLong (AdapterInfo
, PORT_RESET
, AdapterInfo
->ioaddr
+ SCBPort
);
3365 // wait for 5 milli seconds here!
3367 DelayIt (AdapterInfo
, 5000);
3369 // TCO Errata work around for 559s only
3370 // -----------------------------------------------------------------------------------
3371 // TCO Workaround Code
3373 // -----------------------------------------------------------------------------------
3374 // 1. Issue SW-RST ^^^ (already done above)
3375 // 2. Issue a redundant Set CU Base CMD immediately
3376 // Do not set the General Pointer before the Set CU Base cycle
3377 // Do not check the SCB CMD before the Set CU Base cycle
3378 // 3. Wait for the SCB-CMD to be cleared
3379 // this indicates the transition to post-driver
3380 // 4. Poll the TCO-Req bit in the PMDR to be cleared
3381 // this indicates the tco activity has stopped for real
3382 // 5. Proceed with the nominal Driver Init:
3383 // Actual Set CU & RU Base ...
3385 // Check for ICH2 device ID. If this is an ICH2,
3386 // do the TCO workaround code.
3388 if (AdapterInfo
->VendorID
== D102_DEVICE_ID
||
3389 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_1
||
3390 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_2
||
3391 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_3
||
3392 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_4
||
3393 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_5
||
3394 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_6
||
3395 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_7
||
3396 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_8
||
3397 AdapterInfo
->RevID
>= 8) { // do the TCO fix
3399 // donot load the scb pointer but just give load_cu cmd.
3401 OutByte (AdapterInfo
, CU_CMD_BASE
, AdapterInfo
->ioaddr
+ SCBCmd
);
3403 // wait for command to be accepted.
3405 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
3407 // read PMDR register and check bit 1 in it to see if TCO is active
3411 // wait for 5 milli seconds
3415 tco_stat
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ 0x1b);
3416 if ((tco_stat
& 2) == 0) {
3418 // is the activity bit clear??
3424 DelayIt (AdapterInfo
, 1);
3427 if ((tco_stat
& 2) != 0) {
3440 TODO: Add function description
3442 @param AdapterInfo TODO: add argument description
3444 @return TODO: add return values
3449 IN NIC_DATA_INSTANCE
*AdapterInfo
3457 OutLong (AdapterInfo
, POR_SELECTIVE_RESET
, AdapterInfo
->ioaddr
+ SCBPort
);
3459 // wait for this to complete
3463 // wait for 2 milli seconds here!
3465 DelayIt (AdapterInfo
, 2000);
3468 stat
= InLong (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBPort
);
3474 // wait for 1 milli second
3476 DelayIt (AdapterInfo
, 1000);
3480 return PXE_STATCODE_DEVICE_FAILURE
;
3488 TODO: Add function description
3490 @param AdapterInfo TODO: add argument description
3492 @return TODO: add return values
3497 IN NIC_DATA_INSTANCE
*AdapterInfo
3501 if (SoftwareReset (AdapterInfo
) != 0) {
3502 return PXE_STATCODE_DEVICE_FAILURE
;
3506 // disable interrupts
3508 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
3511 // Load the base registers with 0s (we will give the complete address as
3512 // offset later when we issue any command
3514 if ((ret_val
= Load_Base_Regs (AdapterInfo
)) != 0) {
3518 if ((ret_val
= SetupCBlink (AdapterInfo
)) != 0) {
3522 if ((ret_val
= SetupReceiveQueues (AdapterInfo
)) != 0) {
3527 // detect the PHY only if we need to detect the cable as requested by the
3528 // initialize parameters
3530 AdapterInfo
->PhyAddress
= 0xFF;
3532 if (AdapterInfo
->CableDetect
!= 0) {
3533 if (!PhyDetect (AdapterInfo
)) {
3534 return PXE_STATCODE_DEVICE_FAILURE
;
3538 if ((ret_val
= E100bSetupIAAddr (AdapterInfo
)) != 0) {
3542 if ((ret_val
= Configure (AdapterInfo
)) != 0) {