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 BC75A2235229E for ; Tue, 6 Mar 2018 17:30:50 -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 5383F1435; Tue, 6 Mar 2018 17:37:05 -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 132733F24A; Tue, 6 Mar 2018 17:37:05 -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:36 -0600 Message-Id: <20180307013637.16462-4-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 3/4] NonDiscoverablePciDeviceDxe: Added MMIO 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:51 -0000 Added PCI IO to MMIO translation for Virtio case into the PCI IO protocol functions. Added Virtio device type into the PCI IO protocol initialization procedure. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Daniil Egranov --- .../NonDiscoverablePciDeviceDxe.c | 3 +- .../NonDiscoverablePciDeviceDxe.inf | 5 +- .../NonDiscoverablePciDeviceIo.c | 240 ++++++++++++++++++++- 3 files changed, 241 insertions(+), 7 deletions(-) diff --git a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.c b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.c index 3e9ff6620d..2c3eeca914 100644 --- a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.c +++ b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.c @@ -1,6 +1,6 @@ /** @file - Copyright (C) 2016, Linaro Ltd. All rights reserved.
+ Copyright (C) 2016-2018, Linaro Ltd. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this @@ -32,6 +32,7 @@ SupportedNonDiscoverableDevices[] = { &gEdkiiNonDiscoverableUfsDeviceGuid, &gEdkiiNonDiscoverableUhciDeviceGuid, &gEdkiiNonDiscoverableXhciDeviceGuid, + &gEdkiiNonDiscoverableVirtioDeviceGuid }; // diff --git a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf index ac551a82ab..a7bf5a5fc1 100644 --- a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf +++ b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf @@ -1,7 +1,7 @@ ## @file # PCI I/O driver for non-discoverable devices. # -# Copyright (C) 2016, Linaro Ltd. +# Copyright (C) 2016-2018, Linaro Ltd. # # This program and the accompanying materials are licensed and made available # under the terms and conditions of the BSD License which accompanies this @@ -30,6 +30,7 @@ [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec + OvmfPkg/OvmfPkg.dec [LibraryClasses] BaseMemoryLib @@ -54,3 +55,5 @@ gEdkiiNonDiscoverableUfsDeviceGuid ## CONSUMES ## GUID gEdkiiNonDiscoverableUhciDeviceGuid ## CONSUMES ## GUID gEdkiiNonDiscoverableXhciDeviceGuid ## CONSUMES ## GUID + gEdkiiNonDiscoverableVirtioDeviceGuid ## CONSUMES ## GUID + diff --git a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c index 0e42ae4bf6..cb99bf0ba6 100644 --- a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c +++ b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c @@ -1,7 +1,7 @@ /** @file Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
- Copyright (c) 2016, Linaro, Ltd. All rights reserved.
+ Copyright (c) 2016-2018, Linaro, Ltd. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -17,8 +17,12 @@ #include +#include + #include +#include + #include typedef struct { @@ -374,6 +378,82 @@ PciIoMemWrite ( } /** + Translate PCI IO to MMIO for VirtIo Non-Discoverable devices. + + @param BaseAddress A base MMIO memory address of a VirtIo device. + @param PciIoOffset PCI IO offset. + @param DevConfigAddress The address is a device specific config space. + + @retval EFI_SUCCESS The address translated successfully. + @retval EFI_UNSUPPORTED The PCI IO address can not be translated. + +**/ +STATIC +EFI_STATUS +EFIAPI +VirtioPciIoToMemIoTranslation ( + IN UINTN BaseAddress, + IN UINTN PciIoOffset, + IN OUT UINTN *Address, + IN OUT BOOLEAN *DevConfigAddress + ) +{ + EFI_STATUS Status; + UINTN Offset; + INTN DevConfigSpaceOffset; + + Status = EFI_SUCCESS; + Offset = PciIoOffset; + *DevConfigAddress = FALSE; + DevConfigSpaceOffset = 0; + + // + //Check if it's device specific config space + // + if (PciIoOffset >= VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI ) { + Offset = VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI; + DevConfigSpaceOffset = PciIoOffset - VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI; + *DevConfigAddress = TRUE; + } + + switch (Offset) { + case VIRTIO_PCI_OFFSET_DEVICE_FEATURES: + *Address = BaseAddress + VIRTIO_MMIO_OFFSET_HOST_FEATURES; + break; + case VIRTIO_PCI_OFFSET_GUEST_FEATURES: + *Address = BaseAddress + VIRTIO_MMIO_OFFSET_GUEST_FEATURES; + break; + case VIRTIO_PCI_OFFSET_QUEUE_ADDRESS: + *Address = BaseAddress + VIRTIO_MMIO_OFFSET_QUEUE_PFN; + break; + case VIRTIO_PCI_OFFSET_QUEUE_SIZE: + *Address = BaseAddress + VIRTIO_MMIO_OFFSET_QUEUE_NUM_MAX; + break; + case VIRTIO_PCI_OFFSET_QUEUE_SELECT: + *Address = BaseAddress + VIRTIO_MMIO_OFFSET_QUEUE_SEL; + break; + case VIRTIO_PCI_OFFSET_QUEUE_NOTIFY: + *Address = BaseAddress + VIRTIO_MMIO_OFFSET_QUEUE_NOTIFY; + break; + case VIRTIO_PCI_OFFSET_QUEUE_DEVICE_STATUS: + *Address = BaseAddress + VIRTIO_MMIO_OFFSET_STATUS; + break; + case VIRTIO_PCI_OFFSET_QUEUE_DEVICE_ISR: + Status = EFI_UNSUPPORTED; + break; + case VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI: + case VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI_WITH_MSI_X: + *Address = BaseAddress + VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_MMIO + DevConfigSpaceOffset; + break; + default: + Status = EFI_UNSUPPORTED; + break; + } + + return Status; +} + +/** Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space. @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. @@ -398,8 +478,72 @@ PciIoIoRead ( IN OUT VOID *Buffer ) { - ASSERT (FALSE); - return EFI_UNSUPPORTED; + NON_DISCOVERABLE_PCI_DEVICE *Dev; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc; + UINTN Length; + UINTN Address; + UINT32 ReadData; + BOOLEAN IsDevConfigSpace; + EFI_STATUS Status; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO (This); + + // + // Only allow accesses to the BARs we emulate + // + Status = GetBarResource (Dev, BarIndex, &Desc); + if (EFI_ERROR (Status)) { + return Status; + } + + Length = Count << ((UINTN)Width & 0x3); + if (Offset + Length > Desc->AddrLen) { + return EFI_UNSUPPORTED; + } + + // + // Non-Discoverable devices are MMIO devices. Translate PCI IO requests to MMIO. + // + + // + // VirtIo + // + if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableVirtioDeviceGuid)) { + // + // Check for a valid data size + // + if ((Length != 1) && (Length != 2) && + (Length != 4) && (Length != 8)) { + return EFI_INVALID_PARAMETER; + } + + Status = VirtioPciIoToMemIoTranslation (Desc->AddrRangeMin, Offset, &Address, &IsDevConfigSpace); + if (!EFI_ERROR (Status)) { + if (IsDevConfigSpace == TRUE) { // Device-specific configuration registers + // + // The device-specific memory area of Virtio-MMIO can only be written in + // byte accesses. This is not currently in the Virtio spec. + // + MmioReadBuffer8 (Address, Length, Buffer); + } else if (Length < 8) { // 32-bit MMIO registers + ReadData = MmioRead32 (Address); + // The PCI IO register width may not be the same as MMIO register. + // Virtio MMIO registers are always 32-bit + CopyMem (Buffer, &ReadData, Length); + } else { + Status = EFI_INVALID_PARAMETER; + } + } + } else { + Status = EFI_UNSUPPORTED; + } + + ASSERT_EFI_ERROR (Status); + return Status; } /** @@ -427,8 +571,72 @@ PciIoIoWrite ( IN OUT VOID *Buffer ) { - ASSERT (FALSE); - return EFI_UNSUPPORTED; + NON_DISCOVERABLE_PCI_DEVICE *Dev; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc; + UINTN Length; + UINTN Address; + UINT32 WriteData; + BOOLEAN IsDevConfigSpace; + EFI_STATUS Status; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO (This); + + // + // Only allow accesses to the BARs we emulate + // + Status = GetBarResource (Dev, BarIndex, &Desc); + if (EFI_ERROR (Status)) { + return Status; + } + + Length = Count << ((UINTN)Width & 0x3); + if (Offset + Length > Desc->AddrLen) { + return EFI_UNSUPPORTED; + } + + // + // Non-Discoverable devices are MMIO devices. Translate PCI IO requests to MMIO. + // + + // + // VirtIo + // + if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableVirtioDeviceGuid)) { + // + // Check for a valid data size + // + if ((Length != 1) && (Length != 2) && + (Length != 4) && (Length != 8)) { + return EFI_INVALID_PARAMETER; + } + + Status = VirtioPciIoToMemIoTranslation (Desc->AddrRangeMin, Offset, &Address, &IsDevConfigSpace); + if (!EFI_ERROR (Status)) { + if (IsDevConfigSpace == TRUE) { // Device-specific configuration registers + // + // The device-specific memory area of Virtio-MMIO can only be written in + // byte accesses. This is not currently in the Virtio spec. + // + MmioWriteBuffer8 (Address, Length, Buffer); + } else if (Length < 8) { // 32-bit MMIO registers + // The PCI IO register width may not be the same as MMIO register. + // Virtio MMIO registers are always 32-bit + CopyMem (&WriteData, Buffer, Length); + MmioWrite32 (Address, WriteData); + } else { + return EFI_INVALID_PARAMETER; + } + } + } else { + Status = EFI_UNSUPPORTED; + } + + ASSERT_EFI_ERROR (Status); + return Status; } /** @@ -1408,6 +1616,7 @@ InitializePciIoProtocol ( { EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc; INTN Idx; + UINT32 VirtioMagicValue; InitializeListHead (&Dev->UncachedAllocationList); @@ -1471,6 +1680,15 @@ InitializePciIoProtocol ( Dev->ConfigSpace.Hdr.ClassCode[1] = 0x9; // UFS controller subclass; Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE; Dev->BarOffset = 0; + } else if (CompareGuid (Dev->Device->Type, + &gEdkiiNonDiscoverableVirtioDeviceGuid)) { + Dev->ConfigSpace.Hdr.VendorId = VIRTIO_VENDOR_ID; // Required Virtio vendor + Dev->ConfigSpace.Hdr.DeviceId = 0x1000; // Required Virtio device id + Dev->ConfigSpace.Hdr.RevisionID = 0x0; + Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care + Dev->ConfigSpace.Hdr.ClassCode[1] = 0x0; // don't care + Dev->ConfigSpace.Hdr.ClassCode[2] = 0x0; // don't care + Dev->BarOffset = 0; } else { ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); } @@ -1496,6 +1714,18 @@ InitializePciIoProtocol ( } Dev->ConfigSpace.Device.Bar[Idx] = (UINT32)Desc->AddrRangeMin; + + // + // Initialize Virtio device Id + // + if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableVirtioDeviceGuid)) { + VirtioMagicValue = MmioRead32 (Dev->ConfigSpace.Device.Bar[Idx] + VIRTIO_MMIO_OFFSET_MAGIC); + if (VirtioMagicValue == VIRTIO_MMIO_MAGIC) { + Dev->ConfigSpace.Device.SubsystemID = MmioRead32 (Dev->ConfigSpace.Device.Bar[Idx] + + VIRTIO_MMIO_OFFSET_DEVICE_ID); + } + } + Dev->BarCount++; if (Desc->AddrSpaceGranularity == 64) { -- 2.11.0