From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=217.140.101.70; helo=foss.arm.com; envelope-from=daniil.egranov@arm.com; receiver=edk2-devel@lists.01.org Received: from foss.arm.com (foss.arm.com [217.140.101.70]) by ml01.01.org (Postfix) with ESMTP id C714E224C0F58 for ; Tue, 6 Mar 2018 17:30:51 -0800 (PST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 57F2E1684; Tue, 6 Mar 2018 17:37:06 -0800 (PST) Received: from usa.arm.com (dbox2.austin.arm.com [10.118.34.22]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 1706D3F24A; Tue, 6 Mar 2018 17:37:06 -0800 (PST) From: Daniil Egranov To: edk2-devel@lists.01.org Cc: leif.lindholm@linaro.org, ard.biesheuvel@linaro.org, Daniil Egranov Date: Tue, 6 Mar 2018 19:36:37 -0600 Message-Id: <20180307013637.16462-5-daniil.egranov@arm.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180307013637.16462-1-daniil.egranov@arm.com> References: <20180307013637.16462-1-daniil.egranov@arm.com> Subject: [PATCH 4/4] VirtioPciDeviceDxe: Added non-discoverable Virtio support X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 07 Mar 2018 01:30:52 -0000 The VirtioPciDeviceDxe was extended to support a non-discoverable MMIO Virtio case. The Virtio spec defines both PCI and MMIO device types with the set of registers that are not the same between these two types of devices. All PCI registers have corresponding MMIO registers but the number of registers is less then MMIO. The width of MMIO registers and PCI registers is not always the same. Compared to PCI, MMIO Virtio devices required more registers to be programmed in some cases. Added detection that a PCI device is based on a non-discoverable device and allows MMIO transactions. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Daniil Egranov --- OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c | 143 +++++++++++++++++++++- OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h | 21 +++- OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf | 4 +- OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c | 117 +++++++++++++++++- 4 files changed, 278 insertions(+), 7 deletions(-) diff --git a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c index d4b4ec21c3..df2a4ea116 100644 --- a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c +++ b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c @@ -4,7 +4,7 @@ Copyright (C) 2012, Red Hat, Inc. Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.
- Copyright (C) 2013, ARM Ltd. + Copyright (C) 2013 - 2018, ARM Ltd. Copyright (C) 2017, AMD Inc, All rights reserved.
This program and the accompanying materials are licensed and made available @@ -215,6 +215,147 @@ VirtioPciIoWrite ( /** + Read a word from Region 0 of the device specified by PciMemIo. + + Region 0 must be an iomem region. This is an internal function for the PCI + implementation of the protocol. + + @param[in] Dev Virtio PCI device. + + @param[in] FieldOffset Source offset. + + @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }. + + @param[in] BufferSize Number of bytes available in the target buffer. Must + equal FieldSize. + + @param[out] Buffer Target buffer. + + + @return Status code returned by PciIo->Io.Read(). + +**/ +EFI_STATUS +EFIAPI +VirtioPciMemIoRead ( + IN VIRTIO_PCI_DEVICE *Dev, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + UINTN Count; + EFI_PCI_IO_PROTOCOL_WIDTH Width; + EFI_PCI_IO_PROTOCOL *PciIo; + + ASSERT (FieldSize == BufferSize); + + PciIo = Dev->PciIo; + Count = 1; + + switch (FieldSize) { + case 1: + Width = EfiPciIoWidthUint8; + break; + + case 2: + Width = EfiPciIoWidthUint16; + break; + + case 4: + Width = EfiPciIoWidthUint32; + break; + + case 8: + Width = EfiPciIoWidthUint64; + break; + + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + return PciIo->Mem.Read ( + PciIo, + Width, + PCI_BAR_IDX0, + FieldOffset, + Count, + Buffer + ); +} + +/** + + Write a word into Region 0 of the device specified by PciMemIo. + + Region 0 must be an iomem region. This is an internal function for the PCI + implementation of the protocol. + + @param[in] Dev Virtio PCI device. + + @param[in] FieldOffset Destination offset. + + @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }. + + @param[in] Value Little endian value to write, converted to UINT64. + The least significant FieldSize bytes will be used. + + + @return Status code returned by PciIo->Io.Write(). + +**/ +EFI_STATUS +EFIAPI +VirtioPciMemIoWrite ( + IN VIRTIO_PCI_DEVICE *Dev, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINT64 Value + ) +{ + UINTN Count; + EFI_PCI_IO_PROTOCOL_WIDTH Width; + EFI_PCI_IO_PROTOCOL *PciIo; + + PciIo = Dev->PciIo; + Count = 1; + + switch (FieldSize) { + case 1: + Width = EfiPciIoWidthUint8; + break; + + case 2: + Width = EfiPciIoWidthUint16; + break; + + case 4: + Width = EfiPciIoWidthUint32; + break; + + case 8: + Width = EfiPciIoWidthUint64; + break; + + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + return PciIo->Mem.Write ( + PciIo, + Width, + PCI_BAR_IDX0, + FieldOffset, + Count, + &Value + ); +} + +/** + Device probe function for this driver. The DXE core calls this function for any given device in order to see if the diff --git a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h index 1f0dc45d50..e91191689c 100644 --- a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h +++ b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.h @@ -2,7 +2,7 @@ Internal definitions for the VirtIo PCI Device driver - Copyright (C) 2013, ARM Ltd + Copyright (C) 2013-2018, ARM Ltd Copyright (c) 2017, AMD Inc, All rights reserved.
This program and the accompanying materials are licensed and made available @@ -58,6 +58,25 @@ VirtioPciIoWrite ( IN UINT64 Value ); +EFI_STATUS +EFIAPI +VirtioPciMemIoRead ( + IN VIRTIO_PCI_DEVICE *Dev, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +VirtioPciMemIoWrite ( + IN VIRTIO_PCI_DEVICE *Dev, + IN UINTN FieldOffset, + IN UINTN FieldSize, + IN UINT64 Value + ); + /******************************************** * PCI Functions for VIRTIO_DEVICE_PROTOCOL *******************************************/ diff --git a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf index 4b5d1a493e..675b156c82 100644 --- a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf +++ b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf @@ -2,7 +2,7 @@ # This driver produces the VirtIo Device Protocol instances for VirtIo PCI # Device # -# Copyright (C) 2013, ARM Ltd +# Copyright (C) 2013-2018, 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 @@ -28,6 +28,7 @@ [Packages] MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec OvmfPkg/OvmfPkg.dec [LibraryClasses] @@ -41,3 +42,4 @@ [Protocols] gEfiPciIoProtocolGuid ## TO_START gVirtioDeviceProtocolGuid ## BY_START + gEdkiiNonDiscoverableDeviceProtocolGuid diff --git a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c index b52060d13d..45b49f0915 100644 --- a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c +++ b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciFunctions.c @@ -4,7 +4,7 @@ Copyright (C) 2012, Red Hat, Inc. Copyright (c) 2012, Intel Corporation. All rights reserved.
- Copyright (C) 2013, ARM Ltd. + Copyright (C) 2013-2018, ARM Ltd. Copyright (C) 2017, AMD Inc, All rights reserved.
This program and the accompanying materials are licensed and made available @@ -21,10 +21,76 @@ #include #include #include + +#include + #include "VirtioPciDevice.h" /** + Check if virtvo PCI device is a non discoverable virtio MMIO device. + + @param[in] Dev Pointer to the virtio PCI device structure. + + @return TRUE if PCI device is a non discoverable device. + +**/ +STATIC +BOOLEAN +VirtioIsNonDiscoverableMmioDevice ( + IN VIRTIO_PCI_DEVICE *Dev + ) +{ + EFI_HANDLE *HandleBuffer; + EFI_PCI_IO_PROTOCOL *PciIo; + NON_DISCOVERABLE_DEVICE *Device; + EFI_STATUS Status; + UINTN HIndex; + UINTN HandleCount; + BOOLEAN RetStatus; + + RetStatus = FALSE; + Status = gBS->LocateHandleBuffer (ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer); + + if (!EFI_ERROR (Status)) { + for (HIndex = 0; HIndex < HandleCount; ++HIndex) { + Status = gBS->OpenProtocol (HandleBuffer[HIndex], + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (EFI_ERROR (Status)) { + continue; + } + + if (PciIo == Dev->PciIo) { + Status = gBS->OpenProtocol (HandleBuffer[HIndex], + &gEdkiiNonDiscoverableDeviceProtocolGuid, + (VOID **) &Device, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (!EFI_ERROR (Status)) { + RetStatus = TRUE; + } + break; + } + } + } + + gBS->FreePool (HandleBuffer); + return RetStatus; +} + +/** + Read a word from Region 0 of the device specified by VirtIo Device protocol. The function implements the ReadDevice protocol member of @@ -219,7 +285,21 @@ VirtioPciSetQueueAlignment ( IN UINT32 Alignment ) { - return EFI_SUCCESS; + VIRTIO_PCI_DEVICE *Dev; + EFI_STATUS Status; + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + Status = EFI_SUCCESS; + + // This register is required to be programmed for MMIO type of devices. + // Virtio MMIO device can be registered as a non-discoverable device on + // PCI bus, check if it's the case. + if (VirtioIsNonDiscoverableMmioDevice (Dev)) { + Status = VirtioPciMemIoWrite (Dev, VIRTIO_MMIO_OFFSET_QUEUE_ALIGN, + sizeof (UINT32), Alignment); + } + + return Status; } EFI_STATUS @@ -229,7 +309,22 @@ VirtioPciSetPageSize ( IN UINT32 PageSize ) { - return (PageSize == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED; + VIRTIO_PCI_DEVICE *Dev; + EFI_STATUS Status; + + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + + // This register is required to be programmed for MMIO type of devices. + // Virtio MMIO device can be registered as a non-discoverable device on + // PCI bus, check if it's the case. + if (VirtioIsNonDiscoverableMmioDevice (Dev)) { + Status = VirtioPciMemIoWrite (Dev, VIRTIO_MMIO_OFFSET_GUEST_PAGE_SIZE, + sizeof (UINT32), PageSize); + } else { + Status = (PageSize == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED; + } + + return Status; } EFI_STATUS @@ -254,11 +349,25 @@ VirtioPciSetQueueSize ( IN UINT16 Size ) { + VIRTIO_PCI_DEVICE *Dev; + EFI_STATUS Status; + // // This function is only applicable in Virtio-MMIO. // (The QueueSize field is read-only in Virtio proper (PCI)) // - return EFI_SUCCESS; + Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); + Status = EFI_SUCCESS; + + // This register is required to be programmed for MMIO type of devices. + // Virtio MMIO device can be registered as a non-discoverable device on + // PCI bus, check if it's the case. + if (VirtioIsNonDiscoverableMmioDevice (Dev)) { + Status = VirtioPciMemIoWrite (Dev, VIRTIO_MMIO_OFFSET_QUEUE_NUM, + sizeof (UINT32), (UINT32) Size); + } + + return Status; } EFI_STATUS -- 2.11.0