From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-io0-x229.google.com (mail-io0-x229.google.com [IPv6:2607:f8b0:4001:c06::229]) (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 09E4C81EA9 for ; Thu, 24 Nov 2016 10:14:30 -0800 (PST) Received: by mail-io0-x229.google.com with SMTP id j65so90859400iof.0 for ; Thu, 24 Nov 2016 10:14:29 -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=q2k/86QWozclLvLhpAhUMpvR0wVgevOETHJeWvRlAvE=; b=joy0So3WLCrEG/GZN4Pyv4wfP5mAVlhqFuExiqL374SZIX0LOKJZ6CgalJ/jWVAD3b b9lXP1UA1DJDvTNkFrc9/5Yhl0zRxCIPQlOJDN41wDzLX+ACEXOuBNPM32r7N46/kWTU l9k9FUKAewhbzhrHZ0YGcG9bqoMcOwe1zEEpk= 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=q2k/86QWozclLvLhpAhUMpvR0wVgevOETHJeWvRlAvE=; b=DU6Vy2u5G+4QoBFi0WeTWWECo5jGqj90OKUk1Kig8ZHUDKE80GE3NUNztMPgditAHd BzCx9kGyiLNbmjkR3bfeyqBlVSW2wNdle6iMBi3/SrvjXhvecQ/sS71+/UPJrNp14zN8 0zS3CGLrGwjAo++IMx2PB7MaQduMHdPTbyjHZhDYJqyvf9cxY9JrBAwn1akOAEZIGsVB mTnn7Qlvj0vZr9k/QyK8OqneBJEvzBMGpA1t/EXhSbHssItMxX4WMt3iuhpZHBkSrjqB DZVPoW2JUklj9cFJv0lW0UGR7KUsn4kJGKyM+J4e3loFoRm5JWWVITTwY3Yf4NuGA1hn 19SQ== X-Gm-Message-State: AKaTC01Vr9jhrhvfYOSdJ8mcuFF53pZziVQu5btcadlXBN+nB1+wfa3ZUwRsOxj3s2T2RkOUW2YI43IkrsB8y3/b X-Received: by 10.107.2.8 with SMTP id 8mr2962119ioc.83.1480011268673; Thu, 24 Nov 2016 10:14:28 -0800 (PST) MIME-Version: 1.0 Received: by 10.107.59.147 with HTTP; Thu, 24 Nov 2016 10:14:28 -0800 (PST) In-Reply-To: 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: Thu, 24 Nov 2016 18:14:28 +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: Thu, 24 Nov 2016 18:14:30 -0000 Content-Type: text/plain; charset=UTF-8 Ray, I still need some help understanding how you think this is supposed to work Thanks, Ard. On 18 November 2016 at 12:30, Ard Biesheuvel wrote: > On 17 November 2016 at 03:29, Ni, Ruiyu wrote: [...] >>> +// >>> +// 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 >>