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

@ -26,19 +26,18 @@
//
#pragma pack(1)
typedef struct {
VIRTIO_HDR Generic;
UINT64 VhdrCapacity;
UINT32 VhdrSizeMax;
UINT32 VhdrSegMax;
UINT16 VhdrCylinders;
UINT8 VhdrHeads;
UINT8 VhdrSectors;
UINT32 VhdrBlkSize;
} VBLK_HDR;
UINT64 Capacity;
UINT32 SizeMax;
UINT32 SegMax;
UINT16 Cylinders;
UINT8 Heads;
UINT8 Sectors;
UINT32 BlkSize;
} VIRTIO_BLK_CONFIG;
#pragma pack()
#define OFFSET_OF_VBLK(Field) OFFSET_OF (VBLK_HDR, Field)
#define SIZE_OF_VBLK(Field) (sizeof ((VBLK_HDR *) 0)->Field)
#define OFFSET_OF_VBLK(Field) OFFSET_OF (VIRTIO_BLK_CONFIG, Field)
#define SIZE_OF_VBLK(Field) (sizeof ((VIRTIO_BLK_CONFIG *) 0)->Field)
#define VIRTIO_BLK_F_BARRIER BIT0
#define VIRTIO_BLK_F_SIZE_MAX BIT1

View File

@ -1,5 +1,4 @@
/** @file
Virtio Network Device specific type and macro definitions corresponding to
the virtio-0.9.5 specification.
@ -25,14 +24,13 @@
//
#pragma pack(1)
typedef struct {
VIRTIO_HDR Generic;
UINT8 VhdrMac[6];
UINT16 VhdrLinkStatus;
} VNET_HDR;
UINT8 Mac[6];
UINT16 LinkStatus;
} VIRTIO_NET_CONFIG;
#pragma pack()
#define OFFSET_OF_VNET(Field) OFFSET_OF (VNET_HDR, Field)
#define SIZE_OF_VNET(Field) (sizeof ((VNET_HDR *) 0)->Field)
#define OFFSET_OF_VNET(Field) OFFSET_OF (VIRTIO_NET_CONFIG, Field)
#define SIZE_OF_VNET(Field) (sizeof ((VIRTIO_NET_CONFIG *) 0)->Field)
//
// Queue Identifiers
@ -91,7 +89,7 @@ typedef struct {
#define VIRTIO_NET_HDR_GSO_ECN BIT7
//
// Link Status Bits in VNET_HDR.VhdrLinkStatus
// Link Status Bits in VIRTIO_NET_CONFIG.LinkStatus
//
#define VIRTIO_NET_S_LINK_UP BIT0
#define VIRTIO_NET_S_ANNOUNCE BIT1

View File

@ -26,22 +26,21 @@
//
#pragma pack(1)
typedef struct {
VIRTIO_HDR Generic;
UINT32 VhdrNumQueues;
UINT32 VhdrSegMax;
UINT32 VhdrMaxSectors;
UINT32 VhdrCmdPerLun;
UINT32 VhdrEventInfoSize;
UINT32 VhdrSenseSize;
UINT32 VhdrCdbSize;
UINT16 VhdrMaxChannel;
UINT16 VhdrMaxTarget;
UINT32 VhdrMaxLun;
} VSCSI_HDR;
UINT32 NumQueues;
UINT32 SegMax;
UINT32 MaxSectors;
UINT32 CmdPerLun;
UINT32 EventInfoSize;
UINT32 SenseSize;
UINT32 CdbSize;
UINT16 MaxChannel;
UINT16 MaxTarget;
UINT32 MaxLun;
} VIRTIO_SCSI_CONFIG;
#pragma pack()
#define OFFSET_OF_VSCSI(Field) OFFSET_OF (VSCSI_HDR, Field)
#define SIZE_OF_VSCSI(Field) (sizeof ((VSCSI_HDR *) 0)->Field)
#define OFFSET_OF_VSCSI(Field) OFFSET_OF (VIRTIO_SCSI_CONFIG, Field)
#define SIZE_OF_VSCSI(Field) (sizeof ((VIRTIO_SCSI_CONFIG *) 0)->Field)
#define VIRTIO_SCSI_F_INOUT BIT0
#define VIRTIO_SCSI_F_HOTPLUG BIT1

View File

@ -17,17 +17,19 @@
#ifndef _VIRTIO_LIB_H_
#define _VIRTIO_LIB_H_
#include <Protocol/PciIo.h>
#include <Protocol/VirtioDevice.h>
#include <IndustryStandard/Virtio.h>
/**
Write a word into Region 0 of the device specified by PciIo.
Write a word into VirtIo Device Specific Region
Region 0 must be an iomem region. This is an internal function for the
driver-specific VIRTIO_CFG_WRITE() macros.
The VirtIo Device Specific Region must be an iomem region.
This is an internal function for the driver-specific VIRTIO_CFG_WRITE()
macros.
@param[in] PciIo Target PCI device.
@param[in] VirtIo Target Virtio device.
@param[in] FieldOffset Destination offset.
@ -37,27 +39,28 @@
The least significant FieldSize bytes will be used.
@return Status code returned by PciIo->Io.Write().
@return Status code returned by VirtIo->WriteDevice().
**/
EFI_STATUS
EFIAPI
VirtioWrite (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINTN FieldOffset,
IN UINTN FieldSize,
IN UINT64 Value
VirtioWriteDevice (
IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
IN UINTN FieldOffset,
IN UINTN FieldSize,
IN UINT64 Value
);
/**
Read a word from Region 0 of the device specified by PciIo.
Read a word from VirtIo Device Specific Region
Region 0 must be an iomem region. This is an internal function for the
driver-specific VIRTIO_CFG_READ() macros.
The VirtIo Device Specific Region must be an iomem region.
This is an internal function for the driver-specific VIRTIO_CFG_READ()
macros.
@param[in] PciIo Source PCI device.
@param[in] VirtIo Source Virtio device.
@param[in] FieldOffset Source offset.
@ -69,17 +72,17 @@ VirtioWrite (
@param[out] Buffer Target buffer.
@return Status code returned by PciIo->Io.Read().
@return Status code returned by VirtIo->ReadDevice().
**/
EFI_STATUS
EFIAPI
VirtioRead (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINTN FieldOffset,
IN UINTN FieldSize,
IN UINTN BufferSize,
OUT VOID *Buffer
VirtioReadDevice (
IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
IN UINTN FieldOffset,
IN UINTN FieldSize,
IN UINTN BufferSize,
OUT VOID *Buffer
);
@ -218,7 +221,7 @@ VirtioAppendDesc (
Notify the host about the descriptor chain just built, and wait until the
host processes it.
@param[in] PciIo The target virtio PCI device to notify.
@param[in] VirtIo The target virtio device to notify.
@param[in] VirtQueueId Identifies the queue for the target device.
@ -229,7 +232,7 @@ VirtioAppendDesc (
of the descriptor chain.
@return Error code from VirtioWrite() if it fails.
@return Error code from VirtIo->SetQueueNotify() if it fails.
@retval EFI_SUCCESS Otherwise, the host processed all descriptors.
@ -237,10 +240,10 @@ VirtioAppendDesc (
EFI_STATUS
EFIAPI
VirtioFlush (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT16 VirtQueueId,
IN OUT VRING *Ring,
IN DESC_INDICES *Indices
IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
IN UINT16 VirtQueueId,
IN OUT VRING *Ring,
IN DESC_INDICES *Indices
);
#endif // _VIRTIO_LIB_H_

View File

@ -3,6 +3,7 @@
Utility functions used by virtio device drivers.
Copyright (C) 2012, Red Hat, Inc.
Portion of Copyright (C) 2013, ARM Ltd.
This program and the accompanying materials are licensed and made available
under the terms and conditions of the BSD License which accompanies this
@ -14,7 +15,6 @@
**/
#include <IndustryStandard/Pci22.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
@ -26,12 +26,12 @@
/**
Write a word into Region 0 of the device specified by PciIo.
Write a word into Region 0 of the device specified by VirtIo.
Region 0 must be an iomem region. This is an internal function for the
driver-specific VIRTIO_CFG_WRITE() macros.
@param[in] PciIo Target PCI device.
@param[in] VirtIo Target VirtIo device.
@param[in] FieldOffset Destination offset.
@ -41,63 +41,30 @@
The least significant FieldSize bytes will be used.
@return Status code returned by PciIo->Io.Write().
@return Status code returned by VirtIo->Io.Write().
**/
EFI_STATUS
EFIAPI
VirtioWrite (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINTN FieldOffset,
IN UINTN FieldSize,
IN UINT64 Value
VirtioWriteDevice (
IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
IN UINTN FieldOffset,
IN UINTN FieldSize,
IN UINT64 Value
)
{
UINTN Count;
EFI_PCI_IO_PROTOCOL_WIDTH Width;
Count = 1;
switch (FieldSize) {
case 1:
Width = EfiPciIoWidthUint8;
break;
case 2:
Width = EfiPciIoWidthUint16;
break;
case 8:
Count = 2;
// fall through
case 4:
Width = EfiPciIoWidthUint32;
break;
default:
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
return PciIo->Io.Write (
PciIo,
Width,
PCI_BAR_IDX0,
FieldOffset,
Count,
&Value
);
return VirtIo->WriteDevice (VirtIo, FieldOffset, FieldSize, Value);
}
/**
Read a word from Region 0 of the device specified by PciIo.
Read a word from Region 0 of the device specified by VirtIo.
Region 0 must be an iomem region. This is an internal function for the
driver-specific VIRTIO_CFG_READ() macros.
@param[in] PciIo Source PCI device.
@param[in] VirtIo Source VirtIo device.
@param[in] FieldOffset Source offset.
@ -109,55 +76,20 @@ VirtioWrite (
@param[out] Buffer Target buffer.
@return Status code returned by PciIo->Io.Read().
@return Status code returned by VirtIo->Io.Read().
**/
EFI_STATUS
EFIAPI
VirtioRead (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINTN FieldOffset,
IN UINTN FieldSize,
IN UINTN BufferSize,
OUT VOID *Buffer
VirtioReadDevice (
IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
IN UINTN FieldOffset,
IN UINTN FieldSize,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
UINTN Count;
EFI_PCI_IO_PROTOCOL_WIDTH Width;
ASSERT (FieldSize == BufferSize);
Count = 1;
switch (FieldSize) {
case 1:
Width = EfiPciIoWidthUint8;
break;
case 2:
Width = EfiPciIoWidthUint16;
break;
case 8:
Count = 2;
// fall through
case 4:
Width = EfiPciIoWidthUint32;
break;
default:
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
return PciIo->Io.Read (
PciIo,
Width,
PCI_BAR_IDX0,
FieldOffset,
Count,
Buffer
);
return VirtIo->ReadDevice (VirtIo, FieldOffset, FieldSize, BufferSize, Buffer);
}
@ -376,7 +308,7 @@ VirtioAppendDesc (
Notify the host about the descriptor chain just built, and wait until the
host processes it.
@param[in] PciIo The target virtio PCI device to notify.
@param[in] VirtIo The target virtio device to notify.
@param[in] VirtQueueId Identifies the queue for the target device.
@ -387,7 +319,7 @@ VirtioAppendDesc (
of the descriptor chain.
@return Error code from VirtioWrite() if it fails.
@return Error code from VirtIo->SetQueueNotify() if it fails.
@retval EFI_SUCCESS Otherwise, the host processed all descriptors.
@ -395,10 +327,10 @@ VirtioAppendDesc (
EFI_STATUS
EFIAPI
VirtioFlush (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT16 VirtQueueId,
IN OUT VRING *Ring,
IN DESC_INDICES *Indices
IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
IN UINT16 VirtQueueId,
IN OUT VRING *Ring,
IN DESC_INDICES *Indices
)
{
UINT16 NextAvailIdx;
@ -427,12 +359,7 @@ VirtioFlush (
// OK.
//
MemoryFence();
Status = VirtioWrite (
PciIo,
OFFSET_OF (VIRTIO_HDR, VhdrQueueNotify),
sizeof (UINT16),
VirtQueueId
);
Status = VirtIo->SetQueueNotify (VirtIo, VirtQueueId);
if (EFI_ERROR (Status)) {
return Status;
}

View File

@ -411,6 +411,7 @@
}
OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf
OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf

View File

@ -266,6 +266,7 @@ INF MdeModulePkg/Universal/Metronome/Metronome.inf
INF PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
INF OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf
INF OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
INF OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
INF OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
INF OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf

View File

@ -418,6 +418,7 @@
}
OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf
OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf

View File

@ -266,6 +266,7 @@ INF MdeModulePkg/Universal/Metronome/Metronome.inf
INF PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
INF OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf
INF OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
INF OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
INF OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
INF OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf

View File

@ -416,6 +416,7 @@
}
OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf
OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf

View File

@ -266,6 +266,7 @@ INF MdeModulePkg/Universal/Metronome/Metronome.inf
INF PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
INF OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf
INF OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
INF OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
INF OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
INF OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf

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);

View File

@ -21,7 +21,6 @@
#include <Protocol/BlockIo.h>
#include <Protocol/ComponentName.h>
#include <Protocol/DriverBinding.h>
#include <Protocol/PciIo.h>
#include <IndustryStandard/Virtio.h>
@ -34,14 +33,13 @@ typedef struct {
// at various call depths. The table to the right should make it easier to
// track them.
//
// field init function init dpth
// ---------------------- ------------------ ---------
UINT32 Signature; // DriverBindingStart 0
EFI_PCI_IO_PROTOCOL *PciIo; // DriverBindingStart 0
UINT64 OriginalPciAttributes; // DriverBindingStart 0
VRING Ring; // VirtioRingInit 2
EFI_BLOCK_IO_PROTOCOL BlockIo; // VirtioBlkInit 1
EFI_BLOCK_IO_MEDIA BlockIoMedia; // VirtioBlkInit 1
// field init function init dpth
// --------------------- ------------------ ---------
UINT32 Signature; // DriverBindingStart 0
VIRTIO_DEVICE_PROTOCOL *VirtIo; // DriverBindingStart 0
VRING Ring; // VirtioRingInit 2
EFI_BLOCK_IO_PROTOCOL BlockIo; // VirtioBlkInit 1
EFI_BLOCK_IO_MEDIA BlockIoMedia; // VirtioBlkInit 1
} VBLK_DEV;
#define VIRTIO_BLK_FROM_BLOCK_IO(BlockIoPointer) \
@ -66,11 +64,6 @@ typedef struct {
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).
@ -82,11 +75,10 @@ typedef struct {
@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.
@return Error codes from the OpenProtocol() boot service.
**/
@ -117,14 +109,14 @@ VirtioBlkDriverBindingSupported (
@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(),
or the InstallProtocolInterface() boot service.
service, VirtioBlkInit(), or the
InstallProtocolInterface() boot service.
**/

View File

@ -38,5 +38,5 @@
VirtioLib
[Protocols]
gEfiBlockIoProtocolGuid ## BY_START
gEfiPciIoProtocolGuid ## TO_START
gEfiBlockIoProtocolGuid ## BY_START
gVirtioDeviceProtocolGuid ## TO_START

View File

@ -139,20 +139,20 @@ VirtioNetGetControllerName (
}
//
// confirm that the device is managed by this driver, using the PCI IO
// confirm that the device is managed by this driver, using the VirtIo
// Protocol
//
Status = EfiTestManagedDevice (
ControllerHandle,
gVirtioNetDriverBinding.DriverBindingHandle,
&gEfiPciIoProtocolGuid
&gVirtioDeviceProtocolGuid
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// we don't give different names to the bus (= parent, = PCI) handle and the
// we don't give different names to the bus (= parent) handle and the
// child (= MAC) handle
//
return LookupUnicodeString2 (

View File

@ -15,7 +15,6 @@
**/
#include <IndustryStandard/Pci.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DevicePathLib.h>
#include <Library/MemoryAllocationLib.h>
@ -50,8 +49,7 @@
unused.
@retval EFI_UNSUPPORTED The host doesn't supply a MAC address.
@return Status codes from Dev->PciIo->Io.Read(),
VIRTIO_CFG_READ() and VIRTIO_CFG_WRITE().
@return Status codes from VirtIo protocol members.
@retval EFI_SUCCESS Configuration values retrieved.
*/
STATIC
@ -67,6 +65,7 @@ VirtioNetGetFeatures (
EFI_STATUS Status;
UINT8 NextDevStat;
UINT32 Features;
UINTN MacIdx;
UINT16 LinkStatus;
//
@ -74,19 +73,19 @@ VirtioNetGetFeatures (
// Initialization Sequence), but don't complete setting it up.
//
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)) {
return Status;
}
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 YieldDevice;
}
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 YieldDevice;
}
@ -94,7 +93,7 @@ VirtioNetGetFeatures (
//
// 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 YieldDevice;
}
@ -106,16 +105,16 @@ VirtioNetGetFeatures (
Status = EFI_UNSUPPORTED;
goto YieldDevice;
}
Status = Dev->PciIo->Io.Read (Dev->PciIo, // PciIo
EfiPciIoWidthUint8, // Width
PCI_BAR_IDX0, // BarIndex
OFFSET_OF_VNET (VhdrMac), // Offset
SIZE_OF_VNET (VhdrMac), // Count
MacAddress // Buffer
for (MacIdx = 0; MacIdx < SIZE_OF_VNET (Mac); ++MacIdx) {
Status = Dev->VirtIo->ReadDevice (Dev->VirtIo,
OFFSET_OF_VNET (Mac) + MacIdx, // Offset
1, // FieldSize
1, // BufferSize
&MacAddress->Addr[MacIdx] // Buffer
);
if (EFI_ERROR (Status)) {
goto YieldDevice;
if (EFI_ERROR (Status)) {
goto YieldDevice;
}
}
//
@ -126,7 +125,7 @@ VirtioNetGetFeatures (
}
else {
*MediaPresentSupported = TRUE;
Status = VIRTIO_CFG_READ (Dev, VhdrLinkStatus, &LinkStatus);
Status = VIRTIO_CFG_READ (Dev, LinkStatus, &LinkStatus);
if (EFI_ERROR (Status)) {
goto YieldDevice;
}
@ -134,7 +133,7 @@ VirtioNetGetFeatures (
}
YieldDevice:
VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus,
Dev->VirtIo->SetDeviceStatus (Dev->VirtIo,
EFI_ERROR (Status) ? VSTAT_FAILED : 0);
return Status;
@ -207,9 +206,9 @@ VirtioNetSnpPopulate (
Dev->Snp.Mode = &Dev->Snm;
Dev->Snm.State = EfiSimpleNetworkStopped;
Dev->Snm.HwAddressSize = SIZE_OF_VNET (VhdrMac);
Dev->Snm.MediaHeaderSize = SIZE_OF_VNET (VhdrMac) + // dst MAC
SIZE_OF_VNET (VhdrMac) + // src MAC
Dev->Snm.HwAddressSize = SIZE_OF_VNET (Mac);
Dev->Snm.MediaHeaderSize = SIZE_OF_VNET (Mac) + // dst MAC
SIZE_OF_VNET (Mac) + // src MAC
2; // Ethertype
Dev->Snm.MaxPacketSize = 1500;
Dev->Snm.NvRamSize = 0;
@ -222,7 +221,7 @@ VirtioNetSnpPopulate (
Dev->Snm.MacAddressChangeable = FALSE;
Dev->Snm.MultipleTxSupported = TRUE;
ASSERT (SIZE_OF_VNET (VhdrMac) <= sizeof (EFI_MAC_ADDRESS));
ASSERT (SIZE_OF_VNET (Mac) <= sizeof (EFI_MAC_ADDRESS));
Status = VirtioNetGetFeatures (Dev, &Dev->Snm.CurrentAddress,
&Dev->Snm.MediaPresentSupported, &Dev->Snm.MediaPresent);
@ -230,8 +229,8 @@ VirtioNetSnpPopulate (
goto CloseWaitForPacket;
}
CopyMem (&Dev->Snm.PermanentAddress, &Dev->Snm.CurrentAddress,
SIZE_OF_VNET (VhdrMac));
SetMem (&Dev->Snm.BroadcastAddress, SIZE_OF_VNET (VhdrMac), 0xFF);
SIZE_OF_VNET (Mac));
SetMem (&Dev->Snm.BroadcastAddress, SIZE_OF_VNET (Mac), 0xFF);
//
// VirtioNetExitBoot() is queued by ExitBootServices(); its purpose is to
@ -348,31 +347,36 @@ VirtioNetDriverBindingSupported (
)
{
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
PCI_TYPE00 Pci;
VIRTIO_DEVICE_PROTOCOL *VirtIo;
Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
(VOID **)&PciIo, This->DriverBindingHandle, DeviceHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER);
//
// 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
&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 VirtIo access to
// the device; to be released
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0,
sizeof Pci / sizeof (UINT32), &Pci);
//
// virtio-0.9.5, 2.1 PCI Discovery:
// the network device has Subsystem Device ID 1
//
if (Status == EFI_SUCCESS) {
Status = (Pci.Hdr.VendorId == 0x1AF4 &&
Pci.Hdr.DeviceId >= 0x1000 && Pci.Hdr.DeviceId <= 0x103F &&
Pci.Hdr.RevisionID == 0x00 &&
Pci.Device.SubsystemID == VIRTIO_SUBSYSTEM_NETWORK_CARD) ? EFI_SUCCESS : EFI_UNSUPPORTED;
if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_NETWORK_CARD) {
Status = EFI_UNSUPPORTED;
}
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
//
// We needed VirtIo access only transitorily, to see whether we support the
// device or not.
//
gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, DeviceHandle);
return Status;
}
@ -438,7 +442,7 @@ VirtioNetDriverBindingStart (
VNET_DEV *Dev;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
MAC_ADDR_DEVICE_PATH MacNode;
VOID *ChildPciIo;
VOID *ChildVirtIo;
//
// allocate space for the driver instance
@ -449,43 +453,24 @@ VirtioNetDriverBindingStart (
}
Dev->Signature = VNET_SIG;
//
// get PCI access to the device and keep it open
//
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 FreeVirtioNet;
}
//
// save original PCI attributes and enable IO space access
//
Status = Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationGet,
0, &Dev->OrigPciAttributes);
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;
}
//
// now we can run a basic one-shot virtio-net initialization required to
// retrieve the MAC address
//
Status = VirtioNetSnpPopulate (Dev);
if (EFI_ERROR (Status)) {
goto RestorePciAttributes;
goto CloseVirtIo;
}
//
// get the device path of the virtio-net PCI device -- one-shot open
// get the device path of the virtio-net device -- one-shot open
//
Status = gBS->OpenProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid,
(VOID **)&DevicePath, This->DriverBindingHandle,
@ -523,11 +508,11 @@ VirtioNetDriverBindingStart (
}
//
// make a note that we keep this device open with PciIo for the sake of this
// make a note that we keep this device open with VirtIo for the sake of this
// child
//
Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
&ChildPciIo, This->DriverBindingHandle,
Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
&ChildVirtIo, This->DriverBindingHandle,
Dev->MacHandle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
if (EFI_ERROR (Status)) {
goto UninstallMultiple;
@ -547,12 +532,8 @@ FreeMacDevicePath:
Evacuate:
VirtioNetSnpEvacuate (Dev);
RestorePciAttributes:
Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
Dev->OrigPciAttributes, NULL);
ClosePciIo:
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
CloseVirtIo:
gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, DeviceHandle);
FreeVirtioNet:
@ -637,7 +618,7 @@ VirtioNetDriverBindingStop (
Status = EFI_DEVICE_ERROR;
}
else {
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, Dev->MacHandle);
gBS->UninstallMultipleProtocolInterfaces (Dev->MacHandle,
&gEfiDevicePathProtocolGuid, Dev->MacDevicePath,
@ -645,8 +626,6 @@ VirtioNetDriverBindingStop (
NULL);
FreePool (Dev->MacDevicePath);
VirtioNetSnpEvacuate (Dev);
Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
Dev->OrigPciAttributes, NULL);
FreePool (Dev);
}
@ -657,7 +636,7 @@ VirtioNetDriverBindingStop (
//
// release remaining resources, tied directly to the parent handle
//
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, DeviceHandle);
return EFI_SUCCESS;

View File

@ -86,6 +86,6 @@ VirtioNetExitBoot (
Dev = Context;
if (Dev->Snm.State == EfiSimpleNetworkInitialized) {
VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);
Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
}
}

View File

@ -90,7 +90,7 @@ VirtioNetGetStatus (
if (Dev->Snm.MediaPresentSupported) {
UINT16 LinkStatus;
Status = VIRTIO_CFG_READ (Dev, VhdrLinkStatus, &LinkStatus);
Status = VIRTIO_CFG_READ (Dev, LinkStatus, &LinkStatus);
if (EFI_ERROR (Status)) {
goto Exit;
}

View File

@ -57,14 +57,15 @@ VirtioNetInitRing (
//
// step 4b -- allocate selected queue
//
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect, Selector);
Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, Selector);
if (EFI_ERROR (Status)) {
return Status;
}
Status = VIRTIO_CFG_READ (Dev, Generic.VhdrQueueSize, &QueueSize);
Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
if (EFI_ERROR (Status)) {
return Status;
}
//
// For each packet (RX and TX alike), we need two descriptors:
// one for the virtio-net request header, and another one for the data
@ -77,14 +78,34 @@ VirtioNetInitRing (
return Status;
}
//
// 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 = 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 = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueAddress,
(UINTN) Ring->Base >> EFI_PAGE_SHIFT);
Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo,
(UINT32)(UINTN) Ring->Base >> EFI_PAGE_SHIFT);
if (EFI_ERROR (Status)) {
VirtioRingUninit (Ring);
goto ReleaseQueue;
}
return EFI_SUCCESS;
ReleaseQueue:
VirtioRingUninit (Ring);
return Status;
}
@ -287,10 +308,9 @@ VirtioNetInitRx (
// virtio-0.9.5, 2.4.1.4 Notifying the Device
//
MemoryFence ();
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueNotify, VIRTIO_NET_Q_RX);
Status = Dev->VirtIo->SetQueueNotify (Dev->VirtIo, VIRTIO_NET_Q_RX);
if (EFI_ERROR (Status)) {
VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);
Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
FreePool (Dev->RxBuf);
}
@ -366,13 +386,21 @@ VirtioNetInitialize (
// virtio-0.9.5 spec, 2.2.1 Device Initialization Sequence.
//
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 InitFailed;
}
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 DeviceFailed;
}
//
// Set Page Size - MMIO VirtIo Specific
//
Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
if (EFI_ERROR (Status)) {
goto DeviceFailed;
}
@ -381,10 +409,11 @@ VirtioNetInitialize (
// step 4a -- retrieve features. Note that we're past validating required
// features in VirtioNetGetFeatures().
//
Status = VIRTIO_CFG_READ (Dev, Generic.VhdrDeviceFeatureBits, &Features);
Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
if (EFI_ERROR (Status)) {
goto DeviceFailed;
}
ASSERT (Features & VIRTIO_NET_F_MAC);
ASSERT (Dev->Snm.MediaPresentSupported ==
!!(Features & VIRTIO_NET_F_STATUS));
@ -406,7 +435,7 @@ VirtioNetInitialize (
// step 5 -- keep only the features we want
//
Features &= VIRTIO_NET_F_MAC | VIRTIO_NET_F_STATUS;
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits, Features);
Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);
if (EFI_ERROR (Status)) {
goto ReleaseTxRing;
}
@ -415,7 +444,7 @@ VirtioNetInitialize (
// step 6 -- virtio-net 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 ReleaseTxRing;
}
@ -441,7 +470,7 @@ ReleaseTxAux:
VirtioNetShutdownTx (Dev);
AbortDevice:
VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);
Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
ReleaseTxRing:
VirtioRingUninit (&Dev->TxRing);
@ -453,7 +482,7 @@ DeviceFailed:
//
// restore device status invariant for the EfiSimpleNetworkStarted state
//
VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);
Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
InitFailed:
gBS->RestoreTPL (OldTpl);

View File

@ -147,14 +147,14 @@ VirtioNetReceive (
CopyMem (Buffer, RxPtr, RxLen);
if (DestAddr != NULL) {
CopyMem (DestAddr, RxPtr, SIZE_OF_VNET (VhdrMac));
CopyMem (DestAddr, RxPtr, SIZE_OF_VNET (Mac));
}
RxPtr += SIZE_OF_VNET (VhdrMac);
RxPtr += SIZE_OF_VNET (Mac);
if (SrcAddr != NULL) {
CopyMem (SrcAddr, RxPtr, SIZE_OF_VNET (VhdrMac));
CopyMem (SrcAddr, RxPtr, SIZE_OF_VNET (Mac));
}
RxPtr += SIZE_OF_VNET (VhdrMac);
RxPtr += SIZE_OF_VNET (Mac);
if (Protocol != NULL) {
*Protocol = (UINT16) ((RxPtr[0] << 8) | RxPtr[1]);
@ -177,9 +177,7 @@ RecycleDesc:
*Dev->RxRing.Avail.Idx = AvailIdx;
MemoryFence ();
NotifyStatus = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueNotify,
VIRTIO_NET_Q_RX);
NotifyStatus = Dev->VirtIo->SetQueueNotify (Dev->VirtIo, VIRTIO_NET_Q_RX);
if (!EFI_ERROR (Status)) { // earlier error takes precedence
Status = NotifyStatus;
}

View File

@ -63,7 +63,7 @@ VirtioNetShutdown (
break;
}
VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);
Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
VirtioNetShutdownRx (Dev);
VirtioNetShutdownTx (Dev);
VirtioRingUninit (&Dev->TxRing);

View File

@ -127,15 +127,15 @@ VirtioNetTransmit (
goto Exit;
}
Ptr = Buffer;
ASSERT (SIZE_OF_VNET (VhdrMac) <= sizeof (EFI_MAC_ADDRESS));
ASSERT (SIZE_OF_VNET (Mac) <= sizeof (EFI_MAC_ADDRESS));
CopyMem (Ptr, DestAddr, SIZE_OF_VNET (VhdrMac));
Ptr += SIZE_OF_VNET (VhdrMac);
CopyMem (Ptr, DestAddr, SIZE_OF_VNET (Mac));
Ptr += SIZE_OF_VNET (Mac);
CopyMem (Ptr,
(SrcAddr == NULL) ? &Dev->Snm.CurrentAddress : SrcAddr,
SIZE_OF_VNET (VhdrMac));
Ptr += SIZE_OF_VNET (VhdrMac);
SIZE_OF_VNET (Mac));
Ptr += SIZE_OF_VNET (Mac);
*Ptr++ = (UINT8) (*Protocol >> 8);
*Ptr++ = (UINT8) *Protocol;
@ -161,7 +161,7 @@ VirtioNetTransmit (
*Dev->TxRing.Avail.Idx = AvailIdx;
MemoryFence ();
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueNotify, VIRTIO_NET_Q_TX);
Status = Dev->VirtIo->SetQueueNotify (Dev->VirtIo, VIRTIO_NET_Q_TX);
Exit:
gBS->RestoreTPL (OldTpl);

View File

@ -24,7 +24,6 @@
#include <Protocol/ComponentName2.h>
#include <Protocol/DevicePath.h>
#include <Protocol/DriverBinding.h>
#include <Protocol/PciIo.h>
#include <Protocol/SimpleNetwork.h>
#define VNET_SIG SIGNATURE_32 ('V', 'N', 'E', 'T')
@ -75,8 +74,7 @@ typedef struct {
// field init function
// ------------------ ------------------------------
UINT32 Signature; // VirtioNetDriverBindingStart
EFI_PCI_IO_PROTOCOL *PciIo; // VirtioNetDriverBindingStart
UINT64 OrigPciAttributes; // VirtioNetDriverBindingStart
VIRTIO_DEVICE_PROTOCOL *VirtIo; // VirtioNetDriverBindingStart
EFI_SIMPLE_NETWORK_PROTOCOL Snp; // VirtioNetSnpPopulate
EFI_SIMPLE_NETWORK_MODE Snm; // VirtioNetSnpPopulate
EFI_EVENT ExitBoot; // VirtioNetSnpPopulate
@ -109,15 +107,15 @@ typedef struct {
#define VIRTIO_NET_FROM_SNP(SnpPointer) \
CR (SnpPointer, VNET_DEV, Snp, VNET_SIG)
#define VIRTIO_CFG_WRITE(Dev, Field, Value) (VirtioWrite ( \
(Dev)->PciIo, \
#define VIRTIO_CFG_WRITE(Dev, Field, Value) (VirtioWriteDevice ( \
(Dev)->VirtIo, \
OFFSET_OF_VNET (Field), \
SIZE_OF_VNET (Field), \
(Value) \
))
#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioRead ( \
(Dev)->PciIo, \
#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioReadDevice ( \
(Dev)->VirtIo, \
OFFSET_OF_VNET (Field), \
SIZE_OF_VNET (Field), \
sizeof *(Pointer), \

View File

@ -57,4 +57,4 @@
[Protocols]
gEfiSimpleNetworkProtocolGuid ## BY_START
gEfiDevicePathProtocolGuid ## BY_START
gEfiPciIoProtocolGuid ## TO_START
gVirtioDeviceProtocolGuid ## TO_START

View File

@ -38,7 +38,6 @@
**/
#include <IndustryStandard/Pci.h>
#include <IndustryStandard/VirtioScsi.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
@ -51,15 +50,14 @@
/**
Convenience macros to read and write region 0 IO space elements of the
virtio-scsi PCI device, for configuration purposes.
Convenience macros to read and write configuration elements of the
virtio-scsi VirtIo device.
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 VSCSI_DEV structure whose PCI IO space
we're accessing. Dev->PciIo must be valid.
@param[in] Dev Pointer to the VSCSI_DEV structure.
@param[in] Field A field name from VSCSI_HDR, identifying the virtio-scsi
configuration item to access.
@ -72,19 +70,19 @@
one of UINT8, UINT16, UINT32, UINT64.
@return Status codes returned by VirtioWrite() / VirtioRead().
@return Status codes 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_VSCSI (Field), \
SIZE_OF_VSCSI (Field), \
(Value) \
))
#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioRead ( \
(Dev)->PciIo, \
#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioReadDevice ( \
(Dev)->VirtIo, \
OFFSET_OF_VSCSI (Field), \
SIZE_OF_VSCSI (Field), \
sizeof *(Pointer), \
@ -471,7 +469,7 @@ VirtioScsiPassThru (
// EFI_NOT_READY would save us the effort, but it would also suggest that the
// caller retry.
//
if (VirtioFlush (Dev->PciIo, VIRTIO_SCSI_REQUEST_QUEUE, &Dev->Ring,
if (VirtioFlush (Dev->VirtIo, VIRTIO_SCSI_REQUEST_QUEUE, &Dev->Ring,
&Indices) != EFI_SUCCESS) {
Packet->InTransferLength = 0;
Packet->OutTransferLength = 0;
@ -718,19 +716,27 @@ VirtioScsiInit (
// 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;
}
@ -738,13 +744,13 @@ VirtioScsiInit (
//
// 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;
}
Dev->InOutSupported = !!(Features & VIRTIO_SCSI_F_INOUT);
Status = VIRTIO_CFG_READ (Dev, VhdrMaxChannel, &MaxChannel);
Status = VIRTIO_CFG_READ (Dev, MaxChannel, &MaxChannel);
if (EFI_ERROR (Status)) {
goto Failed;
}
@ -756,7 +762,7 @@ VirtioScsiInit (
goto Failed;
}
Status = VIRTIO_CFG_READ (Dev, VhdrNumQueues, &NumQueues);
Status = VIRTIO_CFG_READ (Dev, NumQueues, &NumQueues);
if (EFI_ERROR (Status)) {
goto Failed;
}
@ -765,7 +771,7 @@ VirtioScsiInit (
goto Failed;
}
Status = VIRTIO_CFG_READ (Dev, VhdrMaxTarget, &Dev->MaxTarget);
Status = VIRTIO_CFG_READ (Dev, MaxTarget, &Dev->MaxTarget);
if (EFI_ERROR (Status)) {
goto Failed;
}
@ -773,7 +779,7 @@ VirtioScsiInit (
Dev->MaxTarget = PcdGet16 (PcdVirtioScsiMaxTargetLimit);
}
Status = VIRTIO_CFG_READ (Dev, VhdrMaxLun, &Dev->MaxLun);
Status = VIRTIO_CFG_READ (Dev, MaxLun, &Dev->MaxLun);
if (EFI_ERROR (Status)) {
goto Failed;
}
@ -781,7 +787,7 @@ VirtioScsiInit (
Dev->MaxLun = PcdGet32 (PcdVirtioScsiMaxLunLimit);
}
Status = VIRTIO_CFG_READ (Dev, VhdrMaxSectors, &Dev->MaxSectors);
Status = VIRTIO_CFG_READ (Dev, MaxSectors, &Dev->MaxSectors);
if (EFI_ERROR (Status)) {
goto Failed;
}
@ -797,12 +803,11 @@ VirtioScsiInit (
//
// step 4b -- allocate request virtqueue
//
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect,
VIRTIO_SCSI_REQUEST_QUEUE);
Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, VIRTIO_SCSI_REQUEST_QUEUE);
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;
}
@ -820,11 +825,24 @@ VirtioScsiInit (
}
//
// 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;
}
@ -834,8 +852,8 @@ VirtioScsiInit (
// the known (or unknown) VIRTIO_SCSI_F_* or VIRTIO_F_* capabilities (see
// virtio-0.9.5, Appendices B and I), except bidirectional transfers.
//
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits,
Features & VIRTIO_SCSI_F_INOUT);
Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo,
Features & VIRTIO_SCSI_F_INOUT);
if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
@ -844,11 +862,11 @@ VirtioScsiInit (
// We expect these maximum sizes from the host. Since they are
// guest-negotiable, ask for them rather than just checking them.
//
Status = VIRTIO_CFG_WRITE (Dev, VhdrCdbSize, VIRTIO_SCSI_CDB_SIZE);
Status = VIRTIO_CFG_WRITE (Dev, CdbSize, VIRTIO_SCSI_CDB_SIZE);
if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
Status = VIRTIO_CFG_WRITE (Dev, VhdrSenseSize, VIRTIO_SCSI_SENSE_SIZE);
Status = VIRTIO_CFG_WRITE (Dev, SenseSize, VIRTIO_SCSI_SENSE_SIZE);
if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
@ -857,7 +875,7 @@ VirtioScsiInit (
// 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;
}
@ -901,10 +919,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);
Dev->InOutSupported = FALSE;
Dev->MaxTarget = 0;
@ -928,7 +946,7 @@ VirtioScsiUninit (
// 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);
Dev->InOutSupported = FALSE;
Dev->MaxTarget = 0;
@ -953,11 +971,8 @@ VirtioScsiUninit (
// The implementation follows:
// - Driver Writer's Guide for UEFI 2.3.1 v1.01
// - 5.1.3.4 OpenProtocol() and CloseProtocol()
// - 18 PCI Driver Design Guidelines
// - 18.3 PCI drivers
// - UEFI Spec 2.3.1 + Errata C
// - 6.3 Protocol Handler Services
// - 13.4 EFI PCI I/O Protocol
//
EFI_STATUS
@ -968,57 +983,37 @@ VirtioScsiDriverBindingSupported (
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
PCI_TYPE00 Pci;
EFI_STATUS Status;
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_SCSI_HOST) ? EFI_SUCCESS : EFI_UNSUPPORTED;
if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_SCSI_HOST) {
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;
}
@ -1040,43 +1035,19 @@ VirtioScsiDriverBindingStart (
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 FreeVirtioScsi;
}
//
// 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-scsi 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-scsi device.
// VirtIo access granted, configure virtio-scsi device.
//
Status = VirtioScsiInit (Dev);
if (EFI_ERROR (Status)) {
goto RestorePciAttributes;
goto CloseVirtIo;
}
//
@ -1096,12 +1067,8 @@ VirtioScsiDriverBindingStart (
UninitDev:
VirtioScsiUninit (Dev);
RestorePciAttributes:
Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
Dev->OriginalPciAttributes, NULL);
ClosePciIo:
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
CloseVirtIo:
gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, DeviceHandle);
FreeVirtioScsi:
@ -1149,10 +1116,7 @@ VirtioScsiDriverBindingStop (
VirtioScsiUninit (Dev);
Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
Dev->OriginalPciAttributes, NULL);
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, DeviceHandle);
FreePool (Dev);

View File

@ -20,7 +20,6 @@
#include <Protocol/ComponentName.h>
#include <Protocol/DriverBinding.h>
#include <Protocol/PciIo.h>
#include <Protocol/ScsiPassThruExt.h>
#include <IndustryStandard/Virtio.h>
@ -49,18 +48,17 @@ typedef struct {
// at various call depths. The table to the right should make it easier to
// track them.
//
// field init function init depth
// ---------------------- ------------------ ----------
UINT32 Signature; // DriverBindingStart 0
EFI_PCI_IO_PROTOCOL *PciIo; // DriverBindingStart 0
UINT64 OriginalPciAttributes; // DriverBindingStart 0
BOOLEAN InOutSupported; // VirtioScsiInit 1
UINT16 MaxTarget; // VirtioScsiInit 1
UINT32 MaxLun; // VirtioScsiInit 1
UINT32 MaxSectors; // VirtioScsiInit 1
VRING Ring; // VirtioRingInit 2
EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru; // VirtioScsiInit 1
EFI_EXT_SCSI_PASS_THRU_MODE PassThruMode; // VirtioScsiInit 1
// field init function init depth
// ---------------- ------------------ ----------
UINT32 Signature; // DriverBindingStart 0
VIRTIO_DEVICE_PROTOCOL *VirtIo; // DriverBindingStart 0
BOOLEAN InOutSupported; // VirtioScsiInit 1
UINT16 MaxTarget; // VirtioScsiInit 1
UINT32 MaxLun; // VirtioScsiInit 1
UINT32 MaxSectors; // VirtioScsiInit 1
VRING Ring; // VirtioRingInit 2
EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru; // VirtioScsiInit 1
EFI_EXT_SCSI_PASS_THRU_MODE PassThruMode; // VirtioScsiInit 1
} VSCSI_DEV;
#define VIRTIO_SCSI_FROM_PASS_THRU(PassThruPointer) \

View File

@ -40,7 +40,7 @@
[Protocols]
gEfiExtScsiPassThruProtocolGuid ## BY_START
gEfiPciIoProtocolGuid ## TO_START
gVirtioDeviceProtocolGuid ## TO_START
[Pcd]
gUefiOvmfPkgTokenSpaceGuid.PcdVirtioScsiMaxTargetLimit ## CONSUMES