OvmfPkg: Make the VirtIo devices use the new VIRTIO_DEVICE_PROTOCOL

This change replaces the accesses to the PCI bus from the Block, Scsi and Net drivers by
the use of the new VIRTIO_DEVICE_PROTOCOL protocol that abstracts the transport layer.
It means these drivers can be used on PCI and MMIO transport layer.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Olivier Martin <olivier.martin@arm.com>

v5:
- VirtioFlush(): update comment block in VirtioLib.[hc]; error code is
  propagated from VirtIo->SetQueueNotify().
- VirtioBlkInit(): jump to Failed label if SetPageSize() fails
- VirtioBlkInit(): fixup comment, and add error handling, near
  SetQueueNum() call
- VirtioBlkDriverBindingStart(): remove redundant (always false) check for
  a subsystem device ID different from VIRTIO_SUBSYSTEM_BLOCK_DEVICE;
  VirtioBlkDriverBindingSupported() handles it already
- VirtioNetGetFeatures(): update stale comment block
- VirtioNetGetFeatures(): retrieve MAC address byte for byte (open-coded
  loop)
- VirtioNetDriverBindingStart(): remove redundant (always false) check for
  a subsystem device ID different from VIRTIO_SUBSYSTEM_NETWORK_CARD;
  VirtioNetDriverBindingSupported() handles it already
- VirtioNetInitRing(): call SetQueueNum() and SetQueueAlign() for proper
  MMIO operation
- VirtioNetInitialize(): fix destination error label for when
  SetPageSize() fails
- VirtioScsi.c: fix comment block of VIRTIO_CFG_WRITE()/VIRTIO_CFG_READ()
- VirtioScsiInit(): fix destination error label for when SetPageSize()
  fails
- VirtioScsiInit(): call SetQueueNum() and SetQueueAlign() for proper MMIO
  operation

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14966 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Olivier Martin
2013-12-11 16:58:22 +00:00
committed by jljusten
parent 6fb4e772a0
commit 56f65ed838
27 changed files with 388 additions and 532 deletions

View File

@@ -23,7 +23,6 @@
**/
#include <IndustryStandard/Pci.h>
#include <IndustryStandard/VirtioBlk.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
@@ -37,14 +36,14 @@
/**
Convenience macros to read and write region 0 IO space elements of the
virtio-blk PCI device, for configuration purposes.
virtio-blk device, for configuration purposes.
The following macros make it possible to specify only the "core parameters"
for such accesses and to derive the rest. By the time VIRTIO_CFG_WRITE()
returns, the transaction will have been completed.
@param[in] Dev Pointer to the VBLK_DEV structure whose PCI IO space
we're accessing. Dev->PciIo must be valid.
@param[in] Dev Pointer to the VBLK_DEV structure whose VirtIo space
we're accessing. Dev->VirtIo must be valid.
@param[in] Field A field name from VBLK_HDR, identifying the virtio-blk
configuration item to access.
@@ -57,19 +56,19 @@
one of UINT8, UINT16, UINT32, UINT64.
@return Status code returned by VirtioWrite() / VirtioRead().
@return Status code returned by VirtioWriteDevice() / VirtioReadDevice().
**/
#define VIRTIO_CFG_WRITE(Dev, Field, Value) (VirtioWrite ( \
(Dev)->PciIo, \
#define VIRTIO_CFG_WRITE(Dev, Field, Value) (VirtioWriteDevice ( \
(Dev)->VirtIo, \
OFFSET_OF_VBLK (Field), \
SIZE_OF_VBLK (Field), \
(Value) \
))
#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioRead ( \
(Dev)->PciIo, \
#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioReadDevice ( \
(Dev)->VirtIo, \
OFFSET_OF_VBLK (Field), \
SIZE_OF_VBLK (Field), \
sizeof *(Pointer), \
@@ -229,7 +228,7 @@ VerifyReadWriteRequest (
@retval EFI_SUCCESS Transfer complete.
@retval EFI_DEVICE_ERROR Failed to notify host side via PCI write, or
@retval EFI_DEVICE_ERROR Failed to notify host side via VirtIo write, or
unable to parse host response, or host response
is not VIRTIO_BLK_S_OK.
@@ -324,7 +323,7 @@ SynchronousRequest (
//
// virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).
//
if (VirtioFlush (Dev->PciIo, 0, &Dev->Ring, &Indices) == EFI_SUCCESS &&
if (VirtioFlush (Dev->VirtIo, 0, &Dev->Ring, &Indices) == EFI_SUCCESS &&
HostStatus == VIRTIO_BLK_S_OK) {
return EFI_SUCCESS;
}
@@ -500,11 +499,6 @@ VirtioBlkFlushBlocks (
underlying device
- 9 Driver Binding Protocol -- for exporting ourselves
Specs relevant in the specific sense:
- UEFI Spec 2.3.1 + Errata C, 13.4 EFI PCI I/O Protocol
- Driver Writer's Guide for UEFI 2.3.1 v1.01, 18 PCI Driver Design
Guidelines, 18.3 PCI drivers.
@param[in] This The EFI_DRIVER_BINDING_PROTOCOL object
incorporating this driver (independently of
any device).
@@ -516,11 +510,11 @@ VirtioBlkFlushBlocks (
@retval EFI_SUCCESS The driver supports the device being probed.
@retval EFI_UNSUPPORTED Based on virtio-blk PCI discovery, we do not support
@retval EFI_UNSUPPORTED Based on virtio-blk discovery, we do not support
the device.
@return Error codes from the OpenProtocol() boot service or
the PciIo protocol.
the VirtIo protocol.
**/
@@ -533,56 +527,36 @@ VirtioBlkDriverBindingSupported (
)
{
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
PCI_TYPE00 Pci;
VIRTIO_DEVICE_PROTOCOL *VirtIo;
//
// Attempt to open the device with the PciIo set of interfaces. On success,
// the protocol is "instantiated" for the PCI device. Covers duplicate open
// Attempt to open the device with the VirtIo set of interfaces. On success,
// the protocol is "instantiated" for the VirtIo device. Covers duplicate open
// attempts (EFI_ALREADY_STARTED).
//
Status = gBS->OpenProtocol (
DeviceHandle, // candidate device
&gEfiPciIoProtocolGuid, // for generic PCI access
(VOID **)&PciIo, // handle to instantiate
&gVirtioDeviceProtocolGuid, // for generic VirtIo access
(VOID **)&VirtIo, // handle to instantiate
This->DriverBindingHandle, // requestor driver identity
DeviceHandle, // ControllerHandle, according to
// the UEFI Driver Model
EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive PciIo access to
EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
// the device; to be released
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Read entire PCI configuration header for more extensive check ahead.
//
Status = PciIo->Pci.Read (
PciIo, // (protocol, device)
// handle
EfiPciIoWidthUint32, // access width & copy
// mode
0, // Offset
sizeof Pci / sizeof (UINT32), // Count
&Pci // target buffer
);
if (Status == EFI_SUCCESS) {
//
// virtio-0.9.5, 2.1 PCI Discovery
//
Status = (Pci.Hdr.VendorId == 0x1AF4 &&
Pci.Hdr.DeviceId >= 0x1000 && Pci.Hdr.DeviceId <= 0x103F &&
Pci.Hdr.RevisionID == 0x00 &&
Pci.Device.SubsystemID == VIRTIO_SUBSYSTEM_BLOCK_DEVICE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) {
Status = EFI_UNSUPPORTED;
}
//
// We needed PCI IO access only transitorily, to see whether we support the
// We needed VirtIo access only transitorily, to see whether we support the
// device or not.
//
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, DeviceHandle);
return Status;
}
@@ -594,8 +568,8 @@ VirtioBlkDriverBindingSupported (
device.
@param[in out] Dev The driver instance to configure. The caller is
responsible for Dev->PciIo's validity (ie. working IO
access to the underlying virtio-blk PCI device).
responsible for Dev->VirtIo's validity (ie. working IO
access to the underlying virtio-blk device).
@retval EFI_SUCCESS Setup complete.
@@ -626,19 +600,27 @@ VirtioBlkInit (
// Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
//
NextDevStat = 0; // step 1 -- reset device
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
if (EFI_ERROR (Status)) {
goto Failed;
}
NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
if (EFI_ERROR (Status)) {
goto Failed;
}
NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
if (EFI_ERROR (Status)) {
goto Failed;
}
//
// Set Page Size - MMIO VirtIo Specific
//
Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -646,11 +628,12 @@ VirtioBlkInit (
//
// step 4a -- retrieve and validate features
//
Status = VIRTIO_CFG_READ (Dev, Generic.VhdrDeviceFeatureBits, &Features);
Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
if (EFI_ERROR (Status)) {
goto Failed;
}
Status = VIRTIO_CFG_READ (Dev, VhdrCapacity, &NumSectors);
Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors);
if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -660,7 +643,7 @@ VirtioBlkInit (
}
if (Features & VIRTIO_BLK_F_BLK_SIZE) {
Status = VIRTIO_CFG_READ (Dev, VhdrBlkSize, &BlockSize);
Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize);
if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -681,11 +664,11 @@ VirtioBlkInit (
//
// step 4b -- allocate virtqueue
//
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect, 0);
Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);
if (EFI_ERROR (Status)) {
goto Failed;
}
Status = VIRTIO_CFG_READ (Dev, Generic.VhdrQueueSize, &QueueSize);
Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -700,22 +683,36 @@ VirtioBlkInit (
}
//
// step 4c -- Report GPFN (guest-physical frame number) of queue. If anything
// fails from here on, we must release the ring resources.
// Additional steps for MMIO: align the queue appropriately, and set the
// size. If anything fails from here on, we must release the ring resources.
//
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueAddress,
(UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT);
Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
//
// step 4c -- Report GPFN (guest-physical frame number) of queue.
//
Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo,
(UINT32)(UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT);
if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
//
// step 5 -- Report understood features. There are no virtio-blk specific
// features to negotiate in virtio-0.9.5, plus we do not want any of the
// device-independent (known or unknown) VIRTIO_F_* capabilities (see
// Appendix B).
//
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits, 0);
Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, 0);
if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
@@ -724,7 +721,7 @@ VirtioBlkInit (
// step 6 -- initialization complete
//
NextDevStat |= VSTAT_DRIVER_OK;
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
@@ -758,10 +755,10 @@ ReleaseQueue:
Failed:
//
// Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
// Status. PCI IO access failure here should not mask the original error.
// Status. VirtIo access failure here should not mask the original error.
//
NextDevStat |= VSTAT_FAILED;
VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);
Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
return Status; // reached only via Failed above
}
@@ -788,7 +785,7 @@ VirtioBlkUninit (
// VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
// the old comms area.
//
VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);
Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
VirtioRingUninit (&Dev->Ring);
@@ -815,13 +812,13 @@ VirtioBlkUninit (
@retval EFI_SUCCESS Driver instance has been created and
initialized for the virtio-blk PCI device, it
initialized for the virtio-blk device, it
is now accessibla via EFI_BLOCK_IO_PROTOCOL.
@retval EFI_OUT_OF_RESOURCES Memory allocation failed.
@return Error codes from the OpenProtocol() boot
service, the PciIo protocol, VirtioBlkInit(),
service, the VirtIo protocol, VirtioBlkInit(),
or the InstallProtocolInterface() boot service.
**/
@@ -842,43 +839,19 @@ VirtioBlkDriverBindingStart (
return EFI_OUT_OF_RESOURCES;
}
Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
(VOID **)&Dev->PciIo, This->DriverBindingHandle,
Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
(VOID **)&Dev->VirtIo, This->DriverBindingHandle,
DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
if (EFI_ERROR (Status)) {
goto FreeVirtioBlk;
}
//
// We must retain and ultimately restore the original PCI attributes of the
// device. See Driver Writer's Guide for UEFI 2.3.1 v1.01, 18.3 PCI drivers /
// 18.3.2 Start() and Stop().
//
// The third parameter ("Attributes", input) is ignored by the Get operation.
// The fourth parameter ("Result", output) is ignored by the Enable and Set
// operations.
//
// For virtio-blk we only need IO space access.
//
Status = Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationGet,
0, &Dev->OriginalPciAttributes);
if (EFI_ERROR (Status)) {
goto ClosePciIo;
}
Status = Dev->PciIo->Attributes (Dev->PciIo,
EfiPciIoAttributeOperationEnable,
EFI_PCI_IO_ATTRIBUTE_IO, NULL);
if (EFI_ERROR (Status)) {
goto ClosePciIo;
}
//
// PCI IO access granted, configure virtio-blk device.
// VirtIo access granted, configure virtio-blk device.
//
Status = VirtioBlkInit (Dev);
if (EFI_ERROR (Status)) {
goto RestorePciAttributes;
goto CloseVirtIo;
}
//
@@ -897,12 +870,8 @@ VirtioBlkDriverBindingStart (
UninitDev:
VirtioBlkUninit (Dev);
RestorePciAttributes:
Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
Dev->OriginalPciAttributes, NULL);
ClosePciIo:
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
CloseVirtIo:
gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, DeviceHandle);
FreeVirtioBlk:
@@ -973,10 +942,7 @@ VirtioBlkDriverBindingStop (
VirtioBlkUninit (Dev);
Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
Dev->OriginalPciAttributes, NULL);
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, DeviceHandle);
FreePool (Dev);