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