TianoCore EDK2 master
Loading...
Searching...
No Matches
VirtioSerialRing.c
Go to the documentation of this file.
1
12#include <Library/DebugLib.h>
15#include <Library/UefiLib.h>
16#include <Library/VirtioLib.h>
17
18#include "VirtioSerial.h"
19
21VOID *
22BufferPtr (
24 IN UINT32 BufferNr
25 )
26{
27 return Ring->Buffers + Ring->BufferSize * BufferNr;
28}
29
32BufferAddr (
34 IN UINT32 BufferNr
35 )
36{
37 return Ring->DeviceAddress + Ring->BufferSize * BufferNr;
38}
39
41UINT32
42BufferNext (
44 )
45{
46 return Ring->Indices.NextDescIdx % Ring->Ring.QueueSize;
47}
48
50EFIAPI
51VirtioSerialInitRing (
53 IN UINT16 Index,
54 IN UINT32 BufferSize
55 )
56{
57 VIRTIO_SERIAL_RING *Ring = Dev->Rings + Index;
58 EFI_STATUS Status;
59 UINT16 QueueSize;
60 UINT64 RingBaseShift;
61
62 //
63 // step 4b -- allocate request virtqueue
64 //
65 Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, Index);
66 if (EFI_ERROR (Status)) {
67 goto Failed;
68 }
69
70 Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
71 if (EFI_ERROR (Status)) {
72 goto Failed;
73 }
74
75 //
76 // VirtioSerial uses one descriptor
77 //
78 if (QueueSize < 1) {
79 Status = EFI_UNSUPPORTED;
80 goto Failed;
81 }
82
83 Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Ring->Ring);
84 if (EFI_ERROR (Status)) {
85 goto Failed;
86 }
87
88 //
89 // If anything fails from here on, we must release the ring resources.
90 //
91 Status = VirtioRingMap (
92 Dev->VirtIo,
93 &Ring->Ring,
94 &RingBaseShift,
95 &Ring->RingMap
96 );
97 if (EFI_ERROR (Status)) {
98 goto ReleaseQueue;
99 }
100
101 //
102 // Additional steps for MMIO: align the queue appropriately, and set the
103 // size. If anything fails from here on, we must unmap the ring resources.
104 //
105 Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
106 if (EFI_ERROR (Status)) {
107 goto UnmapQueue;
108 }
109
110 Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
111 if (EFI_ERROR (Status)) {
112 goto UnmapQueue;
113 }
114
115 //
116 // step 4c -- Report GPFN (guest-physical frame number) of queue.
117 //
118 Status = Dev->VirtIo->SetQueueAddress (
119 Dev->VirtIo,
120 &Ring->Ring,
121 RingBaseShift
122 );
123 if (EFI_ERROR (Status)) {
124 goto UnmapQueue;
125 }
126
127 Ring->BufferCount = QueueSize;
128 Ring->BufferSize = BufferSize;
129 Ring->BufferPages = EFI_SIZE_TO_PAGES (Ring->BufferCount * Ring->BufferSize);
130
131 Status = Dev->VirtIo->AllocateSharedPages (Dev->VirtIo, Ring->BufferPages, (VOID **)&Ring->Buffers);
132 if (EFI_ERROR (Status)) {
133 goto UnmapQueue;
134 }
135
137 Dev->VirtIo,
138 VirtioOperationBusMasterCommonBuffer,
139 Ring->Buffers,
140 EFI_PAGES_TO_SIZE (Ring->BufferPages),
141 &Ring->DeviceAddress,
142 &Ring->BufferMap
143 );
144 if (EFI_ERROR (Status)) {
145 goto ReleasePages;
146 }
147
148 VirtioPrepare (&Ring->Ring, &Ring->Indices);
149 Ring->Ready = TRUE;
150
151 return EFI_SUCCESS;
152
153ReleasePages:
154 Dev->VirtIo->FreeSharedPages (
155 Dev->VirtIo,
156 Ring->BufferPages,
157 Ring->Buffers
158 );
159 Ring->Buffers = NULL;
160
161UnmapQueue:
162 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Ring->RingMap);
163 Ring->RingMap = NULL;
164
165ReleaseQueue:
166 VirtioRingUninit (Dev->VirtIo, &Ring->Ring);
167
168Failed:
169 return Status;
170}
171
172VOID
173EFIAPI
174VirtioSerialUninitRing (
176 IN UINT16 Index
177 )
178{
179 VIRTIO_SERIAL_RING *Ring = Dev->Rings + Index;
180
181 if (Ring->BufferMap) {
182 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Ring->BufferMap);
183 Ring->BufferMap = NULL;
184 }
185
186 if (Ring->Buffers) {
187 Dev->VirtIo->FreeSharedPages (
188 Dev->VirtIo,
189 Ring->BufferPages,
190 Ring->Buffers
191 );
192 Ring->Buffers = NULL;
193 }
194
195 if (!Ring->RingMap) {
196 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Ring->RingMap);
197 Ring->RingMap = NULL;
198 }
199
200 if (Ring->Ring.Base) {
201 VirtioRingUninit (Dev->VirtIo, &Ring->Ring);
202 }
203
204 ZeroMem (Ring, sizeof (*Ring));
205}
206
207VOID
208EFIAPI
209VirtioSerialRingFillRx (
211 IN UINT16 Index
212 )
213{
214 VIRTIO_SERIAL_RING *Ring = Dev->Rings + Index;
215 UINT32 BufferNr;
216
217 for (BufferNr = 0; BufferNr < Ring->BufferCount; BufferNr++) {
218 VirtioSerialRingSendBuffer (Dev, Index, NULL, Ring->BufferSize, FALSE);
219 }
220
221 Dev->VirtIo->SetQueueNotify (Dev->VirtIo, Index);
222}
223
224VOID
225EFIAPI
226VirtioSerialRingClearTx (
228 IN UINT16 Index
229 )
230{
231 while (VirtioSerialRingGetBuffer (Dev, Index, NULL, NULL)) {
232 /* nothing */ }
233}
234
236EFIAPI
237VirtioSerialRingSendBuffer (
239 IN UINT16 Index,
240 IN VOID *Data,
241 IN UINT32 DataSize,
242 IN BOOLEAN Notify
243 )
244{
245 VIRTIO_SERIAL_RING *Ring = Dev->Rings + Index;
246 UINT32 BufferNr = BufferNext (Ring);
247 UINT16 Idx = *Ring->Ring.Avail.Idx;
248 UINT16 Flags = 0;
249
250 ASSERT (DataSize <= Ring->BufferSize);
251
252 if (Data) {
253 /* driver -> device */
254 CopyMem (BufferPtr (Ring, BufferNr), Data, DataSize);
255 } else {
256 /* device -> driver */
257 Flags |= VRING_DESC_F_WRITE;
258 }
259
261 &Ring->Ring,
262 BufferAddr (Ring, BufferNr),
263 DataSize,
264 Flags,
265 &Ring->Indices
266 );
267
268 Ring->Ring.Avail.Ring[Idx % Ring->Ring.QueueSize] =
269 Ring->Indices.HeadDescIdx % Ring->Ring.QueueSize;
270 Ring->Indices.HeadDescIdx = Ring->Indices.NextDescIdx;
271 Idx++;
272
273 MemoryFence ();
274 *Ring->Ring.Avail.Idx = Idx;
275 MemoryFence ();
276
277 if (Notify) {
278 Dev->VirtIo->SetQueueNotify (Dev->VirtIo, Index);
279 }
280
281 return EFI_SUCCESS;
282}
283
284BOOLEAN
285EFIAPI
286VirtioSerialRingHasBuffer (
288 IN UINT16 Index
289 )
290{
291 VIRTIO_SERIAL_RING *Ring = Dev->Rings + Index;
292 UINT16 UsedIdx = *Ring->Ring.Used.Idx;
293
294 if (!Ring->Ready) {
295 return FALSE;
296 }
297
298 if (Ring->LastUsedIdx == UsedIdx) {
299 return FALSE;
300 }
301
302 return TRUE;
303}
304
305BOOLEAN
306EFIAPI
307VirtioSerialRingGetBuffer (
309 IN UINT16 Index,
310 OUT VOID *Data,
311 OUT UINT32 *DataSize
312 )
313{
314 VIRTIO_SERIAL_RING *Ring = Dev->Rings + Index;
315 UINT16 UsedIdx = *Ring->Ring.Used.Idx;
316 volatile VRING_USED_ELEM *UsedElem;
317
318 if (!Ring->Ready) {
319 return FALSE;
320 }
321
322 if (Ring->LastUsedIdx == UsedIdx) {
323 return FALSE;
324 }
325
326 UsedElem = Ring->Ring.Used.UsedElem + (Ring->LastUsedIdx % Ring->Ring.QueueSize);
327
328 if (UsedElem->Len > Ring->BufferSize) {
329 DEBUG ((DEBUG_ERROR, "%a:%d: %d: invalid length\n", __func__, __LINE__, Index));
330 UsedElem->Len = 0;
331 }
332
333 if (Data && DataSize) {
334 CopyMem (Data, BufferPtr (Ring, UsedElem->Id), UsedElem->Len);
335 *DataSize = UsedElem->Len;
336 }
337
338 if (Index % 2 == 0) {
339 /* RX - re-queue buffer */
340 VirtioSerialRingSendBuffer (Dev, Index, NULL, Ring->BufferSize, FALSE);
341 }
342
343 Ring->LastUsedIdx++;
344 return TRUE;
345}
VOID EFIAPI MemoryFence(VOID)
Definition: CpuBreakpoint.c:42
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
#define EFI_PAGES_TO_SIZE(Pages)
Definition: UefiBaseType.h:213
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_STATUS EFIAPI VirtioMapAllBytesInSharedBuffer(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN VIRTIO_MAP_OPERATION Operation, IN VOID *HostAddress, IN UINTN NumberOfBytes, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping)
Definition: VirtioLib.c:469
VOID EFIAPI VirtioAppendDesc(IN OUT VRING *Ring, IN UINT64 BufferDeviceAddress, IN UINT32 BufferSize, IN UINT16 Flags, IN OUT DESC_INDICES *Indices)
Definition: VirtioLib.c:228
EFI_STATUS EFIAPI VirtioRingMap(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN VRING *Ring, OUT UINT64 *RingBaseShift, OUT VOID **Mapping)
Definition: VirtioLib.c:529
VOID EFIAPI VirtioPrepare(IN OUT VRING *Ring, OUT DESC_INDICES *Indices)
Definition: VirtioLib.c:167
EFI_STATUS EFIAPI VirtioRingInit(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN UINT16 QueueSize, OUT VRING *Ring)
Definition: VirtioLib.c:49
VOID EFIAPI VirtioRingUninit(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN OUT VRING *Ring)
Definition: VirtioLib.c:144