VirtioLib.c revision 56f65ed838e8d73e91d54a8ed984d777c936843c
1/** @file
2
3  Utility functions used by virtio device drivers.
4
5  Copyright (C) 2012, Red Hat, Inc.
6  Portion of Copyright (C) 2013, ARM Ltd.
7
8  This program and the accompanying materials are licensed and made available
9  under the terms and conditions of the BSD License which accompanies this
10  distribution. The full text of the license may be found at
11  http://opensource.org/licenses/bsd-license.php
12
13  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
14  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16**/
17
18#include <Library/BaseLib.h>
19#include <Library/BaseMemoryLib.h>
20#include <Library/DebugLib.h>
21#include <Library/MemoryAllocationLib.h>
22#include <Library/UefiBootServicesTableLib.h>
23
24#include <Library/VirtioLib.h>
25
26
27/**
28
29  Write a word into Region 0 of the device specified by VirtIo.
30
31  Region 0 must be an iomem region. This is an internal function for the
32  driver-specific VIRTIO_CFG_WRITE() macros.
33
34  @param[in] VirtIo       Target VirtIo device.
35
36  @param[in] FieldOffset  Destination offset.
37
38  @param[in] FieldSize    Destination field size, must be in { 1, 2, 4, 8 }.
39
40  @param[in] Value        Little endian value to write, converted to UINT64.
41                          The least significant FieldSize bytes will be used.
42
43
44  @return  Status code returned by VirtIo->Io.Write().
45
46**/
47EFI_STATUS
48EFIAPI
49VirtioWriteDevice (
50  IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
51  IN UINTN                  FieldOffset,
52  IN UINTN                  FieldSize,
53  IN UINT64                 Value
54  )
55{
56  return VirtIo->WriteDevice (VirtIo, FieldOffset, FieldSize, Value);
57}
58
59
60/**
61
62  Read a word from Region 0 of the device specified by VirtIo.
63
64  Region 0 must be an iomem region. This is an internal function for the
65  driver-specific VIRTIO_CFG_READ() macros.
66
67  @param[in] VirtIo       Source VirtIo device.
68
69  @param[in] FieldOffset  Source offset.
70
71  @param[in] FieldSize    Source field size, must be in { 1, 2, 4, 8 }.
72
73  @param[in] BufferSize   Number of bytes available in the target buffer. Must
74                          equal FieldSize.
75
76  @param[out] Buffer      Target buffer.
77
78
79  @return  Status code returned by VirtIo->Io.Read().
80
81**/
82EFI_STATUS
83EFIAPI
84VirtioReadDevice (
85  IN  VIRTIO_DEVICE_PROTOCOL *VirtIo,
86  IN  UINTN                  FieldOffset,
87  IN  UINTN                  FieldSize,
88  IN  UINTN                  BufferSize,
89  OUT VOID                   *Buffer
90  )
91{
92  return VirtIo->ReadDevice (VirtIo, FieldOffset, FieldSize, BufferSize, Buffer);
93}
94
95
96/**
97
98  Configure a virtio ring.
99
100  This function sets up internal storage (the guest-host communication area)
101  and lays out several "navigation" (ie. no-ownership) pointers to parts of
102  that storage.
103
104  Relevant sections from the virtio-0.9.5 spec:
105  - 1.1 Virtqueues,
106  - 2.3 Virtqueue Configuration.
107
108  @param[in]                    The number of descriptors to allocate for the
109                                virtio ring, as requested by the host.
110
111  @param[out] Ring              The virtio ring to set up.
112
113  @retval EFI_OUT_OF_RESOURCES  AllocatePages() failed to allocate contiguous
114                                pages for the requested QueueSize. Fields of
115                                Ring have indeterminate value.
116
117  @retval EFI_SUCCESS           Allocation and setup successful. Ring->Base
118                                (and nothing else) is responsible for
119                                deallocation.
120
121**/
122EFI_STATUS
123EFIAPI
124VirtioRingInit (
125  IN  UINT16 QueueSize,
126  OUT VRING  *Ring
127  )
128{
129  UINTN          RingSize;
130  volatile UINT8 *RingPagesPtr;
131
132  RingSize = ALIGN_VALUE (
133               sizeof *Ring->Desc            * QueueSize +
134               sizeof *Ring->Avail.Flags                 +
135               sizeof *Ring->Avail.Idx                   +
136               sizeof *Ring->Avail.Ring      * QueueSize +
137               sizeof *Ring->Avail.UsedEvent,
138               EFI_PAGE_SIZE);
139
140  RingSize += ALIGN_VALUE (
141                sizeof *Ring->Used.Flags                  +
142                sizeof *Ring->Used.Idx                    +
143                sizeof *Ring->Used.UsedElem   * QueueSize +
144                sizeof *Ring->Used.AvailEvent,
145                EFI_PAGE_SIZE);
146
147  Ring->NumPages = EFI_SIZE_TO_PAGES (RingSize);
148  Ring->Base = AllocatePages (Ring->NumPages);
149  if (Ring->Base == NULL) {
150    return EFI_OUT_OF_RESOURCES;
151  }
152  SetMem (Ring->Base, RingSize, 0x00);
153  RingPagesPtr = Ring->Base;
154
155  Ring->Desc = (volatile VOID *) RingPagesPtr;
156  RingPagesPtr += sizeof *Ring->Desc * QueueSize;
157
158  Ring->Avail.Flags = (volatile VOID *) RingPagesPtr;
159  RingPagesPtr += sizeof *Ring->Avail.Flags;
160
161  Ring->Avail.Idx = (volatile VOID *) RingPagesPtr;
162  RingPagesPtr += sizeof *Ring->Avail.Idx;
163
164  Ring->Avail.Ring = (volatile VOID *) RingPagesPtr;
165  RingPagesPtr += sizeof *Ring->Avail.Ring * QueueSize;
166
167  Ring->Avail.UsedEvent = (volatile VOID *) RingPagesPtr;
168  RingPagesPtr += sizeof *Ring->Avail.UsedEvent;
169
170  RingPagesPtr = (volatile UINT8 *) Ring->Base +
171                 ALIGN_VALUE (RingPagesPtr - (volatile UINT8 *) Ring->Base,
172                   EFI_PAGE_SIZE);
173
174  Ring->Used.Flags = (volatile VOID *) RingPagesPtr;
175  RingPagesPtr += sizeof *Ring->Used.Flags;
176
177  Ring->Used.Idx = (volatile VOID *) RingPagesPtr;
178  RingPagesPtr += sizeof *Ring->Used.Idx;
179
180  Ring->Used.UsedElem = (volatile VOID *) RingPagesPtr;
181  RingPagesPtr += sizeof *Ring->Used.UsedElem * QueueSize;
182
183  Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;
184  RingPagesPtr += sizeof *Ring->Used.AvailEvent;
185
186  Ring->QueueSize = QueueSize;
187  return EFI_SUCCESS;
188}
189
190
191/**
192
193  Tear down the internal resources of a configured virtio ring.
194
195  The caller is responsible to stop the host from using this ring before
196  invoking this function: the VSTAT_DRIVER_OK bit must be clear in
197  VhdrDeviceStatus.
198
199  @param[out] Ring  The virtio ring to clean up.
200
201**/
202VOID
203EFIAPI
204VirtioRingUninit (
205  IN OUT VRING *Ring
206  )
207{
208  FreePages (Ring->Base, Ring->NumPages);
209  SetMem (Ring, sizeof *Ring, 0x00);
210}
211
212
213/**
214
215  Turn off interrupt notifications from the host, and prepare for appending
216  multiple descriptors to the virtio ring.
217
218  The calling driver must be in VSTAT_DRIVER_OK state.
219
220  @param[in,out] Ring  The virtio ring we intend to append descriptors to.
221
222  @param[out] Indices  The DESC_INDICES structure to initialize.
223
224**/
225VOID
226EFIAPI
227VirtioPrepare (
228  IN OUT VRING        *Ring,
229  OUT    DESC_INDICES *Indices
230  )
231{
232  //
233  // Prepare for virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device.
234  // We're going to poll the answer, the host should not send an interrupt.
235  //
236  *Ring->Avail.Flags = (UINT16) VRING_AVAIL_F_NO_INTERRUPT;
237
238  //
239  // Prepare for virtio-0.9.5, 2.4.1 Supplying Buffers to the Device.
240  //
241  // Since we support only one in-flight descriptor chain, we can always build
242  // that chain starting at entry #0 of the descriptor table.
243  //
244  Indices->HeadDescIdx = 0;
245  Indices->NextDescIdx = Indices->HeadDescIdx;
246}
247
248
249/**
250
251  Append a contiguous buffer for transmission / reception via the virtio ring.
252
253  This function implements the following section from virtio-0.9.5:
254  - 2.4.1.1 Placing Buffers into the Descriptor Table
255
256  Free space is taken as granted, since the individual drivers support only
257  synchronous requests and host side status is processed in lock-step with
258  request submission. It is the calling driver's responsibility to verify the
259  ring size in advance.
260
261  The caller is responsible for initializing *Indices with VirtioPrepare()
262  first.
263
264  @param[in,out] Ring        The virtio ring to append the buffer to, as a
265                             descriptor.
266
267  @param[in] BufferPhysAddr  (Guest pseudo-physical) start address of the
268                             transmit / receive buffer.
269
270  @param[in] BufferSize      Number of bytes to transmit or receive.
271
272  @param[in] Flags           A bitmask of VRING_DESC_F_* flags. The caller
273                             computes this mask dependent on further buffers to
274                             append and transfer direction.
275                             VRING_DESC_F_INDIRECT is unsupported. The
276                             VRING_DESC.Next field is always set, but the host
277                             only interprets it dependent on VRING_DESC_F_NEXT.
278
279  @param[in,out] Indices     Indices->HeadDescIdx is not accessed.
280                             On input, Indices->NextDescIdx identifies the next
281                             descriptor to carry the buffer. On output,
282                             Indices->NextDescIdx is incremented by one, modulo
283                             2^16.
284
285**/
286VOID
287EFIAPI
288VirtioAppendDesc (
289  IN OUT VRING        *Ring,
290  IN     UINTN        BufferPhysAddr,
291  IN     UINT32       BufferSize,
292  IN     UINT16       Flags,
293  IN OUT DESC_INDICES *Indices
294  )
295{
296  volatile VRING_DESC *Desc;
297
298  Desc        = &Ring->Desc[Indices->NextDescIdx++ % Ring->QueueSize];
299  Desc->Addr  = BufferPhysAddr;
300  Desc->Len   = BufferSize;
301  Desc->Flags = Flags;
302  Desc->Next  = Indices->NextDescIdx % Ring->QueueSize;
303}
304
305
306/**
307
308  Notify the host about the descriptor chain just built, and wait until the
309  host processes it.
310
311  @param[in] VirtIo       The target virtio device to notify.
312
313  @param[in] VirtQueueId  Identifies the queue for the target device.
314
315  @param[in,out] Ring     The virtio ring with descriptors to submit.
316
317  @param[in] Indices      Indices->NextDescIdx is not accessed.
318                          Indices->HeadDescIdx identifies the head descriptor
319                          of the descriptor chain.
320
321
322  @return              Error code from VirtIo->SetQueueNotify() if it fails.
323
324  @retval EFI_SUCCESS  Otherwise, the host processed all descriptors.
325
326**/
327EFI_STATUS
328EFIAPI
329VirtioFlush (
330  IN     VIRTIO_DEVICE_PROTOCOL *VirtIo,
331  IN     UINT16                 VirtQueueId,
332  IN OUT VRING                  *Ring,
333  IN     DESC_INDICES           *Indices
334  )
335{
336  UINT16     NextAvailIdx;
337  EFI_STATUS Status;
338  UINTN      PollPeriodUsecs;
339
340  //
341  // virtio-0.9.5, 2.4.1.2 Updating the Available Ring
342  //
343  // It is not exactly clear from the wording of the virtio-0.9.5
344  // specification, but each entry in the Available Ring references only the
345  // head descriptor of any given descriptor chain.
346  //
347  NextAvailIdx = *Ring->Avail.Idx;
348  Ring->Avail.Ring[NextAvailIdx++ % Ring->QueueSize] =
349    Indices->HeadDescIdx % Ring->QueueSize;
350
351  //
352  // virtio-0.9.5, 2.4.1.3 Updating the Index Field
353  //
354  MemoryFence();
355  *Ring->Avail.Idx = NextAvailIdx;
356
357  //
358  // virtio-0.9.5, 2.4.1.4 Notifying the Device -- gratuitous notifications are
359  // OK.
360  //
361  MemoryFence();
362  Status = VirtIo->SetQueueNotify (VirtIo, VirtQueueId);
363  if (EFI_ERROR (Status)) {
364    return Status;
365  }
366
367  //
368  // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
369  // Wait until the host processes and acknowledges our descriptor chain. The
370  // condition we use for polling is greatly simplified and relies on the
371  // synchronous, lock-step progress.
372  //
373  // Keep slowing down until we reach a poll period of slightly above 1 ms.
374  //
375  PollPeriodUsecs = 1;
376  MemoryFence();
377  while (*Ring->Used.Idx != NextAvailIdx) {
378    gBS->Stall (PollPeriodUsecs); // calls AcpiTimerLib::MicroSecondDelay
379
380    if (PollPeriodUsecs < 1024) {
381      PollPeriodUsecs *= 2;
382    }
383    MemoryFence();
384  }
385
386  MemoryFence();
387  return EFI_SUCCESS;
388}
389