OvmfPkg/VirtioGpuDxe: initialize and tear down VirtIo GPU device
[mirror_edk2.git] / OvmfPkg / VirtioGpuDxe / Commands.c
CommitLineData
c5f235bb
LE
1/** @file\r
2\r
3 VirtIo GPU initialization, and commands (primitives) for the GPU device.\r
4\r
5 Copyright (C) 2016, Red Hat, Inc.\r
6\r
7 This program and the accompanying materials are licensed and made available\r
8 under the terms and conditions of the BSD License which accompanies this\r
9 distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
13 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include <IndustryStandard/VirtioGpu.h>\r
18#include <Library/VirtioLib.h>\r
19\r
20#include "VirtioGpu.h"\r
21\r
22/**\r
23 Configure the VirtIo GPU device that underlies VgpuDev.\r
24\r
25 @param[in,out] VgpuDev The VGPU_DEV object to set up VirtIo messaging for.\r
26 On input, the caller is responsible for having\r
27 initialized VgpuDev->VirtIo. On output, VgpuDev->Ring\r
28 has been initialized, and synchronous VirtIo GPU\r
29 commands (primitives) can be submitted to the device.\r
30\r
31 @retval EFI_SUCCESS VirtIo GPU configuration successful.\r
32\r
33 @retval EFI_UNSUPPORTED The host-side configuration of the VirtIo GPU is not\r
34 supported by this driver.\r
35\r
36 @retval Error codes from underlying functions.\r
37**/\r
38EFI_STATUS\r
39VirtioGpuInit (\r
40 IN OUT VGPU_DEV *VgpuDev\r
41 )\r
42{\r
43 UINT8 NextDevStat;\r
44 EFI_STATUS Status;\r
45 UINT64 Features;\r
46 UINT16 QueueSize;\r
47\r
48 //\r
49 // Execute virtio-v1.0-cs04, 3.1.1 Driver Requirements: Device\r
50 // Initialization.\r
51 //\r
52 // 1. Reset the device.\r
53 //\r
54 NextDevStat = 0;\r
55 Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);\r
56 if (EFI_ERROR (Status)) {\r
57 goto Failed;\r
58 }\r
59\r
60 //\r
61 // 2. Set the ACKNOWLEDGE status bit [...]\r
62 //\r
63 NextDevStat |= VSTAT_ACK;\r
64 Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);\r
65 if (EFI_ERROR (Status)) {\r
66 goto Failed;\r
67 }\r
68\r
69 //\r
70 // 3. Set the DRIVER status bit [...]\r
71 //\r
72 NextDevStat |= VSTAT_DRIVER;\r
73 Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);\r
74 if (EFI_ERROR (Status)) {\r
75 goto Failed;\r
76 }\r
77\r
78 //\r
79 // 4. Read device feature bits...\r
80 //\r
81 Status = VgpuDev->VirtIo->GetDeviceFeatures (VgpuDev->VirtIo, &Features);\r
82 if (EFI_ERROR (Status)) {\r
83 goto Failed;\r
84 }\r
85 if ((Features & VIRTIO_F_VERSION_1) == 0) {\r
86 Status = EFI_UNSUPPORTED;\r
87 goto Failed;\r
88 }\r
89 //\r
90 // We only want the most basic 2D features.\r
91 //\r
92 Features &= VIRTIO_F_VERSION_1;\r
93\r
94 //\r
95 // ... and write the subset of feature bits understood by the [...] driver to\r
96 // the device. [...]\r
97 // 5. Set the FEATURES_OK status bit.\r
98 // 6. Re-read device status to ensure the FEATURES_OK bit is still set [...]\r
99 //\r
100 Status = Virtio10WriteFeatures (VgpuDev->VirtIo, Features, &NextDevStat);\r
101 if (EFI_ERROR (Status)) {\r
102 goto Failed;\r
103 }\r
104\r
105 //\r
106 // 7. Perform device-specific setup, including discovery of virtqueues for\r
107 // the device [...]\r
108 //\r
109 Status = VgpuDev->VirtIo->SetQueueSel (VgpuDev->VirtIo,\r
110 VIRTIO_GPU_CONTROL_QUEUE);\r
111 if (EFI_ERROR (Status)) {\r
112 goto Failed;\r
113 }\r
114 Status = VgpuDev->VirtIo->GetQueueNumMax (VgpuDev->VirtIo, &QueueSize);\r
115 if (EFI_ERROR (Status)) {\r
116 goto Failed;\r
117 }\r
118\r
119 //\r
120 // We implement each VirtIo GPU command that we use with two descriptors:\r
121 // request, response.\r
122 //\r
123 if (QueueSize < 2) {\r
124 Status = EFI_UNSUPPORTED;\r
125 goto Failed;\r
126 }\r
127\r
128 //\r
129 // [...] population of virtqueues [...]\r
130 //\r
131 Status = VirtioRingInit (QueueSize, &VgpuDev->Ring);\r
132 if (EFI_ERROR (Status)) {\r
133 goto Failed;\r
134 }\r
135 Status = VgpuDev->VirtIo->SetQueueAddress (VgpuDev->VirtIo, &VgpuDev->Ring);\r
136 if (EFI_ERROR (Status)) {\r
137 goto ReleaseQueue;\r
138 }\r
139\r
140 //\r
141 // 8. Set the DRIVER_OK status bit.\r
142 //\r
143 NextDevStat |= VSTAT_DRIVER_OK;\r
144 Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);\r
145 if (EFI_ERROR (Status)) {\r
146 goto ReleaseQueue;\r
147 }\r
148\r
149 return EFI_SUCCESS;\r
150\r
151ReleaseQueue:\r
152 VirtioRingUninit (&VgpuDev->Ring);\r
153\r
154Failed:\r
155 //\r
156 // If any of these steps go irrecoverably wrong, the driver SHOULD set the\r
157 // FAILED status bit to indicate that it has given up on the device (it can\r
158 // reset the device later to restart if desired). [...]\r
159 //\r
160 // VirtIo access failure here should not mask the original error.\r
161 //\r
162 NextDevStat |= VSTAT_FAILED;\r
163 VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);\r
164\r
165 return Status;\r
166}\r
167\r
168/**\r
169 De-configure the VirtIo GPU device that underlies VgpuDev.\r
170\r
171 @param[in,out] VgpuDev The VGPU_DEV object to tear down VirtIo messaging\r
172 for. On input, the caller is responsible for having\r
173 called VirtioGpuInit(). On output, VgpuDev->Ring has\r
174 been uninitialized; VirtIo GPU commands (primitives)\r
175 can no longer be submitted to the device.\r
176**/\r
177VOID\r
178VirtioGpuUninit (\r
179 IN OUT VGPU_DEV *VgpuDev\r
180 )\r
181{\r
182 //\r
183 // Resetting the VirtIo device makes it release its resources and forget its\r
184 // configuration.\r
185 //\r
186 VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, 0);\r
187 VirtioRingUninit (&VgpuDev->Ring);\r
188}\r
189\r
190/**\r
191 EFI_EVENT_NOTIFY function for the VGPU_DEV.ExitBoot event. It resets the\r
192 VirtIo device, causing it to release its resources and to forget its\r
193 configuration.\r
194\r
195 This function may only be called (that is, VGPU_DEV.ExitBoot may only be\r
196 signaled) after VirtioGpuInit() returns and before VirtioGpuUninit() is\r
197 called.\r
198\r
199 @param[in] Event Event whose notification function is being invoked.\r
200\r
201 @param[in] Context Pointer to the associated VGPU_DEV object.\r
202**/\r
203VOID\r
204EFIAPI\r
205VirtioGpuExitBoot (\r
206 IN EFI_EVENT Event,\r
207 IN VOID *Context\r
208 )\r
209{\r
210 VGPU_DEV *VgpuDev;\r
211\r
212 VgpuDev = Context;\r
213 VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, 0);\r
214}\r