On Thu, May 16, 2013 at 6:01 AM, Laszlo Ersek <[email protected]> wrote:
> Contributed-under: TianoCore Contribution Agreement 1.0
>
> Signed-off-by: Laszlo Ersek <[email protected]>
> ---
> 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
> [email protected]
> 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
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-devel