Ejemplo n.º 1
0
/**
  Call UNDI to initialize the interface.

  @param  Snp                   Pointer to snp driver structure.
  @param  CableDetectFlag       Do/don't detect the cable (depending on what
                                undi supports).

  @retval EFI_SUCCESS           UNDI is initialized successfully.
  @retval EFI_DEVICE_ERROR      UNDI could not be initialized.
  @retval Other                 Other errors as indicated.

**/
EFI_STATUS
PxeInit (
  SNP_DRIVER *Snp,
  UINT16     CableDetectFlag
  )
{
  PXE_CPB_INITIALIZE  *Cpb;
  VOID                *Addr;
  EFI_STATUS          Status;

  Cpb = Snp->Cpb;
  if (Snp->TxRxBufferSize != 0) {
    Status = Snp->PciIo->AllocateBuffer (
                           Snp->PciIo,
                           AllocateAnyPages,
                           EfiBootServicesData,
                           SNP_MEM_PAGES (Snp->TxRxBufferSize),
                           &Addr,
                           0
                           );

    if (Status != EFI_SUCCESS) {
      DEBUG (
        (EFI_D_ERROR,
        "\nSnp->PxeInit()  AllocateBuffer  %xh (%r)\n",
        Status,
        Status)
        );

      return Status;
    }

    ASSERT (Addr);

    Snp->TxRxBuffer = Addr;
  }

  Cpb->MemoryAddr   = (UINT64)(UINTN) Snp->TxRxBuffer;

  Cpb->MemoryLength = Snp->TxRxBufferSize;

  //
  // let UNDI decide/detect these values
  //
  Cpb->LinkSpeed      = 0;
  Cpb->TxBufCnt       = 0;
  Cpb->TxBufSize      = 0;
  Cpb->RxBufCnt       = 0;
  Cpb->RxBufSize      = 0;

  Cpb->DuplexMode         = PXE_DUPLEX_DEFAULT;

  Cpb->LoopBackMode       = LOOPBACK_NORMAL;

  Snp->Cdb.OpCode     = PXE_OPCODE_INITIALIZE;
  Snp->Cdb.OpFlags    = CableDetectFlag;

  Snp->Cdb.CPBsize    = (UINT16) sizeof (PXE_CPB_INITIALIZE);
  Snp->Cdb.DBsize     = (UINT16) sizeof (PXE_DB_INITIALIZE);

  Snp->Cdb.CPBaddr    = (UINT64)(UINTN) Snp->Cpb;
  Snp->Cdb.DBaddr     = (UINT64)(UINTN) Snp->Db;

  Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
  Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
  Snp->Cdb.IFnum      = Snp->IfNum;
  Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;

  DEBUG ((EFI_D_NET, "\nSnp->undi.initialize()  "));

  (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);

  if (Snp->Cdb.StatCode == PXE_STATCODE_SUCCESS) {
    Snp->Mode.State = EfiSimpleNetworkInitialized;

    Status          = EFI_SUCCESS;
  } else {
    DEBUG (
      (EFI_D_WARN,
      "\nSnp->undi.initialize()  %xh:%xh\n",
      Snp->Cdb.StatFlags,
      Snp->Cdb.StatCode)
      );

    if (Snp->TxRxBuffer != NULL) {
      Snp->PciIo->FreeBuffer (
                    Snp->PciIo,
                    SNP_MEM_PAGES (Snp->TxRxBufferSize),
                    (VOID *) Snp->TxRxBuffer
                    );
    }

    Snp->TxRxBuffer = NULL;

    Status          = EFI_DEVICE_ERROR;
  }

  return Status;
}
Ejemplo n.º 2
0
/**
  Stop this driver on ControllerHandle. This service is called by the
  EFI boot service DisconnectController(). In order to
  make drivers as small as possible, there are a few calling
  restrictions for this service. DisconnectController()
  must follow these calling restrictions. If any other agent wishes
  to call Stop() it must also follow these calling restrictions.

  @param  This              Protocol instance pointer.
  @param  ControllerHandle  Handle of device to stop driver on
  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
                            children is zero stop the entire bus driver.
  @param  ChildHandleBuffer List of Child Handles to Stop.

  @retval EFI_SUCCESS       This driver is removed ControllerHandle
  @retval other             This driver was not removed from this device

**/
EFI_STATUS
EFIAPI
SimpleNetworkDriverStop (
  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
  IN  EFI_HANDLE                     Controller,
  IN  UINTN                          NumberOfChildren,
  IN  EFI_HANDLE                     *ChildHandleBuffer
  )
{
  EFI_STATUS                  Status;
  EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;
  SNP_DRIVER                  *Snp;

  //
  // Get our context back.
  //
  Status = gBS->OpenProtocol (
                  Controller,
                  &gEfiSimpleNetworkProtocolGuid,
                  (VOID **) &SnpProtocol,
                  This->DriverBindingHandle,
                  Controller,
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
                  );

  if (EFI_ERROR (Status)) {
    return EFI_UNSUPPORTED;
  }

  Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);

  Status = gBS->UninstallProtocolInterface (
                  Controller,
                  &gEfiSimpleNetworkProtocolGuid,
                  &Snp->Snp
                  );

  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Close EXIT_BOOT_SERIVES Event
  //
  gBS->CloseEvent (Snp->ExitBootServicesEvent);

  Status = gBS->CloseProtocol (
                  Controller,
                  &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
                  This->DriverBindingHandle,
                  Controller
                  );

  Status = gBS->CloseProtocol (
                  Controller,
                  &gEfiDevicePathProtocolGuid,
                  This->DriverBindingHandle,
                  Controller
                  );

  PxeShutdown (Snp);
  PxeStop (Snp);

  mPciIo->FreeBuffer (
                mPciIo,
                SNP_MEM_PAGES (4096),
                Snp->Cpb
                );

  mPciIo->FreeBuffer (
                mPciIo,
                SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
                Snp
                );

  return Status;
}
/**
  Call UNDI to initialize the interface.

  @param  Snp                   Pointer to snp driver structure.
  @param  CableDetectFlag       Do/don't detect the cable (depending on what
                                undi supports).

  @retval EFI_SUCCESS           UNDI is initialized successfully.
  @retval EFI_DEVICE_ERROR      UNDI could not be initialized.
  @retval Other                 Other errors as indicated.

**/
EFI_STATUS
PxeInit (
  SNP_DRIVER *Snp,
  UINT16     CableDetectFlag
  )
{
  PXE_CPB_INITIALIZE  *Cpb;
  VOID                *Addr;
  EFI_STATUS          Status;

  Status = EFI_SUCCESS;

  Cpb = Snp->Cpb;
  if (Snp->TxRxBufferSize != 0) {
    Status = Snp->PciIo->AllocateBuffer (
                           Snp->PciIo,
                           AllocateAnyPages,
                           EfiBootServicesData,
                           SNP_MEM_PAGES (Snp->TxRxBufferSize),
                           &Addr,
                           0
                           );

    if (Status != EFI_SUCCESS) {
      DEBUG (
        (EFI_D_ERROR,
        "\nSnp->PxeInit()  AllocateBuffer  %xh (%r)\n",
        Status,
        Status)
        );

      return Status;
    }

    ASSERT (Addr);

    Snp->TxRxBuffer = Addr;
  }

  Cpb->MemoryAddr   = (UINT64)(UINTN) Snp->TxRxBuffer;

  Cpb->MemoryLength = Snp->TxRxBufferSize;

  //
  // let UNDI decide/detect these values
  //
  Cpb->LinkSpeed      = 0;
  Cpb->TxBufCnt       = 0;
  Cpb->TxBufSize      = 0;
  Cpb->RxBufCnt       = 0;
  Cpb->RxBufSize      = 0;

  Cpb->DuplexMode         = PXE_DUPLEX_DEFAULT;

  Cpb->LoopBackMode       = LOOPBACK_NORMAL;

  Snp->Cdb.OpCode     = PXE_OPCODE_INITIALIZE;
  Snp->Cdb.OpFlags    = CableDetectFlag;

  Snp->Cdb.CPBsize    = (UINT16) sizeof (PXE_CPB_INITIALIZE);
  Snp->Cdb.DBsize     = (UINT16) sizeof (PXE_DB_INITIALIZE);

  Snp->Cdb.CPBaddr    = (UINT64)(UINTN) Snp->Cpb;
  Snp->Cdb.DBaddr     = (UINT64)(UINTN) Snp->Db;

  Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
  Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
  Snp->Cdb.IFnum      = Snp->IfNum;
  Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;

  DEBUG ((EFI_D_NET, "\nSnp->undi.initialize()  "));

  (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);

  //
  // There are two fields need to be checked here:
  // First is the upper two bits (14 & 15) in the CDB.StatFlags field. Until these bits change to report
  // PXE_STATFLAGS_COMMAND_COMPLETE or PXE_STATFLAGS_COMMAND_FAILED, the command has not been executed by the UNDI.
  // Second is the CDB.StatCode field. After command execution completes, either successfully or not,
  // the CDB.StatCode field contains the result of the command execution.
  //
  if ((((Snp->Cdb.StatFlags) & PXE_STATFLAGS_STATUS_MASK) == PXE_STATFLAGS_COMMAND_COMPLETE) &&
      (Snp->Cdb.StatCode == PXE_STATCODE_SUCCESS)) {
    //
    // If cable detect feature is enabled in CDB.OpFlags, check the CDB.StatFlags to see if there is an
    // active connection to this network device. If the no media StatFlag is set, the UNDI and network
    // device are still initialized.
    //
    if (CableDetectFlag == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) {
      if(((Snp->Cdb.StatFlags) & PXE_STATFLAGS_INITIALIZED_NO_MEDIA) != PXE_STATFLAGS_INITIALIZED_NO_MEDIA) {
        Snp->Mode.MediaPresent = TRUE;
      } else {
        Snp->Mode.MediaPresent = FALSE;
      }
    }

    Snp->Mode.State   = EfiSimpleNetworkInitialized;
    Status            = EFI_SUCCESS;
  } else {
    DEBUG (
      (EFI_D_WARN,
      "\nSnp->undi.initialize()  %xh:%xh\n",
      Snp->Cdb.StatFlags,
      Snp->Cdb.StatCode)
      );

    if (Snp->TxRxBuffer != NULL) {
      Snp->PciIo->FreeBuffer (
                    Snp->PciIo,
                    SNP_MEM_PAGES (Snp->TxRxBufferSize),
                    (VOID *) Snp->TxRxBuffer
                    );
    }

    Snp->TxRxBuffer = NULL;

    Status          = EFI_DEVICE_ERROR;
  }

  return Status;
}
Ejemplo n.º 4
0
/**
  Start this driver on ControllerHandle. This service is called by the
  EFI boot service ConnectController(). In order to make
  drivers as small as possible, there are a few calling restrictions for
  this service. ConnectController() must follow these
  calling restrictions. If any other agent wishes to call Start() it
  must also follow these calling restrictions.

  @param  This                 Protocol instance pointer.
  @param  ControllerHandle     Handle of device to bind driver to.
  @param  RemainingDevicePath  Optional parameter use to pick a specific child
                               device to start.

  @retval EFI_SUCCESS          This driver is added to ControllerHandle
  @retval EFI_DEVICE_ERROR     This driver could not be started due to a device error
  @retval other                This driver does not support this device

**/
EFI_STATUS
EFIAPI
SimpleNetworkDriverStart (
  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
  IN EFI_HANDLE                     Controller,
  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
  )
{
  EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;
  EFI_DEVICE_PATH_PROTOCOL                  *NiiDevicePath;
  EFI_STATUS                                Status;
  PXE_UNDI                                  *Pxe;
  SNP_DRIVER                                *Snp;
  VOID                                      *Address;
  EFI_HANDLE                                Handle;
  PXE_PCI_CONFIG_INFO                       ConfigInfo;
  PCI_TYPE00                                *ConfigHeader;
  UINT32                                    *TempBar;
  UINT8                                     BarIndex;
  PXE_STATFLAGS                             InitStatFlags;

  DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier()  "));

  Status = gBS->OpenProtocol (
                  Controller,
                  &gEfiDevicePathProtocolGuid,
                  (VOID **) &NiiDevicePath,
                  This->DriverBindingHandle,
                  Controller,
                  EFI_OPEN_PROTOCOL_BY_DRIVER
                  );

  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = gBS->LocateDevicePath (
                  &gEfiPciIoProtocolGuid,
                  &NiiDevicePath,
                  &Handle
                  );

  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = gBS->OpenProtocol (
                  Handle,
                  &gEfiPciIoProtocolGuid,
                  (VOID **) &mPciIo,
                  This->DriverBindingHandle,
                  Controller,
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  //
  // Get the NII interface.
  //
  Status = gBS->OpenProtocol (
                  Controller,
                  &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
                  (VOID **) &Nii,
                  This->DriverBindingHandle,
                  Controller,
                  EFI_OPEN_PROTOCOL_BY_DRIVER
                  );
  if (EFI_ERROR (Status)) {
    gBS->CloseProtocol (
          Controller,
          &gEfiDevicePathProtocolGuid,
          This->DriverBindingHandle,
          Controller
          );
    return Status;
  }

  DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n"));

  Pxe = (PXE_UNDI *) (UINTN) (Nii->Id);

  if (Calc8BitCksum (Pxe, Pxe->hw.Len) != 0) {
    DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));
    goto NiiError;
  }

  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
    //
    //  We can get any packets.
    //
  } else if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
    //
    //  We need to be able to get broadcast packets for DHCP.
    //  If we do not have promiscuous support, we must at least have
    //  broadcast support or we cannot do DHCP!
    //
  } else {
    DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));
    goto NiiError;
  }
  //
  // OK, we like this UNDI, and we know snp is not already there on this handle
  // Allocate and initialize a new simple network protocol structure.
  //
  Status = mPciIo->AllocateBuffer (
                        mPciIo,
                        AllocateAnyPages,
                        EfiBootServicesData,
                        SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
                        &Address,
                        0
                        );

  if (Status != EFI_SUCCESS) {
    DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));
    goto NiiError;
  }

  Snp = (SNP_DRIVER *) (UINTN) Address;

  ZeroMem (Snp, sizeof (SNP_DRIVER));

  Snp->PciIo      = mPciIo;
  Snp->Signature  = SNP_DRIVER_SIGNATURE;

  EfiInitializeLock (&Snp->Lock, TPL_NOTIFY);

  Snp->Snp.Revision       = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
  Snp->Snp.Start          = SnpUndi32Start;
  Snp->Snp.Stop           = SnpUndi32Stop;
  Snp->Snp.Initialize     = SnpUndi32Initialize;
  Snp->Snp.Reset          = SnpUndi32Reset;
  Snp->Snp.Shutdown       = SnpUndi32Shutdown;
  Snp->Snp.ReceiveFilters = SnpUndi32ReceiveFilters;
  Snp->Snp.StationAddress = SnpUndi32StationAddress;
  Snp->Snp.Statistics     = SnpUndi32Statistics;
  Snp->Snp.MCastIpToMac   = SnpUndi32McastIpToMac;
  Snp->Snp.NvData         = SnpUndi32NvData;
  Snp->Snp.GetStatus      = SnpUndi32GetStatus;
  Snp->Snp.Transmit       = SnpUndi32Transmit;
  Snp->Snp.Receive        = SnpUndi32Receive;
  Snp->Snp.WaitForPacket  = NULL;

  Snp->Snp.Mode           = &Snp->Mode;

  Snp->TxRxBufferSize     = 0;
  Snp->TxRxBuffer         = NULL;
 
  if (Nii->Revision >= EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION) {
  	Snp->IfNum = Nii->IfNum;

  } else {
    Snp->IfNum = (UINT8) (Nii->IfNum & 0xFF);
  }

  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {
    Snp->IsSwUndi             = FALSE;
    Snp->IssueUndi32Command   = &IssueHwUndiCommand;
  } else {
    Snp->IsSwUndi = TRUE;

    if ((Pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {
      Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) Pxe->sw.EntryPoint;
    } else {
      Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) ((UINT8) (UINTN) Pxe + Pxe->sw.EntryPoint);
    }
  }
  //
  // Allocate a global CPB and DB buffer for this UNDI interface.
  // we do this because:
  //
  // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be
  // within 2GB limit, create them here and map them so that when undi calls
  // v2p callback to check if the physical address is < 2gb, we will pass.
  //
  // -This is not a requirement for 3.1 or later UNDIs but the code looks
  // simpler if we use the same cpb, db variables for both old and new undi
  // interfaces from all the SNP interface calls (we don't map the buffers
  // for the newer undi interfaces though)
  // .
  // -it is OK to allocate one global set of CPB, DB pair for each UNDI
  // interface as EFI does not multi-task and so SNP will not be re-entered!
  //
  Status = mPciIo->AllocateBuffer (
                        mPciIo,
                        AllocateAnyPages,
                        EfiBootServicesData,
                        SNP_MEM_PAGES (4096),
                        &Address,
                        0
                        );

  if (Status != EFI_SUCCESS) {
    DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));
    goto Error_DeleteSNP;
  }

  Snp->Cpb  = (VOID *) (UINTN) Address;
  Snp->Db   = (VOID *) ((UINTN) Address + 2048);

  //
  // PxeStart call is going to give the callback functions to UNDI, these callback
  // functions use the BarIndex values from the snp structure, so these must be initialized
  // with default values before doing a PxeStart. The correct values can be obtained after
  // getting the config information from UNDI
  //
  Snp->MemoryBarIndex = 0;
  Snp->IoBarIndex     = 1;

  //
  // we need the undi init information many times in this snp code, just get it
  // once here and store it in the snp driver structure. to get Init Info
  // from UNDI we have to start undi first.
  //
  Status = PxeStart (Snp);

  if (Status != EFI_SUCCESS) {
    goto Error_DeleteSNP;
  }

  Snp->Cdb.OpCode     = PXE_OPCODE_GET_INIT_INFO;
  Snp->Cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;

  Snp->Cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;
  Snp->Cdb.CPBaddr    = PXE_DBADDR_NOT_USED;

  Snp->Cdb.DBsize     = (UINT16) sizeof (Snp->InitInfo);
  Snp->Cdb.DBaddr     = (UINT64)(UINTN) (&Snp->InitInfo);

  Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
  Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;

  Snp->Cdb.IFnum      = Snp->IfNum;
  Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;

  DEBUG ((EFI_D_NET, "\nSnp->undi.get_init_info()  "));

  (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);

  //
  // Save the INIT Stat Code...
  //
  InitStatFlags = Snp->Cdb.StatFlags;

  if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
    DEBUG ((EFI_D_NET, "\nSnp->undi.init_info()  %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));
    PxeStop (Snp);
    goto Error_DeleteSNP;
  }

  Snp->Cdb.OpCode     = PXE_OPCODE_GET_CONFIG_INFO;
  Snp->Cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;

  Snp->Cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;
  Snp->Cdb.CPBaddr    = PXE_DBADDR_NOT_USED;

  Snp->Cdb.DBsize     = (UINT16) sizeof (ConfigInfo);
  Snp->Cdb.DBaddr     = (UINT64)(UINTN) &ConfigInfo;

  Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
  Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;

  Snp->Cdb.IFnum      = Snp->IfNum;
  Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;

  DEBUG ((EFI_D_NET, "\nSnp->undi.get_config_info()  "));

  (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);

  if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
    DEBUG ((EFI_D_NET, "\nSnp->undi.config_info()  %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));
    PxeStop (Snp);
    goto Error_DeleteSNP;
  }
  //
  // Find the correct BAR to do IO.
  //
  //
  // Enumerate through the PCI BARs for the device to determine which one is
  // the IO BAR.  Save the index of the BAR into the adapter info structure.
  // for  regular 32bit BARs, 0 is memory mapped, 1 is io mapped
  //
  ConfigHeader  = (PCI_TYPE00 *) ConfigInfo.Config.Byte;
  TempBar       = (UINT32 *) ConfigHeader->Device.Bar;
  for (BarIndex = 0; BarIndex <= 5; BarIndex++) {
    if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {
      //
      // This is a 64-bit memory bar, skip this and the
      // next bar as well.
      //
      TempBar++;
    }

    if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {
      Snp->IoBarIndex = BarIndex;
      break;
    }

    TempBar++;
  }

  //
  //  Initialize simple network protocol mode structure
  //
  Snp->Mode.State               = EfiSimpleNetworkStopped;
  Snp->Mode.HwAddressSize       = Snp->InitInfo.HWaddrLen;
  Snp->Mode.MediaHeaderSize     = Snp->InitInfo.MediaHeaderLen;
  Snp->Mode.MaxPacketSize       = Snp->InitInfo.FrameDataLen;
  Snp->Mode.NvRamAccessSize     = Snp->InitInfo.NvWidth;
  Snp->Mode.NvRamSize           = Snp->InitInfo.NvCount * Snp->Mode.NvRamAccessSize;
  Snp->Mode.IfType              = Snp->InitInfo.IFtype;
  Snp->Mode.MaxMCastFilterCount = Snp->InitInfo.MCastFilterCnt;
  Snp->Mode.MCastFilterCount    = 0;

  switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {
  case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:
    Snp->Mode.MediaPresentSupported = TRUE;
    break;

  case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:
  default:
    Snp->Mode.MediaPresentSupported = FALSE;
  }

  switch (InitStatFlags & PXE_STATFLAGS_GET_STATUS_NO_MEDIA_MASK) {
  case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED:
    Snp->MediaStatusSupported = TRUE;
    break;

  case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_NOT_SUPPORTED:
  default:
    Snp->MediaStatusSupported = FALSE;
  }

  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {
    Snp->Mode.MacAddressChangeable = TRUE;
  } else {
    Snp->Mode.MacAddressChangeable = FALSE;
  }

  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {
    Snp->Mode.MultipleTxSupported = TRUE;
  } else {
    Snp->Mode.MultipleTxSupported = FALSE;
  }

  Snp->Mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;

  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {
    Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;

  }

  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
    Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;

  }

  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
    Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;

  }

  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {
    Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;

  }

  if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {
    Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;

  }

  Snp->Mode.ReceiveFilterSetting = 0;

  //
  //  need to get the station address to save in the mode structure. we need to
  // initialize the UNDI first for this.
  //
  Snp->TxRxBufferSize = Snp->InitInfo.MemoryRequired;
  Status              = PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);

  if (EFI_ERROR (Status)) {
    PxeStop (Snp);
    goto Error_DeleteSNP;
  }

  Status = PxeGetStnAddr (Snp);

  if (Status != EFI_SUCCESS) {
    DEBUG ((EFI_D_ERROR, "\nSnp->undi.get_station_addr() failed.\n"));
    PxeShutdown (Snp);
    PxeStop (Snp);
    goto Error_DeleteSNP;
  }

  Snp->Mode.MediaPresent = FALSE;

  //
  // We should not leave UNDI started and initialized here. this DriverStart()
  // routine must only find and attach the SNP interface to UNDI layer that it
  // finds on the given handle!
  // The UNDI layer will be started when upper layers call Snp->start.
  // How ever, this DriverStart() must fill up the snp mode structure which
  // contains the MAC address of the NIC. For this reason we started and
  // initialized UNDI here, now we are done, do a shutdown and stop of the
  // UNDI interface!
  //
  PxeShutdown (Snp);
  PxeStop (Snp);

  //
  // Create EXIT_BOOT_SERIVES Event
  //
  Status = gBS->CreateEventEx (
                  EVT_NOTIFY_SIGNAL,
                  TPL_NOTIFY,
                  SnpNotifyExitBootServices,
                  Snp,
                  &gEfiEventExitBootServicesGuid,
                  &Snp->ExitBootServicesEvent
                  );
  if (EFI_ERROR (Status)) {
    goto Error_DeleteSNP;
  }

  //
  //  add SNP to the undi handle
  //
  Status = gBS->InstallProtocolInterface (
                  &Controller,
                  &gEfiSimpleNetworkProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  &(Snp->Snp)
                  );

  if (!EFI_ERROR (Status)) {
    return Status;
  }

  mPciIo->FreeBuffer (
            mPciIo,
            SNP_MEM_PAGES (4096),
            Snp->Cpb
            );

Error_DeleteSNP:

  mPciIo->FreeBuffer (
                mPciIo,
                SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
                Snp
                );
NiiError:
  gBS->CloseProtocol (
        Controller,
        &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
        This->DriverBindingHandle,
        Controller
        );

  gBS->CloseProtocol (
        Controller,
        &gEfiDevicePathProtocolGuid,
        This->DriverBindingHandle,
        Controller
        );

  //
  // If we got here that means we are in error state.
  //
  if (!EFI_ERROR (Status)) {
    Status = EFI_DEVICE_ERROR;
  }

  return Status;
}
Ejemplo n.º 5
0
EFI_STATUS
pxe_init (
  SNP_DRIVER *snp,
  UINT16     CableDetectFlag
  )
/*++

Routine Description:
 this routine calls undi to initialize the interface.

Arguments:
 snp  - pointer to snp driver structure
 CableDetectFlag - Do/don't detect the cable (depending on what undi supports)

Returns:

--*/
{
  PXE_CPB_INITIALIZE  *cpb;
  VOID                *addr;
  EFI_STATUS          Status;

  cpb = snp->cpb;
  if (snp->tx_rx_bufsize != 0) {
    Status = snp->IoFncs->AllocateBuffer (
                            snp->IoFncs,
                            AllocateAnyPages,
                            EfiBootServicesData,
                            SNP_MEM_PAGES (snp->tx_rx_bufsize),
                            &addr,
                            0
                            );

    if (Status != EFI_SUCCESS) {
      DEBUG (
        (EFI_D_ERROR,
        "\nsnp->pxe_init()  AllocateBuffer  %xh (%r)\n",
        Status,
        Status)
        );

      return Status;
    }

    ASSERT (addr);

    snp->tx_rx_buffer = addr;
  }

  cpb->MemoryAddr   = (UINT64)(UINTN) snp->tx_rx_buffer;

  cpb->MemoryLength = snp->tx_rx_bufsize;

  //
  // let UNDI decide/detect these values
  //
  cpb->LinkSpeed      = 0;
  cpb->TxBufCnt       = 0;
  cpb->TxBufSize      = 0;
  cpb->RxBufCnt       = 0;
  cpb->RxBufSize      = 0;

  cpb->Duplex         = PXE_DUPLEX_DEFAULT;

  cpb->LoopBack       = LOOPBACK_NORMAL;

  snp->cdb.OpCode     = PXE_OPCODE_INITIALIZE;
  snp->cdb.OpFlags    = CableDetectFlag;

  snp->cdb.CPBsize    = sizeof (PXE_CPB_INITIALIZE);
  snp->cdb.DBsize     = sizeof (PXE_DB_INITIALIZE);

  snp->cdb.CPBaddr    = (UINT64)(UINTN) snp->cpb;
  snp->cdb.DBaddr     = (UINT64)(UINTN) snp->db;

  snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;
  snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
  snp->cdb.IFnum      = snp->if_num;
  snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;

  DEBUG ((EFI_D_NET, "\nsnp->undi.initialize()  "));

  (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);

  if (snp->cdb.StatCode == PXE_STATCODE_SUCCESS) {
    snp->mode.State = EfiSimpleNetworkInitialized;

    Status          = EFI_SUCCESS;
  } else {
    DEBUG (
      (EFI_D_WARN,
      "\nsnp->undi.initialize()  %xh:%xh\n",
      snp->cdb.StatFlags,
      snp->cdb.StatCode)
      );

    if (snp->tx_rx_buffer != NULL) {
      snp->IoFncs->FreeBuffer (
                    snp->IoFncs,
                    SNP_MEM_PAGES (snp->tx_rx_bufsize),
                    (VOID *) snp->tx_rx_buffer
                    );
    }

    snp->tx_rx_buffer = NULL;

    Status            = EFI_DEVICE_ERROR;
  }

  return Status;
}