Home | History | Annotate | Download | only in SnpDxe
      1 /** @file
      2   Implementation of driver entry point and driver binding protocol.
      3 
      4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials are licensed
      6 and made available under the terms and conditions of the BSD License which
      7 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 "Snp.h"
     16 
     17 /**
     18   One notified function to stop UNDI device when gBS->ExitBootServices() called.
     19 
     20   @param  Event                   Pointer to this event
     21   @param  Context                 Event handler private data
     22 
     23 **/
     24 VOID
     25 EFIAPI
     26 SnpNotifyExitBootServices (
     27   EFI_EVENT Event,
     28   VOID      *Context
     29   )
     30 {
     31   SNP_DRIVER             *Snp;
     32 
     33   Snp  = (SNP_DRIVER *)Context;
     34 
     35   //
     36   // Shutdown and stop UNDI driver
     37   //
     38   PxeShutdown (Snp);
     39   PxeStop (Snp);
     40 }
     41 
     42 /**
     43   Send command to UNDI. It does nothing currently.
     44 
     45   @param Cdb   command to be sent to UNDI.
     46 
     47   @retval EFI_INVALID_PARAMETER  The command is 0.
     48   @retval EFI_UNSUPPORTED        Default return status because it's not
     49                                  supported currently.
     50 
     51 **/
     52 EFI_STATUS
     53 EFIAPI
     54 IssueHwUndiCommand (
     55   UINT64 Cdb
     56   )
     57 {
     58   DEBUG ((EFI_D_ERROR, "\nIssueHwUndiCommand() - This should not be called!"));
     59 
     60   if (Cdb == 0) {
     61     return EFI_INVALID_PARAMETER;
     62 
     63   }
     64   //
     65   //  %%TBD - For now, nothing is done.
     66   //
     67   return EFI_UNSUPPORTED;
     68 }
     69 
     70 
     71 /**
     72   Compute 8-bit checksum of a buffer.
     73 
     74   @param  Buffer               Pointer to buffer.
     75   @param  Length               Length of buffer in bytes.
     76 
     77   @return 8-bit checksum of all bytes in buffer, or zero if ptr is NULL or len
     78           is zero.
     79 
     80 **/
     81 UINT8
     82 Calc8BitCksum (
     83   VOID  *Buffer,
     84   UINTN Length
     85   )
     86 {
     87   UINT8 *Ptr;
     88   UINT8 Cksum;
     89 
     90   Ptr   = Buffer;
     91   Cksum = 0;
     92 
     93   if (Ptr == NULL || Length == 0) {
     94     return 0;
     95   }
     96 
     97   while (Length-- != 0) {
     98     Cksum = (UINT8) (Cksum + *Ptr++);
     99   }
    100 
    101   return Cksum;
    102 }
    103 
    104 /**
    105   Test to see if this driver supports ControllerHandle. This service
    106   is called by the EFI boot service ConnectController(). In
    107   order to make drivers as small as possible, there are a few calling
    108   restrictions for this service. ConnectController() must
    109   follow these calling restrictions. If any other agent wishes to call
    110   Supported() it must also follow these calling restrictions.
    111 
    112   @param  This                Protocol instance pointer.
    113   @param  ControllerHandle    Handle of device to test.
    114   @param  RemainingDevicePath Optional parameter use to pick a specific child
    115                               device to start.
    116 
    117   @retval EFI_SUCCESS         This driver supports this device.
    118   @retval EFI_ALREADY_STARTED This driver is already running on this device.
    119   @retval other               This driver does not support this device.
    120 
    121 **/
    122 EFI_STATUS
    123 EFIAPI
    124 SimpleNetworkDriverSupported (
    125   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    126   IN EFI_HANDLE                     Controller,
    127   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    128   )
    129 {
    130   EFI_STATUS                                Status;
    131   EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
    132   PXE_UNDI                                  *Pxe;
    133 
    134   Status = gBS->OpenProtocol (
    135                   Controller,
    136                   &gEfiDevicePathProtocolGuid,
    137                   NULL,
    138                   This->DriverBindingHandle,
    139                   Controller,
    140                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    141                   );
    142   if (EFI_ERROR (Status)) {
    143     return Status;
    144   }
    145 
    146   Status = gBS->OpenProtocol (
    147                   Controller,
    148                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
    149                   (VOID **) &NiiProtocol,
    150                   This->DriverBindingHandle,
    151                   Controller,
    152                   EFI_OPEN_PROTOCOL_BY_DRIVER
    153                   );
    154 
    155   if (EFI_ERROR (Status)) {
    156     if (Status == EFI_ALREADY_STARTED) {
    157       DEBUG ((EFI_D_INFO, "Support(): Already Started. on handle %p\n", Controller));
    158     }
    159     return Status;
    160   }
    161 
    162   DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %p\n", Controller));
    163 
    164   //
    165   // check the version, we don't want to connect to the undi16
    166   //
    167   if (NiiProtocol->Type != EfiNetworkInterfaceUndi) {
    168     Status = EFI_UNSUPPORTED;
    169     goto Done;
    170   }
    171   //
    172   // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required.
    173   //
    174   if ((NiiProtocol->Id & 0x0F) != 0) {
    175     DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));
    176     Status = EFI_UNSUPPORTED;
    177     goto Done;
    178   }
    179 
    180   Pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->Id);
    181 
    182   //
    183   //  Verify !PXE revisions.
    184   //
    185   if (Pxe->hw.Signature != PXE_ROMID_SIGNATURE) {
    186     DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));
    187     Status = EFI_UNSUPPORTED;
    188     goto Done;
    189   }
    190 
    191   if (Pxe->hw.Rev < PXE_ROMID_REV) {
    192     DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));
    193     Status = EFI_UNSUPPORTED;
    194     goto Done;
    195   }
    196 
    197   if (Pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {
    198 
    199     DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));
    200     Status = EFI_UNSUPPORTED;
    201     goto Done;
    202 
    203   } else if (Pxe->hw.MajorVer == PXE_ROMID_MAJORVER && Pxe->hw.MinorVer < PXE_ROMID_MINORVER) {
    204     DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));
    205     Status = EFI_UNSUPPORTED;
    206     goto Done;
    207   }
    208   //
    209   // Do S/W UNDI specific checks.
    210   //
    211   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {
    212     if (Pxe->sw.EntryPoint < Pxe->sw.Len) {
    213       DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));
    214       Status = EFI_UNSUPPORTED;
    215       goto Done;
    216     }
    217 
    218     if (Pxe->sw.BusCnt == 0) {
    219       DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));
    220       Status = EFI_UNSUPPORTED;
    221       goto Done;
    222     }
    223   }
    224 
    225   Status = EFI_SUCCESS;
    226   DEBUG ((EFI_D_INFO, "Support(): supported on %p\n", Controller));
    227 
    228 Done:
    229   gBS->CloseProtocol (
    230         Controller,
    231         &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
    232         This->DriverBindingHandle,
    233         Controller
    234         );
    235 
    236   return Status;
    237 }
    238 
    239 /**
    240   Start this driver on ControllerHandle. This service is called by the
    241   EFI boot service ConnectController(). In order to make
    242   drivers as small as possible, there are a few calling restrictions for
    243   this service. ConnectController() must follow these
    244   calling restrictions. If any other agent wishes to call Start() it
    245   must also follow these calling restrictions.
    246 
    247   @param  This                 Protocol instance pointer.
    248   @param  ControllerHandle     Handle of device to bind driver to.
    249   @param  RemainingDevicePath  Optional parameter use to pick a specific child
    250                                device to start.
    251 
    252   @retval EFI_SUCCESS          This driver is added to ControllerHandle
    253   @retval EFI_DEVICE_ERROR     This driver could not be started due to a device error
    254   @retval other                This driver does not support this device
    255 
    256 **/
    257 EFI_STATUS
    258 EFIAPI
    259 SimpleNetworkDriverStart (
    260   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    261   IN EFI_HANDLE                     Controller,
    262   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    263   )
    264 {
    265   EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;
    266   EFI_DEVICE_PATH_PROTOCOL                  *NiiDevicePath;
    267   EFI_STATUS                                Status;
    268   PXE_UNDI                                  *Pxe;
    269   SNP_DRIVER                                *Snp;
    270   VOID                                      *Address;
    271   EFI_HANDLE                                Handle;
    272   UINT8                                     BarIndex;
    273   PXE_STATFLAGS                             InitStatFlags;
    274   EFI_PCI_IO_PROTOCOL                       *PciIo;
    275   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR         *BarDesc;
    276   BOOLEAN                                   FoundIoBar;
    277   BOOLEAN                                   FoundMemoryBar;
    278 
    279   DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier()  "));
    280 
    281   Status = gBS->OpenProtocol (
    282                   Controller,
    283                   &gEfiDevicePathProtocolGuid,
    284                   (VOID **) &NiiDevicePath,
    285                   This->DriverBindingHandle,
    286                   Controller,
    287                   EFI_OPEN_PROTOCOL_BY_DRIVER
    288                   );
    289 
    290   if (EFI_ERROR (Status)) {
    291     return Status;
    292   }
    293 
    294   Status = gBS->LocateDevicePath (
    295                   &gEfiPciIoProtocolGuid,
    296                   &NiiDevicePath,
    297                   &Handle
    298                   );
    299 
    300   if (EFI_ERROR (Status)) {
    301     return Status;
    302   }
    303 
    304   Status = gBS->OpenProtocol (
    305                   Handle,
    306                   &gEfiPciIoProtocolGuid,
    307                   (VOID **) &PciIo,
    308                   This->DriverBindingHandle,
    309                   Controller,
    310                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    311                   );
    312   if (EFI_ERROR (Status)) {
    313     return Status;
    314   }
    315   //
    316   // Get the NII interface.
    317   //
    318   Status = gBS->OpenProtocol (
    319                   Controller,
    320                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
    321                   (VOID **) &Nii,
    322                   This->DriverBindingHandle,
    323                   Controller,
    324                   EFI_OPEN_PROTOCOL_BY_DRIVER
    325                   );
    326   if (EFI_ERROR (Status)) {
    327     gBS->CloseProtocol (
    328           Controller,
    329           &gEfiDevicePathProtocolGuid,
    330           This->DriverBindingHandle,
    331           Controller
    332           );
    333     return Status;
    334   }
    335 
    336   DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n"));
    337 
    338   Pxe = (PXE_UNDI *) (UINTN) (Nii->Id);
    339 
    340   if (Calc8BitCksum (Pxe, Pxe->hw.Len) != 0) {
    341     DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));
    342     goto NiiError;
    343   }
    344 
    345   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
    346     //
    347     //  We can get any packets.
    348     //
    349   } else if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
    350     //
    351     //  We need to be able to get broadcast packets for DHCP.
    352     //  If we do not have promiscuous support, we must at least have
    353     //  broadcast support or we cannot do DHCP!
    354     //
    355   } else {
    356     DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));
    357     goto NiiError;
    358   }
    359   //
    360   // OK, we like this UNDI, and we know snp is not already there on this handle
    361   // Allocate and initialize a new simple network protocol structure.
    362   //
    363   Status = PciIo->AllocateBuffer (
    364                     PciIo,
    365                     AllocateAnyPages,
    366                     EfiBootServicesData,
    367                     SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
    368                     &Address,
    369                     0
    370                     );
    371 
    372   if (Status != EFI_SUCCESS) {
    373     DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));
    374     goto NiiError;
    375   }
    376 
    377   Snp = (SNP_DRIVER *) (UINTN) Address;
    378 
    379   ZeroMem (Snp, sizeof (SNP_DRIVER));
    380 
    381   Snp->PciIo      = PciIo;
    382   Snp->Signature  = SNP_DRIVER_SIGNATURE;
    383 
    384   EfiInitializeLock (&Snp->Lock, TPL_NOTIFY);
    385 
    386   Snp->Snp.Revision       = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
    387   Snp->Snp.Start          = SnpUndi32Start;
    388   Snp->Snp.Stop           = SnpUndi32Stop;
    389   Snp->Snp.Initialize     = SnpUndi32Initialize;
    390   Snp->Snp.Reset          = SnpUndi32Reset;
    391   Snp->Snp.Shutdown       = SnpUndi32Shutdown;
    392   Snp->Snp.ReceiveFilters = SnpUndi32ReceiveFilters;
    393   Snp->Snp.StationAddress = SnpUndi32StationAddress;
    394   Snp->Snp.Statistics     = SnpUndi32Statistics;
    395   Snp->Snp.MCastIpToMac   = SnpUndi32McastIpToMac;
    396   Snp->Snp.NvData         = SnpUndi32NvData;
    397   Snp->Snp.GetStatus      = SnpUndi32GetStatus;
    398   Snp->Snp.Transmit       = SnpUndi32Transmit;
    399   Snp->Snp.Receive        = SnpUndi32Receive;
    400   Snp->Snp.WaitForPacket  = NULL;
    401 
    402   Snp->Snp.Mode           = &Snp->Mode;
    403 
    404   Snp->TxRxBufferSize     = 0;
    405   Snp->TxRxBuffer         = NULL;
    406 
    407   Snp->RecycledTxBuf = AllocatePool (sizeof (UINT64) * SNP_TX_BUFFER_INCREASEMENT);
    408   if (Snp->RecycledTxBuf == NULL) {
    409     Status = EFI_OUT_OF_RESOURCES;
    410     goto Error_DeleteSNP;
    411   }
    412   Snp->MaxRecycledTxBuf    = SNP_TX_BUFFER_INCREASEMENT;
    413   Snp->RecycledTxBufCount  = 0;
    414 
    415   if (Nii->Revision >= EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION) {
    416     Snp->IfNum = Nii->IfNum;
    417 
    418   } else {
    419     Snp->IfNum = (UINT8) (Nii->IfNum & 0xFF);
    420   }
    421 
    422   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {
    423     Snp->IsSwUndi             = FALSE;
    424     Snp->IssueUndi32Command   = &IssueHwUndiCommand;
    425   } else {
    426     Snp->IsSwUndi = TRUE;
    427 
    428     if ((Pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {
    429       Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) Pxe->sw.EntryPoint;
    430     } else {
    431       Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) ((UINT8) (UINTN) Pxe + Pxe->sw.EntryPoint);
    432     }
    433   }
    434   //
    435   // Allocate a global CPB and DB buffer for this UNDI interface.
    436   // we do this because:
    437   //
    438   // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be
    439   // within 2GB limit, create them here and map them so that when undi calls
    440   // v2p callback to check if the physical address is < 2gb, we will pass.
    441   //
    442   // -This is not a requirement for 3.1 or later UNDIs but the code looks
    443   // simpler if we use the same cpb, db variables for both old and new undi
    444   // interfaces from all the SNP interface calls (we don't map the buffers
    445   // for the newer undi interfaces though)
    446   // .
    447   // -it is OK to allocate one global set of CPB, DB pair for each UNDI
    448   // interface as EFI does not multi-task and so SNP will not be re-entered!
    449   //
    450   Status = PciIo->AllocateBuffer (
    451                     PciIo,
    452                     AllocateAnyPages,
    453                     EfiBootServicesData,
    454                     SNP_MEM_PAGES (4096),
    455                     &Address,
    456                     0
    457                     );
    458 
    459   if (Status != EFI_SUCCESS) {
    460     DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));
    461     goto Error_DeleteSNP;
    462   }
    463 
    464   Snp->Cpb  = (VOID *) (UINTN) Address;
    465   Snp->Db   = (VOID *) ((UINTN) Address + 2048);
    466 
    467   //
    468   // Find the correct BAR to do IO.
    469   //
    470   // Enumerate through the PCI BARs for the device to determine which one is
    471   // the IO BAR.  Save the index of the BAR into the adapter info structure.
    472   // for regular 32bit BARs, 0 is memory mapped, 1 is io mapped
    473   //
    474   Snp->MemoryBarIndex = 0;
    475   Snp->IoBarIndex     = 1;
    476   FoundMemoryBar      = FALSE;
    477   FoundIoBar          = FALSE;
    478   for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {
    479     Status = PciIo->GetBarAttributes (
    480                       PciIo,
    481                       BarIndex,
    482                       NULL,
    483                       (VOID**) &BarDesc
    484                       );
    485     if (Status == EFI_UNSUPPORTED) {
    486       continue;
    487     } else if (EFI_ERROR (Status)) {
    488       goto Error_DeleteSNP;
    489     }
    490 
    491     if ((!FoundMemoryBar) && (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM)) {
    492       Snp->MemoryBarIndex = BarIndex;
    493       FoundMemoryBar      = TRUE;
    494     } else if ((!FoundIoBar) && (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_IO)) {
    495       Snp->IoBarIndex = BarIndex;
    496       FoundIoBar      = TRUE;
    497     }
    498 
    499     FreePool (BarDesc);
    500 
    501     if (FoundMemoryBar && FoundIoBar) {
    502       break;
    503     }
    504   }
    505 
    506   Status = PxeStart (Snp);
    507 
    508   if (Status != EFI_SUCCESS) {
    509     goto Error_DeleteSNP;
    510   }
    511 
    512   Snp->Cdb.OpCode     = PXE_OPCODE_GET_INIT_INFO;
    513   Snp->Cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;
    514 
    515   Snp->Cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;
    516   Snp->Cdb.CPBaddr    = PXE_DBADDR_NOT_USED;
    517 
    518   Snp->Cdb.DBsize     = (UINT16) sizeof (Snp->InitInfo);
    519   Snp->Cdb.DBaddr     = (UINT64)(UINTN) (&Snp->InitInfo);
    520 
    521   Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
    522   Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
    523 
    524   Snp->Cdb.IFnum      = Snp->IfNum;
    525   Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;
    526 
    527   DEBUG ((EFI_D_NET, "\nSnp->undi.get_init_info()  "));
    528 
    529   (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
    530 
    531   //
    532   // Save the INIT Stat Code...
    533   //
    534   InitStatFlags = Snp->Cdb.StatFlags;
    535 
    536   if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
    537     DEBUG ((EFI_D_NET, "\nSnp->undi.init_info()  %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));
    538     PxeStop (Snp);
    539     goto Error_DeleteSNP;
    540   }
    541 
    542   //
    543   //  Initialize simple network protocol mode structure
    544   //
    545   Snp->Mode.State               = EfiSimpleNetworkStopped;
    546   Snp->Mode.HwAddressSize       = Snp->InitInfo.HWaddrLen;
    547   Snp->Mode.MediaHeaderSize     = Snp->InitInfo.MediaHeaderLen;
    548   Snp->Mode.MaxPacketSize       = Snp->InitInfo.FrameDataLen;
    549   Snp->Mode.NvRamAccessSize     = Snp->InitInfo.NvWidth;
    550   Snp->Mode.NvRamSize           = Snp->InitInfo.NvCount * Snp->Mode.NvRamAccessSize;
    551   Snp->Mode.IfType              = Snp->InitInfo.IFtype;
    552   Snp->Mode.MaxMCastFilterCount = Snp->InitInfo.MCastFilterCnt;
    553   Snp->Mode.MCastFilterCount    = 0;
    554 
    555   switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {
    556   case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:
    557     Snp->Mode.MediaPresentSupported = TRUE;
    558     break;
    559 
    560   case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:
    561   default:
    562     Snp->Mode.MediaPresentSupported = FALSE;
    563   }
    564 
    565   switch (InitStatFlags & PXE_STATFLAGS_GET_STATUS_NO_MEDIA_MASK) {
    566   case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED:
    567     Snp->MediaStatusSupported = TRUE;
    568     break;
    569 
    570   case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_NOT_SUPPORTED:
    571   default:
    572     Snp->MediaStatusSupported = FALSE;
    573   }
    574 
    575   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {
    576     Snp->Mode.MacAddressChangeable = TRUE;
    577   } else {
    578     Snp->Mode.MacAddressChangeable = FALSE;
    579   }
    580 
    581   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {
    582     Snp->Mode.MultipleTxSupported = TRUE;
    583   } else {
    584     Snp->Mode.MultipleTxSupported = FALSE;
    585   }
    586 
    587   Snp->Mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
    588 
    589   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {
    590     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
    591 
    592   }
    593 
    594   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
    595     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
    596 
    597   }
    598 
    599   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
    600     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
    601 
    602   }
    603 
    604   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {
    605     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
    606 
    607   }
    608 
    609   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {
    610     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
    611 
    612   }
    613 
    614   Snp->Mode.ReceiveFilterSetting = 0;
    615 
    616   //
    617   //  need to get the station address to save in the mode structure. we need to
    618   // initialize the UNDI first for this.
    619   //
    620   Snp->TxRxBufferSize = Snp->InitInfo.MemoryRequired;
    621   Status              = PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);
    622 
    623   if (EFI_ERROR (Status)) {
    624     PxeStop (Snp);
    625     goto Error_DeleteSNP;
    626   }
    627 
    628   Status = PxeGetStnAddr (Snp);
    629 
    630   if (Status != EFI_SUCCESS) {
    631     DEBUG ((EFI_D_ERROR, "\nSnp->undi.get_station_addr() failed.\n"));
    632     PxeShutdown (Snp);
    633     PxeStop (Snp);
    634     goto Error_DeleteSNP;
    635   }
    636 
    637   Snp->Mode.MediaPresent = FALSE;
    638 
    639   //
    640   // We should not leave UNDI started and initialized here. this DriverStart()
    641   // routine must only find and attach the SNP interface to UNDI layer that it
    642   // finds on the given handle!
    643   // The UNDI layer will be started when upper layers call Snp->start.
    644   // How ever, this DriverStart() must fill up the snp mode structure which
    645   // contains the MAC address of the NIC. For this reason we started and
    646   // initialized UNDI here, now we are done, do a shutdown and stop of the
    647   // UNDI interface!
    648   //
    649   PxeShutdown (Snp);
    650   PxeStop (Snp);
    651 
    652   //
    653   // Create EXIT_BOOT_SERIVES Event
    654   //
    655   Status = gBS->CreateEventEx (
    656                   EVT_NOTIFY_SIGNAL,
    657                   TPL_NOTIFY,
    658                   SnpNotifyExitBootServices,
    659                   Snp,
    660                   &gEfiEventExitBootServicesGuid,
    661                   &Snp->ExitBootServicesEvent
    662                   );
    663   if (EFI_ERROR (Status)) {
    664     goto Error_DeleteSNP;
    665   }
    666 
    667   //
    668   //  add SNP to the undi handle
    669   //
    670   Status = gBS->InstallProtocolInterface (
    671                   &Controller,
    672                   &gEfiSimpleNetworkProtocolGuid,
    673                   EFI_NATIVE_INTERFACE,
    674                   &(Snp->Snp)
    675                   );
    676 
    677   if (!EFI_ERROR (Status)) {
    678     return Status;
    679   }
    680 
    681   PciIo->FreeBuffer (
    682            PciIo,
    683            SNP_MEM_PAGES (4096),
    684            Snp->Cpb
    685            );
    686 
    687 Error_DeleteSNP:
    688 
    689   if (Snp->RecycledTxBuf != NULL) {
    690     FreePool (Snp->RecycledTxBuf);
    691   }
    692 
    693   PciIo->FreeBuffer (
    694            PciIo,
    695            SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
    696            Snp
    697            );
    698 NiiError:
    699   gBS->CloseProtocol (
    700         Controller,
    701         &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
    702         This->DriverBindingHandle,
    703         Controller
    704         );
    705 
    706   gBS->CloseProtocol (
    707         Controller,
    708         &gEfiDevicePathProtocolGuid,
    709         This->DriverBindingHandle,
    710         Controller
    711         );
    712 
    713   //
    714   // If we got here that means we are in error state.
    715   //
    716   if (!EFI_ERROR (Status)) {
    717     Status = EFI_DEVICE_ERROR;
    718   }
    719 
    720   return Status;
    721 }
    722 
    723 /**
    724   Stop this driver on ControllerHandle. This service is called by the
    725   EFI boot service DisconnectController(). In order to
    726   make drivers as small as possible, there are a few calling
    727   restrictions for this service. DisconnectController()
    728   must follow these calling restrictions. If any other agent wishes
    729   to call Stop() it must also follow these calling restrictions.
    730 
    731   @param  This              Protocol instance pointer.
    732   @param  ControllerHandle  Handle of device to stop driver on
    733   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
    734                             children is zero stop the entire bus driver.
    735   @param  ChildHandleBuffer List of Child Handles to Stop.
    736 
    737   @retval EFI_SUCCESS       This driver is removed ControllerHandle
    738   @retval other             This driver was not removed from this device
    739 
    740 **/
    741 EFI_STATUS
    742 EFIAPI
    743 SimpleNetworkDriverStop (
    744   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
    745   IN  EFI_HANDLE                     Controller,
    746   IN  UINTN                          NumberOfChildren,
    747   IN  EFI_HANDLE                     *ChildHandleBuffer
    748   )
    749 {
    750   EFI_STATUS                  Status;
    751   EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;
    752   SNP_DRIVER                  *Snp;
    753   EFI_PCI_IO_PROTOCOL         *PciIo;
    754 
    755   //
    756   // Get our context back.
    757   //
    758   Status = gBS->OpenProtocol (
    759                   Controller,
    760                   &gEfiSimpleNetworkProtocolGuid,
    761                   (VOID **) &SnpProtocol,
    762                   This->DriverBindingHandle,
    763                   Controller,
    764                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    765                   );
    766 
    767   if (EFI_ERROR (Status)) {
    768     return EFI_UNSUPPORTED;
    769   }
    770 
    771   Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);
    772 
    773   Status = gBS->UninstallProtocolInterface (
    774                   Controller,
    775                   &gEfiSimpleNetworkProtocolGuid,
    776                   &Snp->Snp
    777                   );
    778 
    779   if (EFI_ERROR (Status)) {
    780     return Status;
    781   }
    782 
    783   //
    784   // Close EXIT_BOOT_SERIVES Event
    785   //
    786   gBS->CloseEvent (Snp->ExitBootServicesEvent);
    787 
    788   Status = gBS->CloseProtocol (
    789                   Controller,
    790                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
    791                   This->DriverBindingHandle,
    792                   Controller
    793                   );
    794 
    795   Status = gBS->CloseProtocol (
    796                   Controller,
    797                   &gEfiDevicePathProtocolGuid,
    798                   This->DriverBindingHandle,
    799                   Controller
    800                   );
    801 
    802   PxeShutdown (Snp);
    803   PxeStop (Snp);
    804 
    805   FreePool (Snp->RecycledTxBuf);
    806 
    807   PciIo = Snp->PciIo;
    808   PciIo->FreeBuffer (
    809            PciIo,
    810            SNP_MEM_PAGES (4096),
    811            Snp->Cpb
    812            );
    813 
    814   PciIo->FreeBuffer (
    815            PciIo,
    816            SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
    817            Snp
    818            );
    819 
    820   return Status;
    821 }
    822 
    823 //
    824 // Simple Network Protocol Driver Global Variables
    825 //
    826 EFI_DRIVER_BINDING_PROTOCOL gSimpleNetworkDriverBinding = {
    827   SimpleNetworkDriverSupported,
    828   SimpleNetworkDriverStart,
    829   SimpleNetworkDriverStop,
    830   0xa,
    831   NULL,
    832   NULL
    833 };
    834 
    835 /**
    836   The SNP driver entry point.
    837 
    838   @param ImageHandle       The driver image handle.
    839   @param SystemTable       The system table.
    840 
    841   @retval EFI_SUCEESS      Initialization routine has found UNDI hardware,
    842                            loaded it's ROM, and installed a notify event for
    843                            the Network Indentifier Interface Protocol
    844                            successfully.
    845   @retval Other            Return value from HandleProtocol for
    846                            DeviceIoProtocol or LoadedImageProtocol
    847 
    848 **/
    849 EFI_STATUS
    850 EFIAPI
    851 InitializeSnpNiiDriver (
    852   IN EFI_HANDLE       ImageHandle,
    853   IN EFI_SYSTEM_TABLE *SystemTable
    854   )
    855 {
    856   return EfiLibInstallDriverBindingComponentName2 (
    857            ImageHandle,
    858            SystemTable,
    859            &gSimpleNetworkDriverBinding,
    860            ImageHandle,
    861            &gSimpleNetworkComponentName,
    862            &gSimpleNetworkComponentName2
    863            );
    864 }
    865