]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/VirtioNetDxe/DriverBinding.c
OvmfPkg/EnrollDefaultKeys: enroll PK/KEK1 from the Type 11 SMBIOS table
[mirror_edk2.git] / OvmfPkg / VirtioNetDxe / DriverBinding.c
1 /** @file
2
3 Driver Binding code and its private helpers for the virtio-net driver.
4
5 Copyright (C) 2013, Red Hat, Inc.
6 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
12 #include <Library/BaseMemoryLib.h>
13 #include <Library/DevicePathLib.h>
14 #include <Library/MemoryAllocationLib.h>
15 #include <Library/UefiBootServicesTableLib.h>
16
17 #include "VirtioNet.h"
18
19 #define RECEIVE_FILTERS_NO_MCAST ((UINT32) ( \
20 EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | \
21 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST | \
22 EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS \
23 ))
24
25 /*
26 Temporarily enable then reset the virtio-net device in order to retrieve
27 configuration values needed by Simple Network Protocol and Simple Network
28 Mode fields.
29
30 Only VirtioNetSnpPopulate() may call this function.
31
32 If the function fails for any reason, the virtio-net device is moved to
33 VSTAT_FAILED instead of being reset. This serves only informative purposes
34 for the host side.
35
36 param[in,out] Dev The VNET_DEV structure being created for
37 the virtio-net device.
38 param[out] MacAddress MAC address configured by the host.
39 param[out] MediaPresentSupported Link status is made available by the host.
40 param[out] MediaPresent If link status is made available by the
41 host, the current link status is stored in
42 *MediaPresent. Otherwise MediaPresent is
43 unused.
44
45 @retval EFI_UNSUPPORTED The host doesn't supply a MAC address.
46 @return Status codes from VirtIo protocol members.
47 @retval EFI_SUCCESS Configuration values retrieved.
48 */
49 STATIC
50 EFI_STATUS
51 EFIAPI
52 VirtioNetGetFeatures (
53 IN OUT VNET_DEV *Dev,
54 OUT EFI_MAC_ADDRESS *MacAddress,
55 OUT BOOLEAN *MediaPresentSupported,
56 OUT BOOLEAN *MediaPresent
57 )
58 {
59 EFI_STATUS Status;
60 UINT8 NextDevStat;
61 UINT64 Features;
62 UINTN MacIdx;
63 UINT16 LinkStatus;
64
65 //
66 // Interrogate the device for features (virtio-0.9.5, 2.2.1 Device
67 // Initialization Sequence), but don't complete setting it up.
68 //
69 NextDevStat = 0; // step 1 -- reset device
70 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
71 if (EFI_ERROR (Status)) {
72 return Status;
73 }
74
75 NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence
76 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
77 if (EFI_ERROR (Status)) {
78 goto YieldDevice;
79 }
80
81 NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
82 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
83 if (EFI_ERROR (Status)) {
84 goto YieldDevice;
85 }
86
87 //
88 // step 4a -- retrieve and validate features
89 //
90 Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
91 if (EFI_ERROR (Status)) {
92 goto YieldDevice;
93 }
94
95 //
96 // get MAC address byte-wise
97 //
98 if ((Features & VIRTIO_NET_F_MAC) == 0) {
99 Status = EFI_UNSUPPORTED;
100 goto YieldDevice;
101 }
102 for (MacIdx = 0; MacIdx < SIZE_OF_VNET (Mac); ++MacIdx) {
103 Status = Dev->VirtIo->ReadDevice (Dev->VirtIo,
104 OFFSET_OF_VNET (Mac) + MacIdx, // Offset
105 1, // FieldSize
106 1, // BufferSize
107 &MacAddress->Addr[MacIdx] // Buffer
108 );
109 if (EFI_ERROR (Status)) {
110 goto YieldDevice;
111 }
112 }
113
114 //
115 // check if link status is reported, and if so, what the link status is
116 //
117 if ((Features & VIRTIO_NET_F_STATUS) == 0) {
118 *MediaPresentSupported = FALSE;
119 }
120 else {
121 *MediaPresentSupported = TRUE;
122 Status = VIRTIO_CFG_READ (Dev, LinkStatus, &LinkStatus);
123 if (EFI_ERROR (Status)) {
124 goto YieldDevice;
125 }
126 *MediaPresent = (BOOLEAN) ((LinkStatus & VIRTIO_NET_S_LINK_UP) != 0);
127 }
128
129 YieldDevice:
130 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo,
131 EFI_ERROR (Status) ? VSTAT_FAILED : 0);
132
133 return Status;
134 }
135
136
137 /**
138 Set up the Simple Network Protocol fields, the Simple Network Mode fields,
139 and the Exit Boot Services Event of the virtio-net driver instance.
140
141 This function may only be called by VirtioNetDriverBindingStart().
142
143 @param[in,out] Dev The VNET_DEV driver instance being created for the
144 virtio-net device.
145
146 @return Status codes from the CreateEvent() boot service or the
147 VirtioNetGetFeatures() function.
148 @retval EFI_SUCCESS Configuration successful.
149 */
150 STATIC
151 EFI_STATUS
152 EFIAPI
153 VirtioNetSnpPopulate (
154 IN OUT VNET_DEV *Dev
155 )
156 {
157 EFI_STATUS Status;
158
159 //
160 // We set up a function here that is asynchronously callable by an
161 // external application to check if there are any packets available for
162 // reception. The least urgent task priority level we can specify for such a
163 // "software interrupt" is TPL_CALLBACK.
164 //
165 // TPL_CALLBACK is also the maximum TPL an SNP implementation is allowed to
166 // run at (see 6.1 Event, Timer, and Task Priority Services in the UEFI
167 // Specification 2.3.1+errC).
168 //
169 // Since we raise our TPL to TPL_CALLBACK in every single function that
170 // accesses the device, and the external application also queues its interest
171 // for received packets at the same TPL_CALLBACK, in effect the
172 // VirtioNetIsPacketAvailable() function will never interrupt any
173 // device-accessing driver function, it will be scheduled in isolation.
174 //
175 // TPL_CALLBACK (which basically this entire driver runs at) is allowed
176 // for "[l]ong term operations (such as file system operations and disk
177 // I/O)". Because none of our functions block, we'd satisfy an even stronger
178 // requirement.
179 //
180 Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_CALLBACK,
181 &VirtioNetIsPacketAvailable, Dev, &Dev->Snp.WaitForPacket);
182 if (EFI_ERROR (Status)) {
183 return Status;
184 }
185
186 Dev->Snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
187 Dev->Snp.Start = &VirtioNetStart;
188 Dev->Snp.Stop = &VirtioNetStop;
189 Dev->Snp.Initialize = &VirtioNetInitialize;
190 Dev->Snp.Reset = &VirtioNetReset;
191 Dev->Snp.Shutdown = &VirtioNetShutdown;
192 Dev->Snp.ReceiveFilters = &VirtioNetReceiveFilters;
193 Dev->Snp.StationAddress = &VirtioNetStationAddress;
194 Dev->Snp.Statistics = &VirtioNetStatistics;
195 Dev->Snp.MCastIpToMac = &VirtioNetMcastIpToMac;
196 Dev->Snp.NvData = &VirtioNetNvData;
197 Dev->Snp.GetStatus = &VirtioNetGetStatus;
198 Dev->Snp.Transmit = &VirtioNetTransmit;
199 Dev->Snp.Receive = &VirtioNetReceive;
200 Dev->Snp.Mode = &Dev->Snm;
201
202 Dev->Snm.State = EfiSimpleNetworkStopped;
203 Dev->Snm.HwAddressSize = SIZE_OF_VNET (Mac);
204 Dev->Snm.MediaHeaderSize = SIZE_OF_VNET (Mac) + // dst MAC
205 SIZE_OF_VNET (Mac) + // src MAC
206 2; // Ethertype
207 Dev->Snm.MaxPacketSize = 1500;
208 Dev->Snm.NvRamSize = 0;
209 Dev->Snm.NvRamAccessSize = 0;
210 Dev->Snm.ReceiveFilterMask = RECEIVE_FILTERS_NO_MCAST;
211 Dev->Snm.ReceiveFilterSetting = RECEIVE_FILTERS_NO_MCAST;
212 Dev->Snm.MaxMCastFilterCount = 0;
213 Dev->Snm.MCastFilterCount = 0;
214 Dev->Snm.IfType = 1; // ethernet
215 Dev->Snm.MacAddressChangeable = FALSE;
216 Dev->Snm.MultipleTxSupported = TRUE;
217
218 ASSERT (SIZE_OF_VNET (Mac) <= sizeof (EFI_MAC_ADDRESS));
219
220 Status = VirtioNetGetFeatures (Dev, &Dev->Snm.CurrentAddress,
221 &Dev->Snm.MediaPresentSupported, &Dev->Snm.MediaPresent);
222 if (EFI_ERROR (Status)) {
223 goto CloseWaitForPacket;
224 }
225 CopyMem (&Dev->Snm.PermanentAddress, &Dev->Snm.CurrentAddress,
226 SIZE_OF_VNET (Mac));
227 SetMem (&Dev->Snm.BroadcastAddress, SIZE_OF_VNET (Mac), 0xFF);
228
229 //
230 // VirtioNetExitBoot() is queued by ExitBootServices(); its purpose is to
231 // cancel any pending virtio requests. The TPL_CALLBACK reasoning is
232 // identical to the one above. There's one difference: this kind of
233 // event is "globally visible", which means it can be signalled as soon as
234 // we create it. We haven't raised our TPL here, hence VirtioNetExitBoot()
235 // could be entered immediately. VirtioNetExitBoot() checks Dev->Snm.State,
236 // so we're safe.
237 //
238 Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
239 &VirtioNetExitBoot, Dev, &Dev->ExitBoot);
240 if (EFI_ERROR (Status)) {
241 goto CloseWaitForPacket;
242 }
243
244 return EFI_SUCCESS;
245
246 CloseWaitForPacket:
247 gBS->CloseEvent (Dev->Snp.WaitForPacket);
248 return Status;
249 }
250
251
252 /**
253 Release any resources allocated by VirtioNetSnpPopulate().
254
255 This function may only be called by VirtioNetDriverBindingStart(), when
256 rolling back a partial, failed driver instance creation, and by
257 VirtioNetDriverBindingStop(), when disconnecting a virtio-net device from the
258 driver.
259
260 @param[in,out] Dev The VNET_DEV driver instance being destroyed.
261 */
262 STATIC
263 VOID
264 EFIAPI
265 VirtioNetSnpEvacuate (
266 IN OUT VNET_DEV *Dev
267 )
268 {
269 //
270 // This function runs either at TPL_CALLBACK already (from
271 // VirtioNetDriverBindingStop()), or it is part of a teardown following
272 // a partial, failed construction in VirtioNetDriverBindingStart(), when
273 // WaitForPacket was never accessible to the world.
274 //
275 gBS->CloseEvent (Dev->ExitBoot);
276 gBS->CloseEvent (Dev->Snp.WaitForPacket);
277 }
278
279
280 /**
281 Tests to see if this driver supports a given controller. If a child device is
282 provided, it further tests to see if this driver supports creating a handle
283 for the specified child device.
284
285 This function checks to see if the driver specified by This supports the
286 device specified by ControllerHandle. Drivers will typically use the device
287 path attached to ControllerHandle and/or the services from the bus I/O
288 abstraction attached to ControllerHandle to determine if the driver supports
289 ControllerHandle. This function may be called many times during platform
290 initialization. In order to reduce boot times, the tests performed by this
291 function must be very small, and take as little time as possible to execute.
292 This function must not change the state of any hardware devices, and this
293 function must be aware that the device specified by ControllerHandle may
294 already be managed by the same driver or a different driver. This function
295 must match its calls to AllocatePages() with FreePages(), AllocatePool() with
296 FreePool(), and OpenProtocol() with CloseProtocol(). Because ControllerHandle
297 may have been previously started by the same driver, if a protocol is already
298 in the opened state, then it must not be closed with CloseProtocol(). This is
299 required to guarantee the state of ControllerHandle is not modified by this
300 function.
301
302 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
303 instance.
304 @param[in] ControllerHandle The handle of the controller to test. This
305 handle must support a protocol interface
306 that supplies an I/O abstraction to the
307 driver.
308 @param[in] RemainingDevicePath A pointer to the remaining portion of a
309 device path. This parameter is ignored by
310 device drivers, and is optional for bus
311 drivers. For bus drivers, if this parameter
312 is not NULL, then the bus driver must
313 determine if the bus controller specified by
314 ControllerHandle and the child controller
315 specified by RemainingDevicePath are both
316 supported by this bus driver.
317
318 @retval EFI_SUCCESS The device specified by ControllerHandle and
319 RemainingDevicePath is supported by the
320 driver specified by This.
321 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
322 RemainingDevicePath is already being managed
323 by the driver specified by This.
324 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
325 RemainingDevicePath is already being managed
326 by a different driver or an application that
327 requires exclusive access. Currently not
328 implemented.
329 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
330 RemainingDevicePath is not supported by the
331 driver specified by This.
332 **/
333
334 STATIC
335 EFI_STATUS
336 EFIAPI
337 VirtioNetDriverBindingSupported (
338 IN EFI_DRIVER_BINDING_PROTOCOL *This,
339 IN EFI_HANDLE DeviceHandle,
340 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
341 )
342 {
343 EFI_STATUS Status;
344 VIRTIO_DEVICE_PROTOCOL *VirtIo;
345
346 //
347 // Attempt to open the device with the VirtIo set of interfaces. On success,
348 // the protocol is "instantiated" for the VirtIo device. Covers duplicate open
349 // attempts (EFI_ALREADY_STARTED).
350 //
351 Status = gBS->OpenProtocol (
352 DeviceHandle, // candidate device
353 &gVirtioDeviceProtocolGuid, // for generic VirtIo access
354 (VOID **)&VirtIo, // handle to instantiate
355 This->DriverBindingHandle, // requestor driver identity
356 DeviceHandle, // ControllerHandle, according to
357 // the UEFI Driver Model
358 EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
359 // the device; to be released
360 );
361 if (EFI_ERROR (Status)) {
362 return Status;
363 }
364
365 if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_NETWORK_CARD) {
366 Status = EFI_UNSUPPORTED;
367 }
368
369 //
370 // We needed VirtIo access only transitorily, to see whether we support the
371 // device or not.
372 //
373 gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
374 This->DriverBindingHandle, DeviceHandle);
375 return Status;
376 }
377
378
379 /**
380 Starts a device controller or a bus controller.
381
382 The Start() function is designed to be invoked from the EFI boot service
383 ConnectController(). As a result, much of the error checking on the
384 parameters to Start() has been moved into this common boot service. It is
385 legal to call Start() from other locations, but the following calling
386 restrictions must be followed, or the system behavior will not be
387 deterministic.
388 1. ControllerHandle must be a valid EFI_HANDLE.
389 2. If RemainingDevicePath is not NULL, then it must be a pointer to a
390 naturally aligned EFI_DEVICE_PATH_PROTOCOL.
391 3. Prior to calling Start(), the Supported() function for the driver
392 specified by This must have been called with the same calling parameters,
393 and Supported() must have returned EFI_SUCCESS.
394
395 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
396 instance.
397 @param[in] ControllerHandle The handle of the controller to start. This
398 handle must support a protocol interface
399 that supplies an I/O abstraction to the
400 driver.
401 @param[in] RemainingDevicePath A pointer to the remaining portion of a
402 device path. This parameter is ignored by
403 device drivers, and is optional for bus
404 drivers. For a bus driver, if this parameter
405 is NULL, then handles for all the children
406 of Controller are created by this driver.
407 If this parameter is not NULL and the first
408 Device Path Node is not the End of Device
409 Path Node, then only the handle for the
410 child device specified by the first Device
411 Path Node of RemainingDevicePath is created
412 by this driver. If the first Device Path
413 Node of RemainingDevicePath is the End of
414 Device Path Node, no child handle is created
415 by this driver.
416
417 @retval EFI_SUCCESS The device was started.
418 @retval EFI_DEVICE_ERROR The device could not be started due to a
419 device error.Currently not implemented.
420 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
421 lack of resources.
422 @retval Others The driver failded to start the device.
423
424 **/
425
426 STATIC
427 EFI_STATUS
428 EFIAPI
429 VirtioNetDriverBindingStart (
430 IN EFI_DRIVER_BINDING_PROTOCOL *This,
431 IN EFI_HANDLE DeviceHandle,
432 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
433 )
434 {
435 EFI_STATUS Status;
436 VNET_DEV *Dev;
437 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
438 MAC_ADDR_DEVICE_PATH MacNode;
439 VOID *ChildVirtIo;
440
441 //
442 // allocate space for the driver instance
443 //
444 Dev = (VNET_DEV *) AllocateZeroPool (sizeof *Dev);
445 if (Dev == NULL) {
446 return EFI_OUT_OF_RESOURCES;
447 }
448 Dev->Signature = VNET_SIG;
449
450 Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
451 (VOID **)&Dev->VirtIo, This->DriverBindingHandle,
452 DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
453 if (EFI_ERROR (Status)) {
454 goto FreeVirtioNet;
455 }
456
457 //
458 // now we can run a basic one-shot virtio-net initialization required to
459 // retrieve the MAC address
460 //
461 Status = VirtioNetSnpPopulate (Dev);
462 if (EFI_ERROR (Status)) {
463 goto CloseVirtIo;
464 }
465
466 //
467 // get the device path of the virtio-net device -- one-shot open
468 //
469 Status = gBS->OpenProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid,
470 (VOID **)&DevicePath, This->DriverBindingHandle,
471 DeviceHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
472 if (EFI_ERROR (Status)) {
473 goto Evacuate;
474 }
475
476 //
477 // create another device path that has the MAC address appended
478 //
479 MacNode.Header.Type = MESSAGING_DEVICE_PATH;
480 MacNode.Header.SubType = MSG_MAC_ADDR_DP;
481 SetDevicePathNodeLength (&MacNode, sizeof MacNode);
482 CopyMem (&MacNode.MacAddress, &Dev->Snm.CurrentAddress,
483 sizeof (EFI_MAC_ADDRESS));
484 MacNode.IfType = Dev->Snm.IfType;
485
486 Dev->MacDevicePath = AppendDevicePathNode (DevicePath, &MacNode.Header);
487 if (Dev->MacDevicePath == NULL) {
488 Status = EFI_OUT_OF_RESOURCES;
489 goto Evacuate;
490 }
491
492 //
493 // create a child handle with the Simple Network Protocol and the new
494 // device path installed on it
495 //
496 Status = gBS->InstallMultipleProtocolInterfaces (&Dev->MacHandle,
497 &gEfiSimpleNetworkProtocolGuid, &Dev->Snp,
498 &gEfiDevicePathProtocolGuid, Dev->MacDevicePath,
499 NULL);
500 if (EFI_ERROR (Status)) {
501 goto FreeMacDevicePath;
502 }
503
504 //
505 // make a note that we keep this device open with VirtIo for the sake of this
506 // child
507 //
508 Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
509 &ChildVirtIo, This->DriverBindingHandle,
510 Dev->MacHandle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
511 if (EFI_ERROR (Status)) {
512 goto UninstallMultiple;
513 }
514
515 return EFI_SUCCESS;
516
517 UninstallMultiple:
518 gBS->UninstallMultipleProtocolInterfaces (Dev->MacHandle,
519 &gEfiDevicePathProtocolGuid, Dev->MacDevicePath,
520 &gEfiSimpleNetworkProtocolGuid, &Dev->Snp,
521 NULL);
522
523 FreeMacDevicePath:
524 FreePool (Dev->MacDevicePath);
525
526 Evacuate:
527 VirtioNetSnpEvacuate (Dev);
528
529 CloseVirtIo:
530 gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
531 This->DriverBindingHandle, DeviceHandle);
532
533 FreeVirtioNet:
534 FreePool (Dev);
535
536 return Status;
537 }
538
539
540 /**
541 Stops a device controller or a bus controller.
542
543 The Stop() function is designed to be invoked from the EFI boot service
544 DisconnectController(). As a result, much of the error checking on the
545 parameters to Stop() has been moved into this common boot service. It is
546 legal to call Stop() from other locations, but the following calling
547 restrictions must be followed, or the system behavior will not be
548 deterministic.
549 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous
550 call to this same driver's Start() function.
551 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a
552 valid EFI_HANDLE. In addition, all of these handles must have been created
553 in this driver's Start() function, and the Start() function must have
554 called OpenProtocol() on ControllerHandle with an Attribute of
555 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
556
557 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
558 instance.
559 @param[in] ControllerHandle A handle to the device being stopped. The
560 handle must support a bus specific I/O
561 protocol for the driver to use to stop the
562 device.
563 @param[in] NumberOfChildren The number of child device handles in
564 ChildHandleBuffer.
565 @param[in] ChildHandleBuffer An array of child handles to be freed. May be
566 NULL if NumberOfChildren is 0.
567
568 @retval EFI_SUCCESS The device was stopped.
569 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device
570 error.
571
572 **/
573 STATIC
574 EFI_STATUS
575 EFIAPI
576 VirtioNetDriverBindingStop (
577 IN EFI_DRIVER_BINDING_PROTOCOL *This,
578 IN EFI_HANDLE DeviceHandle,
579 IN UINTN NumberOfChildren,
580 IN EFI_HANDLE *ChildHandleBuffer
581 )
582 {
583 if (NumberOfChildren > 0) {
584 //
585 // free all resources for whose access we need the child handle, because
586 // the child handle is going away
587 //
588 EFI_STATUS Status;
589 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
590 VNET_DEV *Dev;
591 EFI_TPL OldTpl;
592
593 ASSERT (NumberOfChildren == 1);
594
595 Status = gBS->OpenProtocol (ChildHandleBuffer[0],
596 &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp,
597 This->DriverBindingHandle, DeviceHandle,
598 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
599 ASSERT_EFI_ERROR (Status);
600 Dev = VIRTIO_NET_FROM_SNP (Snp);
601
602 //
603 // prevent any interference with WaitForPacket
604 //
605 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
606
607 ASSERT (Dev->MacHandle == ChildHandleBuffer[0]);
608 if (Dev->Snm.State != EfiSimpleNetworkStopped) {
609 //
610 // device in use, cannot stop driver instance
611 //
612 Status = EFI_DEVICE_ERROR;
613 }
614 else {
615 gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
616 This->DriverBindingHandle, Dev->MacHandle);
617 gBS->UninstallMultipleProtocolInterfaces (Dev->MacHandle,
618 &gEfiDevicePathProtocolGuid, Dev->MacDevicePath,
619 &gEfiSimpleNetworkProtocolGuid, &Dev->Snp,
620 NULL);
621 FreePool (Dev->MacDevicePath);
622 VirtioNetSnpEvacuate (Dev);
623 FreePool (Dev);
624 }
625
626 gBS->RestoreTPL (OldTpl);
627 return Status;
628 }
629
630 //
631 // release remaining resources, tied directly to the parent handle
632 //
633 gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
634 This->DriverBindingHandle, DeviceHandle);
635
636 return EFI_SUCCESS;
637 }
638
639
640 EFI_DRIVER_BINDING_PROTOCOL gVirtioNetDriverBinding = {
641 &VirtioNetDriverBindingSupported,
642 &VirtioNetDriverBindingStart,
643 &VirtioNetDriverBindingStop,
644 0x10,
645 NULL,
646 NULL
647 };