Home | History | Annotate | Download | only in UndiRuntimeDxe
      1 /** @file
      2   Provides basic function upon network adapter card.
      3 
      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
      9 
     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.
     12 
     13 **/
     14 
     15 #include "Undi32.h"
     16 
     17 UINT8 basic_config_cmd[22] = {
     18                     22,        0x08,
     19                     0,           0,
     20                     0, (UINT8)0x80,
     21                     0x32,        0x03,
     22                     1,            0,
     23                     0x2E,           0,
     24                     0x60,           0,
     25                     (UINT8)0xf2,        0x48,
     26                     0,        0x40,
     27                     (UINT8)0xf2, (UINT8)0x80, // 0x40=Force full-duplex
     28                     0x3f,       0x05,
     29 };
     30 
     31 //
     32 // How to wait for the command unit to accept a command.
     33 // Typically this takes 0 ticks.
     34 //
     35 #define wait_for_cmd_done(cmd_ioaddr) \
     36 {                      \
     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);    \
     42 }
     43 
     44 
     45 /**
     46   This function calls the MemIo callback to read a byte from the device's
     47   address space
     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
     51 
     52   @param  Port                            Which port to read from.
     53 
     54   @retval Results                         The data read from the port.
     55 
     56 **/
     57 // TODO:    AdapterInfo - add argument and description to function comment
     58 UINT8
     59 InByte (
     60   IN NIC_DATA_INSTANCE *AdapterInfo,
     61   IN UINT32            Port
     62   )
     63 {
     64   UINT8 Results;
     65 
     66   (*AdapterInfo->Mem_Io) (
     67     AdapterInfo->Unique_ID,
     68     PXE_MEM_READ,
     69     1,
     70     (UINT64)Port,
     71     (UINT64) (UINTN) &Results
     72     );
     73   return Results;
     74 }
     75 
     76 
     77 /**
     78   This function calls the MemIo callback to read a word from the device's
     79   address space
     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
     83 
     84   @param  Port                            Which port to read from.
     85 
     86   @retval Results                         The data read from the port.
     87 
     88 **/
     89 // TODO:    AdapterInfo - add argument and description to function comment
     90 UINT16
     91 InWord (
     92   IN NIC_DATA_INSTANCE *AdapterInfo,
     93   IN UINT32            Port
     94   )
     95 {
     96   UINT16  Results;
     97 
     98   (*AdapterInfo->Mem_Io) (
     99     AdapterInfo->Unique_ID,
    100     PXE_MEM_READ,
    101     2,
    102     (UINT64)Port,
    103     (UINT64)(UINTN)&Results
    104     );
    105   return Results;
    106 }
    107 
    108 
    109 /**
    110   This function calls the MemIo callback to read a dword from the device's
    111   address space
    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
    115 
    116   @param  Port                            Which port to read from.
    117 
    118   @retval Results                         The data read from the port.
    119 
    120 **/
    121 // TODO:    AdapterInfo - add argument and description to function comment
    122 UINT32
    123 InLong (
    124   IN NIC_DATA_INSTANCE *AdapterInfo,
    125   IN UINT32            Port
    126   )
    127 {
    128   UINT32  Results;
    129 
    130   (*AdapterInfo->Mem_Io) (
    131     AdapterInfo->Unique_ID,
    132     PXE_MEM_READ,
    133     4,
    134     (UINT64)Port,
    135     (UINT64)(UINTN)&Results
    136     );
    137   return Results;
    138 }
    139 
    140 
    141 /**
    142   This function calls the MemIo callback to write a byte from the device's
    143   address space
    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
    147 
    148   @param  Data                            Data to write to Port.
    149   @param  Port                            Which port to write to.
    150 
    151   @return none
    152 
    153 **/
    154 // TODO:    AdapterInfo - add argument and description to function comment
    155 VOID
    156 OutByte (
    157   IN NIC_DATA_INSTANCE *AdapterInfo,
    158   IN UINT8             Data,
    159   IN UINT32            Port
    160   )
    161 {
    162   UINT8 Val;
    163 
    164   Val = Data;
    165   (*AdapterInfo->Mem_Io) (
    166      AdapterInfo->Unique_ID,
    167      PXE_MEM_WRITE,
    168      1,
    169      (UINT64)Port,
    170      (UINT64)(UINTN)(UINTN)&Val
    171      );
    172   return ;
    173 }
    174 
    175 
    176 /**
    177   This function calls the MemIo callback to write a word from the device's
    178   address space
    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
    182 
    183   @param  Data                            Data to write to Port.
    184   @param  Port                            Which port to write to.
    185 
    186   @return none
    187 
    188 **/
    189 // TODO:    AdapterInfo - add argument and description to function comment
    190 VOID
    191 OutWord (
    192   IN NIC_DATA_INSTANCE *AdapterInfo,
    193   IN UINT16            Data,
    194   IN UINT32            Port
    195   )
    196 {
    197   UINT16  Val;
    198 
    199   Val = Data;
    200   (*AdapterInfo->Mem_Io) (
    201      AdapterInfo->Unique_ID,
    202      PXE_MEM_WRITE,
    203      2,
    204      (UINT64)Port,
    205      (UINT64)(UINTN)&Val
    206      );
    207   return ;
    208 }
    209 
    210 
    211 /**
    212   This function calls the MemIo callback to write a dword from the device's
    213   address space
    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
    217 
    218   @param  Data                            Data to write to Port.
    219   @param  Port                            Which port to write to.
    220 
    221   @return none
    222 
    223 **/
    224 // TODO:    AdapterInfo - add argument and description to function comment
    225 VOID
    226 OutLong (
    227   IN NIC_DATA_INSTANCE *AdapterInfo,
    228   IN UINT32            Data,
    229   IN UINT32            Port
    230   )
    231 {
    232   UINT32  Val;
    233 
    234   Val = Data;
    235   (*AdapterInfo->Mem_Io) (
    236      AdapterInfo->Unique_ID,
    237      PXE_MEM_WRITE,
    238      4,
    239      (UINT64)Port,
    240      (UINT64)(UINTN)&Val
    241      );
    242   return ;
    243 }
    244 
    245 
    246 /**
    247   TODO: Add function description
    248 
    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
    254 
    255   @return TODO: add return values
    256 
    257 **/
    258 UINTN
    259 MapIt (
    260   IN NIC_DATA_INSTANCE *AdapterInfo,
    261   IN UINT64            MemAddr,
    262   IN UINT32            Size,
    263   IN UINT32            Direction,
    264   OUT UINT64           MappedAddr
    265   )
    266 {
    267   UINT64  *PhyAddr;
    268 
    269   PhyAddr = (UINT64 *) (UINTN) MappedAddr;
    270   //
    271   // mapping is different for theold and new NII protocols
    272   //
    273   if (AdapterInfo->VersionFlag == 0x30) {
    274     if (AdapterInfo->Virt2Phys_30 == (VOID *) NULL) {
    275       *PhyAddr = (UINT64) AdapterInfo->MemoryPtr;
    276     } else {
    277       (*AdapterInfo->Virt2Phys_30) (MemAddr, (UINT64) (UINTN) PhyAddr);
    278     }
    279 
    280     if (*PhyAddr > FOUR_GIGABYTE) {
    281       return PXE_STATCODE_INVALID_PARAMETER;
    282     }
    283   } else {
    284     if (AdapterInfo->Map_Mem == (VOID *) NULL) {
    285       //
    286       // this UNDI cannot handle addresses beyond 4 GB without a map routine
    287       //
    288       if (MemAddr > FOUR_GIGABYTE) {
    289         return PXE_STATCODE_INVALID_PARAMETER;
    290       } else {
    291         *PhyAddr = MemAddr;
    292       }
    293     } else {
    294       (*AdapterInfo->Map_Mem) (
    295         AdapterInfo->Unique_ID,
    296         MemAddr,
    297         Size,
    298         Direction,
    299         MappedAddr
    300         );
    301     }
    302   }
    303 
    304   return PXE_STATCODE_SUCCESS;
    305 }
    306 
    307 
    308 /**
    309   TODO: Add function description
    310 
    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
    316 
    317   @return TODO: add return values
    318 
    319 **/
    320 VOID
    321 UnMapIt (
    322   IN NIC_DATA_INSTANCE *AdapterInfo,
    323   IN UINT64            MemAddr,
    324   IN UINT32            Size,
    325   IN UINT32            Direction,
    326   IN UINT64            MappedAddr
    327   )
    328 {
    329   if (AdapterInfo->VersionFlag > 0x30) {
    330     //
    331     // no mapping service
    332     //
    333     if (AdapterInfo->UnMap_Mem != (VOID *) NULL) {
    334       (*AdapterInfo->UnMap_Mem) (
    335         AdapterInfo->Unique_ID,
    336         MemAddr,
    337         Size,
    338         Direction,
    339         MappedAddr
    340         );
    341 
    342     }
    343   }
    344 
    345   return ;
    346 }
    347 
    348 
    349 /**
    350 
    351   @param  AdapterInfo                     Pointer to the NIC data structure
    352                                           information which the UNDI driver is
    353                                           layering on..
    354 
    355 
    356 **/
    357 // TODO:    MicroSeconds - add argument and description to function comment
    358 VOID
    359 DelayIt (
    360   IN NIC_DATA_INSTANCE *AdapterInfo,
    361   UINT16               MicroSeconds
    362   )
    363 {
    364   if (AdapterInfo->VersionFlag == 0x30) {
    365     (*AdapterInfo->Delay_30) (MicroSeconds);
    366   } else {
    367     (*AdapterInfo->Delay) (AdapterInfo->Unique_ID, MicroSeconds);
    368   }
    369 }
    370 
    371 
    372 /**
    373 
    374   @param  AdapterInfo                     Pointer to the NIC data structure
    375                                           information which the UNDI driver is
    376                                           layering on..
    377 
    378 
    379 **/
    380 // TODO:    flag - add argument and description to function comment
    381 VOID
    382 BlockIt (
    383   IN NIC_DATA_INSTANCE *AdapterInfo,
    384   UINT32               flag
    385   )
    386 {
    387   if (AdapterInfo->VersionFlag == 0x30) {
    388     (*AdapterInfo->Block_30) (flag);
    389   } else {
    390     (*AdapterInfo->Block) (AdapterInfo->Unique_ID, flag);
    391   }
    392 }
    393 
    394 
    395 /**
    396   TODO: Add function description
    397 
    398   @param  AdapterInfo                     TODO: add argument description
    399 
    400   @return TODO: add return values
    401 
    402 **/
    403 UINT8
    404 Load_Base_Regs (
    405   NIC_DATA_INSTANCE *AdapterInfo
    406   )
    407 {
    408   //
    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
    411   //
    412   //
    413   // we reset the statistics totals here because this is where we are loading stats addr
    414   //
    415   AdapterInfo->RxTotals = 0;
    416   AdapterInfo->TxTotals = 0;
    417 
    418   //
    419   // Load the statistics block address.
    420   //
    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;
    425 
    426   wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
    427   OutLong (AdapterInfo, 0, AdapterInfo->ioaddr + SCBPointer);
    428   OutByte (AdapterInfo, RX_ADDR_LOAD, AdapterInfo->ioaddr + SCBCmd);
    429 
    430   wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
    431   OutLong (AdapterInfo, 0, AdapterInfo->ioaddr + SCBPointer);
    432   OutByte (AdapterInfo, CU_CMD_BASE, AdapterInfo->ioaddr + SCBCmd);
    433 
    434   return 0;
    435 }
    436 
    437 
    438 /**
    439   TODO: Add function description
    440 
    441   @param  AdapterInfo                     TODO: add argument description
    442   @param  cmd_ptr                         TODO: add argument description
    443 
    444   @return TODO: add return values
    445 
    446 **/
    447 UINT8
    448 IssueCB (
    449   NIC_DATA_INSTANCE *AdapterInfo,
    450   TxCB              *cmd_ptr
    451   )
    452 {
    453   UINT16  status;
    454 
    455   wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
    456 
    457   //
    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
    462   //
    463   // Ensure that the CU Active Status bit is not on from previous CBs.
    464   //
    465   status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);
    466 
    467   //
    468   // Skip acknowledging the interrupt if it is not already set
    469   //
    470 
    471   //
    472   // ack only the cna the integer
    473   //
    474   if ((status & SCB_STATUS_CNA) != 0) {
    475     OutWord (AdapterInfo, SCB_STATUS_CNA, AdapterInfo->ioaddr + SCBStatus);
    476 
    477   }
    478 
    479   if ((status & SCB_STATUS_CU_MASK) == SCB_STATUS_CU_IDLE) {
    480     //
    481     // give a cu_start
    482     //
    483     OutLong (AdapterInfo, cmd_ptr->PhysTCBAddress, AdapterInfo->ioaddr + SCBPointer);
    484     OutByte (AdapterInfo, CU_START, AdapterInfo->ioaddr + SCBCmd);
    485   } else {
    486     //
    487     // either active or suspended, give a resume
    488     //
    489 
    490     cmd_ptr->PrevTCBVirtualLinkPtr->cb_header.command &= ~(CmdSuspend | CmdIntr);
    491     OutByte (AdapterInfo, CU_RESUME, AdapterInfo->ioaddr + SCBCmd);
    492   }
    493 
    494   return 0;
    495 }
    496 
    497 
    498 /**
    499   TODO: Add function description
    500 
    501   @param  AdapterInfo                     TODO: add argument description
    502 
    503   @return TODO: add return values
    504 
    505 **/
    506 UINT8
    507 Configure (
    508   NIC_DATA_INSTANCE *AdapterInfo
    509   )
    510 {
    511   //
    512   // all command blocks are of TxCB format
    513   //
    514   TxCB  *cmd_ptr;
    515   UINT8 *data_ptr;
    516   volatile INT16 Index;
    517   UINT8 my_filter;
    518 
    519   cmd_ptr   = GetFreeCB (AdapterInfo);
    520   ASSERT (cmd_ptr != NULL);
    521   data_ptr  = (UINT8 *) cmd_ptr + sizeof (struct CB_Header);
    522 
    523   //
    524   // start the config data right after the command header
    525   //
    526   for (Index = 0; Index < sizeof (basic_config_cmd); Index++) {
    527     data_ptr[Index] = basic_config_cmd[Index];
    528   }
    529 
    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));
    532 
    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);
    536 
    537   //
    538   // check if we have to use the AUI port instead
    539   //
    540   if ((AdapterInfo->PhyRecord[0] & 0x8000) != 0) {
    541     data_ptr[15] |= 0x80;
    542     data_ptr[8] = 0;
    543   }
    544 
    545   BlockIt (AdapterInfo, TRUE);
    546   cmd_ptr->cb_header.command = CmdSuspend | CmdConfigure;
    547 
    548   IssueCB (AdapterInfo, cmd_ptr);
    549   wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
    550 
    551   BlockIt (AdapterInfo, FALSE);
    552 
    553   CommandWaitForCompletion (cmd_ptr, AdapterInfo);
    554 
    555   //
    556   // restore the cb values for tx
    557   //
    558   cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr;
    559   cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0;
    560   //
    561   // fields beyond the immediatedata are assumed to be safe
    562   // add the CB to the free list again
    563   //
    564   SetFreeCB (AdapterInfo, cmd_ptr);
    565   return 0;
    566 }
    567 
    568 
    569 /**
    570   TODO: Add function description
    571 
    572   @param  AdapterInfo                     TODO: add argument description
    573 
    574   @return TODO: add return values
    575 
    576 **/
    577 UINT8
    578 E100bSetupIAAddr (
    579   NIC_DATA_INSTANCE *AdapterInfo
    580   )
    581 {
    582   //
    583   // all command blocks are of TxCB format
    584   //
    585   TxCB    *cmd_ptr;
    586   UINT16  *data_ptr;
    587   UINT16  *eaddrs;
    588 
    589   eaddrs    = (UINT16 *) AdapterInfo->CurrentNodeAddress;
    590 
    591   cmd_ptr   = GetFreeCB (AdapterInfo);
    592   ASSERT (cmd_ptr != NULL);
    593   data_ptr  = (UINT16 *) ((UINT8 *) cmd_ptr +sizeof (struct CB_Header));
    594 
    595   //
    596   // AVOID a bug (?!) here by marking the command already completed.
    597   //
    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];
    603 
    604   BlockIt (AdapterInfo, TRUE);
    605   IssueCB (AdapterInfo, cmd_ptr);
    606   wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
    607   BlockIt (AdapterInfo, FALSE);
    608 
    609   CommandWaitForCompletion (cmd_ptr, AdapterInfo);
    610 
    611   //
    612   // restore the cb values for tx
    613   //
    614   cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr;
    615   cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0;
    616   //
    617   // fields beyond the immediatedata are assumed to be safe
    618   // add the CB to the free list again
    619   //
    620   SetFreeCB (AdapterInfo, cmd_ptr);
    621   return 0;
    622 }
    623 
    624 
    625 /**
    626   Instructs the NIC to stop receiving packets.
    627 
    628   @param  AdapterInfo                     Pointer to the NIC data structure
    629                                           information which the UNDI driver is
    630                                           layering on..
    631 
    632 
    633 **/
    634 VOID
    635 StopRU (
    636   IN NIC_DATA_INSTANCE *AdapterInfo
    637   )
    638 {
    639   if (AdapterInfo->Receive_Started) {
    640 
    641     //
    642     // Todo: verify that we must wait for previous command completion.
    643     //
    644     wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
    645 
    646     //
    647     // Disable interrupts, and stop the chip's Rx process.
    648     //
    649     OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
    650     OutWord (AdapterInfo, INT_MASK | RX_ABORT, AdapterInfo->ioaddr + SCBCmd);
    651 
    652     AdapterInfo->Receive_Started = FALSE;
    653   }
    654 
    655   return ;
    656 }
    657 
    658 
    659 /**
    660   Instructs the NIC to start receiving packets.
    661 
    662   @param  AdapterInfo                     Pointer to the NIC data structure
    663                                           information which the UNDI driver is
    664                                           layering on..
    665 
    666   @retval 0                               Successful
    667   @retval -1                              Already Started
    668 
    669 **/
    670 INT8
    671 StartRU (
    672   NIC_DATA_INSTANCE *AdapterInfo
    673   )
    674 {
    675 
    676   if (AdapterInfo->Receive_Started) {
    677     //
    678     // already started
    679     //
    680     return -1;
    681   }
    682 
    683   AdapterInfo->cur_rx_ind = 0;
    684   AdapterInfo->Int_Status = 0;
    685 
    686   wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
    687 
    688   OutLong (AdapterInfo, (UINT32) AdapterInfo->rx_phy_addr, AdapterInfo->ioaddr + SCBPointer);
    689   OutByte (AdapterInfo, RX_START, AdapterInfo->ioaddr + SCBCmd);
    690 
    691   wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
    692 
    693   AdapterInfo->Receive_Started = TRUE;
    694   return 0;
    695 }
    696 
    697 
    698 /**
    699   Configures the chip.  This routine expects the NIC_DATA_INSTANCE structure to be filled in.
    700 
    701   @param  AdapterInfo                     Pointer to the NIC data structure
    702                                           information which the UNDI driver is
    703                                           layering on..
    704 
    705   @retval 0                               Successful
    706   @retval PXE_STATCODE_NOT_ENOUGH_MEMORY  Insufficient length of locked memory
    707   @retval other                           Failure initializing chip
    708 
    709 **/
    710 UINTN
    711 E100bInit (
    712   IN NIC_DATA_INSTANCE *AdapterInfo
    713   )
    714 {
    715   PCI_CONFIG_HEADER *CfgHdr;
    716   UINTN             stat;
    717   UINTN             rx_size;
    718   UINTN             tx_size;
    719 
    720   if (AdapterInfo->MemoryLength < MEMORY_NEEDED) {
    721     return PXE_STATCODE_NOT_ENOUGH_MEMORY;
    722   }
    723 
    724   stat = MapIt (
    725           AdapterInfo,
    726           AdapterInfo->MemoryPtr,
    727           AdapterInfo->MemoryLength,
    728           TO_AND_FROM_DEVICE,
    729           (UINT64)(UINTN) &AdapterInfo->Mapped_MemoryPtr
    730           );
    731 
    732   if (stat != 0) {
    733     return stat;
    734   }
    735 
    736   CfgHdr = (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]);
    737 
    738   //
    739   // fill in the ioaddr, int... from the config space
    740   //
    741   AdapterInfo->int_num = CfgHdr->int_line;
    742 
    743   //
    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;
    747   //
    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;
    755 
    756   //
    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.
    760   //
    761   if (E100bReadEepromAndStationAddress (AdapterInfo) != 0) {
    762     return PXE_STATCODE_DEVICE_FAILURE;
    763 
    764   }
    765   //
    766   // ## calculate the buffer #s depending on memory given
    767   // ## calculate the rx and tx ring pointers
    768   //
    769 
    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);
    777 
    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;
    781 
    782   //
    783   // auto detect.
    784   //
    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);
    790 }
    791 
    792 
    793 /**
    794   Sets the interrupt state for the NIC.
    795 
    796   @param  AdapterInfo                     Pointer to the NIC data structure
    797                                           information which the UNDI driver is
    798                                           layering on..
    799 
    800   @retval 0                               Successful
    801 
    802 **/
    803 UINT8
    804 E100bSetInterruptState (
    805   IN NIC_DATA_INSTANCE *AdapterInfo
    806   )
    807 {
    808   //
    809   // don't set receive interrupt if receiver is disabled...
    810   //
    811   UINT16  cmd_word;
    812 
    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);
    817   } else {
    818     //
    819     // disable ints, should not be given for SW Int.
    820     //
    821     OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
    822   }
    823 
    824   if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_SOFTWARE) != 0) {
    825     //
    826     // reset the bit in our mask, it is only one time!!
    827     //
    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);
    832   }
    833 
    834   return 0;
    835 }
    836 //
    837 // we are not going to disable broadcast for the WOL's sake!
    838 //
    839 
    840 /**
    841   Instructs the NIC to start receiving packets.
    842 
    843   @param  AdapterInfo                     Pointer to the NIC data structure
    844                                           information which the UNDI driver is
    845                                           layering on.. new_filter
    846                                               - cpb                             -
    847                                           cpbsize                         -
    848 
    849   @retval 0                               Successful
    850   @retval -1                              Already Started
    851 
    852 **/
    853 UINTN
    854 E100bSetfilter (
    855   NIC_DATA_INSTANCE *AdapterInfo,
    856   UINT16            new_filter,
    857   UINT64            cpb,
    858   UINT32            cpbsize
    859   )
    860 {
    861   PXE_CPB_RECEIVE_FILTERS *mc_list = (PXE_CPB_RECEIVE_FILTERS *) (UINTN)cpb;
    862   UINT16                  cfg_flt;
    863   UINT16                  old_filter;
    864   UINT16                  Index;
    865   UINT16                  Index2;
    866   UINT16                  mc_count;
    867   TxCB                    *cmd_ptr;
    868   struct MC_CB_STRUCT     *data_ptr;
    869   UINT16                  mc_byte_cnt;
    870 
    871   old_filter  = AdapterInfo->Rx_Filter;
    872 
    873   //
    874   // only these bits need a change in the configuration
    875   // actually change in bcast requires configure but we ignore that change
    876   //
    877   cfg_flt = PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS |
    878             PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
    879 
    880   if ((old_filter & cfg_flt) != (new_filter & cfg_flt)) {
    881     XmitWaitForCompletion (AdapterInfo);
    882 
    883     if (AdapterInfo->Receive_Started) {
    884       StopRU (AdapterInfo);
    885     }
    886 
    887     AdapterInfo->Rx_Filter = (UINT8) (new_filter | PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST);
    888     Configure (AdapterInfo);
    889   }
    890 
    891   //
    892   // check if mcast setting changed
    893   //
    894   if ( ((new_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) !=
    895        (old_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) ) ||
    896        (mc_list != NULL) ) {
    897 
    898 
    899     if (mc_list != NULL) {
    900       mc_count = AdapterInfo->mcast_list.list_len = (UINT16) (cpbsize / PXE_MAC_LENGTH);
    901 
    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];
    905         }
    906       }
    907     }
    908 
    909     //
    910     // are we setting the list or resetting??
    911     //
    912     if ((new_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
    913       //
    914       // we are setting a new list!
    915       //
    916       mc_count = AdapterInfo->mcast_list.list_len;
    917       //
    918       // count should be the actual # of bytes in the list
    919       // so multiply this with 6
    920       //
    921       mc_byte_cnt = (UINT16) ((mc_count << 2) + (mc_count << 1));
    922       AdapterInfo->Rx_Filter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
    923     } else {
    924       //
    925       // disabling the list in the NIC.
    926       //
    927       mc_byte_cnt = mc_count = 0;
    928       AdapterInfo->Rx_Filter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);
    929     }
    930 
    931     //
    932     // before issuing any new command!
    933     //
    934     XmitWaitForCompletion (AdapterInfo);
    935 
    936     if (AdapterInfo->Receive_Started) {
    937       StopRU (AdapterInfo);
    938 
    939     }
    940 
    941     cmd_ptr = GetFreeCB (AdapterInfo);
    942     if (cmd_ptr == NULL) {
    943       return PXE_STATCODE_QUEUE_FULL;
    944     }
    945     //
    946     // fill the command structure and issue
    947     //
    948     data_ptr = (struct MC_CB_STRUCT *) (&cmd_ptr->PhysTBDArrayAddres);
    949     //
    950     // first 2 bytes are the count;
    951     //
    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];
    956       }
    957     }
    958 
    959     cmd_ptr->cb_header.command  = CmdSuspend | CmdMulticastList;
    960     cmd_ptr->cb_header.status   = 0;
    961 
    962     BlockIt (AdapterInfo, TRUE);
    963     IssueCB (AdapterInfo, cmd_ptr);
    964     wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
    965 
    966     BlockIt (AdapterInfo, FALSE);
    967 
    968     CommandWaitForCompletion (cmd_ptr, AdapterInfo);
    969 
    970     cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr;
    971     cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0;
    972     //
    973     // fields beyond the immediatedata are assumed to be safe
    974     // add the CB to the free list again
    975     //
    976     SetFreeCB (AdapterInfo, cmd_ptr);
    977   }
    978 
    979   if (new_filter != 0) {
    980     //
    981     // enable unicast and start the RU
    982     //
    983     AdapterInfo->Rx_Filter = (UINT8) (AdapterInfo->Rx_Filter | (new_filter | PXE_OPFLAGS_RECEIVE_FILTER_UNICAST));
    984     StartRU (AdapterInfo);
    985   } else {
    986     //
    987     // may be disabling everything!
    988     //
    989     if (AdapterInfo->Receive_Started) {
    990       StopRU (AdapterInfo);
    991     }
    992 
    993     AdapterInfo->Rx_Filter |= (~PXE_OPFLAGS_RECEIVE_FILTER_UNICAST);
    994   }
    995 
    996   return 0;
    997 }
    998 
    999 
   1000 /**
   1001   TODO: Add function description
   1002 
   1003   @param  AdapterInfo                     TODO: add argument description
   1004   @param  cpb                             TODO: add argument description
   1005   @param  opflags                         TODO: add argument description
   1006 
   1007   @return TODO: add return values
   1008 
   1009 **/
   1010 UINTN
   1011 E100bTransmit (
   1012   NIC_DATA_INSTANCE *AdapterInfo,
   1013   UINT64            cpb,
   1014   UINT16            opflags
   1015   )
   1016 {
   1017   PXE_CPB_TRANSMIT_FRAGMENTS  *tx_ptr_f;
   1018   PXE_CPB_TRANSMIT            *tx_ptr_1;
   1019   TxCB                        *tcb_ptr;
   1020   UINT64                      Tmp_ptr;
   1021   UINTN                       stat;
   1022   INT32                       Index;
   1023   UINT16                      wait_sec;
   1024 
   1025   tx_ptr_1  = (PXE_CPB_TRANSMIT *) (UINTN) cpb;
   1026   tx_ptr_f  = (PXE_CPB_TRANSMIT_FRAGMENTS *) (UINTN) cpb;
   1027   Tmp_ptr = 0;
   1028 
   1029   //
   1030   // stop reentrancy here
   1031   //
   1032   if (AdapterInfo->in_transmit) {
   1033     return PXE_STATCODE_BUSY;
   1034 
   1035   }
   1036 
   1037   AdapterInfo->in_transmit = TRUE;
   1038 
   1039   //
   1040   // Prevent interrupts from changing the Tx ring from underneath us.
   1041   //
   1042   // Calculate the Tx descriptor entry.
   1043   //
   1044   if ((tcb_ptr = GetFreeCB (AdapterInfo)) == NULL) {
   1045     AdapterInfo->in_transmit = FALSE;
   1046     return PXE_STATCODE_QUEUE_FULL;
   1047   }
   1048 
   1049   AdapterInfo->TxTotals++;
   1050 
   1051   tcb_ptr->cb_header.command  = (CmdSuspend | CmdTx | CmdTxFlex);
   1052   tcb_ptr->cb_header.status   = 0;
   1053 
   1054   //
   1055   // no immediate data, set EOF in the ByteCount
   1056   //
   1057   tcb_ptr->ByteCount = 0x8000;
   1058 
   1059   //
   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
   1063   //
   1064   tcb_ptr->Threshold = 32;
   1065   if ((opflags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
   1066 
   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;
   1071     }
   1072 
   1073     tcb_ptr->TBDCount = (UINT8) tx_ptr_f->FragCnt;
   1074 
   1075     for (Index = 0; Index < tx_ptr_f->FragCnt; Index++) {
   1076       stat = MapIt (
   1077               AdapterInfo,
   1078               tx_ptr_f->FragDesc[Index].FragAddr,
   1079               tx_ptr_f->FragDesc[Index].FragLen,
   1080               TO_DEVICE,
   1081               (UINT64)(UINTN) &Tmp_ptr
   1082               );
   1083       if (stat != 0) {
   1084         SetFreeCB (AdapterInfo, tcb_ptr);
   1085         AdapterInfo->in_transmit = FALSE;
   1086         return PXE_STATCODE_INVALID_PARAMETER;
   1087       }
   1088 
   1089       tcb_ptr->TBDArray[Index].phys_buf_addr  = (UINT32) Tmp_ptr;
   1090       tcb_ptr->TBDArray[Index].buf_len        = tx_ptr_f->FragDesc[Index].FragLen;
   1091     }
   1092 
   1093     tcb_ptr->free_data_ptr = tx_ptr_f->FragDesc[0].FragAddr;
   1094 
   1095   } else {
   1096     //
   1097     // non fragmented case
   1098     //
   1099     tcb_ptr->TBDCount = 1;
   1100     stat = MapIt (
   1101             AdapterInfo,
   1102             tx_ptr_1->FrameAddr,
   1103             tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen,
   1104             TO_DEVICE,
   1105             (UINT64)(UINTN) &Tmp_ptr
   1106             );
   1107     if (stat != 0) {
   1108       SetFreeCB (AdapterInfo, tcb_ptr);
   1109       AdapterInfo->in_transmit = FALSE;
   1110       return PXE_STATCODE_INVALID_PARAMETER;
   1111     }
   1112 
   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;
   1116   }
   1117 
   1118   //
   1119   // must wait for previous command completion only if it was a non-transmit
   1120   //
   1121   BlockIt (AdapterInfo, TRUE);
   1122   IssueCB (AdapterInfo, tcb_ptr);
   1123   BlockIt (AdapterInfo, FALSE);
   1124 
   1125   //
   1126   // see if we need to wait for completion here
   1127   //
   1128   if ((opflags & PXE_OPFLAGS_TRANSMIT_BLOCK) != 0) {
   1129     //
   1130     // don't wait for more than 1 second!!!
   1131     //
   1132     wait_sec = 1000;
   1133     while (tcb_ptr->cb_header.status == 0) {
   1134       DelayIt (AdapterInfo, 10);
   1135       wait_sec--;
   1136       if (wait_sec == 0) {
   1137         break;
   1138       }
   1139     }
   1140     //
   1141     // we need to un-map any mapped buffers here
   1142     //
   1143     if ((opflags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {
   1144 
   1145       for (Index = 0; Index < tx_ptr_f->FragCnt; Index++) {
   1146         Tmp_ptr = tcb_ptr->TBDArray[Index].phys_buf_addr;
   1147         UnMapIt (
   1148           AdapterInfo,
   1149           tx_ptr_f->FragDesc[Index].FragAddr,
   1150           tx_ptr_f->FragDesc[Index].FragLen,
   1151           TO_DEVICE,
   1152           (UINT64) Tmp_ptr
   1153           );
   1154       }
   1155     } else {
   1156       Tmp_ptr = tcb_ptr->TBDArray[0].phys_buf_addr;
   1157       UnMapIt (
   1158         AdapterInfo,
   1159         tx_ptr_1->FrameAddr,
   1160         tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen,
   1161         TO_DEVICE,
   1162         (UINT64) Tmp_ptr
   1163         );
   1164     }
   1165 
   1166     if (tcb_ptr->cb_header.status == 0) {
   1167       SetFreeCB (AdapterInfo, tcb_ptr);
   1168       AdapterInfo->in_transmit = FALSE;
   1169       return PXE_STATCODE_DEVICE_FAILURE;
   1170     }
   1171 
   1172     SetFreeCB (AdapterInfo, tcb_ptr);
   1173   }
   1174   //
   1175   // CB will be set free later in get_status (or when we run out of xmit buffers
   1176   //
   1177   AdapterInfo->in_transmit = FALSE;
   1178 
   1179   return 0;
   1180 }
   1181 
   1182 
   1183 /**
   1184   TODO: Add function description
   1185 
   1186   @param  AdapterInfo                     TODO: add argument description
   1187   @param  cpb                             TODO: add argument description
   1188   @param  db                              TODO: add argument description
   1189 
   1190   @return TODO: add return values
   1191 
   1192 **/
   1193 UINTN
   1194 E100bReceive (
   1195   NIC_DATA_INSTANCE *AdapterInfo,
   1196   UINT64            cpb,
   1197   UINT64            db
   1198   )
   1199 {
   1200   PXE_CPB_RECEIVE *rx_cpbptr;
   1201   PXE_DB_RECEIVE  *rx_dbptr;
   1202   RxFD            *rx_ptr;
   1203   INT32           status;
   1204   INT32           Index;
   1205   UINT16          pkt_len;
   1206   UINT16          ret_code;
   1207   PXE_FRAME_TYPE  pkt_type;
   1208   UINT16          Tmp_len;
   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);
   1214   //
   1215   // acknoledge the interrupts
   1216   //
   1217   OutWord (AdapterInfo, (UINT16) (status & 0xfc00), (UINT32) (AdapterInfo->ioaddr + SCBStatus));
   1218 
   1219   //
   1220   // include the prev ints as well
   1221   //
   1222   status = AdapterInfo->Int_Status;
   1223   rx_cpbptr = (PXE_CPB_RECEIVE *) (UINTN) cpb;
   1224   rx_dbptr  = (PXE_DB_RECEIVE *) (UINTN) db;
   1225 
   1226   rx_ptr    = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];
   1227 
   1228   //
   1229   // be in a loop just in case (we may drop a pkt)
   1230   //
   1231   while ((status = rx_ptr->cb_header.status) & RX_COMPLETE) {
   1232 
   1233     AdapterInfo->RxTotals++;
   1234     //
   1235     // If we own the next entry, it's a new packet. Send it up.
   1236     //
   1237     if (rx_ptr->forwarded) {
   1238       goto FreeRFD;
   1239 
   1240     }
   1241 
   1242     //
   1243     // discard bad frames
   1244     //
   1245 
   1246     //
   1247     // crc, align, dma overrun, too short, receive error (v22 no coll)
   1248     //
   1249     if ((status & 0x0D90) != 0) {
   1250       goto FreeRFD;
   1251 
   1252     }
   1253 
   1254     //
   1255     // make sure the status is OK
   1256     //
   1257     if ((status & 0x02000) == 0) {
   1258       goto FreeRFD;
   1259     }
   1260 
   1261     pkt_len = (UINT16) (rx_ptr->ActualCount & 0x3fff);
   1262 
   1263     if (pkt_len != 0) {
   1264 
   1265       Tmp_len = pkt_len;
   1266       if (pkt_len > rx_cpbptr->BufferLen) {
   1267         Tmp_len = (UINT16) rx_cpbptr->BufferLen;
   1268       }
   1269 
   1270       CopyMem ((INT8 *) (UINTN) rx_cpbptr->BufferAddr, (INT8 *) &rx_ptr->RFDBuffer, Tmp_len);
   1271 
   1272       hdr_ptr = (EtherHeader *) &rx_ptr->RFDBuffer;
   1273       //
   1274       // fill the CDB and break the loop
   1275       //
   1276 
   1277       //
   1278       // includes header
   1279       //
   1280       rx_dbptr->FrameLen = pkt_len;
   1281       rx_dbptr->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
   1282 
   1283       for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
   1284         if (hdr_ptr->dest_addr[Index] != AdapterInfo->CurrentNodeAddress[Index]) {
   1285           break;
   1286         }
   1287       }
   1288 
   1289       if (Index >= PXE_HWADDR_LEN_ETHER) {
   1290         pkt_type = PXE_FRAME_TYPE_UNICAST;
   1291       } else {
   1292         for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
   1293           if (hdr_ptr->dest_addr[Index] != AdapterInfo->BroadcastNodeAddress[Index]) {
   1294             break;
   1295           }
   1296         }
   1297 
   1298         if (Index >= PXE_HWADDR_LEN_ETHER) {
   1299           pkt_type = PXE_FRAME_TYPE_BROADCAST;
   1300         } else {
   1301           if ((hdr_ptr->dest_addr[0] & 1) == 1) {
   1302             //
   1303             // mcast
   1304             //
   1305 
   1306             pkt_type = PXE_FRAME_TYPE_FILTERED_MULTICAST;
   1307           } else {
   1308             pkt_type = PXE_FRAME_TYPE_PROMISCUOUS;
   1309           }
   1310         }
   1311       }
   1312 
   1313       rx_dbptr->Type      = pkt_type;
   1314       rx_dbptr->Protocol  = hdr_ptr->type;
   1315 
   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];
   1319       }
   1320 
   1321       rx_ptr->forwarded = TRUE;
   1322       //
   1323       // success
   1324       //
   1325       ret_code          = 0;
   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;
   1330       }
   1331       break;
   1332     }
   1333 
   1334 FreeRFD:
   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;
   1339     }
   1340 
   1341     rx_ptr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];
   1342   }
   1343 
   1344   if (pkt_type == PXE_FRAME_TYPE_NONE) {
   1345     AdapterInfo->Int_Status &= (~SCB_STATUS_FR);
   1346   }
   1347 
   1348   status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);
   1349   if ((status & SCB_RUS_NO_RESOURCES) != 0) {
   1350     //
   1351     // start the receive unit here!
   1352     // leave all the filled frames,
   1353     //
   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;
   1358   }
   1359 
   1360   return ret_code;
   1361 }
   1362 
   1363 
   1364 /**
   1365   TODO: Add function description
   1366 
   1367   @param  AdapterInfo                     TODO: add argument description
   1368 
   1369   @return TODO: add return values
   1370 
   1371 **/
   1372 INT16
   1373 E100bReadEepromAndStationAddress (
   1374   NIC_DATA_INSTANCE *AdapterInfo
   1375   )
   1376 {
   1377   INT32   Index;
   1378   INT32   Index2;
   1379   UINT16  sum;
   1380   UINT16  eeprom_len;
   1381   UINT8   addr_len;
   1382   UINT16  *eedata;
   1383 
   1384   eedata    = (UINT16 *) (&AdapterInfo->NVData[0]);
   1385 
   1386   sum       = 0;
   1387   addr_len  = E100bGetEepromAddrLen (AdapterInfo);
   1388 
   1389   //
   1390   // in words
   1391   //
   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++) {
   1394     UINT16  value;
   1395     value         = E100bReadEeprom (AdapterInfo, Index, addr_len);
   1396     eedata[Index] = value;
   1397     sum           = (UINT16) (sum + value);
   1398     if (Index < 3) {
   1399       AdapterInfo->PermNodeAddress[Index2++]  = (UINT8) value;
   1400       AdapterInfo->PermNodeAddress[Index2++]  = (UINT8) (value >> 8);
   1401     }
   1402   }
   1403 
   1404   if (sum != 0xBABA) {
   1405     return -1;
   1406   }
   1407 
   1408   for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
   1409     AdapterInfo->CurrentNodeAddress[Index] = AdapterInfo->PermNodeAddress[Index];
   1410   }
   1411 
   1412   for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
   1413     AdapterInfo->BroadcastNodeAddress[Index] = 0xff;
   1414   }
   1415 
   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;
   1420   }
   1421 
   1422   return 0;
   1423 }
   1424 
   1425 //
   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
   1431 //
   1432 
   1433 /**
   1434   TODO: Add function description
   1435 
   1436   @param  AdapterInfo                     TODO: add argument description
   1437 
   1438   @return TODO: add return values
   1439 
   1440 **/
   1441 UINT8
   1442 SetupCBlink (
   1443   NIC_DATA_INSTANCE *AdapterInfo
   1444   )
   1445 {
   1446   TxCB  *head_ptr;
   1447   TxCB  *tail_ptr;
   1448   TxCB  *cur_ptr;
   1449   INT32 Index;
   1450   UINTN array_off;
   1451 
   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;
   1457 
   1458     cur_ptr[Index].PhysTCBAddress     =
   1459     (UINT32) AdapterInfo->tx_phy_addr + (Index * sizeof (TxCB));
   1460 
   1461     cur_ptr[Index].PhysArrayAddr      = (UINT32)(cur_ptr[Index].PhysTCBAddress + array_off);
   1462     cur_ptr[Index].PhysTBDArrayAddres = (UINT32)(cur_ptr[Index].PhysTCBAddress + array_off);
   1463 
   1464     cur_ptr->free_data_ptr = (UINT64) 0;
   1465 
   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];
   1470     }
   1471   }
   1472 
   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;
   1478 
   1479   AdapterInfo->FreeCBCount        = AdapterInfo->TxBufCnt;
   1480   AdapterInfo->FreeTxHeadPtr      = head_ptr;
   1481   //
   1482   // set tail of the free list, next to this would be either in use
   1483   // or the head itself
   1484   //
   1485   AdapterInfo->FreeTxTailPtr  = tail_ptr;
   1486 
   1487   AdapterInfo->xmit_done_head = AdapterInfo->xmit_done_tail = 0;
   1488 
   1489   return 0;
   1490 }
   1491 
   1492 
   1493 /**
   1494   TODO: Add function description
   1495 
   1496   @param  AdapterInfo                     TODO: add argument description
   1497 
   1498   @return TODO: add return values
   1499 
   1500 **/
   1501 TxCB *
   1502 GetFreeCB (
   1503   NIC_DATA_INSTANCE *AdapterInfo
   1504   )
   1505 {
   1506   TxCB  *free_cb_ptr;
   1507 
   1508   //
   1509   // claim any hanging free CBs
   1510   //
   1511   if (AdapterInfo->FreeCBCount <= 1) {
   1512     CheckCBList (AdapterInfo);
   1513   }
   1514 
   1515   //
   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.
   1519   //
   1520 
   1521   if (AdapterInfo->FreeCBCount <= 1) {
   1522     return NULL;
   1523   }
   1524 
   1525   BlockIt (AdapterInfo, TRUE);
   1526   free_cb_ptr                 = AdapterInfo->FreeTxHeadPtr;
   1527   AdapterInfo->FreeTxHeadPtr  = free_cb_ptr->NextTCBVirtualLinkPtr;
   1528   --AdapterInfo->FreeCBCount;
   1529   BlockIt (AdapterInfo, FALSE);
   1530   return free_cb_ptr;
   1531 }
   1532 
   1533 
   1534 /**
   1535   TODO: Add function description
   1536 
   1537   @param  AdapterInfo                     TODO: add argument description
   1538   @param  cb_ptr                          TODO: add argument description
   1539 
   1540   @return TODO: add return values
   1541 
   1542 **/
   1543 VOID
   1544 SetFreeCB (
   1545   IN NIC_DATA_INSTANCE *AdapterInfo,
   1546   IN TxCB              *cb_ptr
   1547   )
   1548 {
   1549   //
   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
   1552   //
   1553   cb_ptr->cb_header.status    = 0;
   1554   cb_ptr->free_data_ptr       = (UINT64) 0;
   1555 
   1556   AdapterInfo->FreeTxTailPtr  = cb_ptr;
   1557   ++AdapterInfo->FreeCBCount;
   1558   return ;
   1559 }
   1560 
   1561 
   1562 /**
   1563   TODO: Add function description
   1564 
   1565   @param  ind                             TODO: add argument description
   1566 
   1567   @return TODO: add return values
   1568 
   1569 **/
   1570 UINT16
   1571 next (
   1572   IN UINT16 ind
   1573   )
   1574 {
   1575   UINT16  Tmp;
   1576 
   1577   Tmp = (UINT16) (ind + 1);
   1578   if (Tmp >= (TX_BUFFER_COUNT << 1)) {
   1579     Tmp = 0;
   1580   }
   1581 
   1582   return Tmp;
   1583 }
   1584 
   1585 
   1586 /**
   1587   TODO: Add function description
   1588 
   1589   @param  AdapterInfo                     TODO: add argument description
   1590 
   1591   @return TODO: add return values
   1592 
   1593 **/
   1594 UINT16
   1595 CheckCBList (
   1596   IN NIC_DATA_INSTANCE *AdapterInfo
   1597   )
   1598 {
   1599   TxCB    *Tmp_ptr;
   1600   UINT16  cnt;
   1601 
   1602   cnt = 0;
   1603   while (1) {
   1604     Tmp_ptr = AdapterInfo->FreeTxTailPtr->NextTCBVirtualLinkPtr;
   1605     if ((Tmp_ptr->cb_header.status & CMD_STATUS_MASK) != 0) {
   1606       //
   1607       // check if Q is full
   1608       //
   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;
   1612 
   1613         UnMapIt (
   1614           AdapterInfo,
   1615           Tmp_ptr->free_data_ptr,
   1616           Tmp_ptr->TBDArray[0].buf_len,
   1617           TO_DEVICE,
   1618           (UINT64) Tmp_ptr->TBDArray[0].phys_buf_addr
   1619           );
   1620 
   1621         AdapterInfo->xmit_done_tail = next (AdapterInfo->xmit_done_tail);
   1622       }
   1623 
   1624       SetFreeCB (AdapterInfo, Tmp_ptr);
   1625     } else {
   1626       break;
   1627     }
   1628   }
   1629 
   1630   return cnt;
   1631 }
   1632 //
   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.
   1640 //
   1641 
   1642 /**
   1643   TODO: Add function description
   1644 
   1645   @param  AdapterInfo                     TODO: add argument description
   1646 
   1647   @return TODO: add return values
   1648 
   1649 **/
   1650 UINT8
   1651 SetupReceiveQueues (
   1652   IN NIC_DATA_INSTANCE *AdapterInfo
   1653   )
   1654 {
   1655   RxFD    *rx_ptr;
   1656   RxFD    *tail_ptr;
   1657   UINT16  Index;
   1658 
   1659   AdapterInfo->cur_rx_ind = 0;
   1660   rx_ptr                  = (&AdapterInfo->rx_ring[0]);
   1661 
   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;
   1667     //
   1668     // RBDs not used, simple memory model
   1669     //
   1670     rx_ptr[Index].rx_buf_addr       = (UINT32) (-1);
   1671 
   1672     //
   1673     // RBDs not used, simple memory model
   1674     //
   1675     rx_ptr[Index].forwarded = FALSE;
   1676 
   1677     //
   1678     // don't use Tmp_ptr if it is beyond the last one
   1679     //
   1680     if (Index < AdapterInfo->RxBufCnt - 1) {
   1681       rx_ptr[Index].cb_header.link = (UINT32) AdapterInfo->rx_phy_addr + ((Index + 1) * sizeof (RxFD));
   1682     }
   1683   }
   1684 
   1685   tail_ptr                    = (&AdapterInfo->rx_ring[AdapterInfo->RxBufCnt - 1]);
   1686   tail_ptr->cb_header.link    = (UINT32) AdapterInfo->rx_phy_addr;
   1687 
   1688   //
   1689   // set the EL bit
   1690   //
   1691   tail_ptr->cb_header.command = 0xC000;
   1692   AdapterInfo->RFDTailPtr = tail_ptr;
   1693   return 0;
   1694 }
   1695 
   1696 
   1697 /**
   1698   TODO: Add function description
   1699 
   1700   @param  AdapterInfo                     TODO: add argument description
   1701   @param  rx_index                        TODO: add argument description
   1702 
   1703   @return TODO: add return values
   1704 
   1705 **/
   1706 VOID
   1707 Recycle_RFD (
   1708   IN NIC_DATA_INSTANCE *AdapterInfo,
   1709   IN UINT16            rx_index
   1710   )
   1711 {
   1712   RxFD  *rx_ptr;
   1713   RxFD  *tail_ptr;
   1714   //
   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;
   1718   //
   1719   rx_ptr                    = &AdapterInfo->rx_ring[rx_index];
   1720   tail_ptr                  = AdapterInfo->RFDTailPtr;
   1721   //
   1722   // set el_bit and suspend bit
   1723   //
   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;
   1729   //
   1730   // resetting the el_bit.
   1731   //
   1732   tail_ptr->cb_header.command = 0;
   1733   //
   1734   // check the receive unit, fix if there is any problem
   1735   //
   1736   return ;
   1737 }
   1738 //
   1739 // Serial EEPROM section.
   1740 //
   1741 //  EEPROM_Ctrl bits.
   1742 //
   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)
   1750 
   1751 //
   1752 // Delay between EEPROM clock transitions.
   1753 // This will actually work with no delay on 33Mhz PCI.
   1754 //
   1755 #define eeprom_delay(nanosec) DelayIt (AdapterInfo, nanosec);
   1756 
   1757 //
   1758 // The EEPROM commands include the alway-set leading bit.
   1759 //
   1760 #define EE_WRITE_CMD  5 // 101b
   1761 #define EE_READ_CMD   6 // 110b
   1762 #define EE_ERASE_CMD  (7 << 6)
   1763 
   1764 VOID
   1765 shift_bits_out (
   1766   IN NIC_DATA_INSTANCE *AdapterInfo,
   1767   IN UINT16            val,
   1768   IN UINT8             num_bits
   1769   )
   1770 /*++
   1771 
   1772 Routine Description:
   1773 
   1774   TODO: Add function description
   1775 
   1776 Arguments:
   1777 
   1778   AdapterInfo - TODO: add argument description
   1779   val         - TODO: add argument description
   1780   num_bits    - TODO: add argument description
   1781 
   1782 Returns:
   1783 
   1784   TODO: add return values
   1785 
   1786 --*/
   1787 {
   1788   INT32   Index;
   1789   UINT8   Tmp;
   1790   UINT32  EEAddr;
   1791 
   1792   EEAddr = AdapterInfo->ioaddr + SCBeeprom;
   1793 
   1794   for (Index = num_bits; Index >= 0; Index--) {
   1795     INT16 dataval;
   1796 
   1797     //
   1798     // will be 0 or 4
   1799     //
   1800     dataval = (INT16) ((val & (1 << Index)) ? EE_DI : 0);
   1801 
   1802     //
   1803     // mask off the data_in bit
   1804     //
   1805     Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) &~EE_DI);
   1806     Tmp = (UINT8) (Tmp | dataval);
   1807     OutByte (AdapterInfo, Tmp, EEAddr);
   1808     eeprom_delay (100);
   1809     //
   1810     // raise the eeprom clock
   1811     //
   1812     OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
   1813     eeprom_delay (150);
   1814     //
   1815     // lower the eeprom clock
   1816     //
   1817     OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
   1818     eeprom_delay (150);
   1819   }
   1820 }
   1821 
   1822 
   1823 /**
   1824   TODO: Add function description
   1825 
   1826   @param  AdapterInfo                     TODO: add argument description
   1827 
   1828   @return TODO: add return values
   1829 
   1830 **/
   1831 UINT16
   1832 shift_bits_in (
   1833   IN NIC_DATA_INSTANCE *AdapterInfo
   1834   )
   1835 {
   1836   UINT8   Tmp;
   1837   INT32   Index;
   1838   UINT16  retval;
   1839   UINT32  EEAddr;
   1840 
   1841   EEAddr  = AdapterInfo->ioaddr + SCBeeprom;
   1842 
   1843   retval  = 0;
   1844   for (Index = 15; Index >= 0; Index--) {
   1845     //
   1846     // raise the clock
   1847     //
   1848 
   1849     //
   1850     // mask off the data_in bit
   1851     //
   1852     Tmp = InByte (AdapterInfo, EEAddr);
   1853     OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
   1854     eeprom_delay (100);
   1855     Tmp     = InByte (AdapterInfo, EEAddr);
   1856     retval  = (UINT16) ((retval << 1) | ((Tmp & EE_DO) ? 1 : 0));
   1857     //
   1858     // lower the clock
   1859     //
   1860     OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
   1861     eeprom_delay (100);
   1862   }
   1863 
   1864   return retval;
   1865 }
   1866 
   1867 
   1868 /**
   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.
   1872 
   1873   @param  AdapterInfo                     Pointer to the NIC data structure
   1874                                           information which the UNDI driver is
   1875                                           layering on..
   1876 
   1877   @retval TRUE                            if it got the access
   1878   @retval FALSE                           if it fails to get the exclusive access
   1879 
   1880 **/
   1881 BOOLEAN
   1882 E100bSetEepromLockOut (
   1883   IN NIC_DATA_INSTANCE  *AdapterInfo
   1884   )
   1885 {
   1886   UINTN wait;
   1887   UINT8 tmp;
   1888 
   1889   if ((AdapterInfo->DeviceID == D102_DEVICE_ID) ||
   1890       (AdapterInfo->RevID >= D102_REVID)) {
   1891 
   1892     wait = 500;
   1893 
   1894     while (wait--) {
   1895 
   1896       tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2);
   1897       tmp |= GCR2_EEPROM_ACCESS_SEMAPHORE;
   1898       OutByte (AdapterInfo, tmp, AdapterInfo->ioaddr + SCBGenCtrl2);
   1899 
   1900       DelayIt (AdapterInfo, 50);
   1901       tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2);
   1902 
   1903       if (tmp & GCR2_EEPROM_ACCESS_SEMAPHORE) {
   1904         return TRUE;
   1905       }
   1906     }
   1907 
   1908     return FALSE;
   1909   }
   1910 
   1911   return TRUE;
   1912 }
   1913 
   1914 
   1915 /**
   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.
   1919 
   1920   @param  AdapterInfo                     Pointer to the NIC data structure
   1921                                           information which the UNDI driver is
   1922                                           layering on..
   1923 
   1924   @return None
   1925 
   1926 **/
   1927 VOID
   1928 E100bReSetEepromLockOut (
   1929   IN NIC_DATA_INSTANCE  *AdapterInfo
   1930   )
   1931 {
   1932   UINT8 tmp;
   1933 
   1934   if ((AdapterInfo->DeviceID == D102_DEVICE_ID) ||
   1935       (AdapterInfo->RevID >= D102_REVID)) {
   1936 
   1937     tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2);
   1938     tmp &= ~(GCR2_EEPROM_ACCESS_SEMAPHORE);
   1939     OutByte (AdapterInfo, tmp, AdapterInfo->ioaddr + SCBGenCtrl2);
   1940 
   1941     DelayIt (AdapterInfo, 50);
   1942   }
   1943 }
   1944 
   1945 
   1946 /**
   1947   Using the NIC data structure information, read the EEPROM to get a Word of data for the MAC address.
   1948 
   1949   @param  AdapterInfo                     Pointer to the NIC data structure
   1950                                           information which the UNDI driver is
   1951                                           layering on..
   1952   @param  Location                        Word offset into the MAC address to read.
   1953   @param  AddrLen                         Number of bits of address length.
   1954 
   1955   @retval RetVal                          The word read from the EEPROM.
   1956 
   1957 **/
   1958 UINT16
   1959 E100bReadEeprom (
   1960   IN NIC_DATA_INSTANCE  *AdapterInfo,
   1961   IN INT32              Location,
   1962   IN UINT8              AddrLen
   1963   )
   1964 {
   1965   UINT16  RetVal;
   1966   UINT8   Tmp;
   1967 
   1968   UINT32  EEAddr;
   1969   UINT16  ReadCmd;
   1970 
   1971   EEAddr  = AdapterInfo->ioaddr + SCBeeprom;
   1972   ReadCmd = (UINT16) (Location | (EE_READ_CMD << AddrLen));
   1973 
   1974   RetVal  = 0;
   1975 
   1976   //
   1977   // get exclusive access to the eeprom first!
   1978   //
   1979   E100bSetEepromLockOut (AdapterInfo);
   1980 
   1981   //
   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
   1986   //
   1987 
   1988   //
   1989   // 11110010b
   1990   //
   1991   Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) & 0xF2);
   1992   OutByte (AdapterInfo, (UINT8) (Tmp | EE_CS), EEAddr);
   1993 
   1994   //
   1995   // 3 for the read opcode 110b
   1996   //
   1997   shift_bits_out (AdapterInfo, ReadCmd, (UINT8) (3 + AddrLen));
   1998 
   1999   //
   2000   // read the eeprom word one bit at a time
   2001   //
   2002   RetVal = shift_bits_in (AdapterInfo);
   2003 
   2004   //
   2005   // Terminate the EEPROM access and leave eeprom in a clean state.
   2006   //
   2007   Tmp = InByte (AdapterInfo, EEAddr);
   2008   Tmp &= ~(EE_CS | EE_DI);
   2009   OutByte (AdapterInfo, Tmp, EEAddr);
   2010 
   2011   //
   2012   // raise the clock and lower the eeprom shift clock
   2013   //
   2014   OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
   2015   eeprom_delay (100);
   2016 
   2017   OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
   2018   eeprom_delay (100);
   2019 
   2020   //
   2021   // giveup access to the eeprom
   2022   //
   2023   E100bReSetEepromLockOut (AdapterInfo);
   2024 
   2025   return RetVal;
   2026 }
   2027 
   2028 
   2029 /**
   2030   Using the NIC data structure information, read the EEPROM to determine how many bits of address length
   2031   this EEPROM is in Words.
   2032 
   2033   @param  AdapterInfo                     Pointer to the NIC data structure
   2034                                           information which the UNDI driver is
   2035                                           layering on..
   2036 
   2037   @retval RetVal                          The word read from the EEPROM.
   2038 
   2039 **/
   2040 UINT8
   2041 E100bGetEepromAddrLen (
   2042   IN NIC_DATA_INSTANCE *AdapterInfo
   2043   )
   2044 {
   2045   UINT8   Tmp;
   2046   UINT8   AddrLen;
   2047   UINT32  EEAddr;
   2048   //
   2049   // assume 64word eeprom (so,6 bits of address_length)
   2050   //
   2051   UINT16  ReadCmd;
   2052 
   2053   EEAddr  = AdapterInfo->ioaddr + SCBeeprom;
   2054   ReadCmd = (EE_READ_CMD << 6);
   2055 
   2056   //
   2057   // get exclusive access to the eeprom first!
   2058   //
   2059   E100bSetEepromLockOut (AdapterInfo);
   2060 
   2061   //
   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
   2067   //
   2068   Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) & 0xF2);
   2069 
   2070   //
   2071   // enable eeprom access
   2072   //
   2073   OutByte (AdapterInfo, (UINT8) (Tmp | EE_CS), EEAddr);
   2074 
   2075   //
   2076   // 3 for opcode, 6 for the default address len
   2077   //
   2078   shift_bits_out (AdapterInfo, ReadCmd, (UINT8) (3 + 6));
   2079 
   2080   //
   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"
   2084   //
   2085 
   2086   //
   2087   // assume the smallest
   2088   //
   2089   AddrLen = 6;
   2090   Tmp     = InByte (AdapterInfo, EEAddr);
   2091   while ((AddrLen < 8) && ((Tmp & EE_DO) != 0)) {
   2092     OutByte (AdapterInfo, (UINT8) (Tmp &~EE_DI), EEAddr);
   2093     eeprom_delay (100);
   2094 
   2095     //
   2096     // raise the eeprom clock
   2097     //
   2098     OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
   2099     eeprom_delay (150);
   2100 
   2101     //
   2102     // lower the eeprom clock
   2103     //
   2104     OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
   2105     eeprom_delay (150);
   2106     Tmp = InByte (AdapterInfo, EEAddr);
   2107     AddrLen++;
   2108   }
   2109 
   2110   //
   2111   // read the eeprom word, even though we don't need this
   2112   //
   2113   shift_bits_in (AdapterInfo);
   2114 
   2115   //
   2116   // Terminate the EEPROM access.
   2117   //
   2118   Tmp = InByte (AdapterInfo, EEAddr);
   2119   Tmp &= ~(EE_CS | EE_DI);
   2120   OutByte (AdapterInfo, Tmp, EEAddr);
   2121 
   2122   //
   2123   // raise the clock and lower the eeprom shift clock
   2124   //
   2125   OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);
   2126   eeprom_delay (100);
   2127 
   2128   OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);
   2129   eeprom_delay (100);
   2130 
   2131   //
   2132   // giveup access to the eeprom!
   2133   //
   2134   E100bReSetEepromLockOut (AdapterInfo);
   2135 
   2136   return AddrLen;
   2137 }
   2138 
   2139 
   2140 /**
   2141   TODO: Add function description
   2142 
   2143   @param  AdapterInfo                     TODO: add argument description
   2144   @param  DBaddr                          TODO: add argument description
   2145   @param  DBsize                          TODO: add argument description
   2146 
   2147   @return TODO: add return values
   2148 
   2149 **/
   2150 UINTN
   2151 E100bStatistics (
   2152   NIC_DATA_INSTANCE *AdapterInfo,
   2153   UINT64            DBaddr,
   2154   UINT16            DBsize
   2155   )
   2156 {
   2157   PXE_DB_STATISTICS db;
   2158   //
   2159   // wait upto one second (each wait is 100 micro s)
   2160   //
   2161   UINT32            Wait;
   2162   Wait = 10000;
   2163   wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
   2164 
   2165   //
   2166   // Clear statistics done marker.
   2167   //
   2168   AdapterInfo->statistics->done_marker = 0;
   2169 
   2170   //
   2171   // Issue statistics dump (or dump w/ reset) command.
   2172   //
   2173   OutByte (
   2174     AdapterInfo,
   2175     (UINT8) (DBsize ? CU_SHOWSTATS : CU_DUMPSTATS),
   2176     (UINT32) (AdapterInfo->ioaddr + SCBCmd)
   2177     );
   2178 
   2179   //
   2180   // Wait for command to complete.
   2181   //
   2182   // zero the db here just to chew up a little more time.
   2183   //
   2184 
   2185   ZeroMem ((VOID *) &db, sizeof db);
   2186 
   2187   while (Wait != 0) {
   2188     //
   2189     // Wait a bit before checking.
   2190     //
   2191 
   2192     DelayIt (AdapterInfo, 100);
   2193 
   2194     //
   2195     // Look for done marker at end of statistics.
   2196     //
   2197 
   2198     switch (AdapterInfo->statistics->done_marker) {
   2199     case 0xA005:
   2200     case 0xA007:
   2201       break;
   2202 
   2203     default:
   2204       Wait--;
   2205       continue;
   2206     }
   2207 
   2208     //
   2209     // if we did not "continue" from the above switch, we are done,
   2210     //
   2211     break;
   2212   }
   2213 
   2214   //
   2215   // If this is a reset, we are out of here!
   2216   //
   2217   if (DBsize == 0) {
   2218     return PXE_STATCODE_SUCCESS;
   2219   }
   2220 
   2221   //
   2222   // Convert NIC statistics counter format to EFI/UNDI
   2223   // specification statistics counter format.
   2224   //
   2225 
   2226   //
   2227   //                54 3210 fedc ba98 7654 3210
   2228   // db.Supported = 01 0000 0100 1101 0001 0111;
   2229   //
   2230   db.Supported = 0x104D17;
   2231 
   2232   //
   2233   // Statistics from the NIC
   2234   //
   2235 
   2236   db.Data[0x01] = AdapterInfo->statistics->rx_good_frames;
   2237 
   2238   db.Data[0x02] = AdapterInfo->statistics->rx_runt_errs;
   2239 
   2240   db.Data[0x08] = AdapterInfo->statistics->rx_crc_errs +
   2241                   AdapterInfo->statistics->rx_align_errs;
   2242 
   2243   db.Data[0x04] = db.Data[0x02] +
   2244                   db.Data[0x08] +
   2245                   AdapterInfo->statistics->rx_resource_errs +
   2246                   AdapterInfo->statistics->rx_overrun_errs;
   2247 
   2248   db.Data[0x00] = db.Data[0x01] + db.Data[0x04];
   2249 
   2250   db.Data[0x0B] = AdapterInfo->statistics->tx_good_frames;
   2251 
   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;
   2257 
   2258   db.Data[0x14] = AdapterInfo->statistics->tx_total_colls;
   2259 
   2260   db.Data[0x0A] = db.Data[0x0B] +
   2261                   db.Data[0x0E] +
   2262                   AdapterInfo->statistics->tx_lost_carrier;
   2263 
   2264   if (DBsize > sizeof db) {
   2265     DBsize = (UINT16) sizeof (db);
   2266   }
   2267 
   2268   CopyMem ((VOID *) (UINTN) DBaddr, (VOID *) &db, (UINTN) DBsize);
   2269 
   2270   return PXE_STATCODE_SUCCESS;
   2271 }
   2272 
   2273 
   2274 /**
   2275   TODO: Add function description
   2276 
   2277   @param  AdapterInfo                     TODO: add argument description
   2278   @param  OpFlags                         TODO: add argument description
   2279 
   2280   @return TODO: add return values
   2281 
   2282 **/
   2283 UINTN
   2284 E100bReset (
   2285   IN NIC_DATA_INSTANCE *AdapterInfo,
   2286   IN INT32             OpFlags
   2287   )
   2288 {
   2289 
   2290   UINT16  save_filter;
   2291   //
   2292   // disable the interrupts
   2293   //
   2294   OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
   2295 
   2296   //
   2297   // wait for the tx queue to complete
   2298   //
   2299   CheckCBList (AdapterInfo);
   2300 
   2301   XmitWaitForCompletion (AdapterInfo);
   2302 
   2303   if (AdapterInfo->Receive_Started) {
   2304     StopRU (AdapterInfo);
   2305   }
   2306 
   2307   InitializeChip (AdapterInfo);
   2308 
   2309   //
   2310   // check the opflags and restart receive filters
   2311   //
   2312   if ((OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {
   2313 
   2314     save_filter = AdapterInfo->Rx_Filter;
   2315     //
   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
   2319     //
   2320     AdapterInfo->Rx_Filter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);
   2321     E100bSetfilter (AdapterInfo, save_filter, (UINT64) 0, (UINT32) 0);
   2322   }
   2323 
   2324   if ((OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) {
   2325     //
   2326     // disable the interrupts
   2327     //
   2328     AdapterInfo->int_mask = 0;
   2329   }
   2330   //
   2331   // else leave the interrupt in the pre-set state!!!
   2332   //
   2333   E100bSetInterruptState (AdapterInfo);
   2334 
   2335   return 0;
   2336 }
   2337 
   2338 
   2339 /**
   2340   TODO: Add function description
   2341 
   2342   @param  AdapterInfo                     TODO: add argument description
   2343 
   2344   @return TODO: add return values
   2345 
   2346 **/
   2347 UINTN
   2348 E100bShutdown (
   2349   IN NIC_DATA_INSTANCE *AdapterInfo
   2350   )
   2351 {
   2352   //
   2353   // disable the interrupts
   2354   //
   2355   OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
   2356 
   2357   //
   2358   // stop the receive unit
   2359   //
   2360   if (AdapterInfo->Receive_Started) {
   2361     StopRU (AdapterInfo);
   2362   }
   2363 
   2364   //
   2365   // wait for the tx queue to complete
   2366   //
   2367   CheckCBList (AdapterInfo);
   2368   if (AdapterInfo->FreeCBCount != AdapterInfo->TxBufCnt) {
   2369     wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
   2370   }
   2371 
   2372   //
   2373   // we do not want to reset the phy, it takes a long time to renegotiate the
   2374   // link after that (3-4 seconds)
   2375   //
   2376   InitializeChip (AdapterInfo);
   2377   SelectiveReset (AdapterInfo);
   2378   return 0;
   2379 }
   2380 
   2381 
   2382 /**
   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.
   2386 
   2387   @param  AdapterInfo                     pointer to the structure that contains
   2388                                           the NIC's context.
   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
   2392                                           register.
   2393 
   2394   @return nothing
   2395 
   2396 **/
   2397 VOID
   2398 MdiWrite (
   2399   IN NIC_DATA_INSTANCE *AdapterInfo,
   2400   IN UINT8             RegAddress,
   2401   IN UINT8             PhyAddress,
   2402   IN UINT16            DataValue
   2403   )
   2404 {
   2405   UINT32  WriteCommand;
   2406 
   2407   WriteCommand = ((UINT32) DataValue) |
   2408                  ((UINT32)(RegAddress << 16)) |
   2409                  ((UINT32)(PhyAddress << 21)) |
   2410                  ((UINT32)(MDI_WRITE << 26));
   2411 
   2412   //
   2413   // Issue the write command to the MDI control register.
   2414   //
   2415   OutLong (AdapterInfo, WriteCommand, AdapterInfo->ioaddr + SCBCtrlMDI);
   2416 
   2417   //
   2418   // wait 20usec before checking status
   2419   //
   2420   DelayIt (AdapterInfo, 20);
   2421 
   2422   //
   2423   // poll for the mdi write to complete
   2424   while ((InLong (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI) &
   2425                     MDI_PHY_READY) == 0){
   2426     DelayIt (AdapterInfo, 20);
   2427   }
   2428 }
   2429 
   2430 
   2431 /**
   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.
   2435 
   2436   @param  AdapterInfo                     pointer to the structure that contains
   2437                                           the NIC's context.
   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
   2441                                           the MII register.
   2442 
   2443 
   2444 **/
   2445 VOID
   2446 MdiRead (
   2447   IN NIC_DATA_INSTANCE *AdapterInfo,
   2448   IN UINT8             RegAddress,
   2449   IN UINT8             PhyAddress,
   2450   IN OUT UINT16        *DataValue
   2451   )
   2452 {
   2453   UINT32  ReadCommand;
   2454 
   2455   ReadCommand = ((UINT32) (RegAddress << 16)) |
   2456                 ((UINT32) (PhyAddress << 21)) |
   2457                 ((UINT32) (MDI_READ << 26));
   2458 
   2459   //
   2460   // Issue the read command to the MDI control register.
   2461   //
   2462   OutLong (AdapterInfo, ReadCommand, AdapterInfo->ioaddr + SCBCtrlMDI);
   2463 
   2464   //
   2465   // wait 20usec before checking status
   2466   //
   2467   DelayIt (AdapterInfo, 20);
   2468 
   2469   //
   2470   // poll for the mdi read to complete
   2471   //
   2472   while ((InLong (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI) &
   2473           MDI_PHY_READY) == 0) {
   2474     DelayIt (AdapterInfo, 20);
   2475 
   2476   }
   2477 
   2478   *DataValue = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI);
   2479 }
   2480 
   2481 
   2482 /**
   2483   This routine will reset the PHY that the adapter is currently
   2484   configured to use.
   2485 
   2486   @param  AdapterInfo                     pointer to the structure that contains
   2487                                           the NIC's context.
   2488 
   2489 
   2490 **/
   2491 VOID
   2492 PhyReset (
   2493   NIC_DATA_INSTANCE *AdapterInfo
   2494   )
   2495 {
   2496   UINT16  MdiControlReg;
   2497 
   2498   MdiControlReg = (MDI_CR_AUTO_SELECT |
   2499                   MDI_CR_RESTART_AUTO_NEG |
   2500                   MDI_CR_RESET);
   2501 
   2502   //
   2503   // Write the MDI control register with our new Phy configuration
   2504   //
   2505   MdiWrite (
   2506     AdapterInfo,
   2507     MDI_CONTROL_REG,
   2508     AdapterInfo->PhyAddress,
   2509     MdiControlReg
   2510     );
   2511 
   2512   return ;
   2513 }
   2514 
   2515 
   2516 /**
   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
   2528   - 503 interface
   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
   2538   technology.
   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
   2541   this range.
   2542   6.  Driver ignores FORCEFDX and SPEED overrides if a 503 interface
   2543   is detected.
   2544 
   2545   @param  AdapterInfo                     pointer to the structure that contains
   2546                                           the NIC's context.
   2547 
   2548   @retval TRUE                            If a Phy was detected, and configured
   2549                                           correctly.
   2550   @retval FALSE                           If a valid phy could not be detected and
   2551                                           configured.
   2552 
   2553 **/
   2554 BOOLEAN
   2555 PhyDetect (
   2556   NIC_DATA_INSTANCE *AdapterInfo
   2557   )
   2558 {
   2559   UINT16  *eedata;
   2560   UINT16  MdiControlReg;
   2561   UINT16  MdiStatusReg;
   2562   BOOLEAN FoundPhy1;
   2563   UINT8   ReNegotiateTime;
   2564 
   2565   eedata          = (UINT16 *) (&AdapterInfo->NVData[0]);
   2566 
   2567   FoundPhy1       = FALSE;
   2568   ReNegotiateTime = 35;
   2569   //
   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
   2573   //
   2574   AdapterInfo->PhyRecord[0] = eedata[6];
   2575   AdapterInfo->PhyRecord[1] = eedata[7];
   2576   AdapterInfo->PhyAddress   = (UINT8) (AdapterInfo->PhyRecord[0] & 7);
   2577 
   2578   //
   2579   // Check for a phy address over-ride of 32 which indicates force use of 82503
   2580   // not detecting the link in this case
   2581   //
   2582   if (AdapterInfo->PhyAddress == 32) {
   2583     //
   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.
   2587     //
   2588     AdapterInfo->LinkSpeed = 10;
   2589     return (TRUE);
   2590   }
   2591 
   2592   //
   2593   // If the Phy Address is between 1-31 then we must first look for phy 1,
   2594   // at that address.
   2595   //
   2596   if ((AdapterInfo->PhyAddress > 0) && (AdapterInfo->PhyAddress < 32)) {
   2597 
   2598     //
   2599     // Read the MDI control and status registers at phy 1
   2600     // and check if we found a valid phy
   2601     //
   2602     MdiRead (
   2603       AdapterInfo,
   2604       MDI_CONTROL_REG,
   2605       AdapterInfo->PhyAddress,
   2606       &MdiControlReg
   2607       );
   2608 
   2609     MdiRead (
   2610       AdapterInfo,
   2611       MDI_STATUS_REG,
   2612       AdapterInfo->PhyAddress,
   2613       &MdiStatusReg
   2614       );
   2615 
   2616     if (!((MdiControlReg == 0xffff) ||
   2617           ((MdiStatusReg == 0) && (MdiControlReg == 0)))) {
   2618 
   2619       //
   2620       // we have a valid phy1
   2621       // Read the status register again because of sticky bits
   2622       //
   2623       FoundPhy1 = TRUE;
   2624       MdiRead (
   2625         AdapterInfo,
   2626         MDI_STATUS_REG,
   2627         AdapterInfo->PhyAddress,
   2628         &MdiStatusReg
   2629         );
   2630 
   2631       //
   2632       // If there is a valid link then use this Phy.
   2633       //
   2634       if (MdiStatusReg & MDI_SR_LINK_STATUS) {
   2635         return (SetupPhy(AdapterInfo));
   2636       }
   2637     }
   2638   }
   2639 
   2640   //
   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
   2643   //
   2644 
   2645   //
   2646   // Read the MDI control and status registers at phy 0
   2647   //
   2648   MdiRead (AdapterInfo, MDI_CONTROL_REG, 0, &MdiControlReg);
   2649   MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);
   2650 
   2651   //
   2652   // check if we found a valid phy 0
   2653   //
   2654   if (((MdiControlReg == 0xffff) ||
   2655        ((MdiStatusReg == 0) && (MdiControlReg == 0)))) {
   2656 
   2657     //
   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
   2661     //
   2662     if (AdapterInfo->PhyAddress == 0x0000) {
   2663       return (FALSE);
   2664     } else {
   2665       //
   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!
   2668       //
   2669       if (AdapterInfo->CableDetect != 0) {
   2670         return FALSE;
   2671 
   2672       }
   2673 
   2674       if (FoundPhy1) {
   2675         //
   2676         // no phy 0, but there is a phy 1 (no link I guess), so use phy 1
   2677         //
   2678         return SetupPhy (AdapterInfo);
   2679       } else {
   2680         //
   2681         // didn't find phy 0 or phy 1, so assume a 503 interface
   2682         //
   2683         AdapterInfo->PhyAddress = 32;
   2684 
   2685         //
   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.
   2688         //
   2689         AdapterInfo->LinkSpeed = 10;
   2690         return (TRUE);
   2691       }
   2692     }
   2693   } else {
   2694     //
   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.
   2700     //
   2701     if (FoundPhy1) {
   2702       //
   2703       // isolate phy 1
   2704       //
   2705       MdiWrite (
   2706         AdapterInfo,
   2707         MDI_CONTROL_REG,
   2708         AdapterInfo->PhyAddress,
   2709         MDI_CR_ISOLATE
   2710         );
   2711 
   2712       //
   2713       // wait 100 microseconds for the phy to isolate.
   2714       //
   2715       DelayIt (AdapterInfo, 100);
   2716     }
   2717 
   2718     //
   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
   2721     //
   2722     MdiWrite (
   2723       AdapterInfo,
   2724       MDI_CONTROL_REG,
   2725       0,
   2726       MDI_CR_AUTO_SELECT
   2727       );
   2728 
   2729     //
   2730     // wait 100 microseconds for the phy to be enabled.
   2731     //
   2732     DelayIt (AdapterInfo, 100);
   2733 
   2734     //
   2735     // restart the auto-negotion process
   2736     //
   2737     MdiWrite (
   2738       AdapterInfo,
   2739       MDI_CONTROL_REG,
   2740       0,
   2741       MDI_CR_RESTART_AUTO_NEG | MDI_CR_AUTO_SELECT
   2742       );
   2743 
   2744     //
   2745     // wait no more than 3.5 seconds for auto-negotiation to complete
   2746     //
   2747     while (ReNegotiateTime) {
   2748       //
   2749       // Read the status register twice because of sticky bits
   2750       //
   2751       MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);
   2752       MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);
   2753 
   2754       if (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE) {
   2755         break;
   2756       }
   2757 
   2758       DelayIt (AdapterInfo, 100);
   2759       ReNegotiateTime--;
   2760     }
   2761 
   2762     //
   2763     // Read the status register again because of sticky bits
   2764     //
   2765     MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);
   2766 
   2767     //
   2768     // If the link was not set
   2769     //
   2770     if ((MdiStatusReg & MDI_SR_LINK_STATUS) == 0) {
   2771       //
   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!
   2774       //
   2775       if (AdapterInfo->CableDetect != 0) {
   2776         return FALSE;
   2777       }
   2778 
   2779       //
   2780       // the link wasn't set, so use phy 1 if phy 1 was present
   2781       //
   2782       if (FoundPhy1) {
   2783         //
   2784         // isolate phy 0
   2785         //
   2786         MdiWrite (AdapterInfo, MDI_CONTROL_REG, 0, MDI_CR_ISOLATE);
   2787 
   2788         //
   2789         // wait 100 microseconds for the phy to isolate.
   2790         //
   2791         DelayIt (AdapterInfo, 100);
   2792 
   2793         //
   2794         // Now re-enable PHY 1
   2795         //
   2796         MdiWrite (
   2797           AdapterInfo,
   2798           MDI_CONTROL_REG,
   2799           AdapterInfo->PhyAddress,
   2800           MDI_CR_AUTO_SELECT
   2801           );
   2802 
   2803         //
   2804         // wait 100 microseconds for the phy to be enabled
   2805         //
   2806         DelayIt (AdapterInfo, 100);
   2807 
   2808         //
   2809         // restart the auto-negotion process
   2810         //
   2811         MdiWrite (
   2812           AdapterInfo,
   2813           MDI_CONTROL_REG,
   2814           AdapterInfo->PhyAddress,
   2815           MDI_CR_RESTART_AUTO_NEG | MDI_CR_AUTO_SELECT
   2816           );
   2817 
   2818         //
   2819         // Don't wait for it to complete (we didn't have link earlier)
   2820         //
   2821         return (SetupPhy (AdapterInfo));
   2822       }
   2823     }
   2824 
   2825     //
   2826     // Definitely using Phy 0
   2827     //
   2828     AdapterInfo->PhyAddress = 0;
   2829     return (SetupPhy(AdapterInfo));
   2830   }
   2831 }
   2832 
   2833 
   2834 /**
   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.
   2846 
   2847   @param  AdapterInfo                     pointer to the structure that contains
   2848                                           the NIC's context.
   2849 
   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
   2854 
   2855 **/
   2856 BOOLEAN
   2857 SetupPhy (
   2858   IN NIC_DATA_INSTANCE *AdapterInfo
   2859   )
   2860 {
   2861   UINT16  MdiControlReg;
   2862   UINT16  MdiStatusReg;
   2863   UINT16  MdiIdLowReg;
   2864   UINT16  MdiIdHighReg;
   2865   UINT16  MdiMiscReg;
   2866   UINT32  PhyId;
   2867   BOOLEAN ForcePhySetting;
   2868 
   2869   ForcePhySetting = FALSE;
   2870 
   2871   //
   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
   2874   // specific code.
   2875   //
   2876   if (((AdapterInfo->LinkSpeedReq) || (AdapterInfo->DuplexReq))) {
   2877     //
   2878     // Find out what kind of technology this Phy is capable of.
   2879     //
   2880     MdiRead (
   2881       AdapterInfo,
   2882       MDI_STATUS_REG,
   2883       AdapterInfo->PhyAddress,
   2884       &MdiStatusReg
   2885       );
   2886 
   2887     //
   2888     // Read the MDI control register at our phy
   2889     //
   2890     MdiRead (
   2891       AdapterInfo,
   2892       MDI_CONTROL_REG,
   2893       AdapterInfo->PhyAddress,
   2894       &MdiControlReg
   2895       );
   2896 
   2897     //
   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.
   2901     //
   2902 
   2903     //
   2904     // If speed is forced to 10mb
   2905     //
   2906     if (AdapterInfo->LinkSpeedReq == 10) {
   2907       //
   2908       // If half duplex is forced
   2909       //
   2910       if ((AdapterInfo->DuplexReq & PXE_FORCE_HALF_DUPLEX) != 0) {
   2911         if (MdiStatusReg & MDI_SR_10T_HALF_DPX) {
   2912 
   2913           MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
   2914           ForcePhySetting = TRUE;
   2915         }
   2916       } else if ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) != 0) {
   2917 
   2918         //
   2919         // If full duplex is forced
   2920         //
   2921         if (MdiStatusReg & MDI_SR_10T_FULL_DPX) {
   2922 
   2923           MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT);
   2924           MdiControlReg |= MDI_CR_FULL_HALF;
   2925           ForcePhySetting = TRUE;
   2926         }
   2927       } else {
   2928         //
   2929         // If auto duplex (we actually set phy to 1/2)
   2930         //
   2931         if (MdiStatusReg & (MDI_SR_10T_FULL_DPX | MDI_SR_10T_HALF_DPX)) {
   2932 
   2933           MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
   2934           ForcePhySetting = TRUE;
   2935         }
   2936       }
   2937     }
   2938 
   2939     //
   2940     // If speed is forced to 100mb
   2941     //
   2942     else if (AdapterInfo->LinkSpeedReq == 100) {
   2943       //
   2944       // If half duplex is forced
   2945       //
   2946       if ((AdapterInfo->DuplexReq & PXE_FORCE_HALF_DUPLEX) != 0) {
   2947         if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE)) {
   2948 
   2949           MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
   2950           MdiControlReg |= MDI_CR_10_100;
   2951           ForcePhySetting = TRUE;
   2952         }
   2953       } else if ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) != 0) {
   2954         //
   2955         // If full duplex is forced
   2956         //
   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;
   2961         }
   2962       } else {
   2963         //
   2964         // If auto duplex (we set phy to 1/2)
   2965         //
   2966         if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE)) {
   2967 
   2968           MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
   2969           MdiControlReg |= MDI_CR_10_100;
   2970           ForcePhySetting = TRUE;
   2971         }
   2972       }
   2973     }
   2974 
   2975     if (!ForcePhySetting) {
   2976       return (FALSE);
   2977     }
   2978 
   2979     //
   2980     // Write the MDI control register with our new Phy configuration
   2981     //
   2982     MdiWrite (
   2983       AdapterInfo,
   2984       MDI_CONTROL_REG,
   2985       AdapterInfo->PhyAddress,
   2986       MdiControlReg
   2987       );
   2988 
   2989     //
   2990     // wait 100 milliseconds for auto-negotiation to complete
   2991     //
   2992     DelayIt (AdapterInfo, 100);
   2993   }
   2994 
   2995   //
   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.
   2999   //
   3000 
   3001   MdiRead (
   3002     AdapterInfo,
   3003     PHY_ID_REG_1,
   3004     AdapterInfo->PhyAddress,
   3005     &MdiIdLowReg
   3006     );
   3007   MdiRead (
   3008     AdapterInfo,
   3009     PHY_ID_REG_2,
   3010     AdapterInfo->PhyAddress,
   3011     &MdiIdHighReg
   3012     );
   3013 
   3014   PhyId = ((UINT32) MdiIdLowReg | ((UINT32) MdiIdHighReg << 16));
   3015 
   3016   //
   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.
   3019   //
   3020   PhyId &= PHY_MODEL_REV_ID_MASK;
   3021 
   3022   //
   3023   // Handle the National TX
   3024   //
   3025   if (PhyId == PHY_NSC_TX) {
   3026 
   3027     MdiRead (
   3028       AdapterInfo,
   3029       NSC_CONG_CONTROL_REG,
   3030       AdapterInfo->PhyAddress,
   3031       &MdiMiscReg
   3032       );
   3033 
   3034     MdiMiscReg |= (NSC_TX_CONG_TXREADY | NSC_TX_CONG_F_CONNECT);
   3035 
   3036     MdiWrite (
   3037       AdapterInfo,
   3038       NSC_CONG_CONTROL_REG,
   3039       AdapterInfo->PhyAddress,
   3040       MdiMiscReg
   3041       );
   3042   }
   3043 
   3044   FindPhySpeedAndDpx (AdapterInfo, PhyId);
   3045 
   3046   //
   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.
   3050   //
   3051 
   3052   return (TRUE);
   3053 }
   3054 
   3055 
   3056 /**
   3057   This routine will figure out what line speed and duplex mode
   3058   the PHY is currently using.
   3059 
   3060   @param  AdapterInfo                     pointer to the structure that contains
   3061                                           the NIC's context.
   3062   @param  PhyId                           The ID of the PHY in question.
   3063 
   3064   @return NOTHING
   3065 
   3066 **/
   3067 VOID
   3068 FindPhySpeedAndDpx (
   3069   IN NIC_DATA_INSTANCE *AdapterInfo,
   3070   IN UINT32            PhyId
   3071   )
   3072 {
   3073   UINT16  MdiStatusReg;
   3074   UINT16  MdiMiscReg;
   3075   UINT16  MdiOwnAdReg;
   3076   UINT16  MdiLinkPartnerAdReg;
   3077 
   3078   //
   3079   // If there was a speed and/or duplex override, then set our current
   3080   // value accordingly
   3081   //
   3082   AdapterInfo->LinkSpeed  = AdapterInfo->LinkSpeedReq;
   3083   AdapterInfo->Duplex = (UINT8) ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) ?
   3084                         FULL_DUPLEX : HALF_DUPLEX);
   3085 
   3086   //
   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
   3089   // us to.
   3090   //
   3091   if (AdapterInfo->LinkSpeed && AdapterInfo->Duplex) {
   3092     return ;
   3093 
   3094   }
   3095   //
   3096   // If we didn't have a valid link, then we'll assume that our current
   3097   // speed is 10mb half-duplex.
   3098   //
   3099 
   3100   //
   3101   // Read the status register twice because of sticky bits
   3102   //
   3103   MdiRead (
   3104     AdapterInfo,
   3105     MDI_STATUS_REG,
   3106     AdapterInfo->PhyAddress,
   3107     &MdiStatusReg
   3108     );
   3109   MdiRead (
   3110     AdapterInfo,
   3111     MDI_STATUS_REG,
   3112     AdapterInfo->PhyAddress,
   3113     &MdiStatusReg
   3114     );
   3115 
   3116   //
   3117   // If there wasn't a valid link then use default speed & duplex
   3118   //
   3119   if (!(MdiStatusReg & MDI_SR_LINK_STATUS)) {
   3120 
   3121     AdapterInfo->LinkSpeed  = 10;
   3122     AdapterInfo->Duplex     = HALF_DUPLEX;
   3123     return ;
   3124   }
   3125 
   3126   //
   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
   3129   // settings.
   3130   //
   3131   if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || (PhyId == PHY_TX_ID)) {
   3132     //
   3133     // Read extended register 0
   3134     //
   3135     MdiRead (
   3136       AdapterInfo,
   3137       EXTENDED_REG_0,
   3138       AdapterInfo->PhyAddress,
   3139       &MdiMiscReg
   3140       );
   3141 
   3142     //
   3143     // Get current speed setting
   3144     //
   3145     if (MdiMiscReg & PHY_100_ER0_SPEED_INDIC) {
   3146       AdapterInfo->LinkSpeed = 100;
   3147     } else {
   3148       AdapterInfo->LinkSpeed = 10;
   3149     }
   3150 
   3151     //
   3152     // Get current duplex setting -- if bit is set then FDX is enabled
   3153     //
   3154     if (MdiMiscReg & PHY_100_ER0_FDX_INDIC) {
   3155       AdapterInfo->Duplex = FULL_DUPLEX;
   3156     } else {
   3157       AdapterInfo->Duplex = HALF_DUPLEX;
   3158     }
   3159 
   3160     return ;
   3161   }
   3162   //
   3163   // Read our link partner's advertisement register
   3164   //
   3165   MdiRead (
   3166     AdapterInfo,
   3167     AUTO_NEG_LINK_PARTNER_REG,
   3168     AdapterInfo->PhyAddress,
   3169     &MdiLinkPartnerAdReg
   3170     );
   3171 
   3172   //
   3173   // See if Auto-Negotiation was complete (bit 5, reg 1)
   3174   //
   3175   MdiRead (
   3176     AdapterInfo,
   3177     MDI_STATUS_REG,
   3178     AdapterInfo->PhyAddress,
   3179     &MdiStatusReg
   3180     );
   3181 
   3182   //
   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.
   3187   //
   3188   if ((MdiLinkPartnerAdReg & NWAY_LP_ABILITY) &&
   3189       (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE)) {
   3190 
   3191     //
   3192     // Read our advertisement register
   3193     //
   3194     MdiRead (
   3195       AdapterInfo,
   3196       AUTO_NEG_ADVERTISE_REG,
   3197       AdapterInfo->PhyAddress,
   3198       &MdiOwnAdReg
   3199       );
   3200 
   3201     //
   3202     // AND the two advertisement registers together, and get rid of any
   3203     // extraneous bits.
   3204     //
   3205     MdiOwnAdReg = (UINT16) (MdiOwnAdReg & (MdiLinkPartnerAdReg & NWAY_LP_ABILITY));
   3206 
   3207     //
   3208     // Get speed setting
   3209     //
   3210     if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX | NWAY_AD_TX_FULL_DPX | NWAY_AD_T4_CAPABLE)) {
   3211       AdapterInfo->LinkSpeed = 100;
   3212     } else {
   3213       AdapterInfo->LinkSpeed = 10;
   3214     }
   3215 
   3216     //
   3217     // Get duplex setting -- use priority resolution algorithm
   3218     //
   3219     if (MdiOwnAdReg & (NWAY_AD_T4_CAPABLE)) {
   3220       AdapterInfo->Duplex = HALF_DUPLEX;
   3221       return ;
   3222     } else if (MdiOwnAdReg & (NWAY_AD_TX_FULL_DPX)) {
   3223       AdapterInfo->Duplex = FULL_DUPLEX;
   3224       return ;
   3225     } else if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX)) {
   3226       AdapterInfo->Duplex = HALF_DUPLEX;
   3227       return ;
   3228     } else if (MdiOwnAdReg & (NWAY_AD_10T_FULL_DPX)) {
   3229       AdapterInfo->Duplex = FULL_DUPLEX;
   3230       return ;
   3231     } else {
   3232       AdapterInfo->Duplex = HALF_DUPLEX;
   3233       return ;
   3234     }
   3235   }
   3236 
   3237   //
   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.
   3244   //
   3245   AdapterInfo->Duplex = HALF_DUPLEX;
   3246 
   3247   if (PhyId == PHY_NSC_TX) {
   3248     //
   3249     // Read register 25 to get the SPEED_10 bit
   3250     //
   3251     MdiRead (
   3252       AdapterInfo,
   3253       NSC_SPEED_IND_REG,
   3254       AdapterInfo->PhyAddress,
   3255       &MdiMiscReg
   3256       );
   3257 
   3258     //
   3259     // If bit 6 was set then we're at 10mb
   3260     //
   3261     if (MdiMiscReg & NSC_TX_SPD_INDC_SPEED) {
   3262       AdapterInfo->LinkSpeed = 10;
   3263     } else {
   3264       AdapterInfo->LinkSpeed = 100;
   3265     }
   3266   }
   3267 
   3268   //
   3269   // If we don't know what line speed we are set at, then we'll default to
   3270   // 10mbs
   3271   //
   3272   else {
   3273     AdapterInfo->LinkSpeed = 10;
   3274   }
   3275 }
   3276 
   3277 
   3278 /**
   3279   TODO: Add function description
   3280 
   3281   @param  AdapterInfo                     TODO: add argument description
   3282 
   3283   @return TODO: add return values
   3284 
   3285 **/
   3286 VOID
   3287 XmitWaitForCompletion (
   3288   NIC_DATA_INSTANCE *AdapterInfo
   3289   )
   3290 {
   3291   TxCB  *TxPtr;
   3292 
   3293   if (AdapterInfo->FreeCBCount == AdapterInfo->TxBufCnt) {
   3294     return ;
   3295   }
   3296 
   3297   //
   3298   // used xmit cb list starts right after the free tail (ends before the
   3299   // free head ptr)
   3300   //
   3301   TxPtr = AdapterInfo->FreeTxTailPtr->NextTCBVirtualLinkPtr;
   3302   while (TxPtr != AdapterInfo->FreeTxHeadPtr) {
   3303     CommandWaitForCompletion (TxPtr, AdapterInfo);
   3304     SetFreeCB (AdapterInfo, TxPtr);
   3305     TxPtr = TxPtr->NextTCBVirtualLinkPtr;
   3306   }
   3307 }
   3308 
   3309 
   3310 /**
   3311   TODO: Add function description
   3312 
   3313   @param  cmd_ptr                         TODO: add argument description
   3314   @param  AdapterInfo                     TODO: add argument description
   3315 
   3316   @return TODO: add return values
   3317 
   3318 **/
   3319 INT8
   3320 CommandWaitForCompletion (
   3321   TxCB              *cmd_ptr,
   3322   NIC_DATA_INSTANCE *AdapterInfo
   3323   )
   3324 {
   3325   INT16 wait;
   3326   wait = 5000;
   3327   while ((cmd_ptr->cb_header.status == 0) && (--wait > 0)) {
   3328     DelayIt (AdapterInfo, 10);
   3329   }
   3330 
   3331   if (cmd_ptr->cb_header.status == 0) {
   3332     return -1;
   3333   }
   3334 
   3335   return 0;
   3336 }
   3337 
   3338 
   3339 /**
   3340   TODO: Add function description
   3341 
   3342   @param  AdapterInfo                     TODO: add argument description
   3343 
   3344   @return TODO: add return values
   3345 
   3346 **/
   3347 INT8
   3348 SoftwareReset (
   3349   NIC_DATA_INSTANCE *AdapterInfo
   3350   )
   3351 {
   3352   UINT8   tco_stat;
   3353   UINT16  wait;
   3354 
   3355   tco_stat = 0;
   3356 
   3357   //
   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
   3360   // action.
   3361   //
   3362 
   3363   OutLong (AdapterInfo, PORT_RESET, AdapterInfo->ioaddr + SCBPort);
   3364   //
   3365   // wait for 5 milli seconds here!
   3366   //
   3367   DelayIt (AdapterInfo, 5000);
   3368   //
   3369   // TCO Errata work around for 559s only
   3370   // -----------------------------------------------------------------------------------
   3371   // TCO Workaround Code
   3372   //  haifa workaround
   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 ...
   3384   //
   3385   // Check for ICH2 device ID.  If this is an ICH2,
   3386   // do the TCO workaround code.
   3387   //
   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
   3398     //
   3399     // donot load the scb pointer but just give load_cu cmd.
   3400     //
   3401     OutByte (AdapterInfo, CU_CMD_BASE, AdapterInfo->ioaddr + SCBCmd);
   3402     //
   3403     // wait for command to be accepted.
   3404     //
   3405     wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);
   3406     //
   3407     // read PMDR register and check bit 1 in it to see if TCO is active
   3408     //
   3409 
   3410     //
   3411     // wait for 5 milli seconds
   3412     //
   3413     wait = 5000;
   3414     while (wait) {
   3415       tco_stat = InByte (AdapterInfo, AdapterInfo->ioaddr + 0x1b);
   3416       if ((tco_stat & 2) == 0) {
   3417         //
   3418         // is the activity bit clear??
   3419         //
   3420         break;
   3421       }
   3422 
   3423       wait--;
   3424       DelayIt (AdapterInfo, 1);
   3425     }
   3426 
   3427     if ((tco_stat & 2) != 0) {
   3428       //
   3429       // not zero??
   3430       //
   3431       return -1;
   3432     }
   3433   }
   3434 
   3435   return 0;
   3436 }
   3437 
   3438 
   3439 /**
   3440   TODO: Add function description
   3441 
   3442   @param  AdapterInfo                     TODO: add argument description
   3443 
   3444   @return TODO: add return values
   3445 
   3446 **/
   3447 UINT8
   3448 SelectiveReset (
   3449   IN NIC_DATA_INSTANCE *AdapterInfo
   3450   )
   3451 {
   3452   UINT16  wait;
   3453   UINT32  stat;
   3454 
   3455   wait  = 10;
   3456   stat  = 0;
   3457   OutLong (AdapterInfo, POR_SELECTIVE_RESET, AdapterInfo->ioaddr + SCBPort);
   3458   //
   3459   // wait for this to complete
   3460   //
   3461 
   3462   //
   3463   // wait for 2 milli seconds here!
   3464   //
   3465   DelayIt (AdapterInfo, 2000);
   3466   while (wait > 0) {
   3467     wait--;
   3468     stat = InLong (AdapterInfo, AdapterInfo->ioaddr + SCBPort);
   3469     if (stat == 0) {
   3470       break;
   3471     }
   3472 
   3473     //
   3474     // wait for 1 milli second
   3475     //
   3476     DelayIt (AdapterInfo, 1000);
   3477   }
   3478 
   3479   if (stat != 0) {
   3480     return PXE_STATCODE_DEVICE_FAILURE;
   3481   }
   3482 
   3483   return 0;
   3484 }
   3485 
   3486 
   3487 /**
   3488   TODO: Add function description
   3489 
   3490   @param  AdapterInfo                     TODO: add argument description
   3491 
   3492   @return TODO: add return values
   3493 
   3494 **/
   3495 UINT16
   3496 InitializeChip (
   3497   IN NIC_DATA_INSTANCE *AdapterInfo
   3498   )
   3499 {
   3500   UINT16  ret_val;
   3501   if (SoftwareReset (AdapterInfo) != 0) {
   3502     return PXE_STATCODE_DEVICE_FAILURE;
   3503   }
   3504 
   3505   //
   3506   // disable interrupts
   3507   //
   3508   OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);
   3509 
   3510   //
   3511   // Load the base registers with 0s (we will give the complete address as
   3512   // offset later when we issue any command
   3513   //
   3514   if ((ret_val = Load_Base_Regs (AdapterInfo)) != 0) {
   3515     return ret_val;
   3516   }
   3517 
   3518   if ((ret_val = SetupCBlink (AdapterInfo)) != 0) {
   3519     return ret_val;
   3520   }
   3521 
   3522   if ((ret_val = SetupReceiveQueues (AdapterInfo)) != 0) {
   3523     return ret_val;
   3524   }
   3525 
   3526   //
   3527   // detect the PHY only if we need to detect the cable as requested by the
   3528   // initialize parameters
   3529   //
   3530   AdapterInfo->PhyAddress = 0xFF;
   3531 
   3532   if (AdapterInfo->CableDetect != 0) {
   3533     if (!PhyDetect (AdapterInfo)) {
   3534       return PXE_STATCODE_DEVICE_FAILURE;
   3535     }
   3536   }
   3537 
   3538   if ((ret_val = E100bSetupIAAddr (AdapterInfo)) != 0) {
   3539     return ret_val;
   3540   }
   3541 
   3542   if ((ret_val = Configure (AdapterInfo)) != 0) {
   3543     return ret_val;
   3544   }
   3545 
   3546   return 0;
   3547 }
   3548