]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Virtio10Dxe/Virtio10.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / Virtio10Dxe / Virtio10.c
CommitLineData
9399f68a
LE
1/** @file\r
2 A non-transitional driver for VirtIo 1.0 PCI devices.\r
3\r
4 Copyright (C) 2016, Red Hat, Inc.\r
de1c57c5 5 Copyright (C) 2017, AMD Inc, All rights reserved.<BR>\r
9399f68a 6\r
b26f0cf9 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
9399f68a
LE
8**/\r
9\r
10#include <IndustryStandard/Pci.h>\r
11#include <IndustryStandard/Virtio.h>\r
12#include <Protocol/PciIo.h>\r
de1c57c5 13#include <Protocol/PciRootBridgeIo.h>\r
9399f68a
LE
14#include <Protocol/VirtioDevice.h>\r
15#include <Library/BaseMemoryLib.h>\r
16#include <Library/DebugLib.h>\r
17#include <Library/MemoryAllocationLib.h>\r
5685a243
LE
18#include <Library/PciCapLib.h>\r
19#include <Library/PciCapPciIoLib.h>\r
9399f68a
LE
20#include <Library/UefiBootServicesTableLib.h>\r
21#include <Library/UefiLib.h>\r
22\r
23#include "Virtio10.h"\r
24\r
9399f68a
LE
25//\r
26// Utility functions\r
27//\r
28\r
29/**\r
30 Transfer data between the caller and a register in a virtio-1.0 register\r
31 block.\r
32\r
33 @param[in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents\r
34 the device.\r
35\r
36 @param[in] Config The "fat pointer" structure that identifies the\r
37 register block to access.\r
38\r
39 @param[in] Write TRUE if the register should be written, FALSE if\r
40 the register should be read.\r
41\r
42 @param[in] FieldOffset The offset of the register within the register\r
43 block.\r
44\r
45 @param[in] FieldSize The size of the register within the register\r
46 block. Can be one of 1, 2, 4 and 8. Accesses to\r
47 8-byte registers are broken up into two 4-byte\r
48 accesses.\r
49\r
50 @param[in,out] Buffer When Write is TRUE, the register is written with\r
51 data from Buffer. When Write is FALSE, the caller\r
52 receives the register value into Buffer.\r
53\r
54 @retval EFI_SUCCESS Register access successful.\r
55\r
56 @retval EFI_INVALID_PARAMETER The register block pointed-to by Config\r
57 doesn't exist; or FieldOffset and FieldSize\r
58 would overflow the register block; or\r
59 FieldSize is invalid.\r
60\r
61 @return Error codes from\r
62 EFI_PCI_IO_PROTOCOL.(Io|Mem).(Read|Write)\r
63 member functions.\r
64**/\r
65STATIC\r
66EFI_STATUS\r
67Virtio10Transfer (\r
ac0a286f
MK
68 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
69 IN VIRTIO_1_0_CONFIG *Config,\r
70 IN BOOLEAN Write,\r
71 IN UINTN FieldOffset,\r
72 IN UINTN FieldSize,\r
73 IN OUT VOID *Buffer\r
9399f68a
LE
74 )\r
75{\r
ac0a286f
MK
76 UINTN Count;\r
77 EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
78 EFI_PCI_IO_PROTOCOL_ACCESS *BarType;\r
79 EFI_PCI_IO_PROTOCOL_IO_MEM Access;\r
9399f68a
LE
80\r
81 if (!Config->Exists ||\r
ac0a286f
MK
82 (FieldSize > Config->Length) ||\r
83 (FieldOffset > Config->Length - FieldSize))\r
84 {\r
9399f68a
LE
85 return EFI_INVALID_PARAMETER;\r
86 }\r
87\r
88 Count = 1;\r
89 switch (FieldSize) {\r
90 case 1:\r
91 Width = EfiPciIoWidthUint8;\r
92 break;\r
93\r
94 case 2:\r
95 Width = EfiPciIoWidthUint16;\r
96 break;\r
97\r
98 case 8:\r
99 Count = 2;\r
ac0a286f
MK
100 //\r
101 // fall through\r
102 //\r
9399f68a
LE
103\r
104 case 4:\r
105 Width = EfiPciIoWidthUint32;\r
106 break;\r
107\r
108 default:\r
109 return EFI_INVALID_PARAMETER;\r
110 }\r
111\r
112 BarType = (Config->BarType == Virtio10BarTypeMem) ? &PciIo->Mem : &PciIo->Io;\r
ac0a286f
MK
113 Access = Write ? BarType->Write : BarType->Read;\r
114\r
115 return Access (\r
116 PciIo,\r
117 Width,\r
118 Config->Bar,\r
119 Config->Offset + FieldOffset,\r
120 Count,\r
121 Buffer\r
122 );\r
9399f68a
LE
123}\r
124\r
9399f68a
LE
125/**\r
126 Determine if a PCI BAR is IO or MMIO.\r
127\r
128 @param[in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents the\r
129 device.\r
130\r
131 @param[in] BarIndex The number of the BAR whose type the caller is\r
132 interested in.\r
133\r
134 @param[out] BarType On output, a VIRTIO_1_0_BAR_TYPE value that gives the\r
135 type of the BAR.\r
136\r
137 @retval EFI_SUCCESS The BAR type has been recognized and stored in\r
138 BarType.\r
139\r
140 @retval EFI_UNSUPPORTED The BAR type couldn't be identified.\r
141\r
142 @return Error codes from\r
143 EFI_PCI_IO_PROTOCOL.GetBarAttributes().\r
144**/\r
145STATIC\r
146EFI_STATUS\r
147GetBarType (\r
ac0a286f
MK
148 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
149 IN UINT8 BarIndex,\r
150 OUT VIRTIO_1_0_BAR_TYPE *BarType\r
9399f68a
LE
151 )\r
152{\r
ac0a286f
MK
153 EFI_STATUS Status;\r
154 VOID *Resources;\r
9399f68a
LE
155\r
156 Status = PciIo->GetBarAttributes (PciIo, BarIndex, NULL, &Resources);\r
157 if (EFI_ERROR (Status)) {\r
158 return Status;\r
159 }\r
160\r
161 Status = EFI_UNSUPPORTED;\r
162\r
163 if (*(UINT8 *)Resources == ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) {\r
ac0a286f 164 EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
9399f68a
LE
165\r
166 Descriptor = Resources;\r
167 switch (Descriptor->ResType) {\r
ac0a286f
MK
168 case ACPI_ADDRESS_SPACE_TYPE_MEM:\r
169 *BarType = Virtio10BarTypeMem;\r
170 Status = EFI_SUCCESS;\r
171 break;\r
172\r
173 case ACPI_ADDRESS_SPACE_TYPE_IO:\r
174 *BarType = Virtio10BarTypeIo;\r
175 Status = EFI_SUCCESS;\r
176 break;\r
177\r
178 default:\r
179 break;\r
9399f68a
LE
180 }\r
181 }\r
182\r
183 FreePool (Resources);\r
184 return Status;\r
185}\r
186\r
9399f68a
LE
187/*\r
188 Traverse the PCI capabilities list of a virtio-1.0 device, and capture the\r
189 locations of the interesting virtio-1.0 register blocks.\r
190\r
191 @param[in,out] Device The VIRTIO_1_0_DEV structure that identifies\r
192 the device. On input, the caller is responsible\r
193 that the Device->PciIo member be live, and that\r
194 the CommonConfig, NotifyConfig,\r
195 NotifyOffsetMultiplier and SpecificConfig\r
196 members be zeroed. On output, said members\r
197 will have been updated from the PCI\r
198 capabilities found.\r
199\r
9399f68a
LE
200 @retval EFI_SUCCESS Traversal successful.\r
201\r
5685a243
LE
202 @return Error codes from PciCapPciIoLib, PciCapLib, and the\r
203 GetBarType() helper function.\r
9399f68a
LE
204*/\r
205STATIC\r
206EFI_STATUS\r
207ParseCapabilities (\r
ac0a286f 208 IN OUT VIRTIO_1_0_DEV *Device\r
9399f68a
LE
209 )\r
210{\r
ac0a286f
MK
211 EFI_STATUS Status;\r
212 PCI_CAP_DEV *PciDevice;\r
213 PCI_CAP_LIST *CapList;\r
214 UINT16 VendorInstance;\r
215 PCI_CAP *VendorCap;\r
5685a243
LE
216\r
217 Status = PciCapPciIoDeviceInit (Device->PciIo, &PciDevice);\r
218 if (EFI_ERROR (Status)) {\r
219 return Status;\r
220 }\r
ac0a286f 221\r
5685a243
LE
222 Status = PciCapListInit (PciDevice, &CapList);\r
223 if (EFI_ERROR (Status)) {\r
224 goto UninitPciDevice;\r
225 }\r
226\r
227 for (VendorInstance = 0;\r
ac0a286f
MK
228 !EFI_ERROR (\r
229 PciCapListFindCap (\r
230 CapList,\r
231 PciCapNormal,\r
232 EFI_PCI_CAPABILITY_ID_VENDOR,\r
233 VendorInstance,\r
234 &VendorCap\r
235 )\r
236 );\r
237 VendorInstance++)\r
238 {\r
239 UINT8 CapLen;\r
240 VIRTIO_PCI_CAP VirtIoCap;\r
241 VIRTIO_1_0_CONFIG *ParsedConfig;\r
9399f68a 242\r
9399f68a
LE
243 //\r
244 // Big enough to accommodate a VIRTIO_PCI_CAP structure?\r
245 //\r
ac0a286f
MK
246 Status = PciCapRead (\r
247 PciDevice,\r
248 VendorCap,\r
249 OFFSET_OF (EFI_PCI_CAPABILITY_VENDOR_HDR, Length),\r
250 &CapLen,\r
251 sizeof CapLen\r
252 );\r
9399f68a 253 if (EFI_ERROR (Status)) {\r
5685a243 254 goto UninitCapList;\r
9399f68a 255 }\r
ac0a286f 256\r
5685a243 257 if (CapLen < sizeof VirtIoCap) {\r
9399f68a
LE
258 //\r
259 // Too small, move to next.\r
260 //\r
261 continue;\r
262 }\r
263\r
264 //\r
265 // Read interesting part of capability.\r
266 //\r
5685a243 267 Status = PciCapRead (PciDevice, VendorCap, 0, &VirtIoCap, sizeof VirtIoCap);\r
9399f68a 268 if (EFI_ERROR (Status)) {\r
5685a243 269 goto UninitCapList;\r
9399f68a 270 }\r
5685a243 271\r
9399f68a 272 switch (VirtIoCap.ConfigType) {\r
ac0a286f
MK
273 case VIRTIO_PCI_CAP_COMMON_CFG:\r
274 ParsedConfig = &Device->CommonConfig;\r
275 break;\r
276 case VIRTIO_PCI_CAP_NOTIFY_CFG:\r
277 ParsedConfig = &Device->NotifyConfig;\r
278 break;\r
279 case VIRTIO_PCI_CAP_DEVICE_CFG:\r
280 ParsedConfig = &Device->SpecificConfig;\r
281 break;\r
282 default:\r
283 //\r
284 // Capability is not interesting.\r
285 //\r
286 continue;\r
9399f68a
LE
287 }\r
288\r
289 //\r
290 // Save the location of the register block into ParsedConfig.\r
291 //\r
292 Status = GetBarType (Device->PciIo, VirtIoCap.Bar, &ParsedConfig->BarType);\r
293 if (EFI_ERROR (Status)) {\r
5685a243 294 goto UninitCapList;\r
9399f68a 295 }\r
ac0a286f 296\r
9399f68a
LE
297 ParsedConfig->Bar = VirtIoCap.Bar;\r
298 ParsedConfig->Offset = VirtIoCap.Offset;\r
299 ParsedConfig->Length = VirtIoCap.Length;\r
300\r
301 if (VirtIoCap.ConfigType == VIRTIO_PCI_CAP_NOTIFY_CFG) {\r
302 //\r
303 // This capability has an additional field called NotifyOffsetMultiplier;\r
304 // parse it too.\r
305 //\r
5685a243 306 if (CapLen < sizeof VirtIoCap + sizeof Device->NotifyOffsetMultiplier) {\r
9399f68a
LE
307 //\r
308 // Too small, move to next.\r
309 //\r
310 continue;\r
311 }\r
312\r
ac0a286f
MK
313 Status = PciCapRead (\r
314 PciDevice,\r
315 VendorCap,\r
316 sizeof VirtIoCap,\r
5685a243 317 &Device->NotifyOffsetMultiplier,\r
ac0a286f
MK
318 sizeof Device->NotifyOffsetMultiplier\r
319 );\r
9399f68a 320 if (EFI_ERROR (Status)) {\r
5685a243 321 goto UninitCapList;\r
9399f68a
LE
322 }\r
323 }\r
324\r
325 //\r
326 // Capability parsed successfully.\r
327 //\r
328 ParsedConfig->Exists = TRUE;\r
329 }\r
330\r
5685a243
LE
331 ASSERT_EFI_ERROR (Status);\r
332\r
333UninitCapList:\r
334 PciCapListUninit (CapList);\r
335\r
336UninitPciDevice:\r
337 PciCapPciIoDeviceUninit (PciDevice);\r
338\r
339 return Status;\r
9399f68a
LE
340}\r
341\r
9399f68a
LE
342/**\r
343 Accumulate the BAR type of a virtio-1.0 register block into a UINT64\r
344 attribute map, such that the latter is suitable for enabling IO / MMIO\r
345 decoding with EFI_PCI_IO_PROTOCOL.Attributes().\r
346\r
347 @param[in] Config The "fat pointer" structure that identifies the\r
348 register block. It is allowed for the register\r
349 block not to exist.\r
350\r
351 @param[in,out] Attributes On output, if the register block exists,\r
352 EFI_PCI_IO_ATTRIBUTE_MEMORY or\r
353 EFI_PCI_IO_ATTRIBUTE_IO is OR-ed into Attributes,\r
354 according to the register block's BAR type.\r
355**/\r
356STATIC\r
357VOID\r
358UpdateAttributes (\r
ac0a286f
MK
359 IN VIRTIO_1_0_CONFIG *Config,\r
360 IN OUT UINT64 *Attributes\r
9399f68a
LE
361 )\r
362{\r
363 if (Config->Exists) {\r
364 *Attributes |= (Config->BarType == Virtio10BarTypeMem) ?\r
ac0a286f
MK
365 EFI_PCI_IO_ATTRIBUTE_MEMORY :\r
366 EFI_PCI_IO_ATTRIBUTE_IO;\r
9399f68a
LE
367 }\r
368}\r
369\r
9399f68a
LE
370//\r
371// VIRTIO_DEVICE_PROTOCOL member functions\r
372//\r
373\r
374STATIC\r
375EFI_STATUS\r
376EFIAPI\r
377Virtio10GetDeviceFeatures (\r
ac0a286f
MK
378 IN VIRTIO_DEVICE_PROTOCOL *This,\r
379 OUT UINT64 *DeviceFeatures\r
9399f68a
LE
380 )\r
381{\r
ac0a286f
MK
382 VIRTIO_1_0_DEV *Dev;\r
383 UINT32 Selector;\r
384 UINT32 Features32[2];\r
9399f68a
LE
385\r
386 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
387\r
388 for (Selector = 0; Selector < 2; ++Selector) {\r
ac0a286f 389 EFI_STATUS Status;\r
9399f68a
LE
390\r
391 //\r
392 // Select the low or high half of the features.\r
393 //\r
ac0a286f
MK
394 Status = Virtio10Transfer (\r
395 Dev->PciIo,\r
396 &Dev->CommonConfig,\r
397 TRUE,\r
9399f68a 398 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceFeatureSelect),\r
ac0a286f
MK
399 sizeof Selector,\r
400 &Selector\r
401 );\r
9399f68a
LE
402 if (EFI_ERROR (Status)) {\r
403 return Status;\r
404 }\r
405\r
406 //\r
407 // Fetch that half.\r
408 //\r
ac0a286f
MK
409 Status = Virtio10Transfer (\r
410 Dev->PciIo,\r
411 &Dev->CommonConfig,\r
412 FALSE,\r
9399f68a 413 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceFeature),\r
ac0a286f
MK
414 sizeof Features32[Selector],\r
415 &Features32[Selector]\r
416 );\r
9399f68a
LE
417 if (EFI_ERROR (Status)) {\r
418 return Status;\r
419 }\r
420 }\r
421\r
422 *DeviceFeatures = LShiftU64 (Features32[1], 32) | Features32[0];\r
423 return EFI_SUCCESS;\r
424}\r
425\r
9399f68a
LE
426STATIC\r
427EFI_STATUS\r
428EFIAPI\r
429Virtio10SetGuestFeatures (\r
430 IN VIRTIO_DEVICE_PROTOCOL *This,\r
ac0a286f 431 IN UINT64 Features\r
9399f68a
LE
432 )\r
433{\r
ac0a286f
MK
434 VIRTIO_1_0_DEV *Dev;\r
435 UINT32 Selector;\r
436 UINT32 Features32[2];\r
9399f68a
LE
437\r
438 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
439\r
440 Features32[0] = (UINT32)Features;\r
441 Features32[1] = (UINT32)RShiftU64 (Features, 32);\r
442\r
443 for (Selector = 0; Selector < 2; ++Selector) {\r
ac0a286f 444 EFI_STATUS Status;\r
9399f68a
LE
445\r
446 //\r
447 // Select the low or high half of the features.\r
448 //\r
ac0a286f
MK
449 Status = Virtio10Transfer (\r
450 Dev->PciIo,\r
451 &Dev->CommonConfig,\r
452 TRUE,\r
9399f68a 453 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DriverFeatureSelect),\r
ac0a286f
MK
454 sizeof Selector,\r
455 &Selector\r
456 );\r
9399f68a
LE
457 if (EFI_ERROR (Status)) {\r
458 return Status;\r
459 }\r
460\r
461 //\r
462 // Write that half.\r
463 //\r
ac0a286f
MK
464 Status = Virtio10Transfer (\r
465 Dev->PciIo,\r
466 &Dev->CommonConfig,\r
467 TRUE,\r
9399f68a 468 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DriverFeature),\r
ac0a286f
MK
469 sizeof Features32[Selector],\r
470 &Features32[Selector]\r
471 );\r
9399f68a
LE
472 if (EFI_ERROR (Status)) {\r
473 return Status;\r
474 }\r
475 }\r
476\r
477 return EFI_SUCCESS;\r
478}\r
479\r
9399f68a
LE
480STATIC\r
481EFI_STATUS\r
482EFIAPI\r
483Virtio10SetQueueAddress (\r
484 IN VIRTIO_DEVICE_PROTOCOL *This,\r
53a4c604
BS
485 IN VRING *Ring,\r
486 IN UINT64 RingBaseShift\r
9399f68a
LE
487 )\r
488{\r
ac0a286f
MK
489 VIRTIO_1_0_DEV *Dev;\r
490 EFI_STATUS Status;\r
491 UINT64 Address;\r
492 UINT16 Enable;\r
9399f68a
LE
493\r
494 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
495\r
ac0a286f 496 Address = (UINTN)Ring->Desc;\r
60ee5629 497 Address += RingBaseShift;\r
ac0a286f
MK
498 Status = Virtio10Transfer (\r
499 Dev->PciIo,\r
500 &Dev->CommonConfig,\r
501 TRUE,\r
502 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueDesc),\r
503 sizeof Address,\r
504 &Address\r
505 );\r
9399f68a
LE
506 if (EFI_ERROR (Status)) {\r
507 return Status;\r
508 }\r
509\r
ac0a286f 510 Address = (UINTN)Ring->Avail.Flags;\r
60ee5629 511 Address += RingBaseShift;\r
ac0a286f
MK
512 Status = Virtio10Transfer (\r
513 Dev->PciIo,\r
514 &Dev->CommonConfig,\r
515 TRUE,\r
516 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueAvail),\r
517 sizeof Address,\r
518 &Address\r
519 );\r
9399f68a
LE
520 if (EFI_ERROR (Status)) {\r
521 return Status;\r
522 }\r
523\r
ac0a286f 524 Address = (UINTN)Ring->Used.Flags;\r
60ee5629 525 Address += RingBaseShift;\r
ac0a286f
MK
526 Status = Virtio10Transfer (\r
527 Dev->PciIo,\r
528 &Dev->CommonConfig,\r
529 TRUE,\r
530 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueUsed),\r
531 sizeof Address,\r
532 &Address\r
533 );\r
9399f68a
LE
534 if (EFI_ERROR (Status)) {\r
535 return Status;\r
536 }\r
537\r
538 Enable = 1;\r
ac0a286f
MK
539 Status = Virtio10Transfer (\r
540 Dev->PciIo,\r
541 &Dev->CommonConfig,\r
542 TRUE,\r
9399f68a 543 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueEnable),\r
ac0a286f
MK
544 sizeof Enable,\r
545 &Enable\r
546 );\r
9399f68a
LE
547 return Status;\r
548}\r
549\r
9399f68a
LE
550STATIC\r
551EFI_STATUS\r
552EFIAPI\r
553Virtio10SetQueueSel (\r
554 IN VIRTIO_DEVICE_PROTOCOL *This,\r
ac0a286f 555 IN UINT16 Index\r
9399f68a
LE
556 )\r
557{\r
ac0a286f
MK
558 VIRTIO_1_0_DEV *Dev;\r
559 EFI_STATUS Status;\r
9399f68a
LE
560\r
561 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
562\r
ac0a286f
MK
563 Status = Virtio10Transfer (\r
564 Dev->PciIo,\r
565 &Dev->CommonConfig,\r
566 TRUE,\r
9399f68a 567 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),\r
ac0a286f
MK
568 sizeof Index,\r
569 &Index\r
570 );\r
9399f68a
LE
571 return Status;\r
572}\r
573\r
9399f68a
LE
574STATIC\r
575EFI_STATUS\r
576EFIAPI\r
577Virtio10SetQueueNotify (\r
578 IN VIRTIO_DEVICE_PROTOCOL *This,\r
ac0a286f 579 IN UINT16 Index\r
9399f68a
LE
580 )\r
581{\r
ac0a286f
MK
582 VIRTIO_1_0_DEV *Dev;\r
583 EFI_STATUS Status;\r
584 UINT16 SavedQueueSelect;\r
585 UINT16 NotifyOffset;\r
9399f68a
LE
586\r
587 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
588\r
589 //\r
590 // Read NotifyOffset first. NotifyOffset is queue specific, so we have\r
591 // to stash & restore the current queue selector around it.\r
592 //\r
593 // So, start with saving the current queue selector.\r
594 //\r
ac0a286f
MK
595 Status = Virtio10Transfer (\r
596 Dev->PciIo,\r
597 &Dev->CommonConfig,\r
598 FALSE,\r
9399f68a 599 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),\r
ac0a286f
MK
600 sizeof SavedQueueSelect,\r
601 &SavedQueueSelect\r
602 );\r
9399f68a
LE
603 if (EFI_ERROR (Status)) {\r
604 return Status;\r
605 }\r
606\r
607 //\r
608 // Select the requested queue.\r
609 //\r
ac0a286f
MK
610 Status = Virtio10Transfer (\r
611 Dev->PciIo,\r
612 &Dev->CommonConfig,\r
613 TRUE,\r
9399f68a 614 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),\r
ac0a286f
MK
615 sizeof Index,\r
616 &Index\r
617 );\r
9399f68a
LE
618 if (EFI_ERROR (Status)) {\r
619 return Status;\r
620 }\r
621\r
622 //\r
623 // Read the QueueNotifyOff field.\r
624 //\r
ac0a286f
MK
625 Status = Virtio10Transfer (\r
626 Dev->PciIo,\r
627 &Dev->CommonConfig,\r
628 FALSE,\r
9399f68a 629 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueNotifyOff),\r
ac0a286f
MK
630 sizeof NotifyOffset,\r
631 &NotifyOffset\r
632 );\r
9399f68a
LE
633 if (EFI_ERROR (Status)) {\r
634 return Status;\r
635 }\r
636\r
637 //\r
638 // Re-select the original queue.\r
639 //\r
ac0a286f
MK
640 Status = Virtio10Transfer (\r
641 Dev->PciIo,\r
642 &Dev->CommonConfig,\r
643 TRUE,\r
9399f68a 644 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),\r
ac0a286f
MK
645 sizeof SavedQueueSelect,\r
646 &SavedQueueSelect\r
647 );\r
9399f68a
LE
648 if (EFI_ERROR (Status)) {\r
649 return Status;\r
650 }\r
651\r
652 //\r
653 // We can now kick the queue.\r
654 //\r
ac0a286f
MK
655 Status = Virtio10Transfer (\r
656 Dev->PciIo,\r
657 &Dev->NotifyConfig,\r
658 TRUE,\r
9399f68a 659 NotifyOffset * Dev->NotifyOffsetMultiplier,\r
ac0a286f
MK
660 sizeof Index,\r
661 &Index\r
662 );\r
9399f68a
LE
663 return Status;\r
664}\r
665\r
9399f68a
LE
666STATIC\r
667EFI_STATUS\r
668EFIAPI\r
669Virtio10SetQueueAlign (\r
670 IN VIRTIO_DEVICE_PROTOCOL *This,\r
ac0a286f 671 IN UINT32 Alignment\r
9399f68a
LE
672 )\r
673{\r
674 return (Alignment == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;\r
675}\r
676\r
9399f68a
LE
677STATIC\r
678EFI_STATUS\r
679EFIAPI\r
680Virtio10SetPageSize (\r
681 IN VIRTIO_DEVICE_PROTOCOL *This,\r
ac0a286f 682 IN UINT32 PageSize\r
9399f68a
LE
683 )\r
684{\r
685 return (PageSize == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;\r
686}\r
687\r
9399f68a
LE
688STATIC\r
689EFI_STATUS\r
690EFIAPI\r
691Virtio10GetQueueNumMax (\r
692 IN VIRTIO_DEVICE_PROTOCOL *This,\r
693 OUT UINT16 *QueueNumMax\r
694 )\r
695{\r
ac0a286f
MK
696 VIRTIO_1_0_DEV *Dev;\r
697 EFI_STATUS Status;\r
9399f68a
LE
698\r
699 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
700\r
ac0a286f
MK
701 Status = Virtio10Transfer (\r
702 Dev->PciIo,\r
703 &Dev->CommonConfig,\r
704 FALSE,\r
9399f68a 705 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSize),\r
ac0a286f
MK
706 sizeof *QueueNumMax,\r
707 QueueNumMax\r
708 );\r
9399f68a
LE
709 return Status;\r
710}\r
711\r
9399f68a
LE
712STATIC\r
713EFI_STATUS\r
714EFIAPI\r
715Virtio10SetQueueNum (\r
716 IN VIRTIO_DEVICE_PROTOCOL *This,\r
ac0a286f 717 IN UINT16 QueueSize\r
9399f68a
LE
718 )\r
719{\r
ac0a286f
MK
720 EFI_STATUS Status;\r
721 UINT16 CurrentSize;\r
9399f68a
LE
722\r
723 //\r
724 // This member function is required for VirtIo MMIO, and a no-op in\r
725 // VirtIo PCI 0.9.5. In VirtIo 1.0, drivers can theoretically use this\r
726 // member to reduce memory consumption, but none of our drivers do. So\r
727 // just check that they set the size that is already in effect.\r
728 //\r
729 Status = Virtio10GetQueueNumMax (This, &CurrentSize);\r
730 if (EFI_ERROR (Status)) {\r
731 return Status;\r
732 }\r
ac0a286f 733\r
9399f68a
LE
734 return (CurrentSize == QueueSize) ? EFI_SUCCESS : EFI_UNSUPPORTED;\r
735}\r
736\r
9399f68a
LE
737STATIC\r
738EFI_STATUS\r
739EFIAPI\r
740Virtio10GetDeviceStatus (\r
741 IN VIRTIO_DEVICE_PROTOCOL *This,\r
742 OUT UINT8 *DeviceStatus\r
743 )\r
744{\r
ac0a286f
MK
745 VIRTIO_1_0_DEV *Dev;\r
746 EFI_STATUS Status;\r
9399f68a
LE
747\r
748 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
749\r
ac0a286f
MK
750 Status = Virtio10Transfer (\r
751 Dev->PciIo,\r
752 &Dev->CommonConfig,\r
753 FALSE,\r
9399f68a 754 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceStatus),\r
ac0a286f
MK
755 sizeof *DeviceStatus,\r
756 DeviceStatus\r
757 );\r
9399f68a
LE
758 return Status;\r
759}\r
760\r
9399f68a
LE
761STATIC\r
762EFI_STATUS\r
763EFIAPI\r
764Virtio10SetDeviceStatus (\r
765 IN VIRTIO_DEVICE_PROTOCOL *This,\r
766 IN UINT8 DeviceStatus\r
767 )\r
768{\r
ac0a286f
MK
769 VIRTIO_1_0_DEV *Dev;\r
770 EFI_STATUS Status;\r
9399f68a
LE
771\r
772 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
773\r
ac0a286f
MK
774 Status = Virtio10Transfer (\r
775 Dev->PciIo,\r
776 &Dev->CommonConfig,\r
777 TRUE,\r
9399f68a 778 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceStatus),\r
ac0a286f
MK
779 sizeof DeviceStatus,\r
780 &DeviceStatus\r
781 );\r
9399f68a
LE
782 return Status;\r
783}\r
784\r
9399f68a
LE
785STATIC\r
786EFI_STATUS\r
787EFIAPI\r
788Virtio10WriteDevice (\r
ac0a286f
MK
789 IN VIRTIO_DEVICE_PROTOCOL *This,\r
790 IN UINTN FieldOffset,\r
791 IN UINTN FieldSize,\r
792 IN UINT64 Value\r
9399f68a
LE
793 )\r
794{\r
ac0a286f
MK
795 VIRTIO_1_0_DEV *Dev;\r
796 EFI_STATUS Status;\r
9399f68a
LE
797\r
798 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
799\r
ac0a286f
MK
800 Status = Virtio10Transfer (\r
801 Dev->PciIo,\r
802 &Dev->SpecificConfig,\r
803 TRUE,\r
804 FieldOffset,\r
805 FieldSize,\r
806 &Value\r
807 );\r
9399f68a
LE
808 return Status;\r
809}\r
810\r
9399f68a
LE
811STATIC\r
812EFI_STATUS\r
813EFIAPI\r
814Virtio10ReadDevice (\r
ac0a286f
MK
815 IN VIRTIO_DEVICE_PROTOCOL *This,\r
816 IN UINTN FieldOffset,\r
817 IN UINTN FieldSize,\r
818 IN UINTN BufferSize,\r
819 OUT VOID *Buffer\r
9399f68a
LE
820 )\r
821{\r
ac0a286f
MK
822 VIRTIO_1_0_DEV *Dev;\r
823 EFI_STATUS Status;\r
9399f68a
LE
824\r
825 if (FieldSize != BufferSize) {\r
826 return EFI_INVALID_PARAMETER;\r
827 }\r
828\r
829 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
830\r
ac0a286f
MK
831 Status = Virtio10Transfer (\r
832 Dev->PciIo,\r
833 &Dev->SpecificConfig,\r
834 FALSE,\r
835 FieldOffset,\r
836 FieldSize,\r
837 Buffer\r
838 );\r
9399f68a
LE
839 return Status;\r
840}\r
841\r
de1c57c5
BS
842STATIC\r
843EFI_STATUS\r
844EFIAPI\r
845Virtio10AllocateSharedPages (\r
846 IN VIRTIO_DEVICE_PROTOCOL *This,\r
847 IN UINTN Pages,\r
848 IN OUT VOID **HostAddress\r
849 )\r
850{\r
ac0a286f
MK
851 VIRTIO_1_0_DEV *Dev;\r
852 EFI_STATUS Status;\r
de1c57c5
BS
853\r
854 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
855\r
856 Status = Dev->PciIo->AllocateBuffer (\r
857 Dev->PciIo,\r
858 AllocateAnyPages,\r
859 EfiBootServicesData,\r
860 Pages,\r
861 HostAddress,\r
862 EFI_PCI_ATTRIBUTE_MEMORY_CACHED\r
863 );\r
864 return Status;\r
865}\r
866\r
867STATIC\r
868VOID\r
869EFIAPI\r
870Virtio10FreeSharedPages (\r
871 IN VIRTIO_DEVICE_PROTOCOL *This,\r
872 IN UINTN Pages,\r
873 IN VOID *HostAddress\r
874 )\r
875{\r
ac0a286f 876 VIRTIO_1_0_DEV *Dev;\r
de1c57c5
BS
877\r
878 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
879\r
880 Dev->PciIo->FreeBuffer (\r
881 Dev->PciIo,\r
882 Pages,\r
883 HostAddress\r
884 );\r
885}\r
886\r
887STATIC\r
888EFI_STATUS\r
889EFIAPI\r
890Virtio10MapSharedBuffer (\r
891 IN VIRTIO_DEVICE_PROTOCOL *This,\r
892 IN VIRTIO_MAP_OPERATION Operation,\r
893 IN VOID *HostAddress,\r
894 IN OUT UINTN *NumberOfBytes,\r
895 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
896 OUT VOID **Mapping\r
897 )\r
898{\r
ac0a286f
MK
899 EFI_STATUS Status;\r
900 VIRTIO_1_0_DEV *Dev;\r
901 EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation;\r
de1c57c5
BS
902\r
903 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
904\r
905 //\r
906 // Map VIRTIO_MAP_OPERATION to EFI_PCI_IO_PROTOCOL_OPERATION\r
907 //\r
908 switch (Operation) {\r
ac0a286f
MK
909 case VirtioOperationBusMasterRead:\r
910 PciIoOperation = EfiPciIoOperationBusMasterRead;\r
911 break;\r
912 case VirtioOperationBusMasterWrite:\r
913 PciIoOperation = EfiPciIoOperationBusMasterWrite;\r
914 break;\r
915 case VirtioOperationBusMasterCommonBuffer:\r
916 PciIoOperation = EfiPciIoOperationBusMasterCommonBuffer;\r
917 break;\r
918 default:\r
919 return EFI_INVALID_PARAMETER;\r
de1c57c5
BS
920 }\r
921\r
922 Status = Dev->PciIo->Map (\r
923 Dev->PciIo,\r
924 PciIoOperation,\r
925 HostAddress,\r
926 NumberOfBytes,\r
927 DeviceAddress,\r
928 Mapping\r
929 );\r
930 return Status;\r
931}\r
932\r
933STATIC\r
934EFI_STATUS\r
935EFIAPI\r
936Virtio10UnmapSharedBuffer (\r
937 IN VIRTIO_DEVICE_PROTOCOL *This,\r
938 IN VOID *Mapping\r
939 )\r
940{\r
941 EFI_STATUS Status;\r
942 VIRTIO_1_0_DEV *Dev;\r
943\r
944 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);\r
945\r
946 Status = Dev->PciIo->Unmap (\r
947 Dev->PciIo,\r
948 Mapping\r
949 );\r
950\r
951 return Status;\r
952}\r
9399f68a 953\r
ac0a286f
MK
954STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate = {\r
955 VIRTIO_SPEC_REVISION (1, 0, 0),\r
956 0, // SubSystemDeviceId, filled in dynamically\r
9399f68a
LE
957 Virtio10GetDeviceFeatures,\r
958 Virtio10SetGuestFeatures,\r
959 Virtio10SetQueueAddress,\r
960 Virtio10SetQueueSel,\r
961 Virtio10SetQueueNotify,\r
962 Virtio10SetQueueAlign,\r
963 Virtio10SetPageSize,\r
964 Virtio10GetQueueNumMax,\r
965 Virtio10SetQueueNum,\r
966 Virtio10GetDeviceStatus,\r
967 Virtio10SetDeviceStatus,\r
968 Virtio10WriteDevice,\r
de1c57c5
BS
969 Virtio10ReadDevice,\r
970 Virtio10AllocateSharedPages,\r
971 Virtio10FreeSharedPages,\r
972 Virtio10MapSharedBuffer,\r
973 Virtio10UnmapSharedBuffer\r
9399f68a
LE
974};\r
975\r
9399f68a
LE
976//\r
977// EFI_DRIVER_BINDING_PROTOCOL member functions\r
978//\r
979\r
980STATIC\r
981EFI_STATUS\r
982EFIAPI\r
983Virtio10BindingSupported (\r
ac0a286f
MK
984 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
985 IN EFI_HANDLE DeviceHandle,\r
986 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
9399f68a
LE
987 )\r
988{\r
ac0a286f
MK
989 EFI_STATUS Status;\r
990 EFI_PCI_IO_PROTOCOL *PciIo;\r
991 PCI_TYPE00 Pci;\r
992\r
993 Status = gBS->OpenProtocol (\r
994 DeviceHandle,\r
995 &gEfiPciIoProtocolGuid,\r
996 (VOID **)&PciIo,\r
997 This->DriverBindingHandle,\r
998 DeviceHandle,\r
999 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1000 );\r
9399f68a
LE
1001 if (EFI_ERROR (Status)) {\r
1002 return Status;\r
1003 }\r
1004\r
ac0a286f
MK
1005 Status = PciIo->Pci.Read (\r
1006 PciIo,\r
1007 EfiPciIoWidthUint32,\r
1008 0,\r
1009 sizeof Pci / sizeof (UINT32),\r
1010 &Pci\r
1011 );\r
9399f68a
LE
1012 if (EFI_ERROR (Status)) {\r
1013 goto CloseProtocol;\r
1014 }\r
1015\r
76569ca8 1016 Status = EFI_UNSUPPORTED;\r
9399f68a
LE
1017 //\r
1018 // Recognize non-transitional modern devices. Also, we'll have to parse the\r
1019 // PCI capability list, so make sure the CapabilityPtr field will be valid.\r
1020 //\r
ac0a286f
MK
1021 if ((Pci.Hdr.VendorId == VIRTIO_VENDOR_ID) &&\r
1022 (Pci.Hdr.DeviceId >= 0x1040) &&\r
1023 (Pci.Hdr.DeviceId <= 0x107F) &&\r
1024 (Pci.Hdr.RevisionID >= 0x01) &&\r
1025 (Pci.Device.SubsystemID >= 0x40) &&\r
1026 ((Pci.Hdr.Status & EFI_PCI_STATUS_CAPABILITY) != 0))\r
1027 {\r
76569ca8
LE
1028 //\r
1029 // The virtio-vga device is special. It can be driven both as a VGA device\r
1030 // with a linear framebuffer, and through its underlying, modern,\r
1031 // virtio-gpu-pci device, which has no linear framebuffer itself. For\r
1032 // compatibility with guest OSes that insist on inheriting a linear\r
1033 // framebuffer from the firmware, we should leave virtio-vga to\r
1034 // QemuVideoDxe, and support only virtio-gpu-pci here.\r
1035 //\r
1036 // Both virtio-vga and virtio-gpu-pci have DeviceId 0x1050, but only the\r
1037 // former has device class PCI_CLASS_DISPLAY_VGA.\r
1038 //\r
ac0a286f 1039 if ((Pci.Hdr.DeviceId != 0x1050) || !IS_PCI_VGA (&Pci)) {\r
76569ca8
LE
1040 Status = EFI_SUCCESS;\r
1041 }\r
9399f68a
LE
1042 }\r
1043\r
1044CloseProtocol:\r
ac0a286f
MK
1045 gBS->CloseProtocol (\r
1046 DeviceHandle,\r
1047 &gEfiPciIoProtocolGuid,\r
1048 This->DriverBindingHandle,\r
1049 DeviceHandle\r
1050 );\r
9399f68a
LE
1051\r
1052 return Status;\r
1053}\r
1054\r
9399f68a
LE
1055STATIC\r
1056EFI_STATUS\r
1057EFIAPI\r
1058Virtio10BindingStart (\r
ac0a286f
MK
1059 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1060 IN EFI_HANDLE DeviceHandle,\r
1061 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
9399f68a
LE
1062 )\r
1063{\r
ac0a286f
MK
1064 VIRTIO_1_0_DEV *Device;\r
1065 EFI_STATUS Status;\r
1066 PCI_TYPE00 Pci;\r
1067 UINT64 SetAttributes;\r
9399f68a
LE
1068\r
1069 Device = AllocateZeroPool (sizeof *Device);\r
1070 if (Device == NULL) {\r
1071 return EFI_OUT_OF_RESOURCES;\r
1072 }\r
1073\r
1074 Device->Signature = VIRTIO_1_0_SIGNATURE;\r
1075 CopyMem (&Device->VirtIo, &mVirtIoTemplate, sizeof mVirtIoTemplate);\r
1076\r
ac0a286f
MK
1077 Status = gBS->OpenProtocol (\r
1078 DeviceHandle,\r
1079 &gEfiPciIoProtocolGuid,\r
1080 (VOID **)&Device->PciIo,\r
1081 This->DriverBindingHandle,\r
1082 DeviceHandle,\r
1083 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1084 );\r
9399f68a
LE
1085 if (EFI_ERROR (Status)) {\r
1086 goto FreeDevice;\r
1087 }\r
1088\r
ac0a286f
MK
1089 Status = Device->PciIo->Pci.Read (\r
1090 Device->PciIo,\r
1091 EfiPciIoWidthUint32,\r
1092 0,\r
1093 sizeof Pci / sizeof (UINT32),\r
1094 &Pci\r
1095 );\r
9399f68a
LE
1096 if (EFI_ERROR (Status)) {\r
1097 goto ClosePciIo;\r
1098 }\r
1099\r
1100 Device->VirtIo.SubSystemDeviceId = Pci.Hdr.DeviceId - 0x1040;\r
1101\r
5685a243 1102 Status = ParseCapabilities (Device);\r
9399f68a
LE
1103 if (EFI_ERROR (Status)) {\r
1104 goto ClosePciIo;\r
1105 }\r
1106\r
ac0a286f
MK
1107 Status = Device->PciIo->Attributes (\r
1108 Device->PciIo,\r
1109 EfiPciIoAttributeOperationGet,\r
1110 0,\r
1111 &Device->OriginalPciAttributes\r
1112 );\r
9399f68a
LE
1113 if (EFI_ERROR (Status)) {\r
1114 goto ClosePciIo;\r
1115 }\r
1116\r
de1c57c5
BS
1117 SetAttributes = (EFI_PCI_IO_ATTRIBUTE_BUS_MASTER |\r
1118 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);\r
9399f68a
LE
1119 UpdateAttributes (&Device->CommonConfig, &SetAttributes);\r
1120 UpdateAttributes (&Device->NotifyConfig, &SetAttributes);\r
1121 UpdateAttributes (&Device->SpecificConfig, &SetAttributes);\r
ac0a286f
MK
1122 Status = Device->PciIo->Attributes (\r
1123 Device->PciIo,\r
1124 EfiPciIoAttributeOperationEnable,\r
1125 SetAttributes,\r
1126 NULL\r
1127 );\r
9399f68a
LE
1128 if (EFI_ERROR (Status)) {\r
1129 goto ClosePciIo;\r
1130 }\r
1131\r
ac0a286f
MK
1132 Status = gBS->InstallProtocolInterface (\r
1133 &DeviceHandle,\r
1134 &gVirtioDeviceProtocolGuid,\r
1135 EFI_NATIVE_INTERFACE,\r
1136 &Device->VirtIo\r
1137 );\r
9399f68a
LE
1138 if (EFI_ERROR (Status)) {\r
1139 goto RestorePciAttributes;\r
1140 }\r
1141\r
1142 return EFI_SUCCESS;\r
1143\r
1144RestorePciAttributes:\r
ac0a286f
MK
1145 Device->PciIo->Attributes (\r
1146 Device->PciIo,\r
1147 EfiPciIoAttributeOperationSet,\r
1148 Device->OriginalPciAttributes,\r
1149 NULL\r
1150 );\r
9399f68a
LE
1151\r
1152ClosePciIo:\r
ac0a286f
MK
1153 gBS->CloseProtocol (\r
1154 DeviceHandle,\r
1155 &gEfiPciIoProtocolGuid,\r
1156 This->DriverBindingHandle,\r
1157 DeviceHandle\r
1158 );\r
9399f68a
LE
1159\r
1160FreeDevice:\r
1161 FreePool (Device);\r
1162\r
1163 return Status;\r
1164}\r
1165\r
9399f68a
LE
1166STATIC\r
1167EFI_STATUS\r
1168EFIAPI\r
1169Virtio10BindingStop (\r
ac0a286f
MK
1170 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1171 IN EFI_HANDLE DeviceHandle,\r
1172 IN UINTN NumberOfChildren,\r
1173 IN EFI_HANDLE *ChildHandleBuffer\r
9399f68a
LE
1174 )\r
1175{\r
ac0a286f
MK
1176 EFI_STATUS Status;\r
1177 VIRTIO_DEVICE_PROTOCOL *VirtIo;\r
1178 VIRTIO_1_0_DEV *Device;\r
1179\r
1180 Status = gBS->OpenProtocol (\r
1181 DeviceHandle,\r
1182 &gVirtioDeviceProtocolGuid,\r
1183 (VOID **)&VirtIo,\r
1184 This->DriverBindingHandle,\r
1185 DeviceHandle,\r
1186 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1187 );\r
9399f68a
LE
1188 if (EFI_ERROR (Status)) {\r
1189 return Status;\r
1190 }\r
1191\r
1192 Device = VIRTIO_1_0_FROM_VIRTIO_DEVICE (VirtIo);\r
1193\r
ac0a286f
MK
1194 Status = gBS->UninstallProtocolInterface (\r
1195 DeviceHandle,\r
1196 &gVirtioDeviceProtocolGuid,\r
1197 &Device->VirtIo\r
1198 );\r
9399f68a
LE
1199 if (EFI_ERROR (Status)) {\r
1200 return Status;\r
1201 }\r
1202\r
ac0a286f
MK
1203 Device->PciIo->Attributes (\r
1204 Device->PciIo,\r
1205 EfiPciIoAttributeOperationSet,\r
1206 Device->OriginalPciAttributes,\r
1207 NULL\r
1208 );\r
1209 gBS->CloseProtocol (\r
1210 DeviceHandle,\r
1211 &gEfiPciIoProtocolGuid,\r
1212 This->DriverBindingHandle,\r
1213 DeviceHandle\r
1214 );\r
9399f68a
LE
1215 FreePool (Device);\r
1216\r
1217 return EFI_SUCCESS;\r
1218}\r
1219\r
ac0a286f 1220STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = {\r
9399f68a
LE
1221 &Virtio10BindingSupported,\r
1222 &Virtio10BindingStart,\r
1223 &Virtio10BindingStop,\r
1224 0x10, // Version\r
1225 NULL, // ImageHandle, to be overwritten\r
1226 NULL // DriverBindingHandle, to be overwritten\r
1227};\r
1228\r
9399f68a
LE
1229//\r
1230// EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL\r
1231// implementations\r
1232//\r
1233\r
1234STATIC\r
ac0a286f 1235EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {\r
9399f68a
LE
1236 { "eng;en", L"Virtio 1.0 PCI Driver" },\r
1237 { NULL, NULL }\r
1238};\r
1239\r
1240STATIC\r
ac0a286f 1241EFI_COMPONENT_NAME_PROTOCOL mComponentName;\r
9399f68a
LE
1242\r
1243STATIC\r
1244EFI_STATUS\r
1245EFIAPI\r
1246Virtio10GetDriverName (\r
ac0a286f
MK
1247 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
1248 IN CHAR8 *Language,\r
1249 OUT CHAR16 **DriverName\r
9399f68a
LE
1250 )\r
1251{\r
1252 return LookupUnicodeString2 (\r
1253 Language,\r
1254 This->SupportedLanguages,\r
1255 mDriverNameTable,\r
1256 DriverName,\r
1257 (BOOLEAN)(This == &mComponentName) // Iso639Language\r
1258 );\r
1259}\r
1260\r
1261STATIC\r
1262EFI_STATUS\r
1263EFIAPI\r
1264Virtio10GetDeviceName (\r
ac0a286f
MK
1265 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
1266 IN EFI_HANDLE DeviceHandle,\r
1267 IN EFI_HANDLE ChildHandle,\r
1268 IN CHAR8 *Language,\r
1269 OUT CHAR16 **ControllerName\r
9399f68a
LE
1270 )\r
1271{\r
1272 return EFI_UNSUPPORTED;\r
1273}\r
1274\r
1275STATIC\r
ac0a286f 1276EFI_COMPONENT_NAME_PROTOCOL mComponentName = {\r
9399f68a
LE
1277 &Virtio10GetDriverName,\r
1278 &Virtio10GetDeviceName,\r
1279 "eng"\r
1280};\r
1281\r
1282STATIC\r
ac0a286f
MK
1283EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {\r
1284 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&Virtio10GetDriverName,\r
1285 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&Virtio10GetDeviceName,\r
9399f68a
LE
1286 "en"\r
1287};\r
1288\r
9399f68a
LE
1289//\r
1290// Entry point of this driver\r
1291//\r
1292\r
1293EFI_STATUS\r
1294EFIAPI\r
1295Virtio10EntryPoint (\r
ac0a286f
MK
1296 IN EFI_HANDLE ImageHandle,\r
1297 IN EFI_SYSTEM_TABLE *SystemTable\r
9399f68a
LE
1298 )\r
1299{\r
1300 return EfiLibInstallDriverBindingComponentName2 (\r
1301 ImageHandle,\r
1302 SystemTable,\r
1303 &mDriverBinding,\r
1304 ImageHandle,\r
1305 &mComponentName,\r
1306 &mComponentName2\r
1307 );\r
1308}\r