123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711 |
- /** @file
- Driver Binding code and its private helpers for the virtio-net driver.
- Copyright (C) 2013, Red Hat, Inc.
- Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #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 VirtIo protocol members.
- @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;
- UINT64 Features;
- UINTN MacIdx;
- 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 = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence
- Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
- if (EFI_ERROR (Status)) {
- goto YieldDevice;
- }
- NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
- Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
- if (EFI_ERROR (Status)) {
- goto YieldDevice;
- }
- //
- // step 4a -- retrieve and validate features
- //
- Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
- if (EFI_ERROR (Status)) {
- goto YieldDevice;
- }
- //
- // get MAC address byte-wise
- //
- if ((Features & VIRTIO_NET_F_MAC) == 0) {
- Status = EFI_UNSUPPORTED;
- goto YieldDevice;
- }
- for (MacIdx = 0; MacIdx < SIZE_OF_VNET (Mac); ++MacIdx) {
- Status = Dev->VirtIo->ReadDevice (
- Dev->VirtIo,
- OFFSET_OF_VNET (Mac) + MacIdx, // Offset
- 1, // FieldSize
- 1, // BufferSize
- &MacAddress->Addr[MacIdx] // 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 {
- *MediaPresentSupported = TRUE;
- Status = VIRTIO_CFG_READ (Dev, LinkStatus, &LinkStatus);
- if (EFI_ERROR (Status)) {
- goto YieldDevice;
- }
- *MediaPresent = (BOOLEAN)((LinkStatus & VIRTIO_NET_S_LINK_UP) != 0);
- }
- YieldDevice:
- Dev->VirtIo->SetDeviceStatus (
- Dev->VirtIo,
- 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 (Mac);
- Dev->Snm.MediaHeaderSize = SIZE_OF_VNET (Mac) + // dst MAC
- SIZE_OF_VNET (Mac) + // 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 (Mac) <= 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 (Mac)
- );
- SetMem (&Dev->Snm.BroadcastAddress, SIZE_OF_VNET (Mac), 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;
- VIRTIO_DEVICE_PROTOCOL *VirtIo;
- //
- // Attempt to open the device with the VirtIo set of interfaces. On success,
- // the protocol is "instantiated" for the VirtIo device. Covers duplicate open
- // attempts (EFI_ALREADY_STARTED).
- //
- Status = gBS->OpenProtocol (
- DeviceHandle, // candidate device
- &gVirtioDeviceProtocolGuid, // for generic VirtIo access
- (VOID **)&VirtIo, // handle to instantiate
- This->DriverBindingHandle, // requestor driver identity
- DeviceHandle, // ControllerHandle, according to
- // the UEFI Driver Model
- EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
- // the device; to be released
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_NETWORK_CARD) {
- Status = EFI_UNSUPPORTED;
- }
- //
- // We needed VirtIo access only transitorily, to see whether we support the
- // device or not.
- //
- gBS->CloseProtocol (
- DeviceHandle,
- &gVirtioDeviceProtocolGuid,
- 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 failed 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 *ChildVirtIo;
- //
- // allocate space for the driver instance
- //
- Dev = (VNET_DEV *)AllocateZeroPool (sizeof *Dev);
- if (Dev == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- Dev->Signature = VNET_SIG;
- Status = gBS->OpenProtocol (
- DeviceHandle,
- &gVirtioDeviceProtocolGuid,
- (VOID **)&Dev->VirtIo,
- This->DriverBindingHandle,
- DeviceHandle,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- goto FreeVirtioNet;
- }
- //
- // 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 CloseVirtIo;
- }
- //
- // get the device path of the virtio-net 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 VirtIo for the sake of this
- // child
- //
- Status = gBS->OpenProtocol (
- DeviceHandle,
- &gVirtioDeviceProtocolGuid,
- &ChildVirtIo,
- 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);
- CloseVirtIo:
- gBS->CloseProtocol (
- DeviceHandle,
- &gVirtioDeviceProtocolGuid,
- 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,
- &gVirtioDeviceProtocolGuid,
- This->DriverBindingHandle,
- Dev->MacHandle
- );
- gBS->UninstallMultipleProtocolInterfaces (
- Dev->MacHandle,
- &gEfiDevicePathProtocolGuid,
- Dev->MacDevicePath,
- &gEfiSimpleNetworkProtocolGuid,
- &Dev->Snp,
- NULL
- );
- FreePool (Dev->MacDevicePath);
- VirtioNetSnpEvacuate (Dev);
- FreePool (Dev);
- }
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
- //
- // release remaining resources, tied directly to the parent handle
- //
- gBS->CloseProtocol (
- DeviceHandle,
- &gVirtioDeviceProtocolGuid,
- This->DriverBindingHandle,
- DeviceHandle
- );
- return EFI_SUCCESS;
- }
- EFI_DRIVER_BINDING_PROTOCOL gVirtioNetDriverBinding = {
- &VirtioNetDriverBindingSupported,
- &VirtioNetDriverBindingStart,
- &VirtioNetDriverBindingStop,
- 0x10,
- NULL,
- NULL
- };
|