On Thu, May 16, 2013 at 6:01 AM, Laszlo Ersek <ler...@redhat.com> wrote:
> Contributed-under: TianoCore Contribution Agreement 1.0
>
> Signed-off-by: Laszlo Ersek <ler...@redhat.com>
> ---
>  OvmfPkg/VirtioNetDxe/DriverBinding.c |  676 
> ++++++++++++++++++++++++++++++++++
>  1 files changed, 676 insertions(+), 0 deletions(-)
>  create mode 100644 OvmfPkg/VirtioNetDxe/DriverBinding.c
>
> diff --git a/OvmfPkg/VirtioNetDxe/DriverBinding.c 
> b/OvmfPkg/VirtioNetDxe/DriverBinding.c
> new file mode 100644
> index 0000000..d9cbe73
> --- /dev/null
> +++ b/OvmfPkg/VirtioNetDxe/DriverBinding.c
> @@ -0,0 +1,676 @@
> +/** @file
> +
> +  Driver Binding code and its private helpers for the virtio-net driver.
> +
> +  Copyright (C) 2013, Red Hat, Inc.
> +
> +  UEFI API documentation:
> +  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
> +
> +  This program and the accompanying materials are licensed and made available
> +  under the terms and conditions of the BSD License which accompanies this
> +  distribution. The full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 
> WITHOUT
> +  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include <IndustryStandard/Pci.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +
> +#include "VirtioNet.h"
> +
> +#define RECEIVE_FILTERS_NO_MCAST ((UINT32) (       \
> +          EFI_SIMPLE_NETWORK_RECEIVE_UNICAST     | \
> +          EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST   | \
> +          EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS   \
> +          ))
> +
> +/*
> +  Temporarily enable then reset the virtio-net device in order to retrieve
> +  configuration values needed by Simple Network Protocol and Simple Network
> +  Mode fields.
> +
> +  Only VirtioNetSnpPopulate() may call this function.
> +
> +  If the function fails for any reason, the virtio-net device is moved to
> +  VSTAT_FAILED instead of being reset. This serves only informative purposes
> +  for the host side.
> +
> +  param[in out] Dev                 The VNET_DEV structure being created for
> +                                    the virtio-net device.
> +  param[out] MacAddress             MAC address configured by the host.
> +  param[out] MediaPresentSupported  Link status is made available by the 
> host.
> +  param[out] MediaPresent           If link status is made available by the
> +                                    host, the current link status is stored 
> in
> +                                    *MediaPresent. Otherwise MediaPresent is
> +                                    unused.
> +
> +  @retval EFI_UNSUPPORTED           The host doesn't supply a MAC address.
> +  @return                           Status codes from Dev->PciIo->Io.Read(),
> +                                    VIRTIO_CFG_READ() and VIRTIO_CFG_WRITE().
> +  @retval EFI_SUCCESS               Configuration values retrieved.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +VirtioNetGetFeatures (
> +  IN OUT  VNET_DEV        *Dev,
> +  OUT     EFI_MAC_ADDRESS *MacAddress,
> +  OUT     BOOLEAN         *MediaPresentSupported,
> +  OUT     BOOLEAN         *MediaPresent
> +  )
> +{
> +  EFI_STATUS Status;
> +  UINT8      NextDevStat;
> +  UINT32     Features;
> +  UINT16     LinkStatus;
> +
> +  //
> +  // Interrogate the device for features (virtio-0.9.5, 2.2.1 Device
> +  // Initialization Sequence), but don't complete setting it up.
> +  //
> +  NextDevStat = 0;             // step 1 -- reset device
> +  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  NextDevStat |= VSTAT_ACK;    // step 2 -- acknowledge device presence
> +  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
> +  if (EFI_ERROR (Status)) {
> +    goto YieldDevice;
> +  }
> +
> +  NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
> +  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
> +  if (EFI_ERROR (Status)) {
> +    goto YieldDevice;
> +  }
> +
> +  //
> +  // step 4a -- retrieve and validate features
> +  //
> +  Status = VIRTIO_CFG_READ (Dev, Generic.VhdrDeviceFeatureBits, &Features);
> +  if (EFI_ERROR (Status)) {
> +    goto YieldDevice;
> +  }
> +
> +  //
> +  // get MAC address byte-wise
> +  //
> +  if ((Features & VIRTIO_NET_F_MAC) == 0) {
> +    Status = EFI_UNSUPPORTED;
> +    goto YieldDevice;
> +  }
> +  Status = Dev->PciIo->Io.Read (Dev->PciIo,           // PciIo
> +                            EfiPciIoWidthUint8,       // Width
> +                            PCI_BAR_IDX0,             // BarIndex
> +                            OFFSET_OF_VNET (VhdrMac), // Offset
> +                            SIZE_OF_VNET (VhdrMac),   // Count
> +                            MacAddress                // Buffer
> +                            );
> +
> +  if (EFI_ERROR (Status)) {
> +    goto YieldDevice;
> +  }
> +
> +  //
> +  // check if link status is reported, and if so, what the link status is
> +  //
> +  if ((Features & VIRTIO_NET_F_STATUS) == 0) {
> +    *MediaPresentSupported = FALSE;
> +  }
> +  else {

Nit-pick: we generally use "} else {"

I don't think your version violates the coding style.

-Jordan

> +    *MediaPresentSupported = TRUE;
> +    Status = VIRTIO_CFG_READ (Dev, VhdrLinkStatus, &LinkStatus);
> +    if (EFI_ERROR (Status)) {
> +      goto YieldDevice;
> +    }
> +    *MediaPresent = !!(LinkStatus & VIRTIO_NET_S_LINK_UP);
> +  }
> +
> +YieldDevice:
> +  VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus,
> +    EFI_ERROR (Status) ? VSTAT_FAILED : 0);
> +
> +  return Status;
> +}
> +
> +
> +/**
> +  Set up the Simple Network Protocol fields, the Simple Network Mode fields,
> +  and the Exit Boot Services Event of the virtio-net driver instance.
> +
> +  This function may only be called by VirtioNetDriverBindingStart().
> +
> +  @param[in out] Dev  The VNET_DEV driver instance being created for the
> +                      virtio-net device.
> +
> +  @return              Status codes from the CreateEvent() boot service or 
> the
> +                       VirtioNetGetFeatures() function.
> +  @retval EFI_SUCCESS  Configuration successful.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +VirtioNetSnpPopulate (
> +  IN OUT VNET_DEV *Dev
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  //
> +  // We set up a function here that is asynchronously callable by an
> +  // external application to check if there are any packets available for
> +  // reception. The least urgent task priority level we can specify for such 
> a
> +  // "software interrupt" is TPL_CALLBACK.
> +  //
> +  // TPL_CALLBACK is also the maximum TPL an SNP implementation is allowed to
> +  // run at (see 6.1 Event, Timer, and Task Priority Services in the UEFI
> +  // Specification 2.3.1+errC).
> +  //
> +  // Since we raise our TPL to TPL_CALLBACK in every single function that
> +  // accesses the device, and the external application also queues its 
> interest
> +  // for received packets at the same TPL_CALLBACK, in effect the
> +  // VirtioNetIsPacketAvailable() function will never interrupt any
> +  // device-accessing driver function, it will be scheduled in isolation.
> +  //
> +  // TPL_CALLBACK (which basically this entire driver runs at) is allowed
> +  // for "[l]ong term operations (such as file system operations and disk
> +  // I/O)". Because none of our functions block, we'd satisfy an even 
> stronger
> +  // requirement.
> +  //
> +  Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_CALLBACK,
> +                  &VirtioNetIsPacketAvailable, Dev, &Dev->Snp.WaitForPacket);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Dev->Snp.Revision       = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
> +  Dev->Snp.Start          = &VirtioNetStart;
> +  Dev->Snp.Stop           = &VirtioNetStop;
> +  Dev->Snp.Initialize     = &VirtioNetInitialize;
> +  Dev->Snp.Reset          = &VirtioNetReset;
> +  Dev->Snp.Shutdown       = &VirtioNetShutdown;
> +  Dev->Snp.ReceiveFilters = &VirtioNetReceiveFilters;
> +  Dev->Snp.StationAddress = &VirtioNetStationAddress;
> +  Dev->Snp.Statistics     = &VirtioNetStatistics;
> +  Dev->Snp.MCastIpToMac   = &VirtioNetMcastIpToMac;
> +  Dev->Snp.NvData         = &VirtioNetNvData;
> +  Dev->Snp.GetStatus      = &VirtioNetGetStatus;
> +  Dev->Snp.Transmit       = &VirtioNetTransmit;
> +  Dev->Snp.Receive        = &VirtioNetReceive;
> +  Dev->Snp.Mode           = &Dev->Snm;
> +
> +  Dev->Snm.State                 = EfiSimpleNetworkStopped;
> +  Dev->Snm.HwAddressSize         = SIZE_OF_VNET (VhdrMac);
> +  Dev->Snm.MediaHeaderSize       = SIZE_OF_VNET (VhdrMac) + // dst MAC
> +                                   SIZE_OF_VNET (VhdrMac) + // src MAC
> +                                   2;                       // Ethertype
> +  Dev->Snm.MaxPacketSize         = 1500;
> +  Dev->Snm.NvRamSize             = 0;
> +  Dev->Snm.NvRamAccessSize       = 0;
> +  Dev->Snm.ReceiveFilterMask     = RECEIVE_FILTERS_NO_MCAST;
> +  Dev->Snm.ReceiveFilterSetting  = RECEIVE_FILTERS_NO_MCAST;
> +  Dev->Snm.MaxMCastFilterCount   = 0;
> +  Dev->Snm.MCastFilterCount      = 0;
> +  Dev->Snm.IfType                = 1; // ethernet
> +  Dev->Snm.MacAddressChangeable  = FALSE;
> +  Dev->Snm.MultipleTxSupported   = TRUE;
> +
> +  ASSERT (SIZE_OF_VNET (VhdrMac) <= sizeof (EFI_MAC_ADDRESS));
> +
> +  Status = VirtioNetGetFeatures (Dev, &Dev->Snm.CurrentAddress,
> +             &Dev->Snm.MediaPresentSupported, &Dev->Snm.MediaPresent);
> +  if (EFI_ERROR (Status)) {
> +    goto CloseWaitForPacket;
> +  }
> +  CopyMem (&Dev->Snm.PermanentAddress, &Dev->Snm.CurrentAddress,
> +    SIZE_OF_VNET (VhdrMac));
> +  SetMem (&Dev->Snm.BroadcastAddress, SIZE_OF_VNET (VhdrMac), 0xFF);
> +
> +  //
> +  // VirtioNetExitBoot() is queued by ExitBootServices(); its purpose is to
> +  // cancel any pending virtio requests. The TPL_CALLBACK reasoning is
> +  // identical to the one above. There's one difference: this kind of
> +  // event is "globally visible", which means it can be signalled as soon as
> +  // we create it. We haven't raised our TPL here, hence VirtioNetExitBoot()
> +  // could be entered immediately. VirtioNetExitBoot() checks Dev->Snm.State,
> +  // so we're safe.
> +  //
> +  Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
> +                  &VirtioNetExitBoot, Dev, &Dev->ExitBoot);
> +  if (EFI_ERROR (Status)) {
> +    goto CloseWaitForPacket;
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +CloseWaitForPacket:
> +  gBS->CloseEvent (Dev->Snp.WaitForPacket);
> +  return Status;
> +}
> +
> +
> +/**
> +  Release any resources allocated by VirtioNetSnpPopulate().
> +
> +  This function may only be called by VirtioNetDriverBindingStart(), when
> +  rolling back a partial, failed driver instance creation, and by
> +  VirtioNetDriverBindingStop(), when disconnecting a virtio-net device from 
> the
> +  driver.
> +
> +  @param[in out] Dev  The VNET_DEV driver instance being destroyed.
> +*/
> +STATIC
> +VOID
> +EFIAPI
> +VirtioNetSnpEvacuate (
> +  IN OUT VNET_DEV *Dev
> +  )
> +{
> +  //
> +  // This function runs either at TPL_CALLBACK already (from
> +  // VirtioNetDriverBindingStop()), or it is part of a teardown following
> +  // a partial, failed construction in VirtioNetDriverBindingStart(), when
> +  // WaitForPacket was never accessible to the world.
> +  //
> +  gBS->CloseEvent (Dev->ExitBoot);
> +  gBS->CloseEvent (Dev->Snp.WaitForPacket);
> +}
> +
> +
> +/**
> +  Tests to see if this driver supports a given controller. If a child device 
> is
> +  provided, it further tests to see if this driver supports creating a handle
> +  for the specified child device.
> +
> +  This function checks to see if the driver specified by This supports the
> +  device specified by ControllerHandle. Drivers will typically use the device
> +  path attached to ControllerHandle and/or the services from the bus I/O
> +  abstraction attached to ControllerHandle to determine if the driver 
> supports
> +  ControllerHandle. This function may be called many times during platform
> +  initialization. In order to reduce boot times, the tests performed by this
> +  function must be very small, and take as little time as possible to 
> execute.
> +  This function must not change the state of any hardware devices, and this
> +  function must be aware that the device specified by ControllerHandle may
> +  already be managed by the same driver or a different driver. This function
> +  must match its calls to AllocatePages() with FreePages(), AllocatePool() 
> with
> +  FreePool(), and OpenProtocol() with CloseProtocol(). Because 
> ControllerHandle
> +  may have been previously started by the same driver, if a protocol is 
> already
> +  in the opened state, then it must not be closed with CloseProtocol(). This 
> is
> +  required to guarantee the state of ControllerHandle is not modified by this
> +  function.
> +
> +  @param[in]  This                 A pointer to the 
> EFI_DRIVER_BINDING_PROTOCOL
> +                                   instance.
> +  @param[in]  ControllerHandle     The handle of the controller to test. This
> +                                   handle must support a protocol interface
> +                                   that supplies an I/O abstraction to the
> +                                   driver.
> +  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a
> +                                   device path.  This parameter is ignored by
> +                                   device drivers, and is optional for bus
> +                                   drivers. For bus drivers, if this 
> parameter
> +                                   is not NULL, then the bus driver must
> +                                   determine if the bus controller specified 
> by
> +                                   ControllerHandle and the child controller
> +                                   specified by RemainingDevicePath are both
> +                                   supported by this bus driver.
> +
> +  @retval EFI_SUCCESS              The device specified by ControllerHandle 
> and
> +                                   RemainingDevicePath is supported by the
> +                                   driver specified by This.
> +  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle 
> and
> +                                   RemainingDevicePath is already being 
> managed
> +                                   by the driver specified by This.
> +  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle 
> and
> +                                   RemainingDevicePath is already being 
> managed
> +                                   by a different driver or an application 
> that
> +                                   requires exclusive access. Currently not
> +                                   implemented.
> +  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle 
> and
> +                                   RemainingDevicePath is not supported by 
> the
> +                                   driver specified by This.
> +**/
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +VirtioNetDriverBindingSupported (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  DeviceHandle,
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> +  )
> +{
> +  EFI_STATUS          Status;
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  PCI_TYPE00          Pci;
> +
> +  Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
> +                  (VOID **)&PciIo, This->DriverBindingHandle, DeviceHandle,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0,
> +                        sizeof Pci / sizeof (UINT32), &Pci);
> +
> +  //
> +  // virtio-0.9.5, 2.1 PCI Discovery:
> +  // the network device has Subsystem Device ID 1
> +  //
> +  if (Status == EFI_SUCCESS) {
> +    Status = (Pci.Hdr.VendorId == 0x1AF4 &&
> +              Pci.Hdr.DeviceId >= 0x1000 && Pci.Hdr.DeviceId <= 0x103F &&
> +              Pci.Hdr.RevisionID == 0x00 &&
> +              Pci.Device.SubsystemID == 0x01) ? EFI_SUCCESS : 
> EFI_UNSUPPORTED;
> +  }
> +
> +  gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
> +         This->DriverBindingHandle, DeviceHandle);
> +  return Status;
> +}
> +
> +
> +/**
> +  Starts a device controller or a bus controller.
> +
> +  The Start() function is designed to be invoked from the EFI boot service
> +  ConnectController(). As a result, much of the error checking on the
> +  parameters to Start() has been moved into this  common boot service. It is
> +  legal to call Start() from other locations,  but the following calling
> +  restrictions must be followed, or the system behavior will not be
> +  deterministic.
> +  1. ControllerHandle must be a valid EFI_HANDLE.
> +  2. If RemainingDevicePath is not NULL, then it must be a pointer to a
> +     naturally aligned EFI_DEVICE_PATH_PROTOCOL.
> +  3. Prior to calling Start(), the Supported() function for the driver
> +     specified by This must have been called with the same calling 
> parameters,
> +     and Supported() must have returned EFI_SUCCESS.
> +
> +  @param[in]  This                 A pointer to the 
> EFI_DRIVER_BINDING_PROTOCOL
> +                                   instance.
> +  @param[in]  ControllerHandle     The handle of the controller to start. 
> This
> +                                   handle  must support a protocol interface
> +                                   that supplies  an I/O abstraction to the
> +                                   driver.
> +  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a
> +                                   device path.  This  parameter is ignored 
> by
> +                                   device drivers, and is optional for bus
> +                                   drivers. For a bus driver, if this 
> parameter
> +                                   is NULL, then handles  for all the 
> children
> +                                   of Controller are created by this driver.
> +                                   If this parameter is not NULL and the 
> first
> +                                   Device Path Node is  not the End of Device
> +                                   Path Node, then only the handle for the
> +                                   child device specified by the first Device
> +                                   Path Node of  RemainingDevicePath is 
> created
> +                                   by this driver. If the first Device Path
> +                                   Node of RemainingDevicePath is  the End of
> +                                   Device Path Node, no child handle is 
> created
> +                                   by this driver.
> +
> +  @retval EFI_SUCCESS              The device was started.
> +  @retval EFI_DEVICE_ERROR         The device could not be started due to a
> +                                   device error.Currently not implemented.
> +  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to 
> a
> +                                   lack of resources.
> +  @retval Others                   The driver failded to start the device.
> +
> +**/
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +VirtioNetDriverBindingStart (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  DeviceHandle,
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> +  )
> +{
> +  EFI_STATUS               Status;
> +  VNET_DEV                 *Dev;
> +  EFI_DEVICE_PATH_PROTOCOL *DevicePath;
> +  MAC_ADDR_DEVICE_PATH     MacNode;
> +  VOID                     *ChildPciIo;
> +
> +  //
> +  // allocate space for the driver instance
> +  //
> +  Dev = (VNET_DEV *) AllocateZeroPool (sizeof *Dev);
> +  if (Dev == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +  Dev->Signature = VNET_SIG;
> +
> +  //
> +  // get PCI access to the device and keep it open
> +  //
> +  Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
> +                  (VOID **)&Dev->PciIo, This->DriverBindingHandle,
> +                  DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
> +  if (EFI_ERROR (Status)) {
> +    goto FreeVirtioNet;
> +  }
> +
> +  //
> +  // save original PCI attributes and enable IO space access
> +  //
> +  Status = Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationGet,
> +                         0, &Dev->OrigPciAttributes);
> +  if (EFI_ERROR (Status)) {
> +    goto ClosePciIo;
> +  }
> +
> +  Status = Dev->PciIo->Attributes (Dev->PciIo,
> +                         EfiPciIoAttributeOperationEnable,
> +                         EFI_PCI_IO_ATTRIBUTE_IO, NULL);
> +  if (EFI_ERROR (Status)) {
> +    goto ClosePciIo;
> +  }
> +
> +  //
> +  // now we can run a basic one-shot virtio-net initialization required to
> +  // retrieve the MAC address
> +  //
> +  Status = VirtioNetSnpPopulate (Dev);
> +  if (EFI_ERROR (Status)) {
> +    goto RestorePciAttributes;
> +  }
> +
> +  //
> +  // get the device path of the virtio-net PCI device -- one-shot open
> +  //
> +  Status = gBS->OpenProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid,
> +                  (VOID **)&DevicePath, This->DriverBindingHandle,
> +                  DeviceHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> +  if (EFI_ERROR (Status)) {
> +    goto Evacuate;
> +  }
> +
> +  //
> +  // create another device path that has the MAC address appended
> +  //
> +  MacNode.Header.Type    = MESSAGING_DEVICE_PATH;
> +  MacNode.Header.SubType = MSG_MAC_ADDR_DP;
> +  SetDevicePathNodeLength (&MacNode, sizeof MacNode);
> +  CopyMem (&MacNode.MacAddress, &Dev->Snm.CurrentAddress,
> +    sizeof (EFI_MAC_ADDRESS));
> +  MacNode.IfType         = Dev->Snm.IfType;
> +
> +  Dev->MacDevicePath = AppendDevicePathNode (DevicePath, &MacNode.Header);
> +  if (Dev->MacDevicePath == NULL) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto Evacuate;
> +  }
> +
> +  //
> +  // create a child handle with the Simple Network Protocol and the new
> +  // device path installed on it
> +  //
> +  Status = gBS->InstallMultipleProtocolInterfaces (&Dev->MacHandle,
> +                  &gEfiSimpleNetworkProtocolGuid, &Dev->Snp,
> +                  &gEfiDevicePathProtocolGuid,    Dev->MacDevicePath,
> +                  NULL);
> +  if (EFI_ERROR (Status)) {
> +    goto FreeMacDevicePath;
> +  }
> +
> +  //
> +  // make a note that we keep this device open with PciIo for the sake of 
> this
> +  // child
> +  //
> +  Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
> +                  &ChildPciIo, This->DriverBindingHandle,
> +                  Dev->MacHandle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
> +  if (EFI_ERROR (Status)) {
> +    goto UninstallMultiple;
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +UninstallMultiple:
> +  gBS->UninstallMultipleProtocolInterfaces (Dev->MacHandle,
> +         &gEfiDevicePathProtocolGuid,    Dev->MacDevicePath,
> +         &gEfiSimpleNetworkProtocolGuid, &Dev->Snp,
> +         NULL);
> +
> +FreeMacDevicePath:
> +  FreePool (Dev->MacDevicePath);
> +
> +Evacuate:
> +  VirtioNetSnpEvacuate (Dev);
> +
> +RestorePciAttributes:
> +  Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
> +                Dev->OrigPciAttributes, NULL);
> +
> +ClosePciIo:
> +  gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
> +         This->DriverBindingHandle, DeviceHandle);
> +
> +FreeVirtioNet:
> +  FreePool (Dev);
> +
> +  return Status;
> +}
> +
> +
> +/**
> +  Stops a device controller or a bus controller.
> +
> +  The Stop() function is designed to be invoked from the EFI boot service
> +  DisconnectController().  As a result, much of the error checking on the
> +  parameters to Stop() has been moved  into this common boot service. It is
> +  legal to call Stop() from other locations,  but the following calling
> +  restrictions must be followed, or the system behavior will not be
> +  deterministic.
> +  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous
> +     call to this same driver's Start() function.
> +  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a
> +     valid EFI_HANDLE. In addition, all of these handles must have been 
> created
> +     in this driver's Start() function, and the Start() function must have
> +     called OpenProtocol() on ControllerHandle with an Attribute of
> +     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
> +
> +  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL
> +                                instance.
> +  @param[in]  ControllerHandle  A handle to the device being stopped. The
> +                                handle must  support a bus specific I/O
> +                                protocol for the driver  to use to stop the
> +                                device.
> +  @param[in]  NumberOfChildren  The number of child device handles in
> +                                ChildHandleBuffer.
> +  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be
> +                                NULL  if NumberOfChildren is 0.
> +
> +  @retval EFI_SUCCESS           The device was stopped.
> +  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a 
> device
> +                                error.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +VirtioNetDriverBindingStop (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  DeviceHandle,
> +  IN UINTN                       NumberOfChildren,
> +  IN EFI_HANDLE                  *ChildHandleBuffer
> +  )
> +{
> +  if (NumberOfChildren > 0) {
> +    //
> +    // free all resources for whose access we need the child handle, because
> +    // the child handle is going away
> +    //
> +    EFI_STATUS                  Status;
> +    EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
> +    VNET_DEV                    *Dev;
> +    EFI_TPL                     OldTpl;
> +
> +    ASSERT (NumberOfChildren == 1);
> +
> +    Status = gBS->OpenProtocol (ChildHandleBuffer[0],
> +                    &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp,
> +                    This->DriverBindingHandle, DeviceHandle,
> +                    EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> +    ASSERT_EFI_ERROR (Status);
> +    Dev = VIRTIO_NET_FROM_SNP (Snp);
> +
> +    //
> +    // prevent any interference with WaitForPacket
> +    //
> +    OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
> +
> +    ASSERT (Dev->MacHandle == ChildHandleBuffer[0]);
> +    if (Dev->Snm.State != EfiSimpleNetworkStopped) {
> +      //
> +      // device in use, cannot stop driver instance
> +      //
> +      Status = EFI_DEVICE_ERROR;
> +    }
> +    else {
> +      gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
> +             This->DriverBindingHandle, Dev->MacHandle);
> +      gBS->UninstallMultipleProtocolInterfaces (Dev->MacHandle,
> +             &gEfiDevicePathProtocolGuid,    Dev->MacDevicePath,
> +             &gEfiSimpleNetworkProtocolGuid, &Dev->Snp,
> +             NULL);
> +      FreePool (Dev->MacDevicePath);
> +      VirtioNetSnpEvacuate (Dev);
> +      Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
> +                    Dev->OrigPciAttributes, NULL);
> +      FreePool (Dev);
> +    }
> +
> +    gBS->RestoreTPL (OldTpl);
> +    return Status;
> +  }
> +
> +  //
> +  // release remaining resources, tied directly to the parent handle
> +  //
> +  gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
> +         This->DriverBindingHandle, DeviceHandle);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +
> +EFI_DRIVER_BINDING_PROTOCOL gVirtioNetDriverBinding = {
> +  &VirtioNetDriverBindingSupported,
> +  &VirtioNetDriverBindingStart,
> +  &VirtioNetDriverBindingStop,
> +  0x10,
> +  NULL,
> +  NULL
> +};
> --
> 1.7.1
>
>
>
> ------------------------------------------------------------------------------
> AlienVault Unified Security Management (USM) platform delivers complete
> security visibility with the essential security capabilities. Easily and
> efficiently configure, manage, and operate all of your security controls
> from a single console and one unified framework. Download a free trial.
> http://p.sf.net/sfu/alienvault_d2d
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/edk2-devel

------------------------------------------------------------------------------
Introducing AppDynamics Lite, a free troubleshooting tool for Java/.NET
Get 100% visibility into your production application - at no cost.
Code-level diagnostics for performance bottlenecks with <2% overhead
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap1
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to