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