On Wed, Nov 02, 2016 at 01:39:26PM +0000, Ard Biesheuvel wrote: > On 1 November 2016 at 22:22, Leif Lindholm <leif.lindh...@linaro.org> wrote: > > On Mon, Oct 31, 2016 at 06:13:08PM +0000, Ard Biesheuvel wrote: > >> This implements support for platform PCI I/O devices, i.e, devices that > >> are not on a PCI bus but that can be drived by generic PCI drivers in > > > > drived->driven? (or substitute "controlled") > > > > That's a typo, not a speako. But yes, let me clean that up > > >> 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. > > > > How do we deal with these devices if there is no RAM below 4GB? > > (Signalling an error and aborting is fine, but worth calling out even > > here in the commit message.) > > > > The same thing the normal PCI I/O implementations do: return an error. > If you plug in a EHCI controller on Seattle that does not support > 64-bit DMA, calls to AllocateBuffer() and Map() will fail in exactly > the same way.
OK - if it's that straightforward, please ignore all of my other comments on that topic. > >> > >> For now, this driver supports coherent DMA only, but support for > >> non-coherent DMA is planned as well. > >> > >> Contributed-under: TianoCore Contribution Agreement 1.0 > >> Signed-off-by: Ard Biesheuvel <ard.biesheu...@linaro.org> > >> --- > >> EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c | 649 > >> ++++++++++++++++++++ > >> EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h | 67 ++ > >> EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c | 268 ++++++++ > >> EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf | 41 ++ > >> EmbeddedPkg/EmbeddedPkg.dsc | 1 + > >> 5 files changed, 1026 insertions(+) > >> > >> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c > >> b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c > >> new file mode 100644 > >> index 000000000000..97ed19353347 > >> --- /dev/null > >> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c > >> @@ -0,0 +1,649 @@ > >> +/** @file > >> + > >> + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> > >> + Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR> > >> + > >> + 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 "PlatformPciIo.h" > >> + > >> +#include <Protocol/PciRootBridgeIo.h> > >> + > >> +typedef struct { > >> + EFI_PHYSICAL_ADDRESS AllocAddress; > >> + VOID *HostAddress; > >> + EFI_PCI_IO_PROTOCOL_OPERATION Operation; > >> + UINTN NumberOfBytes; > >> +} PLATFORM_PCI_IO_MAP_INFO; > >> + > >> +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 > >> + ) > >> +{ > >> + UINT8 *Dst8; > >> + UINT16 *Dst16; > >> + UINT32 *Dst32; > >> + CONST UINT8 *Src8; > >> + CONST UINT16 *Src16; > >> + CONST UINT32 *Src32; > > > > Do any or all of these need to be volatile to ensure retaining access > > order and size (and if not, could we call that out explicitly)? > > > > Good question. But perhaps it is better to put a MemoryFence() at the > end of each loop iteration? That wouldn't prevent repeated reads from the same location, or reads done as a larger element. It would make either very unlikely, but it wouldn't prevent. > >> + >> + // > >> + // 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 > >> + ) > >> +{ > >> + PLATFORM_PCI_IO_DEV *Dev; > >> + UINTN AlignMask; > >> + VOID *Address; > >> + > >> + if (Buffer == NULL) { > >> + return EFI_INVALID_PARAMETER; > >> + } > >> + > >> + Dev = PLATFORM_PCI_IO_DEV_FROM_PCI_IO(This); > >> + > >> + // > >> + // Only allow accesses to the single BAR we emulate > >> + // > >> + if (BarIndex != Dev->BarIndex || Offset >= Dev->BarSize) { > >> + return EFI_UNSUPPORTED; > >> + } > >> + > >> + Address = (VOID*)(UINTN)(Dev->ConfigSpace.Device.Bar[BarIndex] + > >> 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 > >> + ) > >> +{ > >> + PLATFORM_PCI_IO_DEV *Dev; > >> + UINTN AlignMask; > >> + VOID *Address; > >> + > >> + if (Buffer == NULL) { > >> + return EFI_INVALID_PARAMETER; > >> + } > >> + > >> + Dev = PLATFORM_PCI_IO_DEV_FROM_PCI_IO(This); > >> + > >> + // > >> + // Only allow accesses to the single BAR we emulate > >> + // > >> + if (BarIndex != Dev->BarIndex || Offset >= Dev->BarSize) { > >> + return EFI_UNSUPPORTED; > >> + } > >> + > >> + Address = (VOID*)(UINTN)(Dev->ConfigSpace.Device.Bar[BarIndex] + > >> 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 > >> + ) > >> +{ > >> + PLATFORM_PCI_IO_DEV *Dev; > >> + VOID *Address; > >> + > >> + if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) > >> { > >> + return EFI_INVALID_PARAMETER; > >> + } > >> + > >> + Dev = PLATFORM_PCI_IO_DEV_FROM_PCI_IO(This); > >> + > >> + Address = (UINT8 *)&Dev->ConfigSpace + Offset; > >> + > >> + return PciIoMemRW (Width, Count, 1, Buffer, 1, Address); > >> +} > >> + > >> +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 > >> + ) > >> +{ > >> + PLATFORM_PCI_IO_DEV *Dev; > >> + VOID *Address; > >> + > >> + if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) > >> { > >> + return EFI_INVALID_PARAMETER; > >> + } > >> + > >> + Dev = PLATFORM_PCI_IO_DEV_FROM_PCI_IO(This); > >> + > >> + Address = (UINT8 *)&Dev->ConfigSpace + Offset; > >> + > >> + 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 > >> + ) > >> +{ > >> + PLATFORM_PCI_IO_DEV *Dev; > >> + EFI_STATUS Status; > >> + PLATFORM_PCI_IO_MAP_INFO *MapInfo; > >> + > >> + // > >> + // If this device does not support 64-bit DMA addressing, we need to > >> allocate > >> + // a bounce buffer and copy over the data if HostAddress is above 4 GB. > >> + // > >> + Dev = PLATFORM_PCI_IO_DEV_FROM_PCI_IO(This); > >> + if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 && > >> + (UINTN) HostAddress >= SIZE_4GB) { > >> + > >> + // > >> + // Bounce buffering is not possible for consistent mappings > >> + // > >> + if (Operation == EfiPciIoOperationBusMasterCommonBuffer) { > >> + return EFI_UNSUPPORTED; > >> + } > >> + > >> + MapInfo = (PLATFORM_PCI_IO_MAP_INFO *)AllocatePool (sizeof *MapInfo); > >> + if (MapInfo == NULL) { > >> + return EFI_OUT_OF_RESOURCES; > >> + } > >> + > >> + MapInfo->AllocAddress = SIZE_4GB - 1; > >> + 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)) { > > > > Comment on how this can mean the system does not have RAM < 4GB and > > cannot support this device? > > > > Sure > > >> + FreePool (MapInfo); > >> + return Status; > >> + } > >> + if (Operation == EfiPciIoOperationBusMasterRead) { > >> + gBS->CopyMem ((VOID *)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 > >> + ) > >> +{ > >> + PLATFORM_PCI_IO_MAP_INFO *MapInfo; > >> + > >> + MapInfo = Mapping; > >> + if (MapInfo != NULL) { > >> + if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) { > >> + gBS->CopyMem (MapInfo->HostAddress, (VOID *)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 > >> + ) > >> +{ > >> + PLATFORM_PCI_IO_DEV *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 ))) { > > > > Is that indentation before ))) intentional? > > > > That was simply copied from the Omap35xxPkg PciEmulation code. I will > clean that up > > > >> + return EFI_UNSUPPORTED; > >> + } > >> + > >> + // > >> + // Allocate below 4 GB if the dual address cycle attribute has not > >> + // been set. > > > > Comment on incompatibility if no RAM below 4 GB? > > > > Ack > > >> + // > >> + Dev = PLATFORM_PCI_IO_DEV_FROM_PCI_IO(This); > >> + if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) { > >> + AllocAddress = SIZE_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; > > > > Indentation before ) intentional? > > > > Same here > > >> + } > >> + > >> + *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 > >> + ) > >> +{ > >> + PLATFORM_PCI_IO_DEV *Dev; > >> + BOOLEAN Enable; > >> + > >> + Dev = PLATFORM_PCI_IO_DEV_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 platform device specific initialization now. > >> + // > >> + if (Enable && !Dev->Enabled && Dev->PlatformPciIo->Initialize != NULL) { > >> + Dev->PlatformPciIo->Initialize (Dev->PlatformPciIo); > >> + 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 > >> + ) > >> +{ > >> + ASSERT (FALSE); > >> + return EFI_UNSUPPORTED; > >> +} > >> + > >> +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 ( > >> + PLATFORM_PCI_IO_DEV *PlatformPciIoDev > >> + ) > >> +{ > >> + PlatformPciIoDev->ConfigSpace.Hdr.VendorId = 0xFFFF; // no vendor > >> + PlatformPciIoDev->ConfigSpace.Hdr.DeviceId = 0x0000; // device id > >> ignored > > > > Are these IDs noncontroversial? > > Would it be preferable to allocate some real ones? > > > > They are unallocated, and unpopulated PCI config space reads back as > all zeroes, so 0xFFFF is the least likely to ever become allocated. > Device ID is scoped by vendor ID, so it's a don't care in any case. > > On top of that, the whole point of this driver is to match on class > codes, so we are by definition not interested in attaching drivers > that look for a particular Vendor/Device ID I don't disagree with any of what you're saying - I'd just like some input from someone who feels competent to comment. If 0xFFFF is acceptable to everyone, it coud make sense to have a PCI_VENDOR_NONE define. > >> + > >> + switch (PlatformPciIoDev->PlatformPciIo->DeviceType) { > >> + case PlatformPciIoDeviceOhci: > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_OHCI; > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB; > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL; > >> + PlatformPciIoDev->BarSize = SIZE_64KB; > > > > Is the 64KB mainly for SBSA compliance, or is it implicit for OHCI? > > > > Copy/paste from Juno. No clue tbh Ah :) > >> + break; > >> + > >> + case PlatformPciIoDeviceUhci: > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_UHCI; > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB; > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL; > >> + PlatformPciIoDev->BarSize = SIZE_64KB; > >> + break; > >> + > >> + case PlatformPciIoDeviceEhci: > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_EHCI; > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB; > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL; > >> + PlatformPciIoDev->BarSize = SIZE_64KB; > >> + break; > >> + > >> + case PlatformPciIoDeviceXhci: > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_XHCI; > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB; > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL; > >> + PlatformPciIoDev->BarIndex = 0; > >> + PlatformPciIoDev->BarSize = SIZE_64KB; > >> + break; > >> + > >> + case PlatformPciIoDeviceAhci: > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[0] = > >> PCI_IF_MASS_STORAGE_AHCI; > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[1] = > >> PCI_CLASS_MASS_STORAGE_SATADPA; > >> + PlatformPciIoDev->ConfigSpace.Hdr.ClassCode[2] = > >> PCI_CLASS_MASS_STORAGE; > >> + PlatformPciIoDev->BarIndex = 5; > >> + PlatformPciIoDev->BarSize = SIZE_1KB; > >> + break; > >> + > > > > And as a follow-on to comment on previous patch: SdMmc and Ufs? > > > > Indeed. Added in v2 Thanks! > > >> + default: > >> + ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); > >> + } > >> + > >> + PlatformPciIoDev->ConfigSpace.Device.Bar[PlatformPciIoDev->BarIndex] = > >> + > >> PlatformPciIoDev->PlatformPciIo->BaseAddress; > >> + > >> + // Copy protocol structure > >> + CopyMem(&PlatformPciIoDev->PciIo, &PciIoTemplate, sizeof PciIoTemplate); > >> +} > >> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h > >> b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h > >> new file mode 100644 > >> index 000000000000..8fd8dc5e4a11 > >> --- /dev/null > >> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h > >> @@ -0,0 +1,67 @@ > >> +/** @file > >> + > >> + Copyright (C) 2016, Linaro Ltd. All rights reserved.<BR> > >> + > >> + 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 <Library/BaseMemoryLib.h> > >> +#include <Library/DebugLib.h> > >> +#include <Library/MemoryAllocationLib.h> > >> +#include <Library/UefiBootServicesTableLib.h> > >> +#include <Library/UefiLib.h> > >> + > >> +#include <IndustryStandard/Pci.h> > >> + > >> +#include <Protocol/PciIo.h> > >> +#include <Protocol/PlatformPciIo.h> > >> + > >> +#define PLATFORM_PCI_IO_SIG SIGNATURE_32 ('P', 'P', 'I', 'D') > >> + > >> +#define PLATFORM_PCI_IO_DEV_FROM_PCI_IO(PciIoPointer) \ > >> + CR (PciIoPointer, PLATFORM_PCI_IO_DEV, PciIo, > >> PLATFORM_PCI_IO_SIG) > >> + > >> +typedef struct { > >> + UINT32 Signature; > >> + // > >> + // The bound platform PCI I/O protocol instance > >> + // > >> + PLATFORM_PCI_IO *PlatformPciIo; > >> + // > >> + // 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 BAR index which exposes the MMIO control region of the device > >> + // > >> + UINTN BarIndex; > >> + // > >> + // The size of the MMIO control region of the device > >> + // > >> + UINTN BarSize; > >> + // > >> + // The PCI I/O attributes for this device > >> + // > >> + UINT64 Attributes; > >> + // > >> + // Whether this device has been enabled > >> + // > >> + BOOLEAN Enabled; > >> +} PLATFORM_PCI_IO_DEV; > >> + > >> +VOID > >> +InitializePciIoProtocol ( > >> + PLATFORM_PCI_IO_DEV *PlatformPciIoDev > >> + ); > >> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c > >> b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c > >> new file mode 100644 > >> index 000000000000..7f3306e7e891 > >> --- /dev/null > >> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c > >> @@ -0,0 +1,268 @@ > >> +/** @file > >> + > >> + Copyright (C) 2016, Linaro Ltd. All rights reserved.<BR> > >> + > >> + 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 "PlatformPciIo.h" > >> + > >> +#include <Protocol/ComponentName.h> > >> +#include <Protocol/DriverBinding.h> > >> + > >> +// > >> +// Probe, start and stop functions of this driver, called by the DXE core > >> for > >> +// specific devices. > >> +// > >> +// The following specifications document these interfaces: > >> +// - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol > >> +// - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol > >> +// > >> +// The implementation follows: > >> +// - Driver Writer's Guide for UEFI 2.3.1 v1.01 > >> +// - 5.1.3.4 OpenProtocol() and CloseProtocol() > >> +// - UEFI Spec 2.3.1 + Errata C > >> +// - 6.3 Protocol Handler Services > >> +// > >> + > >> +STATIC > >> +EFI_STATUS > >> +EFIAPI > >> +PlatformPciIoDriverBindingSupported ( > >> + IN EFI_DRIVER_BINDING_PROTOCOL *This, > >> + IN EFI_HANDLE DeviceHandle, > >> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > >> + ) > >> +{ > >> + PLATFORM_PCI_IO *PlatformPciIo; > >> + EFI_STATUS Status; > >> + > >> + Status = gBS->OpenProtocol (DeviceHandle, &gPlatformPciIoProtocolGuid, > >> + (VOID **)&PlatformPciIo, This->DriverBindingHandle, > >> + DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); > >> + if (EFI_ERROR (Status)) { > >> + return Status; > >> + } > >> + > >> + // > >> + // We only support the following device types > >> + // > >> + switch (PlatformPciIo->DeviceType) { > >> + case PlatformPciIoDeviceOhci: > >> + case PlatformPciIoDeviceUhci: > >> + case PlatformPciIoDeviceEhci: > >> + case PlatformPciIoDeviceXhci: > >> + case PlatformPciIoDeviceAhci: > > > > SdMmc, Ufs? > > > > Yeah yeah > > >> + // > >> + // Restricted to DMA coherent for now > >> + // > >> + if (PlatformPciIo->DmaType == PlatformPciIoDmaCoherent) { > >> + Status = EFI_SUCCESS; > >> + break; > >> + } > >> + default: > >> + Status = EFI_UNSUPPORTED; > >> + } > >> + > >> + gBS->CloseProtocol (DeviceHandle, &gPlatformPciIoProtocolGuid, > >> + This->DriverBindingHandle, DeviceHandle); > >> + > >> + return Status; > >> +} > >> + > >> +STATIC > >> +EFI_STATUS > >> +EFIAPI > >> +PlatformPciIoDriverBindingStart ( > >> + IN EFI_DRIVER_BINDING_PROTOCOL *This, > >> + IN EFI_HANDLE DeviceHandle, > >> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > >> + ) > >> +{ > >> + PLATFORM_PCI_IO_DEV *Dev; > >> + EFI_STATUS Status; > >> + > >> + Dev = (PLATFORM_PCI_IO_DEV *) AllocateZeroPool (sizeof *Dev); > > > > You usually don't put a space after the cast. > > > > Ack > > >> + if (Dev == NULL) { > >> + return EFI_OUT_OF_RESOURCES; > >> + } > >> + > >> + Status = gBS->OpenProtocol (DeviceHandle, &gPlatformPciIoProtocolGuid, > >> + (VOID **)&Dev->PlatformPciIo, This->DriverBindingHandle, > >> + DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); > >> + if (EFI_ERROR (Status)) { > >> + goto FreeDev; > >> + } > >> + > >> + InitializePciIoProtocol (Dev); > >> + > >> + // > >> + // Setup complete, attempt to export the driver instance's > >> EFI_PCI_IO_PROTOCOL > >> + // interface. > >> + // > >> + Dev->Signature = PLATFORM_PCI_IO_SIG; > >> + Status = gBS->InstallProtocolInterface (&DeviceHandle, > >> &gEfiPciIoProtocolGuid, > >> + EFI_NATIVE_INTERFACE, &Dev->PciIo); > >> + if (EFI_ERROR (Status)) { > >> + goto CloseProtocol; > >> + } > >> + > >> + return EFI_SUCCESS; > >> + > >> +CloseProtocol: > >> + gBS->CloseProtocol (DeviceHandle, &gPlatformPciIoProtocolGuid, > >> + This->DriverBindingHandle, DeviceHandle); > >> + > >> +FreeDev: > >> + FreePool (Dev); > >> + > >> + return Status; > >> +} > >> + > >> + > >> +STATIC > >> +EFI_STATUS > >> +EFIAPI > >> +PlatformPciIoDriverBindingStop ( > >> + IN EFI_DRIVER_BINDING_PROTOCOL *This, > >> + IN EFI_HANDLE DeviceHandle, > >> + IN UINTN NumberOfChildren, > >> + IN EFI_HANDLE *ChildHandleBuffer > >> + ) > >> +{ > >> + EFI_STATUS Status; > >> + EFI_PCI_IO_PROTOCOL *PciIo; > >> + PLATFORM_PCI_IO_DEV *Dev; > >> + > >> + Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, > >> + (VOID **)&PciIo, This->DriverBindingHandle, > >> DeviceHandle, > >> + EFI_OPEN_PROTOCOL_GET_PROTOCOL); > >> + if (EFI_ERROR (Status)) { > >> + return Status; > >> + } > >> + > >> + Dev = PLATFORM_PCI_IO_DEV_FROM_PCI_IO (PciIo); > >> + > >> + // > >> + // Handle Stop() requests for in-use driver instances gracefully. > >> + // > >> + Status = gBS->UninstallProtocolInterface (DeviceHandle, > >> + &gEfiPciIoProtocolGuid, &Dev->PciIo); > >> + if (EFI_ERROR (Status)) { > >> + return Status; > >> + } > >> + > >> + gBS->CloseProtocol (DeviceHandle, &gPlatformPciIoProtocolGuid, > >> + This->DriverBindingHandle, DeviceHandle); > >> + > >> + FreePool (Dev); > >> + > >> + return EFI_SUCCESS; > >> +} > >> + > >> + > >> +// > >> +// The static object that groups the Supported() (ie. probe), Start() and > >> +// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + > >> Errata > >> +// C, 10.1 EFI Driver Binding Protocol. > >> +// > >> +STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = { > >> + &PlatformPciIoDriverBindingSupported, > >> + &PlatformPciIoDriverBindingStart, > >> + &PlatformPciIoDriverBindingStop, > >> + 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed > >> drivers > >> + NULL, > >> + NULL > >> +}; > >> + > >> + > >> +// > >> +// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL > >> and > >> +// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's > >> name > >> +// in English, for display on standard console devices. This is > >> recommended for > >> +// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver > >> Writer's > >> +// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names. > >> +// > > > > Should the strings be split out in order to permit proper unicode > > strings without polluting the C file? As this will be a core library, > > I would quite like to see translations to all kinds of languages. > > > > Do you mean a separate ComponentName.c like other drivers? Yeah. Regards, Leif > >> + > >> +STATIC > >> +EFI_UNICODE_STRING_TABLE mDriverNameTable[] = { > >> + { "eng;en", L"PCI I/O protocol emulation driver for platform devices" }, > >> + { NULL, NULL } > >> +}; > >> + > >> +STATIC > >> +EFI_COMPONENT_NAME_PROTOCOL gComponentName; > >> + > >> +STATIC > >> +EFI_STATUS > >> +EFIAPI > >> +PlatformPciIoGetDriverName ( > >> + IN EFI_COMPONENT_NAME_PROTOCOL *This, > >> + IN CHAR8 *Language, > >> + OUT CHAR16 **DriverName > >> + ) > >> +{ > >> + return LookupUnicodeString2 ( > >> + Language, > >> + This->SupportedLanguages, > >> + mDriverNameTable, > >> + DriverName, > >> + (BOOLEAN)(This == &gComponentName) // Iso639Language > >> + ); > >> +} > >> + > >> +STATIC > >> +EFI_STATUS > >> +EFIAPI > >> +PlatformPciIoGetDeviceName ( > >> + IN EFI_COMPONENT_NAME_PROTOCOL *This, > >> + IN EFI_HANDLE DeviceHandle, > >> + IN EFI_HANDLE ChildHandle, > >> + IN CHAR8 *Language, > >> + OUT CHAR16 **ControllerName > >> + ) > >> +{ > >> + return EFI_UNSUPPORTED; > >> +} > >> + > >> +STATIC > >> +EFI_COMPONENT_NAME_PROTOCOL gComponentName = { > >> + &PlatformPciIoGetDriverName, > >> + &PlatformPciIoGetDeviceName, > >> + "eng" // SupportedLanguages, ISO 639-2 language codes > >> +}; > >> + > >> +STATIC > >> +EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = { > >> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &PlatformPciIoGetDriverName, > >> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &PlatformPciIoGetDeviceName, > >> + "en" // SupportedLanguages, RFC 4646 language codes > >> +}; > >> + > >> + > >> +// > >> +// Entry point of this driver. > >> +// > >> +EFI_STATUS > >> +EFIAPI > >> +PlatformPciIoDxeEntryPoint ( > >> + IN EFI_HANDLE ImageHandle, > >> + IN EFI_SYSTEM_TABLE *SystemTable > >> + ) > >> +{ > >> + return EfiLibInstallDriverBindingComponentName2 ( > >> + ImageHandle, > >> + SystemTable, > >> + &gDriverBinding, > >> + ImageHandle, > >> + &gComponentName, > >> + &gComponentName2 > >> + ); > >> +} > >> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf > >> b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf > >> new file mode 100644 > >> index 000000000000..2b0baf06732c > >> --- /dev/null > >> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf > >> @@ -0,0 +1,41 @@ > >> +## @file > >> +# Copyright (C) 2016, 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 > >> +# 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. > >> +# > >> +## > >> + > >> +[Defines] > >> + INF_VERSION = 0x00010017 > > > > 0019? > > > >> + BASE_NAME = PlatformPciIoDxe > >> + FILE_GUID = 71fd84cd-353b-464d-b7a4-6ea7b96995cb > >> + MODULE_TYPE = UEFI_DRIVER > >> + VERSION_STRING = 1.0 > >> + ENTRY_POINT = PlatformPciIoDxeEntryPoint > >> + > >> +[Sources] > >> + PlatformPciIoDxe.c > >> + PlatformPciIo.c > >> + PlatformPciIo.h > >> + > >> +[Packages] > >> + EmbeddedPkg/EmbeddedPkg.dec > >> + MdePkg/MdePkg.dec > >> + > >> +[LibraryClasses] > >> + BaseMemoryLib > >> + DebugLib > >> + MemoryAllocationLib > >> + UefiBootServicesTableLib > >> + UefiDriverEntryPoint > >> + UefiLib > >> + > >> +[Protocols] > >> + gEfiPciIoProtocolGuid ## BY_START > >> + gPlatformPciIoProtocolGuid ## TO_START > >> diff --git a/EmbeddedPkg/EmbeddedPkg.dsc b/EmbeddedPkg/EmbeddedPkg.dsc > >> index d47c836379c9..47f9d47eb378 100644 > >> --- a/EmbeddedPkg/EmbeddedPkg.dsc > >> +++ b/EmbeddedPkg/EmbeddedPkg.dsc > >> @@ -291,6 +291,7 @@ [Components.common] > >> > >> EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf > >> > >> > >> EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf > >> + EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf > >> > >> [Components.IA32, Components.X64, Components.IPF, Components.ARM] > >> EmbeddedPkg/GdbStub/GdbStub.inf > >> -- > >> 2.7.4 > >> > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel