2 Provides basic function upon network adapter card.
4 Copyright (c) 2006, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 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 data_ptr
= (UINT8
*) (&cmd_ptr
->PhysTBDArrayAddres
);
523 // start the config data right after the command header
525 for (Index
= 0; Index
< sizeof (basic_config_cmd
); Index
++) {
526 data_ptr
[Index
] = basic_config_cmd
[Index
];
529 my_filter
= (UINT8
) ((AdapterInfo
->Rx_Filter
& PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS
) ? 1 : 0);
530 my_filter
= (UINT8
) (my_filter
| ((AdapterInfo
->Rx_Filter
& PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST
) ? 0 : 2));
532 data_ptr
[15] = (UINT8
) (data_ptr
[15] | my_filter
);
533 data_ptr
[19] = (UINT8
) (AdapterInfo
->Duplex
? 0xC0 : 0x80);
534 data_ptr
[21] = (UINT8
) ((AdapterInfo
->Rx_Filter
& PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST
) ? 0x0D : 0x05);
537 // check if we have to use the AUI port instead
539 if ((AdapterInfo
->PhyRecord
[0] & 0x8000) != 0) {
540 data_ptr
[15] |= 0x80;
544 BlockIt (AdapterInfo
, TRUE
);
545 cmd_ptr
->cb_header
.command
= CmdSuspend
| CmdConfigure
;
547 IssueCB (AdapterInfo
, cmd_ptr
);
548 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
550 BlockIt (AdapterInfo
, FALSE
);
552 CommandWaitForCompletion (cmd_ptr
, AdapterInfo
);
555 // restore the cb values for tx
557 cmd_ptr
->PhysTBDArrayAddres
= cmd_ptr
->PhysArrayAddr
;
558 cmd_ptr
->ByteCount
= cmd_ptr
->Threshold
= cmd_ptr
->TBDCount
= 0;
560 // fields beyond the immediatedata are assumed to be safe
561 // add the CB to the free list again
563 SetFreeCB (AdapterInfo
, cmd_ptr
);
569 TODO: Add function description
571 @param AdapterInfo TODO: add argument description
573 @return TODO: add return values
578 NIC_DATA_INSTANCE
*AdapterInfo
582 // all command blocks are of TxCB format
588 eaddrs
= (UINT16
*) AdapterInfo
->CurrentNodeAddress
;
590 cmd_ptr
= GetFreeCB (AdapterInfo
);
591 data_ptr
= (UINT16
*) (&cmd_ptr
->PhysTBDArrayAddres
);
594 // AVOID a bug (?!) here by marking the command already completed.
596 cmd_ptr
->cb_header
.command
= (CmdSuspend
| CmdIASetup
);
597 cmd_ptr
->cb_header
.status
= 0;
598 data_ptr
[0] = eaddrs
[0];
599 data_ptr
[1] = eaddrs
[1];
600 data_ptr
[2] = eaddrs
[2];
602 BlockIt (AdapterInfo
, TRUE
);
603 IssueCB (AdapterInfo
, cmd_ptr
);
604 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
605 BlockIt (AdapterInfo
, FALSE
);
607 CommandWaitForCompletion (cmd_ptr
, AdapterInfo
);
610 // restore the cb values for tx
612 cmd_ptr
->PhysTBDArrayAddres
= cmd_ptr
->PhysArrayAddr
;
613 cmd_ptr
->ByteCount
= cmd_ptr
->Threshold
= cmd_ptr
->TBDCount
= 0;
615 // fields beyond the immediatedata are assumed to be safe
616 // add the CB to the free list again
618 SetFreeCB (AdapterInfo
, cmd_ptr
);
624 Instructs the NIC to stop receiving packets.
626 @param AdapterInfo Pointer to the NIC data structure
627 information which the UNDI driver is
634 IN NIC_DATA_INSTANCE
*AdapterInfo
637 if (AdapterInfo
->Receive_Started
) {
640 // Todo: verify that we must wait for previous command completion.
642 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
645 // Disable interrupts, and stop the chip's Rx process.
647 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
648 OutWord (AdapterInfo
, INT_MASK
| RX_ABORT
, AdapterInfo
->ioaddr
+ SCBCmd
);
650 AdapterInfo
->Receive_Started
= FALSE
;
658 Instructs the NIC to start receiving packets.
660 @param AdapterInfo Pointer to the NIC data structure
661 information which the UNDI driver is
665 @retval -1 Already Started
670 NIC_DATA_INSTANCE
*AdapterInfo
674 if (AdapterInfo
->Receive_Started
) {
681 AdapterInfo
->cur_rx_ind
= 0;
682 AdapterInfo
->Int_Status
= 0;
684 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
686 OutLong (AdapterInfo
, (UINT32
) AdapterInfo
->rx_phy_addr
, AdapterInfo
->ioaddr
+ SCBPointer
);
687 OutByte (AdapterInfo
, RX_START
, AdapterInfo
->ioaddr
+ SCBCmd
);
689 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
691 AdapterInfo
->Receive_Started
= TRUE
;
697 Configures the chip. This routine expects the NIC_DATA_INSTANCE structure to be filled in.
699 @param AdapterInfo Pointer to the NIC data structure
700 information which the UNDI driver is
704 @retval PXE_STATCODE_NOT_ENOUGH_MEMORY Insufficient length of locked memory
705 @retval other Failure initializing chip
710 IN NIC_DATA_INSTANCE
*AdapterInfo
713 PCI_CONFIG_HEADER
*CfgHdr
;
718 if (AdapterInfo
->MemoryLength
< MEMORY_NEEDED
) {
719 return PXE_STATCODE_NOT_ENOUGH_MEMORY
;
724 AdapterInfo
->MemoryPtr
,
725 AdapterInfo
->MemoryLength
,
727 (UINT64
)(UINTN
) &AdapterInfo
->Mapped_MemoryPtr
734 CfgHdr
= (PCI_CONFIG_HEADER
*) &(AdapterInfo
->Config
[0]);
737 // fill in the ioaddr, int... from the config space
739 AdapterInfo
->int_num
= CfgHdr
->int_line
;
742 // we don't need to validate integer number, what if they don't want to assign one?
743 // if (AdapterInfo->int_num == 0 || AdapterInfo->int_num == 0xff)
744 // return PXE_STATCODE_DEVICE_FAILURE;
746 AdapterInfo
->ioaddr
= 0;
747 AdapterInfo
->VendorID
= CfgHdr
->VendorID
;
748 AdapterInfo
->DeviceID
= CfgHdr
->DeviceID
;
749 AdapterInfo
->RevID
= CfgHdr
->RevID
;
750 AdapterInfo
->SubVendorID
= CfgHdr
->SubVendorID
;
751 AdapterInfo
->SubSystemID
= CfgHdr
->SubSystemID
;
752 AdapterInfo
->flash_addr
= 0;
755 // Read the station address EEPROM before doing the reset.
756 // Perhaps this should even be done before accepting the device,
757 // then we wouldn't have a device name with which to report the error.
759 if (E100bReadEepromAndStationAddress (AdapterInfo
) != 0) {
760 return PXE_STATCODE_DEVICE_FAILURE
;
764 // ## calculate the buffer #s depending on memory given
765 // ## calculate the rx and tx ring pointers
768 AdapterInfo
->TxBufCnt
= TX_BUFFER_COUNT
;
769 AdapterInfo
->RxBufCnt
= RX_BUFFER_COUNT
;
770 rx_size
= (AdapterInfo
->RxBufCnt
* sizeof (RxFD
));
771 tx_size
= (AdapterInfo
->TxBufCnt
* sizeof (TxCB
));
772 AdapterInfo
->rx_ring
= (RxFD
*) (UINTN
) (AdapterInfo
->MemoryPtr
);
773 AdapterInfo
->tx_ring
= (TxCB
*) (UINTN
) (AdapterInfo
->MemoryPtr
+ rx_size
);
774 AdapterInfo
->statistics
= (struct speedo_stats
*) (UINTN
) (AdapterInfo
->MemoryPtr
+ rx_size
+ tx_size
);
776 AdapterInfo
->rx_phy_addr
= AdapterInfo
->Mapped_MemoryPtr
;
777 AdapterInfo
->tx_phy_addr
= AdapterInfo
->Mapped_MemoryPtr
+ rx_size
;
778 AdapterInfo
->stat_phy_addr
= AdapterInfo
->tx_phy_addr
+ tx_size
;
783 AdapterInfo
->PhyAddress
= 0xFF;
784 AdapterInfo
->Rx_Filter
= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST
;
785 AdapterInfo
->Receive_Started
= FALSE
;
786 AdapterInfo
->mcast_list
.list_len
= 0;
787 return InitializeChip (AdapterInfo
);
792 Sets the interrupt state for the NIC.
794 @param AdapterInfo Pointer to the NIC data structure
795 information which the UNDI driver is
802 E100bSetInterruptState (
803 IN NIC_DATA_INSTANCE
*AdapterInfo
807 // don't set receive interrupt if receiver is disabled...
811 if ((AdapterInfo
->int_mask
& PXE_OPFLAGS_INTERRUPT_RECEIVE
) != 0) {
812 cmd_word
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCmd
);
813 cmd_word
&= ~INT_MASK
;
814 OutWord (AdapterInfo
, cmd_word
, AdapterInfo
->ioaddr
+ SCBCmd
);
817 // disable ints, should not be given for SW Int.
819 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
822 if ((AdapterInfo
->int_mask
& PXE_OPFLAGS_INTERRUPT_SOFTWARE
) != 0) {
824 // reset the bit in our mask, it is only one time!!
826 AdapterInfo
->int_mask
&= ~(PXE_OPFLAGS_INTERRUPT_SOFTWARE
);
827 cmd_word
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCmd
);
828 cmd_word
|= DRVR_INT
;
829 OutWord (AdapterInfo
, cmd_word
, AdapterInfo
->ioaddr
+ SCBCmd
);
835 // we are not going to disable broadcast for the WOL's sake!
839 Instructs the NIC to start receiving packets.
841 @param AdapterInfo Pointer to the NIC data structure
842 information which the UNDI driver is
843 layering on.. new_filter
848 @retval -1 Already Started
853 NIC_DATA_INSTANCE
*AdapterInfo
,
859 PXE_CPB_RECEIVE_FILTERS
*mc_list
= (PXE_CPB_RECEIVE_FILTERS
*) (UINTN
)cpb
;
866 struct MC_CB_STRUCT
*data_ptr
;
869 old_filter
= AdapterInfo
->Rx_Filter
;
872 // only these bits need a change in the configuration
873 // actually change in bcast requires configure but we ignore that change
875 cfg_flt
= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS
|
876 PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST
;
878 if ((old_filter
& cfg_flt
) != (new_filter
& cfg_flt
)) {
879 XmitWaitForCompletion (AdapterInfo
);
881 if (AdapterInfo
->Receive_Started
) {
882 StopRU (AdapterInfo
);
885 AdapterInfo
->Rx_Filter
= (UINT8
) (new_filter
| PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST
);
886 Configure (AdapterInfo
);
890 // check if mcast setting changed
892 if ( ((new_filter
& PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
) !=
893 (old_filter
& PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
) ) ||
894 (mc_list
!= NULL
) ) {
897 if (mc_list
!= NULL
) {
898 mc_count
= AdapterInfo
->mcast_list
.list_len
= (UINT16
) (cpbsize
/ PXE_MAC_LENGTH
);
900 for (Index
= 0; (Index
< mc_count
&& Index
< MAX_MCAST_ADDRESS_CNT
); Index
++) {
901 for (Index2
= 0; Index2
< PXE_MAC_LENGTH
; Index2
++) {
902 AdapterInfo
->mcast_list
.mc_list
[Index
][Index2
] = mc_list
->MCastList
[Index
][Index2
];
908 // are we setting the list or resetting??
910 if ((new_filter
& PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
) != 0) {
912 // we are setting a new list!
914 mc_count
= AdapterInfo
->mcast_list
.list_len
;
916 // count should be the actual # of bytes in the list
917 // so multiply this with 6
919 mc_byte_cnt
= (UINT16
) ((mc_count
<< 2) + (mc_count
<< 1));
920 AdapterInfo
->Rx_Filter
|= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
;
923 // disabling the list in the NIC.
925 mc_byte_cnt
= mc_count
= 0;
926 AdapterInfo
->Rx_Filter
&= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
);
930 // before issuing any new command!
932 XmitWaitForCompletion (AdapterInfo
);
934 if (AdapterInfo
->Receive_Started
) {
935 StopRU (AdapterInfo
);
939 cmd_ptr
= GetFreeCB (AdapterInfo
);
940 if (cmd_ptr
== NULL
) {
941 return PXE_STATCODE_QUEUE_FULL
;
944 // fill the command structure and issue
946 data_ptr
= (struct MC_CB_STRUCT
*) (&cmd_ptr
->PhysTBDArrayAddres
);
948 // first 2 bytes are the count;
950 data_ptr
->count
= mc_byte_cnt
;
951 for (Index
= 0; Index
< mc_count
; Index
++) {
952 for (Index2
= 0; Index2
< PXE_HWADDR_LEN_ETHER
; Index2
++) {
953 data_ptr
->m_list
[Index
][Index2
] = AdapterInfo
->mcast_list
.mc_list
[Index
][Index2
];
957 cmd_ptr
->cb_header
.command
= CmdSuspend
| CmdMulticastList
;
958 cmd_ptr
->cb_header
.status
= 0;
960 BlockIt (AdapterInfo
, TRUE
);
961 IssueCB (AdapterInfo
, cmd_ptr
);
962 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
964 BlockIt (AdapterInfo
, FALSE
);
966 CommandWaitForCompletion (cmd_ptr
, AdapterInfo
);
968 cmd_ptr
->PhysTBDArrayAddres
= cmd_ptr
->PhysArrayAddr
;
969 cmd_ptr
->ByteCount
= cmd_ptr
->Threshold
= cmd_ptr
->TBDCount
= 0;
971 // fields beyond the immediatedata are assumed to be safe
972 // add the CB to the free list again
974 SetFreeCB (AdapterInfo
, cmd_ptr
);
977 if (new_filter
!= 0) {
979 // enable unicast and start the RU
981 AdapterInfo
->Rx_Filter
= (UINT8
) (AdapterInfo
->Rx_Filter
| (new_filter
| PXE_OPFLAGS_RECEIVE_FILTER_UNICAST
));
982 StartRU (AdapterInfo
);
985 // may be disabling everything!
987 if (AdapterInfo
->Receive_Started
) {
988 StopRU (AdapterInfo
);
991 AdapterInfo
->Rx_Filter
|= (~PXE_OPFLAGS_RECEIVE_FILTER_UNICAST
);
999 TODO: Add function description
1001 @param AdapterInfo TODO: add argument description
1002 @param cpb TODO: add argument description
1003 @param opflags TODO: add argument description
1005 @return TODO: add return values
1010 NIC_DATA_INSTANCE
*AdapterInfo
,
1015 PXE_CPB_TRANSMIT_FRAGMENTS
*tx_ptr_f
;
1016 PXE_CPB_TRANSMIT
*tx_ptr_1
;
1023 tx_ptr_1
= (PXE_CPB_TRANSMIT
*) (UINTN
) cpb
;
1024 tx_ptr_f
= (PXE_CPB_TRANSMIT_FRAGMENTS
*) (UINTN
) cpb
;
1027 // stop reentrancy here
1029 if (AdapterInfo
->in_transmit
) {
1030 return PXE_STATCODE_BUSY
;
1034 AdapterInfo
->in_transmit
= TRUE
;
1037 // Prevent interrupts from changing the Tx ring from underneath us.
1039 // Calculate the Tx descriptor entry.
1041 if ((tcb_ptr
= GetFreeCB (AdapterInfo
)) == NULL
) {
1042 AdapterInfo
->in_transmit
= FALSE
;
1043 return PXE_STATCODE_QUEUE_FULL
;
1046 AdapterInfo
->TxTotals
++;
1048 tcb_ptr
->cb_header
.command
= (CmdSuspend
| CmdTx
| CmdTxFlex
);
1049 tcb_ptr
->cb_header
.status
= 0;
1052 // no immediate data, set EOF in the ByteCount
1054 tcb_ptr
->ByteCount
= 0x8000;
1057 // The data region is always in one buffer descriptor, Tx FIFO
1058 // threshold of 256.
1059 // 82557 multiplies the threashold value by 8, so give 256/8
1061 tcb_ptr
->Threshold
= 32;
1062 if ((opflags
& PXE_OPFLAGS_TRANSMIT_FRAGMENTED
) != 0) {
1064 if (tx_ptr_f
->FragCnt
> MAX_XMIT_FRAGMENTS
) {
1065 SetFreeCB (AdapterInfo
, tcb_ptr
);
1066 AdapterInfo
->in_transmit
= FALSE
;
1067 return PXE_STATCODE_INVALID_PARAMETER
;
1070 tcb_ptr
->TBDCount
= (UINT8
) tx_ptr_f
->FragCnt
;
1072 for (Index
= 0; Index
< tx_ptr_f
->FragCnt
; Index
++) {
1075 tx_ptr_f
->FragDesc
[Index
].FragAddr
,
1076 tx_ptr_f
->FragDesc
[Index
].FragLen
,
1078 (UINT64
)(UINTN
) &Tmp_ptr
1081 SetFreeCB (AdapterInfo
, tcb_ptr
);
1082 AdapterInfo
->in_transmit
= FALSE
;
1083 return PXE_STATCODE_INVALID_PARAMETER
;
1086 tcb_ptr
->TBDArray
[Index
].phys_buf_addr
= (UINT32
) Tmp_ptr
;
1087 tcb_ptr
->TBDArray
[Index
].buf_len
= tx_ptr_f
->FragDesc
[Index
].FragLen
;
1090 tcb_ptr
->free_data_ptr
= tx_ptr_f
->FragDesc
[0].FragAddr
;
1094 // non fragmented case
1096 tcb_ptr
->TBDCount
= 1;
1099 tx_ptr_1
->FrameAddr
,
1100 tx_ptr_1
->DataLen
+ tx_ptr_1
->MediaheaderLen
,
1102 (UINT64
)(UINTN
) &Tmp_ptr
1105 SetFreeCB (AdapterInfo
, tcb_ptr
);
1106 AdapterInfo
->in_transmit
= FALSE
;
1107 return PXE_STATCODE_INVALID_PARAMETER
;
1110 tcb_ptr
->TBDArray
[0].phys_buf_addr
= (UINT32
) (Tmp_ptr
);
1111 tcb_ptr
->TBDArray
[0].buf_len
= tx_ptr_1
->DataLen
+ tx_ptr_1
->MediaheaderLen
;
1112 tcb_ptr
->free_data_ptr
= tx_ptr_1
->FrameAddr
;
1116 // must wait for previous command completion only if it was a non-transmit
1118 BlockIt (AdapterInfo
, TRUE
);
1119 IssueCB (AdapterInfo
, tcb_ptr
);
1120 BlockIt (AdapterInfo
, FALSE
);
1123 // see if we need to wait for completion here
1125 if ((opflags
& PXE_OPFLAGS_TRANSMIT_BLOCK
) != 0) {
1127 // don't wait for more than 1 second!!!
1130 while (tcb_ptr
->cb_header
.status
== 0) {
1131 DelayIt (AdapterInfo
, 10);
1133 if (wait_sec
== 0) {
1138 // we need to un-map any mapped buffers here
1140 if ((opflags
& PXE_OPFLAGS_TRANSMIT_FRAGMENTED
) != 0) {
1142 for (Index
= 0; Index
< tx_ptr_f
->FragCnt
; Index
++) {
1143 Tmp_ptr
= tcb_ptr
->TBDArray
[Index
].phys_buf_addr
;
1146 tx_ptr_f
->FragDesc
[Index
].FragAddr
,
1147 tx_ptr_f
->FragDesc
[Index
].FragLen
,
1153 Tmp_ptr
= tcb_ptr
->TBDArray
[0].phys_buf_addr
;
1156 tx_ptr_1
->FrameAddr
,
1157 tx_ptr_1
->DataLen
+ tx_ptr_1
->MediaheaderLen
,
1163 if (tcb_ptr
->cb_header
.status
== 0) {
1164 SetFreeCB (AdapterInfo
, tcb_ptr
);
1165 AdapterInfo
->in_transmit
= FALSE
;
1166 return PXE_STATCODE_DEVICE_FAILURE
;
1169 SetFreeCB (AdapterInfo
, tcb_ptr
);
1172 // CB will be set free later in get_status (or when we run out of xmit buffers
1174 AdapterInfo
->in_transmit
= FALSE
;
1181 TODO: Add function description
1183 @param AdapterInfo TODO: add argument description
1184 @param cpb TODO: add argument description
1185 @param db TODO: add argument description
1187 @return TODO: add return values
1192 NIC_DATA_INSTANCE
*AdapterInfo
,
1197 PXE_CPB_RECEIVE
*rx_cpbptr
;
1198 PXE_DB_RECEIVE
*rx_dbptr
;
1204 PXE_FRAME_TYPE pkt_type
;
1206 EtherHeader
*hdr_ptr
;
1207 ret_code
= PXE_STATCODE_NO_DATA
;
1208 pkt_type
= PXE_FRAME_TYPE_NONE
;
1209 status
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBStatus
);
1210 AdapterInfo
->Int_Status
= (UINT16
) (AdapterInfo
->Int_Status
| status
);
1212 // acknoledge the interrupts
1214 OutWord (AdapterInfo
, (UINT16
) (status
& 0xfc00), (UINT32
) (AdapterInfo
->ioaddr
+ SCBStatus
));
1217 // include the prev ints as well
1219 status
= AdapterInfo
->Int_Status
;
1220 rx_cpbptr
= (PXE_CPB_RECEIVE
*) (UINTN
) cpb
;
1221 rx_dbptr
= (PXE_DB_RECEIVE
*) (UINTN
) db
;
1223 rx_ptr
= &AdapterInfo
->rx_ring
[AdapterInfo
->cur_rx_ind
];
1226 // be in a loop just in case (we may drop a pkt)
1228 while ((status
= rx_ptr
->cb_header
.status
) & RX_COMPLETE
) {
1230 AdapterInfo
->RxTotals
++;
1232 // If we own the next entry, it's a new packet. Send it up.
1234 if (rx_ptr
->forwarded
) {
1240 // discard bad frames
1244 // crc, align, dma overrun, too short, receive error (v22 no coll)
1246 if ((status
& 0x0D90) != 0) {
1252 // make sure the status is OK
1254 if ((status
& 0x02000) == 0) {
1258 pkt_len
= (UINT16
) (rx_ptr
->ActualCount
& 0x3fff);
1263 if (pkt_len
> rx_cpbptr
->BufferLen
) {
1264 Tmp_len
= (UINT16
) rx_cpbptr
->BufferLen
;
1267 CopyMem ((INT8
*) (UINTN
) rx_cpbptr
->BufferAddr
, (INT8
*) &rx_ptr
->RFDBuffer
, Tmp_len
);
1269 hdr_ptr
= (EtherHeader
*) &rx_ptr
->RFDBuffer
;
1271 // fill the CDB and break the loop
1277 rx_dbptr
->FrameLen
= pkt_len
;
1278 rx_dbptr
->MediaHeaderLen
= PXE_MAC_HEADER_LEN_ETHER
;
1280 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1281 if (hdr_ptr
->dest_addr
[Index
] != AdapterInfo
->CurrentNodeAddress
[Index
]) {
1286 if (Index
>= PXE_HWADDR_LEN_ETHER
) {
1287 pkt_type
= PXE_FRAME_TYPE_UNICAST
;
1289 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1290 if (hdr_ptr
->dest_addr
[Index
] != AdapterInfo
->BroadcastNodeAddress
[Index
]) {
1295 if (Index
>= PXE_HWADDR_LEN_ETHER
) {
1296 pkt_type
= PXE_FRAME_TYPE_BROADCAST
;
1298 if ((hdr_ptr
->dest_addr
[0] & 1) == 1) {
1303 pkt_type
= PXE_FRAME_TYPE_FILTERED_MULTICAST
;
1305 pkt_type
= PXE_FRAME_TYPE_PROMISCUOUS
;
1310 rx_dbptr
->Type
= pkt_type
;
1311 rx_dbptr
->Protocol
= hdr_ptr
->type
;
1313 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1314 rx_dbptr
->SrcAddr
[Index
] = hdr_ptr
->src_addr
[Index
];
1315 rx_dbptr
->DestAddr
[Index
] = hdr_ptr
->dest_addr
[Index
];
1318 rx_ptr
->forwarded
= TRUE
;
1323 Recycle_RFD (AdapterInfo
, AdapterInfo
->cur_rx_ind
);
1324 AdapterInfo
->cur_rx_ind
++;
1325 if (AdapterInfo
->cur_rx_ind
== AdapterInfo
->RxBufCnt
) {
1326 AdapterInfo
->cur_rx_ind
= 0;
1332 Recycle_RFD (AdapterInfo
, AdapterInfo
->cur_rx_ind
);
1333 AdapterInfo
->cur_rx_ind
++;
1334 if (AdapterInfo
->cur_rx_ind
== AdapterInfo
->RxBufCnt
) {
1335 AdapterInfo
->cur_rx_ind
= 0;
1338 rx_ptr
= &AdapterInfo
->rx_ring
[AdapterInfo
->cur_rx_ind
];
1341 if (pkt_type
== PXE_FRAME_TYPE_NONE
) {
1342 AdapterInfo
->Int_Status
&= (~SCB_STATUS_FR
);
1345 status
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBStatus
);
1346 if ((status
& SCB_RUS_NO_RESOURCES
) != 0) {
1348 // start the receive unit here!
1349 // leave all the filled frames,
1351 SetupReceiveQueues (AdapterInfo
);
1352 OutLong (AdapterInfo
, (UINT32
) AdapterInfo
->rx_phy_addr
, AdapterInfo
->ioaddr
+ SCBPointer
);
1353 OutWord (AdapterInfo
, RX_START
, AdapterInfo
->ioaddr
+ SCBCmd
);
1354 AdapterInfo
->cur_rx_ind
= 0;
1362 TODO: Add function description
1364 @param AdapterInfo TODO: add argument description
1366 @return TODO: add return values
1370 E100bReadEepromAndStationAddress (
1371 NIC_DATA_INSTANCE
*AdapterInfo
1381 eedata
= (UINT16
*) (&AdapterInfo
->NVData
[0]);
1384 addr_len
= E100bGetEepromAddrLen (AdapterInfo
);
1389 AdapterInfo
->NVData_Len
= eeprom_len
= (UINT16
) (1 << addr_len
);
1390 for (Index2
= 0, Index
= 0; Index
< eeprom_len
; Index
++) {
1392 value
= E100bReadEeprom (AdapterInfo
, Index
, addr_len
);
1393 eedata
[Index
] = value
;
1394 sum
= (UINT16
) (sum
+ value
);
1396 AdapterInfo
->PermNodeAddress
[Index2
++] = (UINT8
) value
;
1397 AdapterInfo
->PermNodeAddress
[Index2
++] = (UINT8
) (value
>> 8);
1401 if (sum
!= 0xBABA) {
1405 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1406 AdapterInfo
->CurrentNodeAddress
[Index
] = AdapterInfo
->PermNodeAddress
[Index
];
1409 for (Index
= 0; Index
< PXE_HWADDR_LEN_ETHER
; Index
++) {
1410 AdapterInfo
->BroadcastNodeAddress
[Index
] = 0xff;
1413 for (Index
= PXE_HWADDR_LEN_ETHER
; Index
< PXE_MAC_LENGTH
; Index
++) {
1414 AdapterInfo
->CurrentNodeAddress
[Index
] = 0;
1415 AdapterInfo
->PermNodeAddress
[Index
] = 0;
1416 AdapterInfo
->BroadcastNodeAddress
[Index
] = 0;
1423 // CBList is a circular linked list
1424 // 1) When all are free, Tail->next == Head and FreeCount == # allocated
1425 // 2) When none are free, Tail == Head and FreeCount == 0
1426 // 3) when one is free, Tail == Head and Freecount == 1
1427 // 4) First non-Free frame is always at Tail->next
1431 TODO: Add function description
1433 @param AdapterInfo TODO: add argument description
1435 @return TODO: add return values
1440 NIC_DATA_INSTANCE
*AdapterInfo
1449 cur_ptr
= &(AdapterInfo
->tx_ring
[0]);
1450 array_off
= (UINTN
) (&cur_ptr
->TBDArray
) - (UINTN
) cur_ptr
;
1451 for (Index
= 0; Index
< AdapterInfo
->TxBufCnt
; Index
++) {
1452 cur_ptr
[Index
].cb_header
.status
= 0;
1453 cur_ptr
[Index
].cb_header
.command
= 0;
1455 cur_ptr
[Index
].PhysTCBAddress
=
1456 (UINT32
) AdapterInfo
->tx_phy_addr
+ (Index
* sizeof (TxCB
));
1458 cur_ptr
[Index
].PhysArrayAddr
= (UINT32
)(cur_ptr
[Index
].PhysTCBAddress
+ array_off
);
1459 cur_ptr
[Index
].PhysTBDArrayAddres
= (UINT32
)(cur_ptr
[Index
].PhysTCBAddress
+ array_off
);
1461 cur_ptr
->free_data_ptr
= (UINT64
) 0;
1463 if (Index
< AdapterInfo
->TxBufCnt
- 1) {
1464 cur_ptr
[Index
].cb_header
.link
= cur_ptr
[Index
].PhysTCBAddress
+ sizeof (TxCB
);
1465 cur_ptr
[Index
].NextTCBVirtualLinkPtr
= &cur_ptr
[Index
+ 1];
1466 cur_ptr
[Index
+ 1].PrevTCBVirtualLinkPtr
= &cur_ptr
[Index
];
1470 head_ptr
= &cur_ptr
[0];
1471 tail_ptr
= &cur_ptr
[AdapterInfo
->TxBufCnt
- 1];
1472 tail_ptr
->cb_header
.link
= head_ptr
->PhysTCBAddress
;
1473 tail_ptr
->NextTCBVirtualLinkPtr
= head_ptr
;
1474 head_ptr
->PrevTCBVirtualLinkPtr
= tail_ptr
;
1476 AdapterInfo
->FreeCBCount
= AdapterInfo
->TxBufCnt
;
1477 AdapterInfo
->FreeTxHeadPtr
= head_ptr
;
1479 // set tail of the free list, next to this would be either in use
1480 // or the head itself
1482 AdapterInfo
->FreeTxTailPtr
= tail_ptr
;
1484 AdapterInfo
->xmit_done_head
= AdapterInfo
->xmit_done_tail
= 0;
1491 TODO: Add function description
1493 @param AdapterInfo TODO: add argument description
1495 @return TODO: add return values
1500 NIC_DATA_INSTANCE
*AdapterInfo
1506 // claim any hanging free CBs
1508 if (AdapterInfo
->FreeCBCount
<= 1) {
1509 CheckCBList (AdapterInfo
);
1513 // don't use up the last CB problem if the previous CB that the CU used
1514 // becomes the last CB we submit because of the SUSPEND bit we set.
1515 // the CU thinks it was never cleared.
1518 if (AdapterInfo
->FreeCBCount
<= 1) {
1522 BlockIt (AdapterInfo
, TRUE
);
1523 free_cb_ptr
= AdapterInfo
->FreeTxHeadPtr
;
1524 AdapterInfo
->FreeTxHeadPtr
= free_cb_ptr
->NextTCBVirtualLinkPtr
;
1525 --AdapterInfo
->FreeCBCount
;
1526 BlockIt (AdapterInfo
, FALSE
);
1532 TODO: Add function description
1534 @param AdapterInfo TODO: add argument description
1535 @param cb_ptr TODO: add argument description
1537 @return TODO: add return values
1542 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1547 // here we assume cb are returned in the order they are taken out
1548 // and we link the newly freed cb at the tail of free cb list
1550 cb_ptr
->cb_header
.status
= 0;
1551 cb_ptr
->free_data_ptr
= (UINT64
) 0;
1553 AdapterInfo
->FreeTxTailPtr
= cb_ptr
;
1554 ++AdapterInfo
->FreeCBCount
;
1560 TODO: Add function description
1562 @param ind TODO: add argument description
1564 @return TODO: add return values
1574 Tmp
= (UINT16
) (ind
+ 1);
1575 if (Tmp
>= (TX_BUFFER_COUNT
<< 1)) {
1584 TODO: Add function description
1586 @param AdapterInfo TODO: add argument description
1588 @return TODO: add return values
1593 IN NIC_DATA_INSTANCE
*AdapterInfo
1601 Tmp_ptr
= AdapterInfo
->FreeTxTailPtr
->NextTCBVirtualLinkPtr
;
1602 if ((Tmp_ptr
->cb_header
.status
& CMD_STATUS_MASK
) != 0) {
1604 // check if Q is full
1606 if (next (AdapterInfo
->xmit_done_tail
) != AdapterInfo
->xmit_done_head
) {
1607 AdapterInfo
->xmit_done
[AdapterInfo
->xmit_done_tail
] = Tmp_ptr
->free_data_ptr
;
1611 Tmp_ptr
->free_data_ptr
,
1612 Tmp_ptr
->TBDArray
[0].buf_len
,
1614 (UINT64
) Tmp_ptr
->TBDArray
[0].phys_buf_addr
1617 AdapterInfo
->xmit_done_tail
= next (AdapterInfo
->xmit_done_tail
);
1620 SetFreeCB (AdapterInfo
, Tmp_ptr
);
1629 // Description : Initialize the RFD list list by linking each element together
1630 // in a circular list. The simplified memory model is used.
1631 // All data is in the RFD. The RFDs are linked together and the
1632 // last one points back to the first one. When the current RFD
1633 // is processed (frame received), its EL bit is set and the EL
1634 // bit in the previous RXFD is cleared.
1635 // Allocation done during INIT, this is making linked list.
1639 TODO: Add function description
1641 @param AdapterInfo TODO: add argument description
1643 @return TODO: add return values
1647 SetupReceiveQueues (
1648 IN NIC_DATA_INSTANCE
*AdapterInfo
1655 AdapterInfo
->cur_rx_ind
= 0;
1656 rx_ptr
= (&AdapterInfo
->rx_ring
[0]);
1658 for (Index
= 0; Index
< AdapterInfo
->RxBufCnt
; Index
++) {
1659 rx_ptr
[Index
].cb_header
.status
= 0;
1660 rx_ptr
[Index
].cb_header
.command
= 0;
1661 rx_ptr
[Index
].RFDSize
= RX_BUFFER_SIZE
;
1662 rx_ptr
[Index
].ActualCount
= 0;
1664 // RBDs not used, simple memory model
1666 rx_ptr
[Index
].rx_buf_addr
= (UINT32
) (-1);
1669 // RBDs not used, simple memory model
1671 rx_ptr
[Index
].forwarded
= FALSE
;
1674 // don't use Tmp_ptr if it is beyond the last one
1676 if (Index
< AdapterInfo
->RxBufCnt
- 1) {
1677 rx_ptr
[Index
].cb_header
.link
= (UINT32
) AdapterInfo
->rx_phy_addr
+ ((Index
+ 1) * sizeof (RxFD
));
1681 tail_ptr
= (&AdapterInfo
->rx_ring
[AdapterInfo
->RxBufCnt
- 1]);
1682 tail_ptr
->cb_header
.link
= (UINT32
) AdapterInfo
->rx_phy_addr
;
1687 tail_ptr
->cb_header
.command
= 0xC000;
1688 AdapterInfo
->RFDTailPtr
= tail_ptr
;
1694 TODO: Add function description
1696 @param AdapterInfo TODO: add argument description
1697 @param rx_index TODO: add argument description
1699 @return TODO: add return values
1704 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1711 // change the EL bit and change the AdapterInfo->RxTailPtr
1712 // rx_ptr is assumed to be the head of the Q
1713 // AdapterInfo->rx_forwarded[rx_index] = FALSE;
1715 rx_ptr
= &AdapterInfo
->rx_ring
[rx_index
];
1716 tail_ptr
= AdapterInfo
->RFDTailPtr
;
1718 // set el_bit and suspend bit
1720 rx_ptr
->cb_header
.command
= 0xc000;
1721 rx_ptr
->cb_header
.status
= 0;
1722 rx_ptr
->ActualCount
= 0;
1723 rx_ptr
->forwarded
= FALSE
;
1724 AdapterInfo
->RFDTailPtr
= rx_ptr
;
1726 // resetting the el_bit.
1728 tail_ptr
->cb_header
.command
= 0;
1730 // check the receive unit, fix if there is any problem
1735 // Serial EEPROM section.
1737 // EEPROM_Ctrl bits.
1739 #define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */
1740 #define EE_CS 0x02 /* EEPROM chip select. */
1741 #define EE_DI 0x04 /* EEPROM chip data in. */
1742 #define EE_WRITE_0 0x01
1743 #define EE_WRITE_1 0x05
1744 #define EE_DO 0x08 /* EEPROM chip data out. */
1745 #define EE_ENB (0x4800 | EE_CS)
1748 // Delay between EEPROM clock transitions.
1749 // This will actually work with no delay on 33Mhz PCI.
1751 #define eeprom_delay(nanosec) DelayIt (AdapterInfo, nanosec);
1754 // The EEPROM commands include the alway-set leading bit.
1756 #define EE_WRITE_CMD 5 // 101b
1757 #define EE_READ_CMD 6 // 110b
1758 #define EE_ERASE_CMD (7 << 6)
1762 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1768 Routine Description:
1770 TODO: Add function description
1774 AdapterInfo - TODO: add argument description
1775 val - TODO: add argument description
1776 num_bits - TODO: add argument description
1780 TODO: add return values
1788 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
1790 for (Index
= num_bits
; Index
>= 0; Index
--) {
1796 dataval
= (INT16
) ((val
& (1 << Index
)) ? EE_DI
: 0);
1799 // mask off the data_in bit
1801 Tmp
= (UINT8
) (InByte (AdapterInfo
, EEAddr
) &~EE_DI
);
1802 Tmp
= (UINT8
) (Tmp
| dataval
);
1803 OutByte (AdapterInfo
, Tmp
, EEAddr
);
1806 // raise the eeprom clock
1808 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
1811 // lower the eeprom clock
1813 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
1820 TODO: Add function description
1822 @param AdapterInfo TODO: add argument description
1824 @return TODO: add return values
1829 IN NIC_DATA_INSTANCE
*AdapterInfo
1837 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
1840 for (Index
= 15; Index
>= 0; Index
--) {
1846 // mask off the data_in bit
1848 Tmp
= InByte (AdapterInfo
, EEAddr
);
1849 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
1851 Tmp
= InByte (AdapterInfo
, EEAddr
);
1852 retval
= (UINT16
) ((retval
<< 1) | ((Tmp
& EE_DO
) ? 1 : 0));
1856 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
1865 This routine sets the EEPROM lockout bit to gain exclusive access to the
1866 eeprom. the access bit is the most significant bit in the General Control
1867 Register 2 in the SCB space.
1869 @param AdapterInfo Pointer to the NIC data structure
1870 information which the UNDI driver is
1873 @retval TRUE if it got the access
1874 @retval FALSE if it fails to get the exclusive access
1878 E100bSetEepromLockOut (
1879 IN NIC_DATA_INSTANCE
*AdapterInfo
1885 if ((AdapterInfo
->DeviceID
== D102_DEVICE_ID
) ||
1886 (AdapterInfo
->RevID
>= D102_REVID
)) {
1892 tmp
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1893 tmp
|= GCR2_EEPROM_ACCESS_SEMAPHORE
;
1894 OutByte (AdapterInfo
, tmp
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1896 DelayIt (AdapterInfo
, 50);
1897 tmp
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1899 if (tmp
& GCR2_EEPROM_ACCESS_SEMAPHORE
) {
1912 This routine Resets the EEPROM lockout bit to giveup access to the
1913 eeprom. the access bit is the most significant bit in the General Control
1914 Register 2 in the SCB space.
1916 @param AdapterInfo Pointer to the NIC data structure
1917 information which the UNDI driver is
1924 E100bReSetEepromLockOut (
1925 IN NIC_DATA_INSTANCE
*AdapterInfo
1930 if ((AdapterInfo
->DeviceID
== D102_DEVICE_ID
) ||
1931 (AdapterInfo
->RevID
>= D102_REVID
)) {
1933 tmp
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1934 tmp
&= ~(GCR2_EEPROM_ACCESS_SEMAPHORE
);
1935 OutByte (AdapterInfo
, tmp
, AdapterInfo
->ioaddr
+ SCBGenCtrl2
);
1937 DelayIt (AdapterInfo
, 50);
1943 Using the NIC data structure information, read the EEPROM to get a Word of data for the MAC address.
1945 @param AdapterInfo Pointer to the NIC data structure
1946 information which the UNDI driver is
1948 @param Location Word offset into the MAC address to read.
1949 @param AddrLen Number of bits of address length.
1951 @retval RetVal The word read from the EEPROM.
1956 IN NIC_DATA_INSTANCE
*AdapterInfo
,
1967 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
1968 ReadCmd
= (UINT16
) (Location
| (EE_READ_CMD
<< AddrLen
));
1973 // get exclusive access to the eeprom first!
1975 E100bSetEepromLockOut (AdapterInfo
);
1978 // eeprom control reg bits: x,x,x,x,DO,DI,CS,SK
1979 // to write the opcode+data value out one bit at a time in DI starting at msb
1980 // and then out a 1 to sk, wait, out 0 to SK and wait
1981 // repeat this for all the bits to be written
1987 Tmp
= (UINT8
) (InByte (AdapterInfo
, EEAddr
) & 0xF2);
1988 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_CS
), EEAddr
);
1991 // 3 for the read opcode 110b
1993 shift_bits_out (AdapterInfo
, ReadCmd
, (UINT8
) (3 + AddrLen
));
1996 // read the eeprom word one bit at a time
1998 RetVal
= shift_bits_in (AdapterInfo
);
2001 // Terminate the EEPROM access and leave eeprom in a clean state.
2003 Tmp
= InByte (AdapterInfo
, EEAddr
);
2004 Tmp
&= ~(EE_CS
| EE_DI
);
2005 OutByte (AdapterInfo
, Tmp
, EEAddr
);
2008 // raise the clock and lower the eeprom shift clock
2010 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
2013 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
2017 // giveup access to the eeprom
2019 E100bReSetEepromLockOut (AdapterInfo
);
2026 Using the NIC data structure information, read the EEPROM to determine how many bits of address length
2027 this EEPROM is in Words.
2029 @param AdapterInfo Pointer to the NIC data structure
2030 information which the UNDI driver is
2033 @retval RetVal The word read from the EEPROM.
2037 E100bGetEepromAddrLen (
2038 IN NIC_DATA_INSTANCE
*AdapterInfo
2045 // assume 64word eeprom (so,6 bits of address_length)
2049 EEAddr
= AdapterInfo
->ioaddr
+ SCBeeprom
;
2050 ReadCmd
= (EE_READ_CMD
<< 6);
2053 // get exclusive access to the eeprom first!
2055 E100bSetEepromLockOut (AdapterInfo
);
2058 // address we are trying to read is 0
2059 // eeprom control reg bits: x,x,x,x,DO,,DI,,CS,SK
2060 // to write the opcode+data value out one bit at a time in DI starting at msb
2061 // and then out a 1 to sk, wait, out 0 to SK and wait
2062 // repeat this for all the bits to be written
2064 Tmp
= (UINT8
) (InByte (AdapterInfo
, EEAddr
) & 0xF2);
2067 // enable eeprom access
2069 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_CS
), EEAddr
);
2072 // 3 for opcode, 6 for the default address len
2074 shift_bits_out (AdapterInfo
, ReadCmd
, (UINT8
) (3 + 6));
2077 // (in case of a 64 word eeprom).
2078 // read the "dummy zero" from EE_DO to say that the address we wrote
2079 // (six 0s) is accepted, write more zeros (until 8) to get a "dummy zero"
2083 // assume the smallest
2086 Tmp
= InByte (AdapterInfo
, EEAddr
);
2087 while ((AddrLen
< 8) && ((Tmp
& EE_DO
) != 0)) {
2088 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_DI
), EEAddr
);
2092 // raise the eeprom clock
2094 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
2098 // lower the eeprom clock
2100 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
2102 Tmp
= InByte (AdapterInfo
, EEAddr
);
2107 // read the eeprom word, even though we don't need this
2109 shift_bits_in (AdapterInfo
);
2112 // Terminate the EEPROM access.
2114 Tmp
= InByte (AdapterInfo
, EEAddr
);
2115 Tmp
&= ~(EE_CS
| EE_DI
);
2116 OutByte (AdapterInfo
, Tmp
, EEAddr
);
2119 // raise the clock and lower the eeprom shift clock
2121 OutByte (AdapterInfo
, (UINT8
) (Tmp
| EE_SHIFT_CLK
), EEAddr
);
2124 OutByte (AdapterInfo
, (UINT8
) (Tmp
&~EE_SHIFT_CLK
), EEAddr
);
2128 // giveup access to the eeprom!
2130 E100bReSetEepromLockOut (AdapterInfo
);
2137 TODO: Add function description
2139 @param AdapterInfo TODO: add argument description
2140 @param DBaddr TODO: add argument description
2141 @param DBsize TODO: add argument description
2143 @return TODO: add return values
2148 NIC_DATA_INSTANCE
*AdapterInfo
,
2153 PXE_DB_STATISTICS db
;
2155 // wait upto one second (each wait is 100 micro s)
2159 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
2162 // Clear statistics done marker.
2164 AdapterInfo
->statistics
->done_marker
= 0;
2167 // Issue statistics dump (or dump w/ reset) command.
2171 (UINT8
) (DBsize
? CU_SHOWSTATS
: CU_DUMPSTATS
),
2172 (UINT32
) (AdapterInfo
->ioaddr
+ SCBCmd
)
2176 // Wait for command to complete.
2178 // zero the db here just to chew up a little more time.
2181 ZeroMem ((VOID
*) &db
, sizeof db
);
2185 // Wait a bit before checking.
2188 DelayIt (AdapterInfo
, 100);
2191 // Look for done marker at end of statistics.
2194 switch (AdapterInfo
->statistics
->done_marker
) {
2205 // if we did not "continue" from the above switch, we are done,
2211 // If this is a reset, we are out of here!
2214 return PXE_STATCODE_SUCCESS
;
2218 // Convert NIC statistics counter format to EFI/UNDI
2219 // specification statistics counter format.
2223 // 54 3210 fedc ba98 7654 3210
2224 // db.Supported = 01 0000 0100 1101 0001 0111;
2226 db
.Supported
= 0x104D17;
2229 // Statistics from the NIC
2232 db
.Data
[0x01] = AdapterInfo
->statistics
->rx_good_frames
;
2234 db
.Data
[0x02] = AdapterInfo
->statistics
->rx_runt_errs
;
2236 db
.Data
[0x08] = AdapterInfo
->statistics
->rx_crc_errs
+
2237 AdapterInfo
->statistics
->rx_align_errs
;
2239 db
.Data
[0x04] = db
.Data
[0x02] +
2241 AdapterInfo
->statistics
->rx_resource_errs
+
2242 AdapterInfo
->statistics
->rx_overrun_errs
;
2244 db
.Data
[0x00] = db
.Data
[0x01] + db
.Data
[0x04];
2246 db
.Data
[0x0B] = AdapterInfo
->statistics
->tx_good_frames
;
2248 db
.Data
[0x0E] = AdapterInfo
->statistics
->tx_coll16_errs
+
2249 AdapterInfo
->statistics
->tx_late_colls
+
2250 AdapterInfo
->statistics
->tx_underruns
+
2251 AdapterInfo
->statistics
->tx_one_colls
+
2252 AdapterInfo
->statistics
->tx_multi_colls
;
2254 db
.Data
[0x14] = AdapterInfo
->statistics
->tx_total_colls
;
2256 db
.Data
[0x0A] = db
.Data
[0x0B] +
2258 AdapterInfo
->statistics
->tx_lost_carrier
;
2260 if (DBsize
> sizeof db
) {
2264 CopyMem ((VOID
*) (UINTN
) DBaddr
, (VOID
*) &db
, (UINTN
) DBsize
);
2266 return PXE_STATCODE_SUCCESS
;
2271 TODO: Add function description
2273 @param AdapterInfo TODO: add argument description
2274 @param OpFlags TODO: add argument description
2276 @return TODO: add return values
2281 IN NIC_DATA_INSTANCE
*AdapterInfo
,
2288 // disable the interrupts
2290 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
2293 // wait for the tx queue to complete
2295 CheckCBList (AdapterInfo
);
2297 XmitWaitForCompletion (AdapterInfo
);
2299 if (AdapterInfo
->Receive_Started
) {
2300 StopRU (AdapterInfo
);
2303 InitializeChip (AdapterInfo
);
2306 // check the opflags and restart receive filters
2308 if ((OpFlags
& PXE_OPFLAGS_RESET_DISABLE_FILTERS
) == 0) {
2310 save_filter
= AdapterInfo
->Rx_Filter
;
2312 // if we give the filter same as Rx_Filter,
2313 // this routine will not set mcast list (it thinks there is no change)
2314 // to force it, we will reset that flag in the Rx_Filter
2316 AdapterInfo
->Rx_Filter
&= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST
);
2317 E100bSetfilter (AdapterInfo
, save_filter
, (UINT64
) 0, (UINT32
) 0);
2320 if ((OpFlags
& PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS
) != 0) {
2322 // disable the interrupts
2324 AdapterInfo
->int_mask
= 0;
2327 // else leave the interrupt in the pre-set state!!!
2329 E100bSetInterruptState (AdapterInfo
);
2336 TODO: Add function description
2338 @param AdapterInfo TODO: add argument description
2340 @return TODO: add return values
2345 IN NIC_DATA_INSTANCE
*AdapterInfo
2349 // disable the interrupts
2351 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
2354 // stop the receive unit
2356 if (AdapterInfo
->Receive_Started
) {
2357 StopRU (AdapterInfo
);
2361 // wait for the tx queue to complete
2363 CheckCBList (AdapterInfo
);
2364 if (AdapterInfo
->FreeCBCount
!= AdapterInfo
->TxBufCnt
) {
2365 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
2369 // we do not want to reset the phy, it takes a long time to renegotiate the
2370 // link after that (3-4 seconds)
2372 InitializeChip (AdapterInfo
);
2373 SelectiveReset (AdapterInfo
);
2379 This routine will write a value to the specified MII register
2380 of an external MDI compliant device (e.g. PHY 100). The command will
2381 execute in polled mode.
2383 @param AdapterInfo pointer to the structure that contains
2385 @param RegAddress The MII register that we are writing to
2386 @param PhyAddress The MDI address of the Phy component.
2387 @param DataValue The value that we are writing to the MII
2395 IN NIC_DATA_INSTANCE
*AdapterInfo
,
2396 IN UINT8 RegAddress
,
2397 IN UINT8 PhyAddress
,
2401 UINT32 WriteCommand
;
2403 WriteCommand
= ((UINT32
) DataValue
) |
2404 ((UINT32
)(RegAddress
<< 16)) |
2405 ((UINT32
)(PhyAddress
<< 21)) |
2406 ((UINT32
)(MDI_WRITE
<< 26));
2409 // Issue the write command to the MDI control register.
2411 OutLong (AdapterInfo
, WriteCommand
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
);
2414 // wait 20usec before checking status
2416 DelayIt (AdapterInfo
, 20);
2419 // poll for the mdi write to complete
2420 while ((InLong (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
) &
2421 MDI_PHY_READY
) == 0){
2422 DelayIt (AdapterInfo
, 20);
2428 This routine will read a value from the specified MII register
2429 of an external MDI compliant device (e.g. PHY 100), and return
2430 it to the calling routine. The command will execute in polled mode.
2432 @param AdapterInfo pointer to the structure that contains
2434 @param RegAddress The MII register that we are reading from
2435 @param PhyAddress The MDI address of the Phy component.
2436 @param DataValue pointer to the value that we read from
2443 IN NIC_DATA_INSTANCE
*AdapterInfo
,
2444 IN UINT8 RegAddress
,
2445 IN UINT8 PhyAddress
,
2446 IN OUT UINT16
*DataValue
2451 ReadCommand
= ((UINT32
) (RegAddress
<< 16)) |
2452 ((UINT32
) (PhyAddress
<< 21)) |
2453 ((UINT32
) (MDI_READ
<< 26));
2456 // Issue the read command to the MDI control register.
2458 OutLong (AdapterInfo
, ReadCommand
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
);
2461 // wait 20usec before checking status
2463 DelayIt (AdapterInfo
, 20);
2466 // poll for the mdi read to complete
2468 while ((InLong (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
) &
2469 MDI_PHY_READY
) == 0) {
2470 DelayIt (AdapterInfo
, 20);
2474 *DataValue
= InWord (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBCtrlMDI
);
2479 This routine will reset the PHY that the adapter is currently
2482 @param AdapterInfo pointer to the structure that contains
2489 NIC_DATA_INSTANCE
*AdapterInfo
2492 UINT16 MdiControlReg
;
2494 MdiControlReg
= (MDI_CR_AUTO_SELECT
|
2495 MDI_CR_RESTART_AUTO_NEG
|
2499 // Write the MDI control register with our new Phy configuration
2504 AdapterInfo
->PhyAddress
,
2513 This routine will detect what phy we are using, set the line
2514 speed, FDX or HDX, and configure the phy if necessary.
2515 The following combinations are supported:
2516 - TX or T4 PHY alone at PHY address 1
2517 - T4 or TX PHY at address 1 and MII PHY at address 0
2518 - 82503 alone (10Base-T mode, no full duplex support)
2519 - 82503 and MII PHY (TX or T4) at address 0
2520 The sequence / priority of detection is as follows:
2521 - PHY 1 with cable termination
2522 - PHY 0 with cable termination
2523 - PHY 1 (if found) without cable termination
2525 Additionally auto-negotiation capable (NWAY) and parallel
2526 detection PHYs are supported. The flow-chart is described in
2527 the 82557 software writer's manual.
2528 NOTE: 1. All PHY MDI registers are read in polled mode.
2529 2. The routines assume that the 82557 has been RESET and we have
2530 obtained the virtual memory address of the CSR.
2531 3. PhyDetect will not RESET the PHY.
2532 4. If FORCEFDX is set, SPEED should also be set. The driver will
2533 check the values for inconsistency with the detected PHY
2535 5. PHY 1 (the PHY on the adapter) may have an address in the range
2536 1 through 31 inclusive. The driver will accept addresses in
2538 6. Driver ignores FORCEFDX and SPEED overrides if a 503 interface
2541 @param AdapterInfo pointer to the structure that contains
2544 @retval TRUE If a Phy was detected, and configured
2546 @retval FALSE If a valid phy could not be detected and
2552 NIC_DATA_INSTANCE
*AdapterInfo
2556 UINT16 MdiControlReg
;
2557 UINT16 MdiStatusReg
;
2559 UINT8 ReNegotiateTime
;
2561 eedata
= (UINT16
*) (&AdapterInfo
->NVData
[0]);
2564 ReNegotiateTime
= 35;
2566 // EEPROM word [6] contains the Primary PHY record in which the least 3 bits
2567 // indicate the PHY address
2568 // and word [7] contains the secondary PHY record
2570 AdapterInfo
->PhyRecord
[0] = eedata
[6];
2571 AdapterInfo
->PhyRecord
[1] = eedata
[7];
2572 AdapterInfo
->PhyAddress
= (UINT8
) (AdapterInfo
->PhyRecord
[0] & 7);
2575 // Check for a phy address over-ride of 32 which indicates force use of 82503
2576 // not detecting the link in this case
2578 if (AdapterInfo
->PhyAddress
== 32) {
2580 // 503 interface over-ride
2581 // Record the current speed and duplex. We will be in half duplex
2582 // mode unless the user used the force full duplex over-ride.
2584 AdapterInfo
->LinkSpeed
= 10;
2589 // If the Phy Address is between 1-31 then we must first look for phy 1,
2592 if ((AdapterInfo
->PhyAddress
> 0) && (AdapterInfo
->PhyAddress
< 32)) {
2595 // Read the MDI control and status registers at phy 1
2596 // and check if we found a valid phy
2601 AdapterInfo
->PhyAddress
,
2608 AdapterInfo
->PhyAddress
,
2612 if (!((MdiControlReg
== 0xffff) ||
2613 ((MdiStatusReg
== 0) && (MdiControlReg
== 0)))) {
2616 // we have a valid phy1
2617 // Read the status register again because of sticky bits
2623 AdapterInfo
->PhyAddress
,
2628 // If there is a valid link then use this Phy.
2630 if (MdiStatusReg
& MDI_SR_LINK_STATUS
) {
2631 return (SetupPhy(AdapterInfo
));
2637 // Next try to detect a PHY at address 0x00 because there was no Phy 1,
2638 // or Phy 1 didn't have link, or we had a phy 0 over-ride
2642 // Read the MDI control and status registers at phy 0
2644 MdiRead (AdapterInfo
, MDI_CONTROL_REG
, 0, &MdiControlReg
);
2645 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2648 // check if we found a valid phy 0
2650 if (((MdiControlReg
== 0xffff) ||
2651 ((MdiStatusReg
== 0) && (MdiControlReg
== 0)))) {
2654 // we don't have a valid phy at address 0
2655 // if phy address was forced to 0, then error out because we
2656 // didn't find a phy at that address
2658 if (AdapterInfo
->PhyAddress
== 0x0000) {
2662 // at this point phy1 does not have link and there is no phy 0 at all
2663 // if we are forced to detect the cable, error out here!
2665 if (AdapterInfo
->CableDetect
!= 0) {
2672 // no phy 0, but there is a phy 1 (no link I guess), so use phy 1
2674 return SetupPhy (AdapterInfo
);
2677 // didn't find phy 0 or phy 1, so assume a 503 interface
2679 AdapterInfo
->PhyAddress
= 32;
2682 // Record the current speed and duplex. We'll be in half duplex
2683 // mode unless the user used the force full duplex over-ride.
2685 AdapterInfo
->LinkSpeed
= 10;
2691 // We have a valid phy at address 0. If phy 0 has a link then we use
2692 // phy 0. If Phy 0 doesn't have a link then we use Phy 1 (no link)
2693 // if phy 1 is present, or phy 0 if phy 1 is not present
2694 // If phy 1 was present, then we must isolate phy 1 before we enable
2695 // phy 0 to see if Phy 0 has a link.
2704 AdapterInfo
->PhyAddress
,
2709 // wait 100 microseconds for the phy to isolate.
2711 DelayIt (AdapterInfo
, 100);
2715 // Since this Phy is at address 0, we must enable it. So clear
2716 // the isolate bit, and set the auto-speed select bit
2726 // wait 100 microseconds for the phy to be enabled.
2728 DelayIt (AdapterInfo
, 100);
2731 // restart the auto-negotion process
2737 MDI_CR_RESTART_AUTO_NEG
| MDI_CR_AUTO_SELECT
2741 // wait no more than 3.5 seconds for auto-negotiation to complete
2743 while (ReNegotiateTime
) {
2745 // Read the status register twice because of sticky bits
2747 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2748 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2750 if (MdiStatusReg
& MDI_SR_AUTO_NEG_COMPLETE
) {
2754 DelayIt (AdapterInfo
, 100);
2759 // Read the status register again because of sticky bits
2761 MdiRead (AdapterInfo
, MDI_STATUS_REG
, 0, &MdiStatusReg
);
2764 // If the link was not set
2766 if ((MdiStatusReg
& MDI_SR_LINK_STATUS
) == 0) {
2768 // PHY1 does not have a link and phy 0 does not have a link
2769 // do not proceed if we need to detect the link!
2771 if (AdapterInfo
->CableDetect
!= 0) {
2776 // the link wasn't set, so use phy 1 if phy 1 was present
2782 MdiWrite (AdapterInfo
, MDI_CONTROL_REG
, 0, MDI_CR_ISOLATE
);
2785 // wait 100 microseconds for the phy to isolate.
2787 DelayIt (AdapterInfo
, 100);
2790 // Now re-enable PHY 1
2795 AdapterInfo
->PhyAddress
,
2800 // wait 100 microseconds for the phy to be enabled
2802 DelayIt (AdapterInfo
, 100);
2805 // restart the auto-negotion process
2810 AdapterInfo
->PhyAddress
,
2811 MDI_CR_RESTART_AUTO_NEG
| MDI_CR_AUTO_SELECT
2815 // Don't wait for it to complete (we didn't have link earlier)
2817 return (SetupPhy (AdapterInfo
));
2822 // Definitely using Phy 0
2824 AdapterInfo
->PhyAddress
= 0;
2825 return (SetupPhy(AdapterInfo
));
2831 This routine will setup phy 1 or phy 0 so that it is configured
2832 to match a speed and duplex over-ride option. If speed or
2833 duplex mode is not explicitly specified in the registry, the
2834 driver will skip the speed and duplex over-ride code, and
2835 assume the adapter is automatically setting the line speed, and
2836 the duplex mode. At the end of this routine, any truly Phy
2837 specific code will be executed (each Phy has its own quirks,
2838 and some require that certain special bits are set).
2839 NOTE: The driver assumes that SPEED and FORCEFDX are specified at the
2840 same time. If FORCEDPX is set without speed being set, the driver
2841 will encouter a fatal error and log a message into the event viewer.
2843 @param AdapterInfo pointer to the structure that contains
2846 @retval TRUE If the phy could be configured correctly
2847 @retval FALSE If the phy couldn't be configured
2848 correctly, because an unsupported
2849 over-ride option was used
2854 IN NIC_DATA_INSTANCE
*AdapterInfo
2857 UINT16 MdiControlReg
;
2858 UINT16 MdiStatusReg
;
2860 UINT16 MdiIdHighReg
;
2863 BOOLEAN ForcePhySetting
;
2865 ForcePhySetting
= FALSE
;
2868 // If we are NOT forcing a setting for line speed or full duplex, then
2869 // we won't force a link setting, and we'll jump down to the phy
2872 if (((AdapterInfo
->LinkSpeedReq
) || (AdapterInfo
->DuplexReq
))) {
2874 // Find out what kind of technology this Phy is capable of.
2879 AdapterInfo
->PhyAddress
,
2884 // Read the MDI control register at our phy
2889 AdapterInfo
->PhyAddress
,
2894 // Now check the validity of our forced option. If the force option is
2895 // valid, then force the setting. If the force option is not valid,
2896 // we'll set a flag indicating that we should error out.
2900 // If speed is forced to 10mb
2902 if (AdapterInfo
->LinkSpeedReq
== 10) {
2904 // If half duplex is forced
2906 if ((AdapterInfo
->DuplexReq
& PXE_FORCE_HALF_DUPLEX
) != 0) {
2907 if (MdiStatusReg
& MDI_SR_10T_HALF_DPX
) {
2909 MdiControlReg
&= ~(MDI_CR_10_100
| MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
2910 ForcePhySetting
= TRUE
;
2912 } else if ((AdapterInfo
->DuplexReq
& PXE_FORCE_FULL_DUPLEX
) != 0) {
2915 // If full duplex is forced
2917 if (MdiStatusReg
& MDI_SR_10T_FULL_DPX
) {
2919 MdiControlReg
&= ~(MDI_CR_10_100
| MDI_CR_AUTO_SELECT
);
2920 MdiControlReg
|= MDI_CR_FULL_HALF
;
2921 ForcePhySetting
= TRUE
;
2925 // If auto duplex (we actually set phy to 1/2)
2927 if (MdiStatusReg
& (MDI_SR_10T_FULL_DPX
| MDI_SR_10T_HALF_DPX
)) {
2929 MdiControlReg
&= ~(MDI_CR_10_100
| MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
2930 ForcePhySetting
= TRUE
;
2936 // If speed is forced to 100mb
2938 else if (AdapterInfo
->LinkSpeedReq
== 100) {
2940 // If half duplex is forced
2942 if ((AdapterInfo
->DuplexReq
& PXE_FORCE_HALF_DUPLEX
) != 0) {
2943 if (MdiStatusReg
& (MDI_SR_TX_HALF_DPX
| MDI_SR_T4_CAPABLE
)) {
2945 MdiControlReg
&= ~(MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
2946 MdiControlReg
|= MDI_CR_10_100
;
2947 ForcePhySetting
= TRUE
;
2949 } else if ((AdapterInfo
->DuplexReq
& PXE_FORCE_FULL_DUPLEX
) != 0) {
2951 // If full duplex is forced
2953 if (MdiStatusReg
& MDI_SR_TX_FULL_DPX
) {
2954 MdiControlReg
&= ~MDI_CR_AUTO_SELECT
;
2955 MdiControlReg
|= (MDI_CR_10_100
| MDI_CR_FULL_HALF
);
2956 ForcePhySetting
= TRUE
;
2960 // If auto duplex (we set phy to 1/2)
2962 if (MdiStatusReg
& (MDI_SR_TX_HALF_DPX
| MDI_SR_T4_CAPABLE
)) {
2964 MdiControlReg
&= ~(MDI_CR_AUTO_SELECT
| MDI_CR_FULL_HALF
);
2965 MdiControlReg
|= MDI_CR_10_100
;
2966 ForcePhySetting
= TRUE
;
2971 if (!ForcePhySetting
) {
2976 // Write the MDI control register with our new Phy configuration
2981 AdapterInfo
->PhyAddress
,
2986 // wait 100 milliseconds for auto-negotiation to complete
2988 DelayIt (AdapterInfo
, 100);
2992 // Find out specifically what Phy this is. We do this because for certain
2993 // phys there are specific bits that must be set so that the phy and the
2994 // 82557 work together properly.
3000 AdapterInfo
->PhyAddress
,
3006 AdapterInfo
->PhyAddress
,
3010 PhyId
= ((UINT32
) MdiIdLowReg
| ((UINT32
) MdiIdHighReg
<< 16));
3013 // And out the revsion field of the Phy ID so that we'll be able to detect
3014 // future revs of the same Phy.
3016 PhyId
&= PHY_MODEL_REV_ID_MASK
;
3019 // Handle the National TX
3021 if (PhyId
== PHY_NSC_TX
) {
3025 NSC_CONG_CONTROL_REG
,
3026 AdapterInfo
->PhyAddress
,
3030 MdiMiscReg
|= (NSC_TX_CONG_TXREADY
| NSC_TX_CONG_F_CONNECT
);
3034 NSC_CONG_CONTROL_REG
,
3035 AdapterInfo
->PhyAddress
,
3040 FindPhySpeedAndDpx (AdapterInfo
, PhyId
);
3043 // We put a hardware fix on to our adapters to work-around the PHY_100 errata
3044 // described below. The following code is only compiled in, if we wanted
3045 // to attempt a software workaround to the PHY_100 A/B step problem.
3053 This routine will figure out what line speed and duplex mode
3054 the PHY is currently using.
3056 @param AdapterInfo pointer to the structure that contains
3058 @param PhyId The ID of the PHY in question.
3064 FindPhySpeedAndDpx (
3065 IN NIC_DATA_INSTANCE
*AdapterInfo
,
3069 UINT16 MdiStatusReg
;
3072 UINT16 MdiLinkPartnerAdReg
;
3075 // If there was a speed and/or duplex override, then set our current
3076 // value accordingly
3078 AdapterInfo
->LinkSpeed
= AdapterInfo
->LinkSpeedReq
;
3079 AdapterInfo
->Duplex
= (UINT8
) ((AdapterInfo
->DuplexReq
& PXE_FORCE_FULL_DUPLEX
) ?
3080 FULL_DUPLEX
: HALF_DUPLEX
);
3083 // If speed and duplex were forced, then we know our current settings, so
3084 // we'll just return. Otherwise, we'll need to figure out what NWAY set
3087 if (AdapterInfo
->LinkSpeed
&& AdapterInfo
->Duplex
) {
3092 // If we didn't have a valid link, then we'll assume that our current
3093 // speed is 10mb half-duplex.
3097 // Read the status register twice because of sticky bits
3102 AdapterInfo
->PhyAddress
,
3108 AdapterInfo
->PhyAddress
,
3113 // If there wasn't a valid link then use default speed & duplex
3115 if (!(MdiStatusReg
& MDI_SR_LINK_STATUS
)) {
3117 AdapterInfo
->LinkSpeed
= 10;
3118 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3123 // If this is an Intel PHY (a T4 PHY_100 or a TX PHY_TX), then read bits
3124 // 1 and 0 of extended register 0, to get the current speed and duplex
3127 if ((PhyId
== PHY_100_A
) || (PhyId
== PHY_100_C
) || (PhyId
== PHY_TX_ID
)) {
3129 // Read extended register 0
3134 AdapterInfo
->PhyAddress
,
3139 // Get current speed setting
3141 if (MdiMiscReg
& PHY_100_ER0_SPEED_INDIC
) {
3142 AdapterInfo
->LinkSpeed
= 100;
3144 AdapterInfo
->LinkSpeed
= 10;
3148 // Get current duplex setting -- if bit is set then FDX is enabled
3150 if (MdiMiscReg
& PHY_100_ER0_FDX_INDIC
) {
3151 AdapterInfo
->Duplex
= FULL_DUPLEX
;
3153 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3159 // Read our link partner's advertisement register
3163 AUTO_NEG_LINK_PARTNER_REG
,
3164 AdapterInfo
->PhyAddress
,
3165 &MdiLinkPartnerAdReg
3169 // See if Auto-Negotiation was complete (bit 5, reg 1)
3174 AdapterInfo
->PhyAddress
,
3179 // If a True NWAY connection was made, then we can detect speed/duplex by
3180 // ANDing our adapter's advertised abilities with our link partner's
3181 // advertised ablilities, and then assuming that the highest common
3182 // denominator was chosed by NWAY.
3184 if ((MdiLinkPartnerAdReg
& NWAY_LP_ABILITY
) &&
3185 (MdiStatusReg
& MDI_SR_AUTO_NEG_COMPLETE
)) {
3188 // Read our advertisement register
3192 AUTO_NEG_ADVERTISE_REG
,
3193 AdapterInfo
->PhyAddress
,
3198 // AND the two advertisement registers together, and get rid of any
3201 MdiOwnAdReg
= (UINT16
) (MdiOwnAdReg
& (MdiLinkPartnerAdReg
& NWAY_LP_ABILITY
));
3204 // Get speed setting
3206 if (MdiOwnAdReg
& (NWAY_AD_TX_HALF_DPX
| NWAY_AD_TX_FULL_DPX
| NWAY_AD_T4_CAPABLE
)) {
3207 AdapterInfo
->LinkSpeed
= 100;
3209 AdapterInfo
->LinkSpeed
= 10;
3213 // Get duplex setting -- use priority resolution algorithm
3215 if (MdiOwnAdReg
& (NWAY_AD_T4_CAPABLE
)) {
3216 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3218 } else if (MdiOwnAdReg
& (NWAY_AD_TX_FULL_DPX
)) {
3219 AdapterInfo
->Duplex
= FULL_DUPLEX
;
3221 } else if (MdiOwnAdReg
& (NWAY_AD_TX_HALF_DPX
)) {
3222 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3224 } else if (MdiOwnAdReg
& (NWAY_AD_10T_FULL_DPX
)) {
3225 AdapterInfo
->Duplex
= FULL_DUPLEX
;
3228 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3234 // If we are connected to a dumb (non-NWAY) repeater or hub, and the line
3235 // speed was determined automatically by parallel detection, then we have
3236 // no way of knowing exactly what speed the PHY is set to unless that PHY
3237 // has a propietary register which indicates speed in this situation. The
3238 // NSC TX PHY does have such a register. Also, since NWAY didn't establish
3239 // the connection, the duplex setting should HALF duplex.
3241 AdapterInfo
->Duplex
= HALF_DUPLEX
;
3243 if (PhyId
== PHY_NSC_TX
) {
3245 // Read register 25 to get the SPEED_10 bit
3250 AdapterInfo
->PhyAddress
,
3255 // If bit 6 was set then we're at 10mb
3257 if (MdiMiscReg
& NSC_TX_SPD_INDC_SPEED
) {
3258 AdapterInfo
->LinkSpeed
= 10;
3260 AdapterInfo
->LinkSpeed
= 100;
3265 // If we don't know what line speed we are set at, then we'll default to
3269 AdapterInfo
->LinkSpeed
= 10;
3275 TODO: Add function description
3277 @param AdapterInfo TODO: add argument description
3279 @return TODO: add return values
3283 XmitWaitForCompletion (
3284 NIC_DATA_INSTANCE
*AdapterInfo
3289 if (AdapterInfo
->FreeCBCount
== AdapterInfo
->TxBufCnt
) {
3294 // used xmit cb list starts right after the free tail (ends before the
3297 TxPtr
= AdapterInfo
->FreeTxTailPtr
->NextTCBVirtualLinkPtr
;
3298 while (TxPtr
!= AdapterInfo
->FreeTxHeadPtr
) {
3299 CommandWaitForCompletion (TxPtr
, AdapterInfo
);
3300 SetFreeCB (AdapterInfo
, TxPtr
);
3301 TxPtr
= TxPtr
->NextTCBVirtualLinkPtr
;
3307 TODO: Add function description
3309 @param cmd_ptr TODO: add argument description
3310 @param AdapterInfo TODO: add argument description
3312 @return TODO: add return values
3316 CommandWaitForCompletion (
3318 NIC_DATA_INSTANCE
*AdapterInfo
3323 while ((cmd_ptr
->cb_header
.status
== 0) && (--wait
> 0)) {
3324 DelayIt (AdapterInfo
, 10);
3327 if (cmd_ptr
->cb_header
.status
== 0) {
3336 TODO: Add function description
3338 @param AdapterInfo TODO: add argument description
3340 @return TODO: add return values
3345 NIC_DATA_INSTANCE
*AdapterInfo
3354 // Reset the chip: stop Tx and Rx processes and clear counters.
3355 // This takes less than 10usec and will easily finish before the next
3359 OutLong (AdapterInfo
, PORT_RESET
, AdapterInfo
->ioaddr
+ SCBPort
);
3361 // wait for 5 milli seconds here!
3363 DelayIt (AdapterInfo
, 5000);
3365 // TCO Errata work around for 559s only
3366 // -----------------------------------------------------------------------------------
3367 // TCO Workaround Code
3369 // -----------------------------------------------------------------------------------
3370 // 1. Issue SW-RST ^^^ (already done above)
3371 // 2. Issue a redundant Set CU Base CMD immediately
3372 // Do not set the General Pointer before the Set CU Base cycle
3373 // Do not check the SCB CMD before the Set CU Base cycle
3374 // 3. Wait for the SCB-CMD to be cleared
3375 // this indicates the transition to post-driver
3376 // 4. Poll the TCO-Req bit in the PMDR to be cleared
3377 // this indicates the tco activity has stopped for real
3378 // 5. Proceed with the nominal Driver Init:
3379 // Actual Set CU & RU Base ...
3381 // Check for ICH2 device ID. If this is an ICH2,
3382 // do the TCO workaround code.
3384 if (AdapterInfo
->VendorID
== D102_DEVICE_ID
||
3385 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_1
||
3386 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_2
||
3387 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_3
||
3388 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_4
||
3389 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_5
||
3390 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_6
||
3391 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_7
||
3392 AdapterInfo
->VendorID
== ICH3_DEVICE_ID_8
||
3393 AdapterInfo
->RevID
>= 8) { // do the TCO fix
3395 // donot load the scb pointer but just give load_cu cmd.
3397 OutByte (AdapterInfo
, CU_CMD_BASE
, AdapterInfo
->ioaddr
+ SCBCmd
);
3399 // wait for command to be accepted.
3401 wait_for_cmd_done (AdapterInfo
->ioaddr
+ SCBCmd
);
3403 // read PMDR register and check bit 1 in it to see if TCO is active
3407 // wait for 5 milli seconds
3411 tco_stat
= InByte (AdapterInfo
, AdapterInfo
->ioaddr
+ 0x1b);
3412 if ((tco_stat
& 2) == 0) {
3414 // is the activity bit clear??
3420 DelayIt (AdapterInfo
, 1);
3423 if ((tco_stat
& 2) != 0) {
3436 TODO: Add function description
3438 @param AdapterInfo TODO: add argument description
3440 @return TODO: add return values
3445 IN NIC_DATA_INSTANCE
*AdapterInfo
3453 OutLong (AdapterInfo
, POR_SELECTIVE_RESET
, AdapterInfo
->ioaddr
+ SCBPort
);
3455 // wait for this to complete
3459 // wait for 2 milli seconds here!
3461 DelayIt (AdapterInfo
, 2000);
3464 stat
= InLong (AdapterInfo
, AdapterInfo
->ioaddr
+ SCBPort
);
3470 // wait for 1 milli second
3472 DelayIt (AdapterInfo
, 1000);
3476 return PXE_STATCODE_DEVICE_FAILURE
;
3484 TODO: Add function description
3486 @param AdapterInfo TODO: add argument description
3488 @return TODO: add return values
3493 IN NIC_DATA_INSTANCE
*AdapterInfo
3497 if (SoftwareReset (AdapterInfo
) != 0) {
3498 return PXE_STATCODE_DEVICE_FAILURE
;
3502 // disable interrupts
3504 OutWord (AdapterInfo
, INT_MASK
, AdapterInfo
->ioaddr
+ SCBCmd
);
3507 // Load the base registers with 0s (we will give the complete address as
3508 // offset later when we issue any command
3510 if ((ret_val
= Load_Base_Regs (AdapterInfo
)) != 0) {
3514 if ((ret_val
= SetupCBlink (AdapterInfo
)) != 0) {
3518 if ((ret_val
= SetupReceiveQueues (AdapterInfo
)) != 0) {
3523 // detect the PHY only if we need to detect the cable as requested by the
3524 // initialize parameters
3526 AdapterInfo
->PhyAddress
= 0xFF;
3528 if (AdapterInfo
->CableDetect
!= 0) {
3529 if (!PhyDetect (AdapterInfo
)) {
3530 return PXE_STATCODE_DEVICE_FAILURE
;
3534 if ((ret_val
= E100bSetupIAAddr (AdapterInfo
)) != 0) {
3538 if ((ret_val
= Configure (AdapterInfo
)) != 0) {