]>
Commit | Line | Data |
---|---|---|
3bb56c06 OM |
1 | /** @file\r |
2 | \r | |
3 | This driver produces Virtio Device Protocol instances for Virtio PCI devices.\r | |
4 | \r | |
5 | Copyright (C) 2012, Red Hat, Inc.\r | |
694673c9 | 6 | Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>\r |
3bb56c06 | 7 | Copyright (C) 2013, ARM Ltd.\r |
4157b841 | 8 | Copyright (C) 2017, AMD Inc, All rights reserved.<BR>\r |
3bb56c06 | 9 | \r |
b26f0cf9 | 10 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
3bb56c06 OM |
11 | \r |
12 | **/\r | |
13 | \r | |
14 | #include <IndustryStandard/Pci.h>\r | |
15 | #include <Library/BaseMemoryLib.h>\r | |
16 | #include <Library/DebugLib.h>\r | |
17 | #include <Library/MemoryAllocationLib.h>\r | |
18 | #include <Library/UefiBootServicesTableLib.h>\r | |
19 | #include <Library/UefiLib.h>\r | |
20 | \r | |
21 | #include "VirtioPciDevice.h"\r | |
22 | \r | |
ac0a286f | 23 | STATIC VIRTIO_DEVICE_PROTOCOL mDeviceProtocolTemplate = {\r |
3bb56c06 OM |
24 | 0, // Revision\r |
25 | 0, // SubSystemDeviceId\r | |
26 | VirtioPciGetDeviceFeatures, // GetDeviceFeatures\r | |
27 | VirtioPciSetGuestFeatures, // SetGuestFeatures\r | |
3bb56c06 OM |
28 | VirtioPciSetQueueAddress, // SetQueueAddress\r |
29 | VirtioPciSetQueueSel, // SetQueueSel\r | |
30 | VirtioPciSetQueueNotify, // SetQueueNotify\r | |
31 | VirtioPciSetQueueAlignment, // SetQueueAlignment\r | |
32 | VirtioPciSetPageSize, // SetPageSize\r | |
33 | VirtioPciGetQueueSize, // GetQueueNumMax\r | |
34 | VirtioPciSetQueueSize, // SetQueueNum\r | |
35 | VirtioPciGetDeviceStatus, // GetDeviceStatus\r | |
36 | VirtioPciSetDeviceStatus, // SetDeviceStatus\r | |
37 | VirtioPciDeviceWrite, // WriteDevice\r | |
4157b841 BS |
38 | VirtioPciDeviceRead, // ReadDevice\r |
39 | VirtioPciAllocateSharedPages, // AllocateSharedPages\r | |
40 | VirtioPciFreeSharedPages, // FreeSharedPages\r | |
41 | VirtioPciMapSharedBuffer, // MapSharedBuffer\r | |
42 | VirtioPciUnmapSharedBuffer, // UnmapSharedBuffer\r | |
3bb56c06 OM |
43 | };\r |
44 | \r | |
45 | /**\r | |
46 | \r | |
47 | Read a word from Region 0 of the device specified by PciIo.\r | |
48 | \r | |
49 | Region 0 must be an iomem region. This is an internal function for the PCI\r | |
50 | implementation of the protocol.\r | |
51 | \r | |
52 | @param[in] Dev Virtio PCI device.\r | |
53 | \r | |
54 | @param[in] FieldOffset Source offset.\r | |
55 | \r | |
56 | @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }.\r | |
57 | \r | |
58 | @param[in] BufferSize Number of bytes available in the target buffer. Must\r | |
59 | equal FieldSize.\r | |
60 | \r | |
61 | @param[out] Buffer Target buffer.\r | |
62 | \r | |
63 | \r | |
64 | @return Status code returned by PciIo->Io.Read().\r | |
65 | \r | |
66 | **/\r | |
67 | EFI_STATUS\r | |
68 | EFIAPI\r | |
69 | VirtioPciIoRead (\r | |
ac0a286f MK |
70 | IN VIRTIO_PCI_DEVICE *Dev,\r |
71 | IN UINTN FieldOffset,\r | |
72 | IN UINTN FieldSize,\r | |
73 | IN UINTN BufferSize,\r | |
74 | OUT VOID *Buffer\r | |
3bb56c06 OM |
75 | )\r |
76 | {\r | |
ac0a286f MK |
77 | UINTN Count;\r |
78 | EFI_PCI_IO_PROTOCOL_WIDTH Width;\r | |
79 | EFI_PCI_IO_PROTOCOL *PciIo;\r | |
3bb56c06 OM |
80 | \r |
81 | ASSERT (FieldSize == BufferSize);\r | |
82 | \r | |
83 | PciIo = Dev->PciIo;\r | |
84 | Count = 1;\r | |
85 | \r | |
86 | switch (FieldSize) {\r | |
87 | case 1:\r | |
88 | Width = EfiPciIoWidthUint8;\r | |
89 | break;\r | |
90 | \r | |
91 | case 2:\r | |
92 | Width = EfiPciIoWidthUint16;\r | |
93 | break;\r | |
94 | \r | |
95 | case 8:\r | |
96 | //\r | |
97 | // The 64bit PCI I/O is broken down into two 32bit reads to prevent\r | |
98 | // any alignment or width issues.\r | |
99 | // The UEFI spec says under EFI_PCI_IO_PROTOCOL.Io.Write():\r | |
100 | //\r | |
101 | // The I/O operations are carried out exactly as requested. The caller\r | |
102 | // is responsible for any alignment and I/O width issues which the\r | |
103 | // bus, device, platform, or type of I/O might require. For example on\r | |
104 | // some platforms, width requests of EfiPciIoWidthUint64 do not work.\r | |
105 | //\r | |
106 | Count = 2;\r | |
107 | \r | |
ac0a286f MK |
108 | //\r |
109 | // fall through\r | |
110 | //\r | |
3bb56c06 OM |
111 | case 4:\r |
112 | Width = EfiPciIoWidthUint32;\r | |
113 | break;\r | |
114 | \r | |
115 | default:\r | |
116 | ASSERT (FALSE);\r | |
117 | return EFI_INVALID_PARAMETER;\r | |
118 | }\r | |
119 | \r | |
120 | return PciIo->Io.Read (\r | |
121 | PciIo,\r | |
122 | Width,\r | |
123 | PCI_BAR_IDX0,\r | |
124 | FieldOffset,\r | |
125 | Count,\r | |
126 | Buffer\r | |
127 | );\r | |
128 | }\r | |
129 | \r | |
130 | /**\r | |
131 | \r | |
132 | Write a word into Region 0 of the device specified by PciIo.\r | |
133 | \r | |
134 | Region 0 must be an iomem region. This is an internal function for the PCI\r | |
135 | implementation of the protocol.\r | |
136 | \r | |
137 | @param[in] Dev Virtio PCI device.\r | |
138 | \r | |
139 | @param[in] FieldOffset Destination offset.\r | |
140 | \r | |
141 | @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }.\r | |
142 | \r | |
143 | @param[in] Value Little endian value to write, converted to UINT64.\r | |
144 | The least significant FieldSize bytes will be used.\r | |
145 | \r | |
146 | \r | |
147 | @return Status code returned by PciIo->Io.Write().\r | |
148 | \r | |
149 | **/\r | |
150 | EFI_STATUS\r | |
151 | EFIAPI\r | |
152 | VirtioPciIoWrite (\r | |
ac0a286f MK |
153 | IN VIRTIO_PCI_DEVICE *Dev,\r |
154 | IN UINTN FieldOffset,\r | |
155 | IN UINTN FieldSize,\r | |
156 | IN UINT64 Value\r | |
3bb56c06 OM |
157 | )\r |
158 | {\r | |
ac0a286f MK |
159 | UINTN Count;\r |
160 | EFI_PCI_IO_PROTOCOL_WIDTH Width;\r | |
161 | EFI_PCI_IO_PROTOCOL *PciIo;\r | |
3bb56c06 OM |
162 | \r |
163 | PciIo = Dev->PciIo;\r | |
164 | Count = 1;\r | |
165 | \r | |
166 | switch (FieldSize) {\r | |
167 | case 1:\r | |
168 | Width = EfiPciIoWidthUint8;\r | |
169 | break;\r | |
170 | \r | |
171 | case 2:\r | |
172 | Width = EfiPciIoWidthUint16;\r | |
173 | break;\r | |
174 | \r | |
175 | case 8:\r | |
176 | //\r | |
177 | // The 64bit PCI I/O is broken down into two 32bit writes to prevent\r | |
178 | // any alignment or width issues.\r | |
179 | // The UEFI spec says under EFI_PCI_IO_PROTOCOL.Io.Write():\r | |
180 | //\r | |
181 | // The I/O operations are carried out exactly as requested. The caller\r | |
182 | // is responsible for any alignment and I/O width issues which the\r | |
183 | // bus, device, platform, or type of I/O might require. For example on\r | |
184 | // some platforms, width requests of EfiPciIoWidthUint64 do not work\r | |
185 | //\r | |
186 | Count = Count * 2;\r | |
187 | \r | |
ac0a286f MK |
188 | //\r |
189 | // fall through\r | |
190 | //\r | |
3bb56c06 OM |
191 | case 4:\r |
192 | Width = EfiPciIoWidthUint32;\r | |
193 | break;\r | |
194 | \r | |
195 | default:\r | |
196 | ASSERT (FALSE);\r | |
197 | return EFI_INVALID_PARAMETER;\r | |
198 | }\r | |
199 | \r | |
200 | return PciIo->Io.Write (\r | |
201 | PciIo,\r | |
202 | Width,\r | |
203 | PCI_BAR_IDX0,\r | |
204 | FieldOffset,\r | |
205 | Count,\r | |
206 | &Value\r | |
207 | );\r | |
208 | }\r | |
209 | \r | |
210 | /**\r | |
211 | \r | |
212 | Device probe function for this driver.\r | |
213 | \r | |
214 | The DXE core calls this function for any given device in order to see if the\r | |
215 | driver can drive the device.\r | |
216 | \r | |
217 | @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r | |
218 | incorporating this driver (independently of\r | |
219 | any device).\r | |
220 | \r | |
221 | @param[in] DeviceHandle The device to probe.\r | |
222 | \r | |
223 | @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.\r | |
224 | \r | |
225 | \r | |
226 | @retval EFI_SUCCESS The driver supports the device being probed.\r | |
227 | \r | |
228 | @retval EFI_UNSUPPORTED Based on virtio-pci discovery, we do not support\r | |
229 | the device.\r | |
230 | \r | |
231 | @return Error codes from the OpenProtocol() boot service or\r | |
232 | the PciIo protocol.\r | |
233 | \r | |
234 | **/\r | |
235 | STATIC\r | |
236 | EFI_STATUS\r | |
237 | EFIAPI\r | |
238 | VirtioPciDeviceBindingSupported (\r | |
ac0a286f MK |
239 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r |
240 | IN EFI_HANDLE DeviceHandle,\r | |
241 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r | |
3bb56c06 OM |
242 | )\r |
243 | {\r | |
ac0a286f MK |
244 | EFI_STATUS Status;\r |
245 | EFI_PCI_IO_PROTOCOL *PciIo;\r | |
246 | PCI_TYPE00 Pci;\r | |
3bb56c06 OM |
247 | \r |
248 | //\r | |
249 | // Attempt to open the device with the PciIo set of interfaces. On success,\r | |
250 | // the protocol is "instantiated" for the PCI device. Covers duplicate open\r | |
251 | // attempts (EFI_ALREADY_STARTED).\r | |
252 | //\r | |
253 | Status = gBS->OpenProtocol (\r | |
254 | DeviceHandle, // candidate device\r | |
255 | &gEfiPciIoProtocolGuid, // for generic PCI access\r | |
256 | (VOID **)&PciIo, // handle to instantiate\r | |
257 | This->DriverBindingHandle, // requestor driver identity\r | |
258 | DeviceHandle, // ControllerHandle, according to\r | |
259 | // the UEFI Driver Model\r | |
260 | EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive PciIo access to\r | |
261 | // the device; to be released\r | |
262 | );\r | |
263 | if (EFI_ERROR (Status)) {\r | |
264 | return Status;\r | |
265 | }\r | |
266 | \r | |
267 | //\r | |
268 | // Read entire PCI configuration header for more extensive check ahead.\r | |
269 | //\r | |
270 | Status = PciIo->Pci.Read (\r | |
271 | PciIo, // (protocol, device)\r | |
272 | // handle\r | |
273 | EfiPciIoWidthUint32, // access width & copy\r | |
274 | // mode\r | |
275 | 0, // Offset\r | |
276 | sizeof Pci / sizeof (UINT32), // Count\r | |
277 | &Pci // target buffer\r | |
278 | );\r | |
279 | \r | |
280 | if (Status == EFI_SUCCESS) {\r | |
281 | //\r | |
282 | // virtio-0.9.5, 2.1 PCI Discovery\r | |
283 | //\r | |
284 | if ((Pci.Hdr.VendorId == VIRTIO_VENDOR_ID) &&\r | |
285 | (Pci.Hdr.DeviceId >= 0x1000) &&\r | |
286 | (Pci.Hdr.DeviceId <= 0x103F) &&\r | |
ac0a286f MK |
287 | (Pci.Hdr.RevisionID == 0x00))\r |
288 | {\r | |
3bb56c06 OM |
289 | Status = EFI_SUCCESS;\r |
290 | } else {\r | |
291 | Status = EFI_UNSUPPORTED;\r | |
292 | }\r | |
293 | }\r | |
294 | \r | |
295 | //\r | |
296 | // We needed PCI IO access only transitorily, to see whether we support the\r | |
297 | // device or not.\r | |
298 | //\r | |
ac0a286f MK |
299 | gBS->CloseProtocol (\r |
300 | DeviceHandle,\r | |
301 | &gEfiPciIoProtocolGuid,\r | |
302 | This->DriverBindingHandle,\r | |
303 | DeviceHandle\r | |
304 | );\r | |
3bb56c06 OM |
305 | \r |
306 | return Status;\r | |
307 | }\r | |
308 | \r | |
309 | /**\r | |
310 | \r | |
311 | Initialize the VirtIo PCI Device\r | |
312 | \r | |
313 | @param[in, out] Dev The driver instance to configure. The caller is\r | |
314 | responsible for Device->PciIo's validity (ie. working IO\r | |
315 | access to the underlying virtio-pci device).\r | |
316 | \r | |
317 | @retval EFI_SUCCESS Setup complete.\r | |
318 | \r | |
319 | @retval EFI_UNSUPPORTED The underlying IO device doesn't support the\r | |
320 | provided address offset and read size.\r | |
321 | \r | |
322 | @return Error codes from PciIo->Pci.Read().\r | |
323 | \r | |
324 | **/\r | |
325 | STATIC\r | |
326 | EFI_STATUS\r | |
327 | EFIAPI\r | |
328 | VirtioPciInit (\r | |
ac0a286f | 329 | IN OUT VIRTIO_PCI_DEVICE *Device\r |
3bb56c06 OM |
330 | )\r |
331 | {\r | |
ac0a286f MK |
332 | EFI_STATUS Status;\r |
333 | EFI_PCI_IO_PROTOCOL *PciIo;\r | |
334 | PCI_TYPE00 Pci;\r | |
3bb56c06 OM |
335 | \r |
336 | ASSERT (Device != NULL);\r | |
337 | PciIo = Device->PciIo;\r | |
338 | ASSERT (PciIo != NULL);\r | |
339 | ASSERT (PciIo->Pci.Read != NULL);\r | |
340 | \r | |
341 | Status = PciIo->Pci.Read (\r | |
ac0a286f MK |
342 | PciIo, // (protocol, device)\r |
343 | // handle\r | |
344 | EfiPciIoWidthUint32, // access width & copy\r | |
345 | // mode\r | |
346 | 0, // Offset\r | |
3bb56c06 | 347 | sizeof (Pci) / sizeof (UINT32), // Count\r |
ac0a286f | 348 | &Pci // target buffer\r |
3bb56c06 OM |
349 | );\r |
350 | if (EFI_ERROR (Status)) {\r | |
351 | return Status;\r | |
352 | }\r | |
353 | \r | |
354 | //\r | |
355 | // Copy protocol template\r | |
356 | //\r | |
ac0a286f MK |
357 | CopyMem (\r |
358 | &Device->VirtioDevice,\r | |
359 | &mDeviceProtocolTemplate,\r | |
360 | sizeof (VIRTIO_DEVICE_PROTOCOL)\r | |
361 | );\r | |
3bb56c06 OM |
362 | \r |
363 | //\r | |
364 | // Initialize the protocol interface attributes\r | |
365 | //\r | |
ac0a286f | 366 | Device->VirtioDevice.Revision = VIRTIO_SPEC_REVISION (0, 9, 5);\r |
3bb56c06 OM |
367 | Device->VirtioDevice.SubSystemDeviceId = Pci.Device.SubsystemID;\r |
368 | \r | |
369 | //\r | |
370 | // Note: We don't support the MSI-X capability. If we did,\r | |
371 | // the offset would become 24 after enabling MSI-X.\r | |
372 | //\r | |
373 | Device->DeviceSpecificConfigurationOffset =\r | |
ac0a286f | 374 | VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI;\r |
3bb56c06 OM |
375 | \r |
376 | return EFI_SUCCESS;\r | |
377 | }\r | |
378 | \r | |
379 | /**\r | |
380 | \r | |
381 | Uninitialize the internals of a virtio-pci device that has been successfully\r | |
382 | set up with VirtioPciInit().\r | |
383 | \r | |
384 | @param[in, out] Dev The device to clean up.\r | |
385 | \r | |
386 | **/\r | |
3bb56c06 OM |
387 | STATIC\r |
388 | VOID\r | |
389 | EFIAPI\r | |
390 | VirtioPciUninit (\r | |
ac0a286f | 391 | IN OUT VIRTIO_PCI_DEVICE *Device\r |
3bb56c06 OM |
392 | )\r |
393 | {\r | |
394 | // Note: This function mirrors VirtioPciInit() that does not allocate any\r | |
395 | // resources - there's nothing to free here.\r | |
396 | }\r | |
397 | \r | |
398 | /**\r | |
399 | \r | |
400 | After we've pronounced support for a specific device in\r | |
401 | DriverBindingSupported(), we start managing said device (passed in by the\r | |
694673c9 | 402 | Driver Execution Environment) with the following service.\r |
3bb56c06 OM |
403 | \r |
404 | See DriverBindingSupported() for specification references.\r | |
405 | \r | |
406 | @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r | |
407 | incorporating this driver (independently of\r | |
408 | any device).\r | |
409 | \r | |
410 | @param[in] DeviceHandle The supported device to drive.\r | |
411 | \r | |
412 | @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.\r | |
413 | \r | |
414 | \r | |
415 | @retval EFI_SUCCESS Driver instance has been created and\r | |
416 | initialized for the virtio-pci device, it\r | |
417 | is now accessible via VIRTIO_DEVICE_PROTOCOL.\r | |
418 | \r | |
419 | @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r | |
420 | \r | |
421 | @return Error codes from the OpenProtocol() boot\r | |
422 | service, the PciIo protocol, VirtioPciInit(),\r | |
423 | or the InstallProtocolInterface() boot service.\r | |
424 | \r | |
425 | **/\r | |
426 | STATIC\r | |
427 | EFI_STATUS\r | |
428 | EFIAPI\r | |
429 | VirtioPciDeviceBindingStart (\r | |
ac0a286f MK |
430 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r |
431 | IN EFI_HANDLE DeviceHandle,\r | |
432 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r | |
3bb56c06 OM |
433 | )\r |
434 | {\r | |
ac0a286f MK |
435 | VIRTIO_PCI_DEVICE *Device;\r |
436 | EFI_STATUS Status;\r | |
3bb56c06 | 437 | \r |
ac0a286f | 438 | Device = (VIRTIO_PCI_DEVICE *)AllocateZeroPool (sizeof *Device);\r |
3bb56c06 OM |
439 | if (Device == NULL) {\r |
440 | return EFI_OUT_OF_RESOURCES;\r | |
441 | }\r | |
442 | \r | |
ac0a286f MK |
443 | Status = gBS->OpenProtocol (\r |
444 | DeviceHandle,\r | |
445 | &gEfiPciIoProtocolGuid,\r | |
446 | (VOID **)&Device->PciIo,\r | |
447 | This->DriverBindingHandle,\r | |
448 | DeviceHandle,\r | |
449 | EFI_OPEN_PROTOCOL_BY_DRIVER\r | |
450 | );\r | |
3bb56c06 OM |
451 | if (EFI_ERROR (Status)) {\r |
452 | goto FreeVirtioPci;\r | |
453 | }\r | |
454 | \r | |
455 | //\r | |
456 | // We must retain and ultimately restore the original PCI attributes of the\r | |
457 | // device. See Driver Writer's Guide for UEFI 2.3.1 v1.01, 18.3 PCI drivers /\r | |
458 | // 18.3.2 Start() and Stop().\r | |
459 | //\r | |
460 | // The third parameter ("Attributes", input) is ignored by the Get operation.\r | |
461 | // The fourth parameter ("Result", output) is ignored by the Enable and Set\r | |
462 | // operations.\r | |
463 | //\r | |
464 | // For virtio-pci we only need IO space access.\r | |
465 | //\r | |
ac0a286f MK |
466 | Status = Device->PciIo->Attributes (\r |
467 | Device->PciIo,\r | |
468 | EfiPciIoAttributeOperationGet,\r | |
469 | 0,\r | |
470 | &Device->OriginalPciAttributes\r | |
471 | );\r | |
3bb56c06 OM |
472 | if (EFI_ERROR (Status)) {\r |
473 | goto ClosePciIo;\r | |
474 | }\r | |
475 | \r | |
78ef454b BS |
476 | Status = Device->PciIo->Attributes (\r |
477 | Device->PciIo,\r | |
478 | EfiPciIoAttributeOperationEnable,\r | |
479 | (EFI_PCI_IO_ATTRIBUTE_IO |\r | |
480 | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),\r | |
481 | NULL\r | |
482 | );\r | |
3bb56c06 OM |
483 | if (EFI_ERROR (Status)) {\r |
484 | goto ClosePciIo;\r | |
485 | }\r | |
486 | \r | |
487 | //\r | |
488 | // PCI IO access granted, configure protocol instance\r | |
489 | //\r | |
490 | \r | |
491 | Status = VirtioPciInit (Device);\r | |
492 | if (EFI_ERROR (Status)) {\r | |
493 | goto RestorePciAttributes;\r | |
494 | }\r | |
495 | \r | |
496 | //\r | |
497 | // Setup complete, attempt to export the driver instance's VirtioDevice\r | |
498 | // interface.\r | |
499 | //\r | |
500 | Device->Signature = VIRTIO_PCI_DEVICE_SIGNATURE;\r | |
ac0a286f MK |
501 | Status = gBS->InstallProtocolInterface (\r |
502 | &DeviceHandle,\r | |
503 | &gVirtioDeviceProtocolGuid,\r | |
504 | EFI_NATIVE_INTERFACE,\r | |
505 | &Device->VirtioDevice\r | |
506 | );\r | |
3bb56c06 OM |
507 | if (EFI_ERROR (Status)) {\r |
508 | goto UninitDev;\r | |
509 | }\r | |
510 | \r | |
511 | return EFI_SUCCESS;\r | |
512 | \r | |
513 | UninitDev:\r | |
514 | VirtioPciUninit (Device);\r | |
515 | \r | |
516 | RestorePciAttributes:\r | |
ac0a286f MK |
517 | Device->PciIo->Attributes (\r |
518 | Device->PciIo,\r | |
519 | EfiPciIoAttributeOperationSet,\r | |
520 | Device->OriginalPciAttributes,\r | |
521 | NULL\r | |
522 | );\r | |
3bb56c06 OM |
523 | \r |
524 | ClosePciIo:\r | |
ac0a286f MK |
525 | gBS->CloseProtocol (\r |
526 | DeviceHandle,\r | |
527 | &gEfiPciIoProtocolGuid,\r | |
528 | This->DriverBindingHandle,\r | |
529 | DeviceHandle\r | |
530 | );\r | |
3bb56c06 OM |
531 | \r |
532 | FreeVirtioPci:\r | |
533 | FreePool (Device);\r | |
534 | \r | |
535 | return Status;\r | |
536 | }\r | |
537 | \r | |
538 | /**\r | |
539 | \r | |
540 | Stop driving the Virtio PCI device\r | |
541 | \r | |
542 | @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r | |
543 | incorporating this driver (independently of any\r | |
544 | device).\r | |
545 | \r | |
546 | @param[in] DeviceHandle Stop driving this device.\r | |
547 | \r | |
548 | @param[in] NumberOfChildren Since this function belongs to a device driver\r | |
549 | only (as opposed to a bus driver), the caller\r | |
550 | environment sets NumberOfChildren to zero, and\r | |
551 | we ignore it.\r | |
552 | \r | |
553 | @param[in] ChildHandleBuffer Ignored (corresponding to NumberOfChildren).\r | |
554 | \r | |
555 | @retval EFI_SUCCESS Driver instance has been stopped and the PCI\r | |
556 | configuration attributes have been restored.\r | |
557 | \r | |
558 | @return Error codes from the OpenProtocol() or\r | |
559 | CloseProtocol(), UninstallProtocolInterface()\r | |
560 | boot services.\r | |
561 | \r | |
562 | **/\r | |
563 | STATIC\r | |
564 | EFI_STATUS\r | |
565 | EFIAPI\r | |
566 | VirtioPciDeviceBindingStop (\r | |
ac0a286f MK |
567 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r |
568 | IN EFI_HANDLE DeviceHandle,\r | |
569 | IN UINTN NumberOfChildren,\r | |
570 | IN EFI_HANDLE *ChildHandleBuffer\r | |
3bb56c06 OM |
571 | )\r |
572 | {\r | |
ac0a286f | 573 | EFI_STATUS Status;\r |
3bb56c06 OM |
574 | VIRTIO_DEVICE_PROTOCOL *VirtioDevice;\r |
575 | VIRTIO_PCI_DEVICE *Device;\r | |
576 | \r | |
577 | Status = gBS->OpenProtocol (\r | |
578 | DeviceHandle, // candidate device\r | |
579 | &gVirtioDeviceProtocolGuid, // retrieve the VirtIo iface\r | |
580 | (VOID **)&VirtioDevice, // target pointer\r | |
581 | This->DriverBindingHandle, // requestor driver identity\r | |
582 | DeviceHandle, // requesting lookup for dev.\r | |
583 | EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no ref. added\r | |
584 | );\r | |
585 | if (EFI_ERROR (Status)) {\r | |
586 | return Status;\r | |
587 | }\r | |
588 | \r | |
589 | Device = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (VirtioDevice);\r | |
590 | \r | |
591 | //\r | |
592 | // Handle Stop() requests for in-use driver instances gracefully.\r | |
593 | //\r | |
ac0a286f MK |
594 | Status = gBS->UninstallProtocolInterface (\r |
595 | DeviceHandle,\r | |
596 | &gVirtioDeviceProtocolGuid,\r | |
597 | &Device->VirtioDevice\r | |
598 | );\r | |
3bb56c06 OM |
599 | if (EFI_ERROR (Status)) {\r |
600 | return Status;\r | |
601 | }\r | |
602 | \r | |
603 | VirtioPciUninit (Device);\r | |
604 | \r | |
ac0a286f MK |
605 | Device->PciIo->Attributes (\r |
606 | Device->PciIo,\r | |
607 | EfiPciIoAttributeOperationSet,\r | |
608 | Device->OriginalPciAttributes,\r | |
609 | NULL\r | |
610 | );\r | |
611 | \r | |
612 | Status = gBS->CloseProtocol (\r | |
613 | DeviceHandle,\r | |
614 | &gEfiPciIoProtocolGuid,\r | |
615 | This->DriverBindingHandle,\r | |
616 | DeviceHandle\r | |
617 | );\r | |
3bb56c06 OM |
618 | \r |
619 | FreePool (Device);\r | |
620 | \r | |
621 | return Status;\r | |
622 | }\r | |
623 | \r | |
3bb56c06 OM |
624 | //\r |
625 | // The static object that groups the Supported() (ie. probe), Start() and\r | |
626 | // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata\r | |
627 | // C, 10.1 EFI Driver Binding Protocol.\r | |
628 | //\r | |
ac0a286f | 629 | STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {\r |
3bb56c06 OM |
630 | &VirtioPciDeviceBindingSupported,\r |
631 | &VirtioPciDeviceBindingStart,\r | |
632 | &VirtioPciDeviceBindingStop,\r | |
633 | 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers\r | |
634 | NULL, // ImageHandle, to be overwritten by\r | |
635 | // EfiLibInstallDriverBindingComponentName2() in VirtioPciEntryPoint()\r | |
636 | NULL // DriverBindingHandle, ditto\r | |
637 | };\r | |
638 | \r | |
3bb56c06 OM |
639 | //\r |
640 | // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and\r | |
641 | // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name\r | |
642 | // in English, for display on standard console devices. This is recommended for\r | |
643 | // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's\r | |
644 | // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.\r | |
645 | //\r | |
646 | STATIC\r | |
ac0a286f | 647 | EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {\r |
3bb56c06 | 648 | { "eng;en", L"Virtio PCI Driver" },\r |
ac0a286f | 649 | { NULL, NULL }\r |
3bb56c06 OM |
650 | };\r |
651 | \r | |
652 | STATIC\r | |
ac0a286f | 653 | EFI_COMPONENT_NAME_PROTOCOL gComponentName;\r |
3bb56c06 OM |
654 | \r |
655 | EFI_STATUS\r | |
656 | EFIAPI\r | |
657 | VirtioPciGetDriverName (\r | |
ac0a286f MK |
658 | IN EFI_COMPONENT_NAME_PROTOCOL *This,\r |
659 | IN CHAR8 *Language,\r | |
660 | OUT CHAR16 **DriverName\r | |
3bb56c06 OM |
661 | )\r |
662 | {\r | |
663 | return LookupUnicodeString2 (\r | |
664 | Language,\r | |
665 | This->SupportedLanguages,\r | |
666 | mDriverNameTable,\r | |
667 | DriverName,\r | |
668 | (BOOLEAN)(This == &gComponentName) // Iso639Language\r | |
669 | );\r | |
670 | }\r | |
671 | \r | |
672 | EFI_STATUS\r | |
673 | EFIAPI\r | |
674 | VirtioPciGetDeviceName (\r | |
ac0a286f MK |
675 | IN EFI_COMPONENT_NAME_PROTOCOL *This,\r |
676 | IN EFI_HANDLE DeviceHandle,\r | |
677 | IN EFI_HANDLE ChildHandle,\r | |
678 | IN CHAR8 *Language,\r | |
679 | OUT CHAR16 **ControllerName\r | |
3bb56c06 OM |
680 | )\r |
681 | {\r | |
682 | return EFI_UNSUPPORTED;\r | |
683 | }\r | |
684 | \r | |
685 | STATIC\r | |
ac0a286f | 686 | EFI_COMPONENT_NAME_PROTOCOL gComponentName = {\r |
3bb56c06 OM |
687 | &VirtioPciGetDriverName,\r |
688 | &VirtioPciGetDeviceName,\r | |
689 | "eng" // SupportedLanguages, ISO 639-2 language codes\r | |
690 | };\r | |
691 | \r | |
692 | STATIC\r | |
ac0a286f MK |
693 | EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {\r |
694 | (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&VirtioPciGetDriverName,\r | |
695 | (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&VirtioPciGetDeviceName,\r | |
3bb56c06 OM |
696 | "en" // SupportedLanguages, RFC 4646 language codes\r |
697 | };\r | |
698 | \r | |
3bb56c06 OM |
699 | //\r |
700 | // Entry point of this driver.\r | |
701 | //\r | |
702 | EFI_STATUS\r | |
703 | EFIAPI\r | |
704 | VirtioPciDeviceEntryPoint (\r | |
ac0a286f MK |
705 | IN EFI_HANDLE ImageHandle,\r |
706 | IN EFI_SYSTEM_TABLE *SystemTable\r | |
3bb56c06 OM |
707 | )\r |
708 | {\r | |
709 | return EfiLibInstallDriverBindingComponentName2 (\r | |
710 | ImageHandle,\r | |
711 | SystemTable,\r | |
712 | &gDriverBinding,\r | |
713 | ImageHandle,\r | |
714 | &gComponentName,\r | |
715 | &gComponentName2\r | |
716 | );\r | |
717 | }\r |