From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-it0-x233.google.com (mail-it0-x233.google.com [IPv6:2607:f8b0:4001:c0b::233]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id F353881EE9 for ; Fri, 18 Nov 2016 04:30:03 -0800 (PST) Received: by mail-it0-x233.google.com with SMTP id c20so24000073itb.0 for ; Fri, 18 Nov 2016 04:30:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=nvG48dYVsTJEepG1vq2ky6B00tRWqfY3tSCnCjLsPLs=; b=A5VEkNxADn9ulMIa5lfuxjR6xeZRGGE+G2qwChziuVwO3E8uBzRVHFeWpIfnsD2wd5 e2OCn7lBY6YwX2ZWth8AuaSmhFBR+2fFdP0BUJZtkRIij57lZdTHrXkgrTaygK8CgPah 5OlztKBW29+pWbfLYUWAWD0+DRVLdFxBBNx8w= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=nvG48dYVsTJEepG1vq2ky6B00tRWqfY3tSCnCjLsPLs=; b=W5us6sK/39uuMtWDIrolkI0P2KM+pnm0xySJ9ewibrDWo7RvWrxeZMi9jDDk3rRmej KjGIKY/bYSfGEZ2STfYbECKwaStI6+jgcJGQSqqTsxV5Szk4MAhiBl9hbPoeMiB0joMy UXuncfwDU+AkUpPtXStFqLWg5P6jUQifRtdhwpJxjB90pa9tQ1IbJwGOogJeACIuibWe K2yxXJA87wKGHv+bZsHXXDQzU1FV7m9DfiS62GGoolhfm5Y9ZAJH5Q2Blr4bqHzfC/YV 3GLZGS+zfdlBT8DRP+nfNLb4IPj2FwcxFzjU0+0OlGnJFgcrXnmWc5vNcXbRpxKWSALR UTWA== X-Gm-Message-State: AKaTC00/BTca9MGSl86oM4Fq5HXi6ZRmknXyUnWhDyKBxuHUqO3O8RHJXnr2rUtdBkTEYhh2dhd1fVqgZF8FavmU X-Received: by 10.107.2.8 with SMTP id 8mr7623315ioc.83.1479472208598; Fri, 18 Nov 2016 04:30:08 -0800 (PST) MIME-Version: 1.0 Received: by 10.107.59.147 with HTTP; Fri, 18 Nov 2016 04:30:08 -0800 (PST) In-Reply-To: <734D49CCEBEEF84792F5B80ED585239D58E7C886@SHSMSX104.ccr.corp.intel.com> References: <1479315571-14953-1-git-send-email-ard.biesheuvel@linaro.org> <1479315571-14953-4-git-send-email-ard.biesheuvel@linaro.org> <734D49CCEBEEF84792F5B80ED585239D58E7C886@SHSMSX104.ccr.corp.intel.com> From: Ard Biesheuvel Date: Fri, 18 Nov 2016 12:30:08 +0000 Message-ID: To: "Ni, Ruiyu" Cc: "edk2-devel@lists.01.org" , "Gao, Liming" , "Kinney, Michael D" , "afish@apple.com" , "mw@semihalf.com" , "leif.lindholm@linaro.org" Subject: Re: [PATCH v3 3/5] MdeModulePkg: implement generic PCI I/O driver for non-discoverable devices X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 18 Nov 2016 12:30:04 -0000 Content-Type: text/plain; charset=UTF-8 On 17 November 2016 at 03:29, Ni, Ruiyu wrote: > > > Thanks/Ray > >> -----Original Message----- >> From: Ard Biesheuvel [mailto:ard.biesheuvel@linaro.org] >> Sent: Thursday, November 17, 2016 12:59 AM >> To: edk2-devel@lists.01.org; Gao, Liming ; Ni, Ruiyu >> ; Kinney, Michael D >> Cc: afish@apple.com; mw@semihalf.com; leif.lindholm@linaro.org; Ard >> Biesheuvel >> Subject: [PATCH v3 3/5] MdeModulePkg: implement generic PCI I/O driver >> for non-discoverable devices >> >> This implements support for non-discoverable PCI compatible devices, i.e, >> devices that are not on a PCI bus but that can be controlled by generic PCI >> drivers in EDK2. >> >> This is implemented as a UEFI driver, which means we take full advantage of >> the UEFI driver model, and only instantiate those devices that are necessary >> for booting. >> >> Care is taken to deal with DMA addressing limitations: DMA mappings and >> allocations are moved below 4 GB if the PCI driver has not informed us that >> the device being driven is 64-bit DMA capable. DMA is implemented as >> coherent, support for non-coherent DMA is implemented by a subsequent >> patch. >> >> Contributed-under: TianoCore Contribution Agreement 1.0 >> Signed-off-by: Ard Biesheuvel >> --- >> >> MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/ComponentName.c >> | 75 ++ >> >> MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePci >> DeviceDxe.c | 223 +++++ >> >> MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePci >> DeviceDxe.inf | 42 + >> >> MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePci >> DeviceIo.c | 868 ++++++++++++++++++++ >> >> MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePci >> DeviceIo.h | 84 ++ >> MdeModulePkg/MdeModulePkg.dsc | 1 + >> 6 files changed, 1293 insertions(+) >> [...] >> diff --git >> a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverable >> PciDeviceIo.c >> b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverable >> PciDeviceIo.c >> new file mode 100644 >> index 000000000000..23466318bfc1 >> --- /dev/null >> +++ >> b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverable >> Pc >> +++ iDeviceIo.c >> @@ -0,0 +1,868 @@ >> +/** @file >> + >> + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
>> + Copyright (c) 2016, 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 distribution. The full text of the license may be >> + found at http://opensource.org/licenses/bsd-license.php >> + >> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" >> BASIS, >> + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER >> EXPRESS OR IMPLIED. >> + >> +**/ >> + >> +#include "NonDiscoverablePciDeviceIo.h" >> + >> +#include >> + >> +#include >> + >> +typedef struct { >> + EFI_PHYSICAL_ADDRESS AllocAddress; >> + VOID *HostAddress; >> + EFI_PCI_IO_PROTOCOL_OPERATION Operation; >> + UINTN NumberOfBytes; >> +} NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO; >> + >> +// >> +// Get the resource associated with BAR number 'BarIndex'. This takes >> +into // account that 64-bit resource use up 2 BAR slots, which means >> +that BAR // n + 1 is reported as not found if BAR n refers to a 64-bit resource. >> +// >> +STATIC >> +EFI_STATUS >> +GetBarResource ( >> + IN NON_DISCOVERABLE_PCI_DEVICE *Dev, >> + IN UINT8 BarIndex, >> + OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptor >> + ) >> +{ >> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc; >> + >> + if (BarIndex < Dev->BarOffset) { >> + return EFI_NOT_FOUND; >> + } >> + >> + BarIndex -= Dev->BarOffset; >> + >> + for (Desc = Dev->Device->Resources; >> + Desc->Desc != ACPI_END_TAG_DESCRIPTOR; >> + Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) { >> + >> + if (BarIndex == 0) { >> + *Descriptor = Desc; >> + return EFI_SUCCESS; >> + } >> + >> + if (Desc->AddrSpaceGranularity == 64) { >> + if (BarIndex == 1) { >> + break; >> + } >> + BarIndex -= 2; > > 1. I think we only need to decrease *one* from BarIndex instead of two, > even for 64bit BAR. > I remember MdeModulePkg/PciBusDxe ever had a bug to treat 64bit > BAR as 2 logic BARs but it should have fixed long ago. > Right. So does that mean BarIndex '2' refers to BARs 4 and 5 if we have 3 64-bit BARs in total? >> + } else { >> + BarIndex -= 1; >> + } >> + } >> + return EFI_NOT_FOUND; >> +} >> + >> +STATIC >> +EFI_STATUS >> +PciIoPollMem ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, >> + IN UINT8 BarIndex, >> + IN UINT64 Offset, >> + IN UINT64 Mask, >> + IN UINT64 Value, >> + IN UINT64 Delay, >> + OUT UINT64 *Result >> + ) >> +{ >> + ASSERT (FALSE); >> + return EFI_UNSUPPORTED; >> +} >> + >> +STATIC >> +EFI_STATUS >> +PciIoPollIo ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, >> + IN UINT8 BarIndex, >> + IN UINT64 Offset, >> + IN UINT64 Mask, >> + IN UINT64 Value, >> + IN UINT64 Delay, >> + OUT UINT64 *Result >> + ) >> +{ >> + ASSERT (FALSE); >> + return EFI_UNSUPPORTED; >> +} >> + >> +STATIC >> +EFI_STATUS >> +PciIoMemRW ( >> + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, >> + IN UINTN Count, >> + IN UINTN DstStride, >> + IN VOID *Dst, >> + IN UINTN SrcStride, >> + OUT CONST VOID *Src >> + ) >> +{ >> + volatile UINT8 *Dst8; >> + volatile UINT16 *Dst16; >> + volatile UINT32 *Dst32; >> + volatile CONST UINT8 *Src8; >> + volatile CONST UINT16 *Src16; >> + volatile CONST UINT32 *Src32; >> + >> + // >> + // Loop for each iteration and move the data // switch (Width & >> + 0x3) { case EfiPciWidthUint8: >> + Dst8 = (UINT8 *)Dst; >> + Src8 = (UINT8 *)Src; >> + for (;Count > 0; Count--, Dst8 += DstStride, Src8 += SrcStride) { >> + *Dst8 = *Src8; >> + } >> + break; >> + case EfiPciWidthUint16: >> + Dst16 = (UINT16 *)Dst; >> + Src16 = (UINT16 *)Src; >> + for (;Count > 0; Count--, Dst16 += DstStride, Src16 += SrcStride) { >> + *Dst16 = *Src16; >> + } >> + break; >> + case EfiPciWidthUint32: >> + Dst32 = (UINT32 *)Dst; >> + Src32 = (UINT32 *)Src; >> + for (;Count > 0; Count--, Dst32 += DstStride, Src32 += SrcStride) { >> + *Dst32 = *Src32; >> + } >> + break; >> + default: >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + return EFI_SUCCESS; >> +} >> + >> +STATIC >> +EFI_STATUS >> +PciIoMemRead ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, >> + IN UINT8 BarIndex, >> + IN UINT64 Offset, >> + IN UINTN Count, >> + IN OUT VOID *Buffer >> + ) >> +{ >> + NON_DISCOVERABLE_PCI_DEVICE *Dev; >> + UINTN AlignMask; >> + VOID *Address; >> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc; >> + 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; >> + } >> + >> + if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) { >> + return EFI_UNSUPPORTED; >> + } >> + >> + Address = (VOID *)((UINTN)Desc->AddrRangeMin + Offset); AlignMask = >> + (1 << (Width & 0x03)) - 1; if ((UINTN)Address & AlignMask) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + switch (Width) { >> + case EfiPciWidthUint8: >> + case EfiPciWidthUint16: >> + case EfiPciWidthUint32: >> + case EfiPciWidthUint64: >> + return PciIoMemRW (Width, Count, 1, Buffer, 1, Address); >> + >> + case EfiPciWidthFifoUint8: >> + case EfiPciWidthFifoUint16: >> + case EfiPciWidthFifoUint32: >> + case EfiPciWidthFifoUint64: >> + return PciIoMemRW (Width, Count, 1, Buffer, 0, Address); >> + >> + case EfiPciWidthFillUint8: >> + case EfiPciWidthFillUint16: >> + case EfiPciWidthFillUint32: >> + case EfiPciWidthFillUint64: >> + return PciIoMemRW (Width, Count, 0, Buffer, 1, Address); >> + >> + default: >> + break; >> + } >> + return EFI_INVALID_PARAMETER; >> +} >> + >> +STATIC >> +EFI_STATUS >> +PciIoMemWrite ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, >> + IN UINT8 BarIndex, >> + IN UINT64 Offset, >> + IN UINTN Count, >> + IN OUT VOID *Buffer >> + ) >> +{ >> + NON_DISCOVERABLE_PCI_DEVICE *Dev; >> + UINTN AlignMask; >> + VOID *Address; >> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc; >> + 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; >> + } >> + >> + if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) { >> + return EFI_UNSUPPORTED; >> + } >> + >> + Address = (VOID *)((UINTN)Desc->AddrRangeMin + Offset); AlignMask = >> + (1 << (Width & 0x03)) - 1; if ((UINTN)Address & AlignMask) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + switch (Width) { >> + case EfiPciWidthUint8: >> + case EfiPciWidthUint16: >> + case EfiPciWidthUint32: >> + case EfiPciWidthUint64: >> + return PciIoMemRW (Width, Count, 1, Address, 1, Buffer); >> + >> + case EfiPciWidthFifoUint8: >> + case EfiPciWidthFifoUint16: >> + case EfiPciWidthFifoUint32: >> + case EfiPciWidthFifoUint64: >> + return PciIoMemRW (Width, Count, 0, Address, 1, Buffer); >> + >> + case EfiPciWidthFillUint8: >> + case EfiPciWidthFillUint16: >> + case EfiPciWidthFillUint32: >> + case EfiPciWidthFillUint64: >> + return PciIoMemRW (Width, Count, 1, Address, 0, Buffer); >> + >> + default: >> + break; >> + } >> + return EFI_INVALID_PARAMETER; >> +} >> + >> +STATIC >> +EFI_STATUS >> +PciIoIoRead ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, >> + IN UINT8 BarIndex, >> + IN UINT64 Offset, >> + IN UINTN Count, >> + IN OUT VOID *Buffer >> + ) >> +{ >> + ASSERT (FALSE); >> + return EFI_UNSUPPORTED; >> +} >> + >> +STATIC >> +EFI_STATUS >> +PciIoIoWrite ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, >> + IN UINT8 BarIndex, >> + IN UINT64 Offset, >> + IN UINTN Count, >> + IN OUT VOID *Buffer >> + ) >> +{ >> + ASSERT (FALSE); >> + return EFI_UNSUPPORTED; >> +} >> + >> +STATIC >> +EFI_STATUS >> +PciIoPciRead ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, >> + IN UINT32 Offset, >> + IN UINTN Count, >> + IN OUT VOID *Buffer >> + ) >> +{ >> + NON_DISCOVERABLE_PCI_DEVICE *Dev; >> + UINTN Length; >> + >> + if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This); >> + Length = Count << ((UINTN)Width & 0x3); >> + >> + if (Offset + Length > sizeof (Dev->ConfigSpace)) { >> + return EFI_UNSUPPORTED; >> + } >> + >> + return PciIoMemRW (Width, Count, 1, Buffer, 1, >> + (UINT8 *)&Dev->ConfigSpace + Offset); } >> + >> +// >> +// taken from MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h >> +// >> +#define SD_MMC_HC_SLOT_OFFSET 0x40 >> + >> +typedef struct { >> + UINT8 FirstBar:3; // bit 0:2 >> + UINT8 Reserved:1; // bit 3 >> + UINT8 SlotNum:3; // bit 4:6 >> + UINT8 Reserved1:1; // bit 7 >> +} SD_MMC_HC_SLOT_INFO; >> + >> +STATIC >> +EFI_STATUS >> +PciIoPciReadSdhci ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, >> + IN UINT32 Offset, >> + IN UINTN Count, >> + IN OUT VOID *Buffer >> + ) >> +{ >> + NON_DISCOVERABLE_PCI_DEVICE *Dev; >> + UINTN Length; >> + SD_MMC_HC_SLOT_INFO *SlotInfo; >> + >> + if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This); >> + Length = Count << ((UINTN)Width & 0x3); >> + >> + // >> + // The SDHCI driver reads beyond the 64-byte PCI config space to read >> + // the number of slots and the BAR offset. So allow that // if >> + (Offset == SD_MMC_HC_SLOT_OFFSET && Length == 1) { >> + SlotInfo = Buffer; >> + >> + SlotInfo->FirstBar = Dev->BarOffset; >> + SlotInfo->SlotNum = Dev->BarCount - 1; > > 2. It's a little bit tricky to hook the SDHCI access. > We need to make this driver generic enough and stable > for future possible requirements. > We now see the needs for SDHCI access. We may have other similar needs. > Can we pass such information from NonDiscoverredPciDevice? > The information like array of can be included in the protocol. > Just my rough idea. Feel free to reject it. > Well, this is another side effect of the design decision of folding SDHCI support into a SDHCI-PCI driver. For other host controller interfaces, there is always a 1:1 relationship between a PCI device and a ?HCI device. However, for SDHCI, the correct way to implement this on the driver side would have been to implement a SDHCI-PCI bus driver that allocates a SHDCI device handle for each slot on the PCI device. That would allow the SDHCI *driver* to only worry about a single device, and there would be no need for this hack. In the first iteration of this series, I did not have this since there was a 1:1 relationship between non-discoverable devices and PCI drivers, but due to the move to ACPI resource descriptors, this is different now. >> + >> + return EFI_SUCCESS; >> + } >> + >> + if (Offset + Length > sizeof (Dev->ConfigSpace)) { >> + return EFI_UNSUPPORTED; >> + } >> + >> + return PciIoMemRW (Width, Count, 1, Buffer, 1, >> + (UINT8 *)&Dev->ConfigSpace + Offset); } >> + >> +STATIC >> +EFI_STATUS >> +PciIoPciWrite ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, >> + IN UINT32 Offset, >> + IN UINTN Count, >> + IN OUT VOID *Buffer >> + ) >> +{ >> + NON_DISCOVERABLE_PCI_DEVICE *Dev; >> + VOID *Address; >> + >> + if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This); >> + Address = (UINT8 *)&Dev->ConfigSpace + Offset; >> + >> + if (Offset + Count * (1UL << (Width & 0x3)) > sizeof (Dev->ConfigSpace)) { >> + return EFI_UNSUPPORTED; >> + } >> + >> + return PciIoMemRW (Width, Count, 1, Address, 1, Buffer); } >> + >> +STATIC >> +EFI_STATUS >> +PciIoCopyMem ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, >> + IN UINT8 DestBarIndex, >> + IN UINT64 DestOffset, >> + IN UINT8 SrcBarIndex, >> + IN UINT64 SrcOffset, >> + IN UINTN Count >> + ) >> +{ >> + ASSERT (FALSE); >> + return EFI_UNSUPPORTED; >> +} >> + >> +STATIC >> +EFI_STATUS >> +CoherentPciIoMap ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, >> + IN VOID *HostAddress, >> + IN OUT UINTN *NumberOfBytes, >> + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, >> + OUT VOID **Mapping >> + ) >> +{ >> + NON_DISCOVERABLE_PCI_DEVICE *Dev; >> + EFI_STATUS Status; >> + NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo; >> + >> + // >> + // If HostAddress exceeds 4 GB, and this device does not support >> + 64-bit DMA // addressing, we need to allocate a bounce buffer and copy >> over the data. >> + // >> + Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This); >> + if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == >> 0 && >> + (UINTN)HostAddress + *NumberOfBytes > SIZE_4GB) { >> + >> + // >> + // Bounce buffering is not possible for consistent mappings >> + // >> + if (Operation == EfiPciIoOperationBusMasterCommonBuffer) { >> + return EFI_UNSUPPORTED; >> + } >> + >> + MapInfo = AllocatePool (sizeof *MapInfo); >> + if (MapInfo == NULL) { >> + return EFI_OUT_OF_RESOURCES; >> + } >> + >> + MapInfo->AllocAddress = MAX_UINT32; >> + MapInfo->HostAddress = HostAddress; >> + MapInfo->Operation = Operation; >> + MapInfo->NumberOfBytes = *NumberOfBytes; >> + >> + Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, >> + EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes), >> + &MapInfo->AllocAddress); >> + if (EFI_ERROR (Status)) { >> + // >> + // If we fail here, it is likely because the system has no memory below >> + // 4 GB to begin with. There is not much we can do about that other than >> + // fail the map request. >> + // >> + FreePool (MapInfo); >> + return EFI_DEVICE_ERROR; >> + } >> + if (Operation == EfiPciIoOperationBusMasterRead) { >> + gBS->CopyMem ((VOID *)(UINTN)MapInfo->AllocAddress, HostAddress, >> + *NumberOfBytes); >> + } >> + *DeviceAddress = MapInfo->AllocAddress; >> + *Mapping = MapInfo; >> + } else { >> + *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress; >> + *Mapping = NULL; >> + } >> + return EFI_SUCCESS; >> +} >> + >> +STATIC >> +EFI_STATUS >> +CoherentPciIoUnmap ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN VOID *Mapping >> + ) >> +{ >> + NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo; >> + >> + MapInfo = Mapping; >> + if (MapInfo != NULL) { >> + if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) { >> + gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo- >> >AllocAddress, >> + MapInfo->NumberOfBytes); >> + } >> + gBS->FreePages (MapInfo->AllocAddress, >> + EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes)); >> + FreePool (MapInfo); >> + } >> + return EFI_SUCCESS; >> +} >> + >> +STATIC >> +EFI_STATUS >> +CoherentPciIoAllocateBuffer ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN EFI_ALLOCATE_TYPE Type, >> + IN EFI_MEMORY_TYPE MemoryType, >> + IN UINTN Pages, >> + OUT VOID **HostAddress, >> + IN UINT64 Attributes >> + ) >> +{ >> + NON_DISCOVERABLE_PCI_DEVICE *Dev; >> + EFI_PHYSICAL_ADDRESS AllocAddress; >> + EFI_ALLOCATE_TYPE AllocType; >> + EFI_STATUS Status; >> + >> + if ((Attributes & ~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | >> + EFI_PCI_ATTRIBUTE_MEMORY_CACHED)) != 0) { >> + return EFI_UNSUPPORTED; >> + } >> + >> + // >> + // Allocate below 4 GB if the dual address cycle attribute has not >> + // been set. If the system has no memory available below 4 GB, there >> + // is little we can do except propagate the error. >> + // >> + Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This); >> + if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == >> 0) { >> + AllocAddress = MAX_UINT32; > > 3. better to use BASE_4GB -1. > >> + AllocType = AllocateMaxAddress; >> + } else { >> + AllocType = AllocateAnyPages; >> + } >> + >> + Status = gBS->AllocatePages (AllocType, MemoryType, Pages, >> +&AllocAddress); >> + if (!EFI_ERROR (Status)) { >> + *HostAddress = (VOID *)(UINTN)AllocAddress; >> + } >> + return Status; >> +} >> + >> +STATIC >> +EFI_STATUS >> +CoherentPciIoFreeBuffer ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN UINTN Pages, >> + IN VOID *HostAddress >> + ) >> +{ >> + FreePages (HostAddress, Pages); >> + return EFI_SUCCESS; >> +} >> + >> + >> +STATIC >> +EFI_STATUS >> +PciIoFlush ( >> + IN EFI_PCI_IO_PROTOCOL *This >> + ) >> +{ >> + return EFI_SUCCESS; >> +} >> + >> +STATIC >> +EFI_STATUS >> +PciIoGetLocation ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + OUT UINTN *SegmentNumber, >> + OUT UINTN *BusNumber, >> + OUT UINTN *DeviceNumber, >> + OUT UINTN *FunctionNumber >> + ) >> +{ >> + if (SegmentNumber == NULL || >> + BusNumber == NULL || >> + DeviceNumber == NULL || >> + FunctionNumber == NULL) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + *SegmentNumber = 0; >> + *BusNumber = 0xff; >> + *DeviceNumber = 0; >> + *FunctionNumber = 0; >> + >> + return EFI_SUCCESS; >> +} >> + >> +STATIC >> +EFI_STATUS >> +PciIoAttributes ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, >> + IN UINT64 Attributes, >> + OUT UINT64 *Result OPTIONAL >> + ) >> +{ >> + NON_DISCOVERABLE_PCI_DEVICE *Dev; >> + BOOLEAN Enable; >> + >> + Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This); >> + >> + Enable = FALSE; >> + switch (Operation) { >> + case EfiPciIoAttributeOperationGet: >> + if (Result == NULL) { >> + return EFI_INVALID_PARAMETER; >> + } >> + *Result = Dev->Attributes; >> + break; >> + >> + case EfiPciIoAttributeOperationSupported: >> + if (Result == NULL) { >> + return EFI_INVALID_PARAMETER; >> + } >> + *Result = EFI_PCI_DEVICE_ENABLE | >> EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE; >> + break; >> + >> + case EfiPciIoAttributeOperationEnable: >> + Attributes |= Dev->Attributes; >> + case EfiPciIoAttributeOperationSet: >> + Enable = ((~Dev->Attributes & Attributes) & EFI_PCI_DEVICE_ENABLE) != >> 0; >> + Dev->Attributes = Attributes; >> + break; >> + >> + case EfiPciIoAttributeOperationDisable: >> + Dev->Attributes &= ~Attributes; >> + break; >> + >> + default: >> + return EFI_INVALID_PARAMETER; >> + }; >> + >> + // >> + // If we're setting any of the EFI_PCI_DEVICE_ENABLE bits, perform >> + // the device specific initialization now. >> + // >> + if (Enable && !Dev->Enabled && Dev->Device->Initialize != NULL) { >> + Dev->Device->Initialize (Dev->Device); >> + Dev->Enabled = TRUE; >> + } >> + return EFI_SUCCESS; >> +} >> + >> +STATIC >> +EFI_STATUS >> +PciIoGetBarAttributes ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN UINT8 BarIndex, >> + OUT UINT64 *Supports OPTIONAL, >> + OUT VOID **Resources OPTIONAL >> + ) >> +{ >> + NON_DISCOVERABLE_PCI_DEVICE *Dev; >> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor, *BarDesc; >> + EFI_ACPI_END_TAG_DESCRIPTOR *End; >> + EFI_STATUS Status; >> + >> + if (Supports == NULL && Resources == NULL) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This); >> + >> + Status = GetBarResource (Dev, BarIndex, &BarDesc); if (EFI_ERROR >> + (Status)) { >> + return Status; >> + } >> + >> + // >> + // Don't expose any configurable attributes for our emulated BAR // >> + if (Supports != NULL) { >> + *Supports = 0; >> + } >> + >> + if (Resources != NULL) { >> + Descriptor = AllocatePool (sizeof >> (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + >> + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); >> + if (Descriptor == NULL) { >> + return EFI_OUT_OF_RESOURCES; >> + } >> + >> + CopyMem (Descriptor, BarDesc, sizeof *Descriptor); >> + >> + End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1); >> + End->Desc = ACPI_END_TAG_DESCRIPTOR; >> + End->Checksum = 0; >> + >> + *Resources = Descriptor; >> + } >> + return EFI_SUCCESS; >> +} >> + >> +STATIC >> +EFI_STATUS >> +PciIoSetBarAttributes ( >> + IN EFI_PCI_IO_PROTOCOL *This, >> + IN UINT64 Attributes, >> + IN UINT8 BarIndex, >> + IN OUT UINT64 *Offset, >> + IN OUT UINT64 *Length >> + ) >> +{ >> + ASSERT (FALSE); >> + return EFI_UNSUPPORTED; >> +} >> + >> +STATIC CONST EFI_PCI_IO_PROTOCOL PciIoTemplate = { >> + PciIoPollMem, >> + PciIoPollIo, >> + { PciIoMemRead, PciIoMemWrite }, >> + { PciIoIoRead, PciIoIoWrite }, >> + { PciIoPciRead, PciIoPciWrite }, >> + PciIoCopyMem, >> + CoherentPciIoMap, >> + CoherentPciIoUnmap, >> + CoherentPciIoAllocateBuffer, >> + CoherentPciIoFreeBuffer, >> + PciIoFlush, >> + PciIoGetLocation, >> + PciIoAttributes, >> + PciIoGetBarAttributes, >> + PciIoSetBarAttributes, >> + 0, >> + 0 >> +}; >> + >> +VOID >> +InitializePciIoProtocol ( >> + NON_DISCOVERABLE_PCI_DEVICE *Dev >> + ) >> +{ >> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc; >> + INTN Idx; >> + >> + InitializeListHead (&Dev->UncachedAllocationList); >> + >> + Dev->ConfigSpace.Hdr.VendorId = PCI_ID_VENDOR_UNKNOWN; >> + Dev->ConfigSpace.Hdr.DeviceId = PCI_ID_DEVICE_DONTCARE; >> + >> + // Copy protocol structure >> + CopyMem(&Dev->PciIo, &PciIoTemplate, sizeof PciIoTemplate); >> + >> + switch (Dev->Device->Type) { >> + case NonDiscoverableDeviceTypeOhci: >> + Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_OHCI; >> + Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB; >> + Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL; >> + Dev->BarOffset = 0; >> + break; >> + >> + case NonDiscoverableDeviceTypeUhci: >> + Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_UHCI; >> + Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB; >> + Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL; >> + Dev->BarOffset = 0; >> + break; >> + >> + case NonDiscoverableDeviceTypeEhci: >> + Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_EHCI; >> + Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB; >> + Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL; >> + Dev->BarOffset = 0; >> + break; >> + >> + case NonDiscoverableDeviceTypeXhci: >> + Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_XHCI; >> + Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB; >> + Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL; >> + Dev->BarOffset = 0; >> + break; >> + >> + case NonDiscoverableDeviceTypeAhci: >> + Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_MASS_STORAGE_AHCI; >> + Dev->ConfigSpace.Hdr.ClassCode[1] = >> PCI_CLASS_MASS_STORAGE_SATADPA; >> + Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE; >> + Dev->BarOffset = 5; >> + break; >> + >> + case NonDiscoverableDeviceTypeSdhci: >> + Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care >> + Dev->ConfigSpace.Hdr.ClassCode[1] = >> PCI_SUBCLASS_SD_HOST_CONTROLLER; >> + Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SYSTEM_PERIPHERAL; >> + Dev->BarOffset = 0; >> + >> + // >> + // Use the special config space accessor so that the SDHCI driver >> + // is able to retrieve the number of slots and the BAR offset >> + // >> + Dev->PciIo.Pci.Read = PciIoPciReadSdhci; >> + break; >> + >> + case NonDiscoverableDeviceTypeUfs: >> + Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care >> + Dev->ConfigSpace.Hdr.ClassCode[1] = 0x9; // UFS controller subclass; >> + Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE; >> + Dev->BarOffset = 0; >> + break; >> + >> + case NonDiscoverableDeviceTypeNvme: >> + Dev->ConfigSpace.Hdr.ClassCode[0] = 0x2; // PCI_IF_NVMHCI >> + Dev->ConfigSpace.Hdr.ClassCode[1] = 0x8; // >> PCI_CLASS_MASS_STORAGE_NVM >> + Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE; >> + Dev->BarOffset = 0; >> + >> + default: >> + ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); } >> + >> + // >> + // Iterate over the resources to populate the virtual BARs // Idx = >> + Dev->BarOffset; for (Desc = Dev->Device->Resources, Dev->BarCount = >> + 0; >> + Desc->Desc != ACPI_END_TAG_DESCRIPTOR; >> + Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) { >> + >> + ASSERT (Desc->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR); >> + ASSERT (Desc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM); >> + >> + if (Idx >= PCI_MAX_BARS || >> + (Idx == PCI_MAX_BARS - 1 && Desc->AddrSpaceGranularity == 64)) { >> + DEBUG ((DEBUG_ERROR, >> + "%a: resource count exceeds number of emulated BARs\n", >> + __FUNCTION__)); >> + ASSERT (FALSE); >> + break; >> + } >> + >> + Dev->ConfigSpace.Device.Bar[Idx] = (UINT32)Desc->AddrRangeMin; >> + Dev->BarCount++; >> + >> + if (Desc->AddrSpaceGranularity == 64) { >> + Dev->ConfigSpace.Device.Bar[Idx] |= 0x4; >> + Dev->ConfigSpace.Device.Bar[++Idx] = (UINT32)(Desc- >> >AddrRangeMin >> 32); >> + } >> + } >> +} >> diff --git >> a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverable >> PciDeviceIo.h >> b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverable >> PciDeviceIo.h >> new file mode 100644 >> index 000000000000..bc0a3d3258f9 >> --- /dev/null >> +++ >> b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverable >> Pc >> +++ iDeviceIo.h >> @@ -0,0 +1,84 @@ >> +/** @file >> + >> + Copyright (C) 2016, 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 distribution. The full text of the license may be >> + found at http://opensource.org/licenses/bsd-license.php >> + >> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" >> BASIS, >> + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER >> EXPRESS OR IMPLIED. >> + >> +**/ >> + >> +#ifndef __NON_DISCOVERABLE_PCI_DEVICE_IO_H__ >> +#define __NON_DISCOVERABLE_PCI_DEVICE_IO_H__ >> + >> +#include >> +#include >> +#include #include >> + >> +#include >> + >> +#include >> + >> +#include >> +#include >> +#include >> + >> +#define NON_DISCOVERABLE_PCI_DEVICE_SIG SIGNATURE_32 ('P', 'P', 'I', >> +'D') >> + >> +#define NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(PciIoPointer) \ >> + CR (PciIoPointer, NON_DISCOVERABLE_PCI_DEVICE, PciIo, \ >> + NON_DISCOVERABLE_PCI_DEVICE_SIG) >> + >> +#define PCI_ID_VENDOR_UNKNOWN 0xffff >> +#define PCI_ID_DEVICE_DONTCARE 0x0000 >> + >> +#define PCI_MAX_BARS 6 >> + >> +typedef struct { >> + UINT32 Signature; >> + // >> + // The bound non-discoverable device protocol instance >> + // >> + NON_DISCOVERABLE_DEVICE *Device; >> + // >> + // The exposed PCI I/O protocol instance. >> + // >> + EFI_PCI_IO_PROTOCOL PciIo; >> + // >> + // The emulated PCI config space of the device. Only the minimally >> +required >> + // items are assigned. >> + // >> + PCI_TYPE00 ConfigSpace; >> + // >> + // The first virtual BAR to assign based on the resources described >> + // by the non-discoverable device. >> + // >> + UINT32 BarOffset; >> + // >> + // The number of virtual BARs we expose based on the number of >> + // resources >> + // >> + UINT32 BarCount; >> + // >> + // The PCI I/O attributes for this device >> + // >> + UINT64 Attributes; >> + // >> + // Whether this device has been enabled >> + // >> + BOOLEAN Enabled; >> +} NON_DISCOVERABLE_PCI_DEVICE; >> + >> +VOID >> +InitializePciIoProtocol ( >> + NON_DISCOVERABLE_PCI_DEVICE *Device >> + ); >> + >> +extern EFI_COMPONENT_NAME_PROTOCOL gComponentName; extern >> +EFI_COMPONENT_NAME2_PROTOCOL gComponentName2; >> + >> +#endif >> diff --git a/MdeModulePkg/MdeModulePkg.dsc >> b/MdeModulePkg/MdeModulePkg.dsc index 43421d610ede..aac05408599d >> 100644 >> --- a/MdeModulePkg/MdeModulePkg.dsc >> +++ b/MdeModulePkg/MdeModulePkg.dsc >> @@ -260,6 +260,7 @@ [Components] >> MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf >> MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.inf >> MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.inf >> + >> + >> MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePci >> Dev >> + iceDxe.inf >> >> MdeModulePkg/Core/Dxe/DxeMain.inf { >> >> -- >> 2.7.4 >