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

View File

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

View File

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

View File

@ -17,17 +17,19 @@
#ifndef _VIRTIO_LIB_H_ #ifndef _VIRTIO_LIB_H_
#define _VIRTIO_LIB_H_ #define _VIRTIO_LIB_H_
#include <Protocol/PciIo.h> #include <Protocol/VirtioDevice.h>
#include <IndustryStandard/Virtio.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 The VirtIo Device Specific Region must be an iomem region.
driver-specific VIRTIO_CFG_WRITE() macros. 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. @param[in] FieldOffset Destination offset.
@ -37,13 +39,13 @@
The least significant FieldSize bytes will be used. 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 EFI_STATUS
EFIAPI EFIAPI
VirtioWrite ( VirtioWriteDevice (
IN EFI_PCI_IO_PROTOCOL *PciIo, IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
IN UINTN FieldOffset, IN UINTN FieldOffset,
IN UINTN FieldSize, IN UINTN FieldSize,
IN UINT64 Value IN UINT64 Value
@ -52,12 +54,13 @@ VirtioWrite (
/** /**
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 The VirtIo Device Specific Region must be an iomem region.
driver-specific VIRTIO_CFG_READ() macros. 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. @param[in] FieldOffset Source offset.
@ -69,13 +72,13 @@ VirtioWrite (
@param[out] Buffer Target buffer. @param[out] Buffer Target buffer.
@return Status code returned by PciIo->Io.Read(). @return Status code returned by VirtIo->ReadDevice().
**/ **/
EFI_STATUS EFI_STATUS
EFIAPI EFIAPI
VirtioRead ( VirtioReadDevice (
IN EFI_PCI_IO_PROTOCOL *PciIo, IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
IN UINTN FieldOffset, IN UINTN FieldOffset,
IN UINTN FieldSize, IN UINTN FieldSize,
IN UINTN BufferSize, IN UINTN BufferSize,
@ -218,7 +221,7 @@ VirtioAppendDesc (
Notify the host about the descriptor chain just built, and wait until the Notify the host about the descriptor chain just built, and wait until the
host processes it. 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. @param[in] VirtQueueId Identifies the queue for the target device.
@ -229,7 +232,7 @@ VirtioAppendDesc (
of the descriptor chain. 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. @retval EFI_SUCCESS Otherwise, the host processed all descriptors.
@ -237,7 +240,7 @@ VirtioAppendDesc (
EFI_STATUS EFI_STATUS
EFIAPI EFIAPI
VirtioFlush ( VirtioFlush (
IN EFI_PCI_IO_PROTOCOL *PciIo, IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
IN UINT16 VirtQueueId, IN UINT16 VirtQueueId,
IN OUT VRING *Ring, IN OUT VRING *Ring,
IN DESC_INDICES *Indices IN DESC_INDICES *Indices

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -23,7 +23,6 @@
**/ **/
#include <IndustryStandard/Pci.h>
#include <IndustryStandard/VirtioBlk.h> #include <IndustryStandard/VirtioBlk.h>
#include <Library/BaseMemoryLib.h> #include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h> #include <Library/DebugLib.h>
@ -37,14 +36,14 @@
/** /**
Convenience macros to read and write region 0 IO space elements of the 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" 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() for such accesses and to derive the rest. By the time VIRTIO_CFG_WRITE()
returns, the transaction will have been completed. returns, the transaction will have been completed.
@param[in] Dev Pointer to the VBLK_DEV structure whose PCI IO space @param[in] Dev Pointer to the VBLK_DEV structure whose VirtIo space
we're accessing. Dev->PciIo must be valid. we're accessing. Dev->VirtIo must be valid.
@param[in] Field A field name from VBLK_HDR, identifying the virtio-blk @param[in] Field A field name from VBLK_HDR, identifying the virtio-blk
configuration item to access. configuration item to access.
@ -57,19 +56,19 @@
one of UINT8, UINT16, UINT32, UINT64. 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 ( \ #define VIRTIO_CFG_WRITE(Dev, Field, Value) (VirtioWriteDevice ( \
(Dev)->PciIo, \ (Dev)->VirtIo, \
OFFSET_OF_VBLK (Field), \ OFFSET_OF_VBLK (Field), \
SIZE_OF_VBLK (Field), \ SIZE_OF_VBLK (Field), \
(Value) \ (Value) \
)) ))
#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioRead ( \ #define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioReadDevice ( \
(Dev)->PciIo, \ (Dev)->VirtIo, \
OFFSET_OF_VBLK (Field), \ OFFSET_OF_VBLK (Field), \
SIZE_OF_VBLK (Field), \ SIZE_OF_VBLK (Field), \
sizeof *(Pointer), \ sizeof *(Pointer), \
@ -229,7 +228,7 @@ VerifyReadWriteRequest (
@retval EFI_SUCCESS Transfer complete. @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 unable to parse host response, or host response
is not VIRTIO_BLK_S_OK. is not VIRTIO_BLK_S_OK.
@ -324,7 +323,7 @@ SynchronousRequest (
// //
// virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D). // 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) { HostStatus == VIRTIO_BLK_S_OK) {
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -500,11 +499,6 @@ VirtioBlkFlushBlocks (
underlying device underlying device
- 9 Driver Binding Protocol -- for exporting ourselves - 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 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object
incorporating this driver (independently of incorporating this driver (independently of
any device). any device).
@ -516,11 +510,11 @@ VirtioBlkFlushBlocks (
@retval EFI_SUCCESS The driver supports the device being probed. @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. the device.
@return Error codes from the OpenProtocol() boot service or @return Error codes from the OpenProtocol() boot service or
the PciIo protocol. the VirtIo protocol.
**/ **/
@ -533,56 +527,36 @@ VirtioBlkDriverBindingSupported (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo; VIRTIO_DEVICE_PROTOCOL *VirtIo;
PCI_TYPE00 Pci;
// //
// Attempt to open the device with the PciIo set of interfaces. On success, // Attempt to open the device with the VirtIo set of interfaces. On success,
// the protocol is "instantiated" for the PCI device. Covers duplicate open // the protocol is "instantiated" for the VirtIo device. Covers duplicate open
// attempts (EFI_ALREADY_STARTED). // attempts (EFI_ALREADY_STARTED).
// //
Status = gBS->OpenProtocol ( Status = gBS->OpenProtocol (
DeviceHandle, // candidate device DeviceHandle, // candidate device
&gEfiPciIoProtocolGuid, // for generic PCI access &gVirtioDeviceProtocolGuid, // for generic VirtIo access
(VOID **)&PciIo, // handle to instantiate (VOID **)&VirtIo, // handle to instantiate
This->DriverBindingHandle, // requestor driver identity This->DriverBindingHandle, // requestor driver identity
DeviceHandle, // ControllerHandle, according to DeviceHandle, // ControllerHandle, according to
// the UEFI Driver Model // 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 // the device; to be released
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return Status; return Status;
} }
// if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) {
// Read entire PCI configuration header for more extensive check ahead. Status = EFI_UNSUPPORTED;
//
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;
} }
// //
// 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. // device or not.
// //
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, DeviceHandle); This->DriverBindingHandle, DeviceHandle);
return Status; return Status;
} }
@ -594,8 +568,8 @@ VirtioBlkDriverBindingSupported (
device. device.
@param[in out] Dev The driver instance to configure. The caller is @param[in out] Dev The driver instance to configure. The caller is
responsible for Dev->PciIo's validity (ie. working IO responsible for Dev->VirtIo's validity (ie. working IO
access to the underlying virtio-blk PCI device). access to the underlying virtio-blk device).
@retval EFI_SUCCESS Setup complete. @retval EFI_SUCCESS Setup complete.
@ -626,19 +600,27 @@ VirtioBlkInit (
// Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence. // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
// //
NextDevStat = 0; // step 1 -- reset device 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)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence 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)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it 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)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
@ -646,11 +628,12 @@ VirtioBlkInit (
// //
// step 4a -- retrieve and validate features // 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)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
Status = VIRTIO_CFG_READ (Dev, VhdrCapacity, &NumSectors);
Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
@ -660,7 +643,7 @@ VirtioBlkInit (
} }
if (Features & VIRTIO_BLK_F_BLK_SIZE) { 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)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
@ -681,11 +664,11 @@ VirtioBlkInit (
// //
// step 4b -- allocate virtqueue // step 4b -- allocate virtqueue
// //
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect, 0); Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
Status = VIRTIO_CFG_READ (Dev, Generic.VhdrQueueSize, &QueueSize); Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
@ -700,22 +683,36 @@ VirtioBlkInit (
} }
// //
// step 4c -- Report GPFN (guest-physical frame number) of queue. If anything // Additional steps for MMIO: align the queue appropriately, and set the
// fails from here on, we must release the ring resources. // size. If anything fails from here on, we must release the ring resources.
// //
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueAddress, Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
(UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto ReleaseQueue; 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 // 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 // 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 // device-independent (known or unknown) VIRTIO_F_* capabilities (see
// Appendix B). // Appendix B).
// //
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits, 0); Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, 0);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto ReleaseQueue; goto ReleaseQueue;
} }
@ -724,7 +721,7 @@ VirtioBlkInit (
// step 6 -- initialization complete // step 6 -- initialization complete
// //
NextDevStat |= VSTAT_DRIVER_OK; NextDevStat |= VSTAT_DRIVER_OK;
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat); Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto ReleaseQueue; goto ReleaseQueue;
} }
@ -758,10 +755,10 @@ ReleaseQueue:
Failed: Failed:
// //
// Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device // 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; NextDevStat |= VSTAT_FAILED;
VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat); Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
return Status; // reached only via Failed above 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 // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
// the old comms area. // the old comms area.
// //
VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0); Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
VirtioRingUninit (&Dev->Ring); VirtioRingUninit (&Dev->Ring);
@ -815,13 +812,13 @@ VirtioBlkUninit (
@retval EFI_SUCCESS Driver instance has been created and @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. is now accessibla via EFI_BLOCK_IO_PROTOCOL.
@retval EFI_OUT_OF_RESOURCES Memory allocation failed. @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
@return Error codes from the OpenProtocol() boot @return Error codes from the OpenProtocol() boot
service, the PciIo protocol, VirtioBlkInit(), service, the VirtIo protocol, VirtioBlkInit(),
or the InstallProtocolInterface() boot service. or the InstallProtocolInterface() boot service.
**/ **/
@ -842,43 +839,19 @@ VirtioBlkDriverBindingStart (
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
} }
Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
(VOID **)&Dev->PciIo, This->DriverBindingHandle, (VOID **)&Dev->VirtIo, This->DriverBindingHandle,
DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto FreeVirtioBlk; goto FreeVirtioBlk;
} }
// //
// We must retain and ultimately restore the original PCI attributes of the // VirtIo access granted, configure virtio-blk device.
// 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.
// //
Status = VirtioBlkInit (Dev); Status = VirtioBlkInit (Dev);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto RestorePciAttributes; goto CloseVirtIo;
} }
// //
@ -897,12 +870,8 @@ VirtioBlkDriverBindingStart (
UninitDev: UninitDev:
VirtioBlkUninit (Dev); VirtioBlkUninit (Dev);
RestorePciAttributes: CloseVirtIo:
Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet, gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
Dev->OriginalPciAttributes, NULL);
ClosePciIo:
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
This->DriverBindingHandle, DeviceHandle); This->DriverBindingHandle, DeviceHandle);
FreeVirtioBlk: FreeVirtioBlk:
@ -973,10 +942,7 @@ VirtioBlkDriverBindingStop (
VirtioBlkUninit (Dev); VirtioBlkUninit (Dev);
Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet, gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
Dev->OriginalPciAttributes, NULL);
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
This->DriverBindingHandle, DeviceHandle); This->DriverBindingHandle, DeviceHandle);
FreePool (Dev); FreePool (Dev);

View File

@ -21,7 +21,6 @@
#include <Protocol/BlockIo.h> #include <Protocol/BlockIo.h>
#include <Protocol/ComponentName.h> #include <Protocol/ComponentName.h>
#include <Protocol/DriverBinding.h> #include <Protocol/DriverBinding.h>
#include <Protocol/PciIo.h>
#include <IndustryStandard/Virtio.h> #include <IndustryStandard/Virtio.h>
@ -35,10 +34,9 @@ typedef struct {
// track them. // track them.
// //
// field init function init dpth // field init function init dpth
// ---------------------- ------------------ --------- // --------------------- ------------------ ---------
UINT32 Signature; // DriverBindingStart 0 UINT32 Signature; // DriverBindingStart 0
EFI_PCI_IO_PROTOCOL *PciIo; // DriverBindingStart 0 VIRTIO_DEVICE_PROTOCOL *VirtIo; // DriverBindingStart 0
UINT64 OriginalPciAttributes; // DriverBindingStart 0
VRING Ring; // VirtioRingInit 2 VRING Ring; // VirtioRingInit 2
EFI_BLOCK_IO_PROTOCOL BlockIo; // VirtioBlkInit 1 EFI_BLOCK_IO_PROTOCOL BlockIo; // VirtioBlkInit 1
EFI_BLOCK_IO_MEDIA BlockIoMedia; // VirtioBlkInit 1 EFI_BLOCK_IO_MEDIA BlockIoMedia; // VirtioBlkInit 1
@ -66,11 +64,6 @@ typedef struct {
underlying device underlying device
- 9 Driver Binding Protocol -- for exporting ourselves - 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 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object
incorporating this driver (independently of incorporating this driver (independently of
any device). any device).
@ -82,11 +75,10 @@ typedef struct {
@retval EFI_SUCCESS The driver supports the device being probed. @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. the device.
@return Error codes from the OpenProtocol() boot service or @return Error codes from the OpenProtocol() boot service.
the PciIo protocol.
**/ **/
@ -117,14 +109,14 @@ VirtioBlkDriverBindingSupported (
@retval EFI_SUCCESS Driver instance has been created and @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. is now accessibla via EFI_BLOCK_IO_PROTOCOL.
@retval EFI_OUT_OF_RESOURCES Memory allocation failed. @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
@return Error codes from the OpenProtocol() boot @return Error codes from the OpenProtocol() boot
service, the PciIo protocol, VirtioBlkInit(), service, VirtioBlkInit(), or the
or the InstallProtocolInterface() boot service. InstallProtocolInterface() boot service.
**/ **/

View File

@ -39,4 +39,4 @@
[Protocols] [Protocols]
gEfiBlockIoProtocolGuid ## BY_START gEfiBlockIoProtocolGuid ## BY_START
gEfiPciIoProtocolGuid ## TO_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 // Protocol
// //
Status = EfiTestManagedDevice ( Status = EfiTestManagedDevice (
ControllerHandle, ControllerHandle,
gVirtioNetDriverBinding.DriverBindingHandle, gVirtioNetDriverBinding.DriverBindingHandle,
&gEfiPciIoProtocolGuid &gVirtioDeviceProtocolGuid
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return 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 // child (= MAC) handle
// //
return LookupUnicodeString2 ( return LookupUnicodeString2 (

View File

@ -15,7 +15,6 @@
**/ **/
#include <IndustryStandard/Pci.h>
#include <Library/BaseMemoryLib.h> #include <Library/BaseMemoryLib.h>
#include <Library/DevicePathLib.h> #include <Library/DevicePathLib.h>
#include <Library/MemoryAllocationLib.h> #include <Library/MemoryAllocationLib.h>
@ -50,8 +49,7 @@
unused. unused.
@retval EFI_UNSUPPORTED The host doesn't supply a MAC address. @retval EFI_UNSUPPORTED The host doesn't supply a MAC address.
@return Status codes from Dev->PciIo->Io.Read(), @return Status codes from VirtIo protocol members.
VIRTIO_CFG_READ() and VIRTIO_CFG_WRITE().
@retval EFI_SUCCESS Configuration values retrieved. @retval EFI_SUCCESS Configuration values retrieved.
*/ */
STATIC STATIC
@ -67,6 +65,7 @@ VirtioNetGetFeatures (
EFI_STATUS Status; EFI_STATUS Status;
UINT8 NextDevStat; UINT8 NextDevStat;
UINT32 Features; UINT32 Features;
UINTN MacIdx;
UINT16 LinkStatus; UINT16 LinkStatus;
// //
@ -74,19 +73,19 @@ VirtioNetGetFeatures (
// Initialization Sequence), but don't complete setting it up. // Initialization Sequence), but don't complete setting it up.
// //
NextDevStat = 0; // step 1 -- reset device 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)) { if (EFI_ERROR (Status)) {
return Status; return Status;
} }
NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence 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)) { if (EFI_ERROR (Status)) {
goto YieldDevice; goto YieldDevice;
} }
NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it 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)) { if (EFI_ERROR (Status)) {
goto YieldDevice; goto YieldDevice;
} }
@ -94,7 +93,7 @@ VirtioNetGetFeatures (
// //
// step 4a -- retrieve and validate features // 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)) { if (EFI_ERROR (Status)) {
goto YieldDevice; goto YieldDevice;
} }
@ -106,17 +105,17 @@ VirtioNetGetFeatures (
Status = EFI_UNSUPPORTED; Status = EFI_UNSUPPORTED;
goto YieldDevice; goto YieldDevice;
} }
Status = Dev->PciIo->Io.Read (Dev->PciIo, // PciIo for (MacIdx = 0; MacIdx < SIZE_OF_VNET (Mac); ++MacIdx) {
EfiPciIoWidthUint8, // Width Status = Dev->VirtIo->ReadDevice (Dev->VirtIo,
PCI_BAR_IDX0, // BarIndex OFFSET_OF_VNET (Mac) + MacIdx, // Offset
OFFSET_OF_VNET (VhdrMac), // Offset 1, // FieldSize
SIZE_OF_VNET (VhdrMac), // Count 1, // BufferSize
MacAddress // Buffer &MacAddress->Addr[MacIdx] // Buffer
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto YieldDevice; goto YieldDevice;
} }
}
// //
// check if link status is reported, and if so, what the link status is // check if link status is reported, and if so, what the link status is
@ -126,7 +125,7 @@ VirtioNetGetFeatures (
} }
else { else {
*MediaPresentSupported = TRUE; *MediaPresentSupported = TRUE;
Status = VIRTIO_CFG_READ (Dev, VhdrLinkStatus, &LinkStatus); Status = VIRTIO_CFG_READ (Dev, LinkStatus, &LinkStatus);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto YieldDevice; goto YieldDevice;
} }
@ -134,7 +133,7 @@ VirtioNetGetFeatures (
} }
YieldDevice: YieldDevice:
VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, Dev->VirtIo->SetDeviceStatus (Dev->VirtIo,
EFI_ERROR (Status) ? VSTAT_FAILED : 0); EFI_ERROR (Status) ? VSTAT_FAILED : 0);
return Status; return Status;
@ -207,9 +206,9 @@ VirtioNetSnpPopulate (
Dev->Snp.Mode = &Dev->Snm; Dev->Snp.Mode = &Dev->Snm;
Dev->Snm.State = EfiSimpleNetworkStopped; Dev->Snm.State = EfiSimpleNetworkStopped;
Dev->Snm.HwAddressSize = SIZE_OF_VNET (VhdrMac); Dev->Snm.HwAddressSize = SIZE_OF_VNET (Mac);
Dev->Snm.MediaHeaderSize = SIZE_OF_VNET (VhdrMac) + // dst MAC Dev->Snm.MediaHeaderSize = SIZE_OF_VNET (Mac) + // dst MAC
SIZE_OF_VNET (VhdrMac) + // src MAC SIZE_OF_VNET (Mac) + // src MAC
2; // Ethertype 2; // Ethertype
Dev->Snm.MaxPacketSize = 1500; Dev->Snm.MaxPacketSize = 1500;
Dev->Snm.NvRamSize = 0; Dev->Snm.NvRamSize = 0;
@ -222,7 +221,7 @@ VirtioNetSnpPopulate (
Dev->Snm.MacAddressChangeable = FALSE; Dev->Snm.MacAddressChangeable = FALSE;
Dev->Snm.MultipleTxSupported = TRUE; 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, Status = VirtioNetGetFeatures (Dev, &Dev->Snm.CurrentAddress,
&Dev->Snm.MediaPresentSupported, &Dev->Snm.MediaPresent); &Dev->Snm.MediaPresentSupported, &Dev->Snm.MediaPresent);
@ -230,8 +229,8 @@ VirtioNetSnpPopulate (
goto CloseWaitForPacket; goto CloseWaitForPacket;
} }
CopyMem (&Dev->Snm.PermanentAddress, &Dev->Snm.CurrentAddress, CopyMem (&Dev->Snm.PermanentAddress, &Dev->Snm.CurrentAddress,
SIZE_OF_VNET (VhdrMac)); SIZE_OF_VNET (Mac));
SetMem (&Dev->Snm.BroadcastAddress, SIZE_OF_VNET (VhdrMac), 0xFF); SetMem (&Dev->Snm.BroadcastAddress, SIZE_OF_VNET (Mac), 0xFF);
// //
// VirtioNetExitBoot() is queued by ExitBootServices(); its purpose is to // VirtioNetExitBoot() is queued by ExitBootServices(); its purpose is to
@ -348,31 +347,36 @@ VirtioNetDriverBindingSupported (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo; VIRTIO_DEVICE_PROTOCOL *VirtIo;
PCI_TYPE00 Pci;
Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, //
(VOID **)&PciIo, This->DriverBindingHandle, DeviceHandle, // Attempt to open the device with the VirtIo set of interfaces. On success,
EFI_OPEN_PROTOCOL_BY_DRIVER); // 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)) { if (EFI_ERROR (Status)) {
return Status; return Status;
} }
Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_NETWORK_CARD) {
sizeof Pci / sizeof (UINT32), &Pci); Status = EFI_UNSUPPORTED;
//
// 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;
} }
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); This->DriverBindingHandle, DeviceHandle);
return Status; return Status;
} }
@ -438,7 +442,7 @@ VirtioNetDriverBindingStart (
VNET_DEV *Dev; VNET_DEV *Dev;
EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_DEVICE_PATH_PROTOCOL *DevicePath;
MAC_ADDR_DEVICE_PATH MacNode; MAC_ADDR_DEVICE_PATH MacNode;
VOID *ChildPciIo; VOID *ChildVirtIo;
// //
// allocate space for the driver instance // allocate space for the driver instance
@ -449,43 +453,24 @@ VirtioNetDriverBindingStart (
} }
Dev->Signature = VNET_SIG; Dev->Signature = VNET_SIG;
// Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
// get PCI access to the device and keep it open (VOID **)&Dev->VirtIo, This->DriverBindingHandle,
//
Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
(VOID **)&Dev->PciIo, This->DriverBindingHandle,
DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto FreeVirtioNet; 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 // now we can run a basic one-shot virtio-net initialization required to
// retrieve the MAC address // retrieve the MAC address
// //
Status = VirtioNetSnpPopulate (Dev); Status = VirtioNetSnpPopulate (Dev);
if (EFI_ERROR (Status)) { 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, Status = gBS->OpenProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid,
(VOID **)&DevicePath, This->DriverBindingHandle, (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 // child
// //
Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
&ChildPciIo, This->DriverBindingHandle, &ChildVirtIo, This->DriverBindingHandle,
Dev->MacHandle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER); Dev->MacHandle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto UninstallMultiple; goto UninstallMultiple;
@ -547,12 +532,8 @@ FreeMacDevicePath:
Evacuate: Evacuate:
VirtioNetSnpEvacuate (Dev); VirtioNetSnpEvacuate (Dev);
RestorePciAttributes: CloseVirtIo:
Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet, gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
Dev->OrigPciAttributes, NULL);
ClosePciIo:
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
This->DriverBindingHandle, DeviceHandle); This->DriverBindingHandle, DeviceHandle);
FreeVirtioNet: FreeVirtioNet:
@ -637,7 +618,7 @@ VirtioNetDriverBindingStop (
Status = EFI_DEVICE_ERROR; Status = EFI_DEVICE_ERROR;
} }
else { else {
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, Dev->MacHandle); This->DriverBindingHandle, Dev->MacHandle);
gBS->UninstallMultipleProtocolInterfaces (Dev->MacHandle, gBS->UninstallMultipleProtocolInterfaces (Dev->MacHandle,
&gEfiDevicePathProtocolGuid, Dev->MacDevicePath, &gEfiDevicePathProtocolGuid, Dev->MacDevicePath,
@ -645,8 +626,6 @@ VirtioNetDriverBindingStop (
NULL); NULL);
FreePool (Dev->MacDevicePath); FreePool (Dev->MacDevicePath);
VirtioNetSnpEvacuate (Dev); VirtioNetSnpEvacuate (Dev);
Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,
Dev->OrigPciAttributes, NULL);
FreePool (Dev); FreePool (Dev);
} }
@ -657,7 +636,7 @@ VirtioNetDriverBindingStop (
// //
// release remaining resources, tied directly to the parent handle // release remaining resources, tied directly to the parent handle
// //
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, DeviceHandle); This->DriverBindingHandle, DeviceHandle);
return EFI_SUCCESS; return EFI_SUCCESS;

View File

@ -86,6 +86,6 @@ VirtioNetExitBoot (
Dev = Context; Dev = Context;
if (Dev->Snm.State == EfiSimpleNetworkInitialized) { 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) { if (Dev->Snm.MediaPresentSupported) {
UINT16 LinkStatus; UINT16 LinkStatus;
Status = VIRTIO_CFG_READ (Dev, VhdrLinkStatus, &LinkStatus); Status = VIRTIO_CFG_READ (Dev, LinkStatus, &LinkStatus);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Exit; goto Exit;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -57,4 +57,4 @@
[Protocols] [Protocols]
gEfiSimpleNetworkProtocolGuid ## BY_START gEfiSimpleNetworkProtocolGuid ## BY_START
gEfiDevicePathProtocolGuid ## 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 <IndustryStandard/VirtioScsi.h>
#include <Library/BaseMemoryLib.h> #include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h> #include <Library/DebugLib.h>
@ -51,15 +50,14 @@
/** /**
Convenience macros to read and write region 0 IO space elements of the Convenience macros to read and write configuration elements of the
virtio-scsi PCI device, for configuration purposes. virtio-scsi VirtIo device.
The following macros make it possible to specify only the "core parameters" 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() for such accesses and to derive the rest. By the time VIRTIO_CFG_WRITE()
returns, the transaction will have been completed. returns, the transaction will have been completed.
@param[in] Dev Pointer to the VSCSI_DEV structure whose PCI IO space @param[in] Dev Pointer to the VSCSI_DEV structure.
we're accessing. Dev->PciIo must be valid.
@param[in] Field A field name from VSCSI_HDR, identifying the virtio-scsi @param[in] Field A field name from VSCSI_HDR, identifying the virtio-scsi
configuration item to access. configuration item to access.
@ -72,19 +70,19 @@
one of UINT8, UINT16, UINT32, UINT64. 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 ( \ #define VIRTIO_CFG_WRITE(Dev, Field, Value) (VirtioWriteDevice ( \
(Dev)->PciIo, \ (Dev)->VirtIo, \
OFFSET_OF_VSCSI (Field), \ OFFSET_OF_VSCSI (Field), \
SIZE_OF_VSCSI (Field), \ SIZE_OF_VSCSI (Field), \
(Value) \ (Value) \
)) ))
#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioRead ( \ #define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioReadDevice ( \
(Dev)->PciIo, \ (Dev)->VirtIo, \
OFFSET_OF_VSCSI (Field), \ OFFSET_OF_VSCSI (Field), \
SIZE_OF_VSCSI (Field), \ SIZE_OF_VSCSI (Field), \
sizeof *(Pointer), \ sizeof *(Pointer), \
@ -471,7 +469,7 @@ VirtioScsiPassThru (
// EFI_NOT_READY would save us the effort, but it would also suggest that the // EFI_NOT_READY would save us the effort, but it would also suggest that the
// caller retry. // 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) { &Indices) != EFI_SUCCESS) {
Packet->InTransferLength = 0; Packet->InTransferLength = 0;
Packet->OutTransferLength = 0; Packet->OutTransferLength = 0;
@ -718,19 +716,27 @@ VirtioScsiInit (
// Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence. // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
// //
NextDevStat = 0; // step 1 -- reset device 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)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence 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)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it 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)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
@ -738,13 +744,13 @@ VirtioScsiInit (
// //
// step 4a -- retrieve and validate features // 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)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
Dev->InOutSupported = !!(Features & VIRTIO_SCSI_F_INOUT); 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)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
@ -756,7 +762,7 @@ VirtioScsiInit (
goto Failed; goto Failed;
} }
Status = VIRTIO_CFG_READ (Dev, VhdrNumQueues, &NumQueues); Status = VIRTIO_CFG_READ (Dev, NumQueues, &NumQueues);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
@ -765,7 +771,7 @@ VirtioScsiInit (
goto Failed; goto Failed;
} }
Status = VIRTIO_CFG_READ (Dev, VhdrMaxTarget, &Dev->MaxTarget); Status = VIRTIO_CFG_READ (Dev, MaxTarget, &Dev->MaxTarget);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
@ -773,7 +779,7 @@ VirtioScsiInit (
Dev->MaxTarget = PcdGet16 (PcdVirtioScsiMaxTargetLimit); Dev->MaxTarget = PcdGet16 (PcdVirtioScsiMaxTargetLimit);
} }
Status = VIRTIO_CFG_READ (Dev, VhdrMaxLun, &Dev->MaxLun); Status = VIRTIO_CFG_READ (Dev, MaxLun, &Dev->MaxLun);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
@ -781,7 +787,7 @@ VirtioScsiInit (
Dev->MaxLun = PcdGet32 (PcdVirtioScsiMaxLunLimit); Dev->MaxLun = PcdGet32 (PcdVirtioScsiMaxLunLimit);
} }
Status = VIRTIO_CFG_READ (Dev, VhdrMaxSectors, &Dev->MaxSectors); Status = VIRTIO_CFG_READ (Dev, MaxSectors, &Dev->MaxSectors);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
@ -797,12 +803,11 @@ VirtioScsiInit (
// //
// step 4b -- allocate request virtqueue // step 4b -- allocate request virtqueue
// //
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect, Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, VIRTIO_SCSI_REQUEST_QUEUE);
VIRTIO_SCSI_REQUEST_QUEUE);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
Status = VIRTIO_CFG_READ (Dev, Generic.VhdrQueueSize, &QueueSize); Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Failed; goto Failed;
} }
@ -820,11 +825,24 @@ VirtioScsiInit (
} }
// //
// step 4c -- Report GPFN (guest-physical frame number) of queue. If anything // Additional steps for MMIO: align the queue appropriately, and set the
// fails from here on, we must release the ring resources. // size. If anything fails from here on, we must release the ring resources.
// //
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueAddress, Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
(UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT); 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)) { if (EFI_ERROR (Status)) {
goto ReleaseQueue; goto ReleaseQueue;
} }
@ -834,7 +852,7 @@ VirtioScsiInit (
// the known (or unknown) VIRTIO_SCSI_F_* or VIRTIO_F_* capabilities (see // the known (or unknown) VIRTIO_SCSI_F_* or VIRTIO_F_* capabilities (see
// virtio-0.9.5, Appendices B and I), except bidirectional transfers. // virtio-0.9.5, Appendices B and I), except bidirectional transfers.
// //
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits, Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo,
Features & VIRTIO_SCSI_F_INOUT); Features & VIRTIO_SCSI_F_INOUT);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto ReleaseQueue; goto ReleaseQueue;
@ -844,11 +862,11 @@ VirtioScsiInit (
// We expect these maximum sizes from the host. Since they are // We expect these maximum sizes from the host. Since they are
// guest-negotiable, ask for them rather than just checking them. // 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)) { if (EFI_ERROR (Status)) {
goto ReleaseQueue; 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)) { if (EFI_ERROR (Status)) {
goto ReleaseQueue; goto ReleaseQueue;
} }
@ -857,7 +875,7 @@ VirtioScsiInit (
// step 6 -- initialization complete // step 6 -- initialization complete
// //
NextDevStat |= VSTAT_DRIVER_OK; NextDevStat |= VSTAT_DRIVER_OK;
Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat); Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto ReleaseQueue; goto ReleaseQueue;
} }
@ -901,10 +919,10 @@ ReleaseQueue:
Failed: Failed:
// //
// Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device // 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; NextDevStat |= VSTAT_FAILED;
VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat); Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
Dev->InOutSupported = FALSE; Dev->InOutSupported = FALSE;
Dev->MaxTarget = 0; Dev->MaxTarget = 0;
@ -928,7 +946,7 @@ VirtioScsiUninit (
// VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
// the old comms area. // the old comms area.
// //
VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0); Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
Dev->InOutSupported = FALSE; Dev->InOutSupported = FALSE;
Dev->MaxTarget = 0; Dev->MaxTarget = 0;
@ -953,11 +971,8 @@ VirtioScsiUninit (
// The implementation follows: // The implementation follows:
// - Driver Writer's Guide for UEFI 2.3.1 v1.01 // - Driver Writer's Guide for UEFI 2.3.1 v1.01
// - 5.1.3.4 OpenProtocol() and CloseProtocol() // - 5.1.3.4 OpenProtocol() and CloseProtocol()
// - 18 PCI Driver Design Guidelines
// - 18.3 PCI drivers
// - UEFI Spec 2.3.1 + Errata C // - UEFI Spec 2.3.1 + Errata C
// - 6.3 Protocol Handler Services // - 6.3 Protocol Handler Services
// - 13.4 EFI PCI I/O Protocol
// //
EFI_STATUS EFI_STATUS
@ -969,56 +984,36 @@ VirtioScsiDriverBindingSupported (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo; VIRTIO_DEVICE_PROTOCOL *VirtIo;
PCI_TYPE00 Pci;
// //
// Attempt to open the device with the PciIo set of interfaces. On success, // Attempt to open the device with the VirtIo set of interfaces. On success,
// the protocol is "instantiated" for the PCI device. Covers duplicate open // the protocol is "instantiated" for the VirtIo device. Covers duplicate open
// attempts (EFI_ALREADY_STARTED). // attempts (EFI_ALREADY_STARTED).
// //
Status = gBS->OpenProtocol ( Status = gBS->OpenProtocol (
DeviceHandle, // candidate device DeviceHandle, // candidate device
&gEfiPciIoProtocolGuid, // for generic PCI access &gVirtioDeviceProtocolGuid, // for generic VirtIo access
(VOID **)&PciIo, // handle to instantiate (VOID **)&VirtIo, // handle to instantiate
This->DriverBindingHandle, // requestor driver identity This->DriverBindingHandle, // requestor driver identity
DeviceHandle, // ControllerHandle, according to DeviceHandle, // ControllerHandle, according to
// the UEFI Driver Model // 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 // the device; to be released
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return Status; return Status;
} }
// if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_SCSI_HOST) {
// Read entire PCI configuration header for more extensive check ahead. Status = EFI_UNSUPPORTED;
//
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;
} }
// //
// 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. // device or not.
// //
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, DeviceHandle); This->DriverBindingHandle, DeviceHandle);
return Status; return Status;
} }
@ -1040,43 +1035,19 @@ VirtioScsiDriverBindingStart (
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
} }
Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
(VOID **)&Dev->PciIo, This->DriverBindingHandle, (VOID **)&Dev->VirtIo, This->DriverBindingHandle,
DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto FreeVirtioScsi; goto FreeVirtioScsi;
} }
// //
// We must retain and ultimately restore the original PCI attributes of the // VirtIo access granted, configure virtio-scsi device.
// 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.
// //
Status = VirtioScsiInit (Dev); Status = VirtioScsiInit (Dev);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto RestorePciAttributes; goto CloseVirtIo;
} }
// //
@ -1096,12 +1067,8 @@ VirtioScsiDriverBindingStart (
UninitDev: UninitDev:
VirtioScsiUninit (Dev); VirtioScsiUninit (Dev);
RestorePciAttributes: CloseVirtIo:
Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet, gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
Dev->OriginalPciAttributes, NULL);
ClosePciIo:
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
This->DriverBindingHandle, DeviceHandle); This->DriverBindingHandle, DeviceHandle);
FreeVirtioScsi: FreeVirtioScsi:
@ -1149,10 +1116,7 @@ VirtioScsiDriverBindingStop (
VirtioScsiUninit (Dev); VirtioScsiUninit (Dev);
Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet, gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
Dev->OriginalPciAttributes, NULL);
gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
This->DriverBindingHandle, DeviceHandle); This->DriverBindingHandle, DeviceHandle);
FreePool (Dev); FreePool (Dev);

View File

@ -20,7 +20,6 @@
#include <Protocol/ComponentName.h> #include <Protocol/ComponentName.h>
#include <Protocol/DriverBinding.h> #include <Protocol/DriverBinding.h>
#include <Protocol/PciIo.h>
#include <Protocol/ScsiPassThruExt.h> #include <Protocol/ScsiPassThruExt.h>
#include <IndustryStandard/Virtio.h> #include <IndustryStandard/Virtio.h>
@ -50,10 +49,9 @@ typedef struct {
// track them. // track them.
// //
// field init function init depth // field init function init depth
// ---------------------- ------------------ ---------- // ---------------- ------------------ ----------
UINT32 Signature; // DriverBindingStart 0 UINT32 Signature; // DriverBindingStart 0
EFI_PCI_IO_PROTOCOL *PciIo; // DriverBindingStart 0 VIRTIO_DEVICE_PROTOCOL *VirtIo; // DriverBindingStart 0
UINT64 OriginalPciAttributes; // DriverBindingStart 0
BOOLEAN InOutSupported; // VirtioScsiInit 1 BOOLEAN InOutSupported; // VirtioScsiInit 1
UINT16 MaxTarget; // VirtioScsiInit 1 UINT16 MaxTarget; // VirtioScsiInit 1
UINT32 MaxLun; // VirtioScsiInit 1 UINT32 MaxLun; // VirtioScsiInit 1

View File

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