public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH 0/5] EmbeddedPkg: generic support for reusing PCI drivers for platform devices
@ 2016-10-31 18:13 Ard Biesheuvel
  2016-10-31 18:13 ` [PATCH 1/5] EmbeddedPkg: introduce platform PCI I/O protocol Ard Biesheuvel
                   ` (5 more replies)
  0 siblings, 6 replies; 26+ messages in thread
From: Ard Biesheuvel @ 2016-10-31 18:13 UTC (permalink / raw)
  To: edk2-devel, leif.lindholm; +Cc: Ard Biesheuvel

After having reviewed PciEmulation.c #6, it is time to implement this in a
more generic way, taking into account DMA limitations and DMA coherency.

So implement a new platform PCI I/O protocol, and a UEFI_DRIVER module that
binds to those protocols to expose the PCI I/O abstraction that generic
AHCI/XHCI etc drivers can talk to.

Tested with AHCI on QEMU.

Ard Biesheuvel (5):
  EmbeddedPkg: introduce platform PCI I/O protocol
  EmbeddedPkg: introduce platform PCI I/O registration library
  EmbeddedPkg: implement generic platform PCI I/O driver
  ArmPkg/CpuDxe: set DmaBufferAlignment according to CWG
  EmbeddedPkg/PlatformPciIoDxe: add support for non-coherent DMA

 ArmPkg/Drivers/CpuDxe/CpuDxe.c                                                                |   4 +-
 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c                                          | 853 ++++++++++++++++++++
 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h                                          |  72 ++
 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c                                       | 271 +++++++
 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf                                     |  43 +
 EmbeddedPkg/EmbeddedPkg.dec                                                                   |   2 +
 EmbeddedPkg/EmbeddedPkg.dsc                                                                   |   3 +
 EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h                              |  46 ++
 EmbeddedPkg/Include/Protocol/PlatformPciIo.h                                                  |  74 ++
 EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c   | 115 +++
 EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf |  34 +
 11 files changed, 1516 insertions(+), 1 deletion(-)
 create mode 100644 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c
 create mode 100644 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h
 create mode 100644 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c
 create mode 100644 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf
 create mode 100644 EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h
 create mode 100644 EmbeddedPkg/Include/Protocol/PlatformPciIo.h
 create mode 100644 EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c
 create mode 100644 EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf

-- 
2.7.4



^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 1/5] EmbeddedPkg: introduce platform PCI I/O protocol
  2016-10-31 18:13 [PATCH 0/5] EmbeddedPkg: generic support for reusing PCI drivers for platform devices Ard Biesheuvel
@ 2016-10-31 18:13 ` Ard Biesheuvel
  2016-11-01 21:54   ` Leif Lindholm
  2016-10-31 18:13 ` [PATCH 2/5] EmbeddedPkg: introduce platform PCI I/O registration library Ard Biesheuvel
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 26+ messages in thread
From: Ard Biesheuvel @ 2016-10-31 18:13 UTC (permalink / raw)
  To: edk2-devel, leif.lindholm; +Cc: Ard Biesheuvel

Introduce a protocol that can be exposed by a platform for devices that
can be driven by a PCI driver, (e.g., AHCI, XHCI), but do not live on a
PCI bus. This used to be called 'PCI emulation' but given that we only
emulate the PCI config space and nothing else, it tends to be a bit
confusing so this introduces the term 'platform PCI I/O' instead.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 EmbeddedPkg/EmbeddedPkg.dec                  |  1 +
 EmbeddedPkg/Include/Protocol/PlatformPciIo.h | 74 ++++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec
index 2c2cf41103c2..84a6f4d01077 100644
--- a/EmbeddedPkg/EmbeddedPkg.dec
+++ b/EmbeddedPkg/EmbeddedPkg.dec
@@ -69,6 +69,7 @@ [Protocols.common]
   gAndroidFastbootPlatformProtocolGuid =  { 0x524685a0, 0x89a0, 0x11e3, {0x9d, 0x4d, 0xbf, 0xa9, 0xf6, 0xa4, 0x03, 0x08}}
   gUsbDeviceProtocolGuid =  { 0x021bd2ca, 0x51d2, 0x11e3, {0x8e, 0x56, 0xb7, 0x54, 0x17, 0xc7,  0x0b, 0x44 }}
   gPlatformGpioProtocolGuid = { 0x52ce9845, 0x5af4, 0x43e2, {0xba, 0xfd, 0x23, 0x08, 0x12, 0x54, 0x7a, 0xc2 }}
+  gPlatformPciIoProtocolGuid = { 0x0d51905b, 0xb77e, 0x452a, {0xa2, 0xc0, 0xec, 0xa0, 0xcc, 0x8d, 0x51, 0x4a }}
 
 [PcdsFeatureFlag.common]
   gEmbeddedTokenSpaceGuid.PcdEmbeddedMacBoot|FALSE|BOOLEAN|0x00000001
diff --git a/EmbeddedPkg/Include/Protocol/PlatformPciIo.h b/EmbeddedPkg/Include/Protocol/PlatformPciIo.h
new file mode 100644
index 000000000000..a7bd584049ac
--- /dev/null
+++ b/EmbeddedPkg/Include/Protocol/PlatformPciIo.h
@@ -0,0 +1,74 @@
+/** @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.
+
+**/
+
+#ifndef __PLATFORM_PCI_IO_H__
+#define __PLATFORM_PCI_IO_H__
+
+#define PLATFORM_PCI_IO_PROTOCOL_GUID \
+  { 0x0d51905b, 0xb77e, 0x452a, {0xa2, 0xc0, 0xec, 0xa0, 0xcc, 0x8d, 0x51, 0x4a } }
+
+//
+// Protocol interface structure
+//
+typedef struct _PLATFORM_PCI_IO PLATFORM_PCI_IO;
+
+//
+// Data Types
+//
+typedef enum {
+  PlatformPciIoDeviceOhci,
+  PlatformPciIoDeviceUhci,
+  PlatformPciIoDeviceEhci,
+  PlatformPciIoDeviceXhci,
+  PlatformPciIoDeviceAhci,
+  PlatformPciIoDeviceMax,
+} PLATFORM_PCI_IO_DEVICE_TYPE;
+
+typedef enum {
+  PlatformPciIoDmaCoherent,
+  PlatformPciIoDmaNonCoherent,
+  PlatformPciIoDmaMax,
+} PLATFORM_PCI_IO_DMA_TYPE;
+
+//
+// Function Prototypes
+//
+typedef
+EFI_STATUS
+(EFIAPI *PLATFORM_PCI_IO_INIT) (
+  IN  PLATFORM_PCI_IO     *This
+  );
+
+struct _PLATFORM_PCI_IO {
+  //
+  // The MMIO address of the device
+  //
+  EFI_PHYSICAL_ADDRESS          BaseAddress;
+  //
+  // The type of device
+  //
+  PLATFORM_PCI_IO_DEVICE_TYPE   DeviceType;
+  //
+  // Whether this device is DMA coherent
+  //
+  PLATFORM_PCI_IO_DMA_TYPE      DmaType;
+  //
+  // Initialization function for the device
+  //
+  PLATFORM_PCI_IO_INIT          Initialize;
+};
+
+extern EFI_GUID gPlatformPciIoProtocolGuid;
+
+#endif
-- 
2.7.4



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 2/5] EmbeddedPkg: introduce platform PCI I/O registration library
  2016-10-31 18:13 [PATCH 0/5] EmbeddedPkg: generic support for reusing PCI drivers for platform devices Ard Biesheuvel
  2016-10-31 18:13 ` [PATCH 1/5] EmbeddedPkg: introduce platform PCI I/O protocol Ard Biesheuvel
@ 2016-10-31 18:13 ` Ard Biesheuvel
  2016-11-01 21:57   ` Leif Lindholm
  2016-10-31 18:13 ` [PATCH 3/5] EmbeddedPkg: implement generic platform PCI I/O driver Ard Biesheuvel
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 26+ messages in thread
From: Ard Biesheuvel @ 2016-10-31 18:13 UTC (permalink / raw)
  To: edk2-devel, leif.lindholm; +Cc: Ard Biesheuvel

This introduces the PlatformPciIoDeviceRegistrationLib library class and
a default implementation to help platforms expose platform devices that
may be driven by a PCI driver.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 EmbeddedPkg/EmbeddedPkg.dec                                                                   |   1 +
 EmbeddedPkg/EmbeddedPkg.dsc                                                                   |   2 +
 EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h                              |  46 ++++++++
 EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c   | 115 ++++++++++++++++++++
 EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf |  34 ++++++
 5 files changed, 198 insertions(+)

diff --git a/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec
index 84a6f4d01077..226036858880 100644
--- a/EmbeddedPkg/EmbeddedPkg.dec
+++ b/EmbeddedPkg/EmbeddedPkg.dec
@@ -44,6 +44,7 @@ [LibraryClasses.common]
   EblNetworkLib|Include/Library/EblNetworkLib.h
   GdbSerialLib|Include/Library/GdbSerialLib.h
   DebugAgentTimerLib|Include/Library/DebugAgentTimerLib.h
+  PlatformPciIoDeviceRegistrationLib|Include/Library/PlatformPciIoDeviceRegistrationLib.h
 
 
 [Guids.common]
diff --git a/EmbeddedPkg/EmbeddedPkg.dsc b/EmbeddedPkg/EmbeddedPkg.dsc
index eb7af800f0b2..d47c836379c9 100644
--- a/EmbeddedPkg/EmbeddedPkg.dsc
+++ b/EmbeddedPkg/EmbeddedPkg.dsc
@@ -290,5 +290,7 @@ [Components.common]
   EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf
   EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf
 
+  EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf
+
 [Components.IA32, Components.X64, Components.IPF, Components.ARM]
   EmbeddedPkg/GdbStub/GdbStub.inf
diff --git a/EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h b/EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h
new file mode 100644
index 000000000000..07f163abc701
--- /dev/null
+++ b/EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h
@@ -0,0 +1,46 @@
+/** @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.
+
+**/
+
+#ifndef __PLATFORM_PCI_IO_DEVICE_REGISTRATION_LIB_H__
+#define __PLATFORM_PCI_IO_DEVICE_REGISTRATION_LIB_H__
+
+#include <Protocol/PlatformPciIo.h>
+
+/**
+  Register a platform device for PCI I/O protocol emulation
+
+  @param[in]      BaseAddress     The MMIO base address of the platform device
+  @param[in]      DeviceType      The type of platform device
+  @param[in]      DmaType         Whether the device is DMA coherent
+  @param[in]      InitFunc        Initialization routine to be invoked when the
+                                  device is enabled
+  @param[in,out]  Handle          The handle onto which to install the platform
+                                  PCI I/O protocol has been installed.
+                                  If Handle is NULL or *Handle is NULL, a new
+                                  handle will be allocated.
+
+  @retval EFI_SUCCESS             The registration succeeded.
+  @retval other                   The registration failed.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformPciIoRegisterDevice (
+  IN      EFI_PHYSICAL_ADDRESS          BaseAddress,
+  IN      PLATFORM_PCI_IO_DEVICE_TYPE   DeviceType,
+  IN      PLATFORM_PCI_IO_DMA_TYPE      DmaType,
+  IN      PLATFORM_PCI_IO_INIT          InitFunc,
+  IN OUT  EFI_HANDLE                    *Handle OPTIONAL
+  );
+
+#endif
diff --git a/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c b/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c
new file mode 100644
index 000000000000..1ce5abb137df
--- /dev/null
+++ b/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c
@@ -0,0 +1,115 @@
+/** @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/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PlatformPciIoDeviceRegistrationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/PlatformPciIo.h>
+
+#pragma pack (1)
+typedef struct {
+  VENDOR_DEVICE_PATH                  Vendor;
+  UINT64                              BaseAddress;
+  EFI_DEVICE_PATH_PROTOCOL            End;
+} PLATFORM_PCI_IO_DEVICE_PATH;
+
+#pragma pack ()
+
+/**
+  Register a platform device for PCI I/O protocol emulation
+
+  @param[in]      BaseAddress     The MMIO base address of the platform device
+  @param[in]      DeviceType      The type of platform device
+  @param[in]      DmaType         Whether the device is DMA coherent
+  @param[in]      InitFunc        Initialization routine to be invoked when the
+                                  device is enabled
+  @param[in,out]  Handle          The handle onto which to install the platform
+                                  PCI I/O protocol has been installed.
+                                  If Handle is NULL or *Handle is NULL, a new
+                                  handle will be allocated.
+
+  @retval EFI_SUCCESS             The registration succeeded.
+  @retval other                   The registration failed.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformPciIoRegisterDevice (
+  IN      EFI_PHYSICAL_ADDRESS          BaseAddress,
+  IN      PLATFORM_PCI_IO_DEVICE_TYPE   DeviceType,
+  IN      PLATFORM_PCI_IO_DMA_TYPE      DmaType,
+  IN      PLATFORM_PCI_IO_INIT          InitFunc,
+  IN OUT  EFI_HANDLE                    *Handle
+  )
+{
+  PLATFORM_PCI_IO               *Device;
+  PLATFORM_PCI_IO_DEVICE_PATH   *DevicePath;
+  EFI_HANDLE                    LocalHandle;
+  EFI_STATUS                    Status;
+
+  if (DeviceType >= PlatformPciIoDeviceMax || DmaType >= PlatformPciIoDmaMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Handle == NULL) {
+    Handle = &LocalHandle;
+    LocalHandle = NULL;
+  }
+
+  Device = (PLATFORM_PCI_IO *)AllocateZeroPool (sizeof *Device);
+  if (Device == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Device->BaseAddress = BaseAddress;
+  Device->DeviceType = DeviceType;
+  Device->DmaType = DmaType;
+  Device->Initialize = InitFunc;
+
+  DevicePath = (PLATFORM_PCI_IO_DEVICE_PATH *)CreateDeviceNode (
+                                                HARDWARE_DEVICE_PATH,
+                                                HW_VENDOR_DP,
+                                                sizeof (*DevicePath));
+  if (DevicePath == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto FreeDevice;
+  }
+
+  CopyGuid (&DevicePath->Vendor.Guid, &gPlatformPciIoProtocolGuid);
+  DevicePath->BaseAddress = BaseAddress;
+
+  SetDevicePathNodeLength (&DevicePath->Vendor,
+    sizeof (*DevicePath) - sizeof (DevicePath->End));
+  SetDevicePathEndNode (&DevicePath->End);
+
+  Status = gBS->InstallMultipleProtocolInterfaces (Handle,
+                  &gPlatformPciIoProtocolGuid, Device,
+                  &gEfiDevicePathProtocolGuid, DevicePath);
+  if (EFI_ERROR (Status)) {
+    goto FreeDevicePath;
+  }
+  return EFI_SUCCESS;
+
+FreeDevicePath:
+  FreePool (DevicePath);
+
+FreeDevice:
+  FreePool (Device);
+
+  return Status;
+}
diff --git a/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf b/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf
new file mode 100644
index 000000000000..282db3ab59ab
--- /dev/null
+++ b/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf
@@ -0,0 +1,34 @@
+# @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.
+#
+
+[Defines]
+  INF_VERSION                    = 0x00010017
+  BASE_NAME                      = PlatformPciIoDeviceRegistrationLib
+  FILE_GUID                      = 8802ae41-8184-49cb-8aec-62627cd7ceb4
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PlatformPciIoDeviceRegistrationLib
+
+[Sources]
+  PlatformPciIoDeviceRegistrationLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  DevicePathLib
+  UefiBootServicesTableLib
+
+[Protocols]
+  gPlatformPciIoProtocolGuid
-- 
2.7.4



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 3/5] EmbeddedPkg: implement generic platform PCI I/O driver
  2016-10-31 18:13 [PATCH 0/5] EmbeddedPkg: generic support for reusing PCI drivers for platform devices Ard Biesheuvel
  2016-10-31 18:13 ` [PATCH 1/5] EmbeddedPkg: introduce platform PCI I/O protocol Ard Biesheuvel
  2016-10-31 18:13 ` [PATCH 2/5] EmbeddedPkg: introduce platform PCI I/O registration library Ard Biesheuvel
@ 2016-10-31 18:13 ` Ard Biesheuvel
  2016-11-01 22:22   ` Leif Lindholm
  2016-10-31 18:13 ` [PATCH 4/5] ArmPkg/CpuDxe: set DmaBufferAlignment according to CWG Ard Biesheuvel
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 26+ messages in thread
From: Ard Biesheuvel @ 2016-10-31 18:13 UTC (permalink / raw)
  To: edk2-devel, leif.lindholm; +Cc: Ard Biesheuvel

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
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.

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.biesheuvel@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;
+
+  //
+  // 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)) {
+      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         ))) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Allocate below 4 GB if the dual address cycle attribute has not
+  // been set.
+  //
+  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;
+  }
+
+  *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
+
+  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;
+    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;
+
+  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:
+    //
+    // 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);
+  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.
+//
+
+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
+  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



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 4/5] ArmPkg/CpuDxe: set DmaBufferAlignment according to CWG
  2016-10-31 18:13 [PATCH 0/5] EmbeddedPkg: generic support for reusing PCI drivers for platform devices Ard Biesheuvel
                   ` (2 preceding siblings ...)
  2016-10-31 18:13 ` [PATCH 3/5] EmbeddedPkg: implement generic platform PCI I/O driver Ard Biesheuvel
@ 2016-10-31 18:13 ` Ard Biesheuvel
  2016-11-01 22:32   ` Leif Lindholm
  2016-10-31 18:13 ` [PATCH 5/5] EmbeddedPkg/PlatformPciIoDxe: add support for non-coherent DMA Ard Biesheuvel
  2016-11-01 21:45 ` [PATCH 0/5] EmbeddedPkg: generic support for reusing PCI drivers for platform devices Leif Lindholm
  5 siblings, 1 reply; 26+ messages in thread
From: Ard Biesheuvel @ 2016-10-31 18:13 UTC (permalink / raw)
  To: edk2-devel, leif.lindholm; +Cc: Ard Biesheuvel

The DmaBufferAlignment currently defaults to 4, which is dangerously
small and may result in lost data on platform that perform non-coherent
DMA. So instead, take the CWG value from the cache info registers.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 ArmPkg/Drivers/CpuDxe/CpuDxe.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
index d089cb2d119f..ddc64fd255a0 100644
--- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
@@ -225,7 +225,7 @@ EFI_CPU_ARCH_PROTOCOL mCpu = {
   CpuGetTimerValue,
   CpuSetMemoryAttributes,
   0,          // NumberOfTimers
-  4,          // DmaBufferAlignment
+  2048,       // DmaBufferAlignment
 };
 
 EFI_STATUS
@@ -239,6 +239,8 @@ CpuDxeInitialize (
 
   InitializeExceptions (&mCpu);
 
+  mCpu.DmaBufferAlignment = ArmCacheWritebackGranule ();
+
   Status = gBS->InstallMultipleProtocolInterfaces (
                 &mCpuHandle,
                 &gEfiCpuArchProtocolGuid,           &mCpu,
-- 
2.7.4



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 5/5] EmbeddedPkg/PlatformPciIoDxe: add support for non-coherent DMA
  2016-10-31 18:13 [PATCH 0/5] EmbeddedPkg: generic support for reusing PCI drivers for platform devices Ard Biesheuvel
                   ` (3 preceding siblings ...)
  2016-10-31 18:13 ` [PATCH 4/5] ArmPkg/CpuDxe: set DmaBufferAlignment according to CWG Ard Biesheuvel
@ 2016-10-31 18:13 ` Ard Biesheuvel
  2016-11-01 22:43   ` Leif Lindholm
  2016-11-01 21:45 ` [PATCH 0/5] EmbeddedPkg: generic support for reusing PCI drivers for platform devices Leif Lindholm
  5 siblings, 1 reply; 26+ messages in thread
From: Ard Biesheuvel @ 2016-10-31 18:13 UTC (permalink / raw)
  To: edk2-devel, leif.lindholm; +Cc: Ard Biesheuvel

Add support for bounce buffering using uncached mappings when DMA mappings
are not aligned to the CPU's DMA buffer alignment.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c      | 204 ++++++++++++++++++++
 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h      |   5 +
 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c   |  17 +-
 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf |   2 +
 4 files changed, 221 insertions(+), 7 deletions(-)

diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c
index 97ed19353347..658d096c73c1 100644
--- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c
+++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c
@@ -15,6 +15,8 @@
 
 #include "PlatformPciIo.h"
 
+#include <Library/DxeServicesTableLib.h>
+
 #include <Protocol/PciRootBridgeIo.h>
 
 typedef struct {
@@ -454,6 +456,201 @@ CoherentPciIoFreeBuffer (
   return EFI_SUCCESS;
 }
 
+STATIC
+EFI_STATUS
+NonCoherentPciIoFreeBuffer (
+  IN  EFI_PCI_IO_PROTOCOL         *This,
+  IN  UINTN                       Pages,
+  IN  VOID                        *HostAddress
+  )
+{
+  EFI_STATUS        Status;
+
+  Status = gDS->SetMemorySpaceAttributes (
+                  (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
+                  EFI_PAGES_TO_SIZE (Pages),
+                  EFI_MEMORY_WB);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  FreePages (HostAddress, Pages);
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+NonCoherentPciIoAllocateBuffer (
+  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
+  )
+{
+  EFI_STATUS        Status;
+
+  Status = CoherentPciIoAllocateBuffer (This, Type, MemoryType, Pages,
+             HostAddress, Attributes);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gDS->SetMemorySpaceAttributes (
+                  (EFI_PHYSICAL_ADDRESS)(UINTN)*HostAddress,
+                  EFI_PAGES_TO_SIZE (Pages),
+                  EFI_MEMORY_WC);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gCpu->FlushDataCache (
+                   gCpu,
+                   (EFI_PHYSICAL_ADDRESS)(UINTN)*HostAddress,
+                   EFI_PAGES_TO_SIZE (Pages),
+                   EfiCpuFlushTypeInvalidate);
+  if (EFI_ERROR (Status)) {
+    NonCoherentPciIoFreeBuffer (This, Pages, *HostAddress);
+  }
+  return Status;
+}
+
+STATIC
+EFI_STATUS
+NonCoherentPciIoMap (
+  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;
+  UINTN                             AlignMask;
+  VOID                              *AllocAddress;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR   GcdDescriptor;
+  BOOLEAN                           UncachedMapping;
+
+  MapInfo = (PLATFORM_PCI_IO_MAP_INFO *)AllocatePool (sizeof *MapInfo);
+  if (MapInfo == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  MapInfo->HostAddress = HostAddress;
+  MapInfo->Operation = Operation;
+  MapInfo->NumberOfBytes = *NumberOfBytes;
+
+  //
+  // Bounce buffering is not possible for consistent mappings, so
+  // check we are mapping a cached buffer for consistent DMA
+  //
+  if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
+    Status = gDS->GetMemorySpaceDescriptor (
+                    (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
+                    &GcdDescriptor);
+    if (!EFI_ERROR (Status)) {
+      UncachedMapping = (GcdDescriptor.Attributes & EFI_MEMORY_WC) != 0;
+    } else {
+      UncachedMapping = FALSE;
+    }
+  }
+
+  //
+  // If this device does not support 64-bit DMA addressing, we need to allocate
+  // a bounce buffer and copy over the data if HostAddress >= 4 GB. We also need
+  // to allocate a bounce buffer if the mapping is not aligned to the CPU's
+  // DMA buffer alignment.
+  //
+  Dev = PLATFORM_PCI_IO_DEV_FROM_PCI_IO(This);
+  AlignMask = gCpu->DmaBufferAlignment - 1;
+  if (((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&
+       (UINTN) HostAddress >= SIZE_4GB) ||
+       ((((UINTN) HostAddress || *NumberOfBytes) & AlignMask) != 0 &&
+        !UncachedMapping)) {
+
+    Status = NonCoherentPciIoAllocateBuffer (This, AllocateAnyPages,
+               EfiBootServicesData, EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
+               &AllocAddress, 0);
+    if (EFI_ERROR (Status)) {
+      goto FreeMapInfo;
+    }
+    MapInfo->AllocAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress;
+    if (Operation == EfiPciIoOperationBusMasterRead) {
+      gBS->CopyMem (AllocAddress, HostAddress, *NumberOfBytes);
+    }
+    *DeviceAddress = MapInfo->AllocAddress;
+  } else {
+    MapInfo->AllocAddress = 0;
+    *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
+
+    //
+    // We are not using a bounce buffer: the mapping is sufficiently
+    // aligned to allow us to simply flush the caches. Note that cleaning
+    // the caches is necessary for both data directions:
+    // - for bus master read, we want the latest data to be present
+    //   in main memory
+    // - for bus master write, we don't want any stale dirty cachelines that
+    //   may be written back unexpectedly, and clobber the data written to
+    //   main memory by the device.
+    //
+    gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
+            *NumberOfBytes, EfiCpuFlushTypeWriteBack);
+  }
+
+  *Mapping = MapInfo;
+  return EFI_SUCCESS;
+
+FreeMapInfo:
+  FreePool (MapInfo);
+
+  return Status;
+}
+
+STATIC
+EFI_STATUS
+NonCoherentPciIoUnmap (
+  IN  EFI_PCI_IO_PROTOCOL          *This,
+  IN  VOID                         *Mapping
+  )
+{
+  PLATFORM_PCI_IO_MAP_INFO  *MapInfo;
+
+  if (Mapping == NULL) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  MapInfo = Mapping;
+  if (MapInfo->AllocAddress != 0) {
+    //
+    // We are using a bounce buffer: copy back the data if necessary,
+    // and free the buffer.
+    //
+    if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
+      gBS->CopyMem (MapInfo->HostAddress, (VOID *)MapInfo->AllocAddress,
+             MapInfo->NumberOfBytes);
+    }
+    NonCoherentPciIoFreeBuffer (This,
+      EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
+      (VOID *)(UINTN)MapInfo->AllocAddress);
+  } else {
+    //
+    // We are *not* using a bounce buffer: if this is a bus master write,
+    // we have to invalidate the caches so the CPU will see the uncached
+    // data written by the device.
+    //
+    if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
+      gCpu->FlushDataCache (gCpu,
+              (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,
+              MapInfo->NumberOfBytes, EfiCpuFlushTypeInvalidate);
+    }
+  }
+  FreePool (MapInfo);
+  return EFI_SUCCESS;
+}
 
 STATIC
 EFI_STATUS
@@ -646,4 +843,11 @@ InitializePciIoProtocol (
 
   // Copy protocol structure
   CopyMem(&PlatformPciIoDev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);
+
+  if (PlatformPciIoDev->PlatformPciIo->DmaType == PlatformPciIoDmaNonCoherent) {
+    PlatformPciIoDev->PciIo.AllocateBuffer = NonCoherentPciIoAllocateBuffer;
+    PlatformPciIoDev->PciIo.FreeBuffer = NonCoherentPciIoFreeBuffer;
+    PlatformPciIoDev->PciIo.Map = NonCoherentPciIoMap;
+    PlatformPciIoDev->PciIo.Unmap = NonCoherentPciIoUnmap;
+  }
 }
diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h
index 8fd8dc5e4a11..b7b792b85ae4 100644
--- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h
+++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h
@@ -12,6 +12,8 @@
 
 **/
 
+#include <PiDxe.h>
+
 #include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
 #include <Library/MemoryAllocationLib.h>
@@ -20,6 +22,7 @@
 
 #include <IndustryStandard/Pci.h>
 
+#include <Protocol/Cpu.h>
 #include <Protocol/PciIo.h>
 #include <Protocol/PlatformPciIo.h>
 
@@ -28,6 +31,8 @@
 #define PLATFORM_PCI_IO_DEV_FROM_PCI_IO(PciIoPointer) \
           CR (PciIoPointer, PLATFORM_PCI_IO_DEV, PciIo, PLATFORM_PCI_IO_SIG)
 
+extern EFI_CPU_ARCH_PROTOCOL      *gCpu;
+
 typedef struct {
   UINT32                  Signature;
   //
diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c
index 7f3306e7e891..fa4719686a6d 100644
--- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c
+++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c
@@ -17,6 +17,8 @@
 #include <Protocol/ComponentName.h>
 #include <Protocol/DriverBinding.h>
 
+EFI_CPU_ARCH_PROTOCOL      *gCpu;
+
 //
 // Probe, start and stop functions of this driver, called by the DXE core for
 // specific devices.
@@ -60,13 +62,9 @@ PlatformPciIoDriverBindingSupported (
   case PlatformPciIoDeviceEhci:
   case PlatformPciIoDeviceXhci:
   case PlatformPciIoDeviceAhci:
-    //
-    // Restricted to DMA coherent for now
-    //
-    if (PlatformPciIo->DmaType == PlatformPciIoDmaCoherent) {
-      Status = EFI_SUCCESS;
-      break;
-    }
+    Status = EFI_SUCCESS;
+    break;
+
   default:
     Status = EFI_UNSUPPORTED;
   }
@@ -257,6 +255,11 @@ PlatformPciIoDxeEntryPoint (
   IN EFI_SYSTEM_TABLE *SystemTable
   )
 {
+  EFI_STATUS      Status;
+
+  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
+  ASSERT_EFI_ERROR(Status);
+
   return EfiLibInstallDriverBindingComponentName2 (
            ImageHandle,
            SystemTable,
diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf
index 2b0baf06732c..670dcc5a9ff2 100644
--- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf
+++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf
@@ -31,11 +31,13 @@ [Packages]
 [LibraryClasses]
   BaseMemoryLib
   DebugLib
+  DxeServicesTableLib
   MemoryAllocationLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
   UefiLib
 
 [Protocols]
+  gEfiCpuArchProtocolGuid         ## CONSUMES
   gEfiPciIoProtocolGuid           ## BY_START
   gPlatformPciIoProtocolGuid      ## TO_START
-- 
2.7.4



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH 0/5] EmbeddedPkg: generic support for reusing PCI drivers for platform devices
  2016-10-31 18:13 [PATCH 0/5] EmbeddedPkg: generic support for reusing PCI drivers for platform devices Ard Biesheuvel
                   ` (4 preceding siblings ...)
  2016-10-31 18:13 ` [PATCH 5/5] EmbeddedPkg/PlatformPciIoDxe: add support for non-coherent DMA Ard Biesheuvel
@ 2016-11-01 21:45 ` Leif Lindholm
  5 siblings, 0 replies; 26+ messages in thread
From: Leif Lindholm @ 2016-11-01 21:45 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: edk2-devel

On Mon, Oct 31, 2016 at 06:13:05PM +0000, Ard Biesheuvel wrote:
> After having reviewed PciEmulation.c #6, it is time to implement this in a
> more generic way, taking into account DMA limitations and DMA coherency.
> 
> So implement a new platform PCI I/O protocol, and a UEFI_DRIVER module that
> binds to those protocols to expose the PCI I/O abstraction that generic
> AHCI/XHCI etc drivers can talk to.
> 
> Tested with AHCI on QEMU.

So, a) I'm really happy to see this - it doesn't solve the
peripherally connected issue with how to provide an interface to
enable UEFI drivers for devices on non-discoverable buses, but it
suggests I've been wrong to see them as the same thing.

And if this means we never have to merge #6 at all, everybody wins.

But b) I'm currently jetlagged and at 2200m altitude, so prepare for
even more silly questions than usual.

> Ard Biesheuvel (5):
>   EmbeddedPkg: introduce platform PCI I/O protocol
>   EmbeddedPkg: introduce platform PCI I/O registration library
>   EmbeddedPkg: implement generic platform PCI I/O driver
>   ArmPkg/CpuDxe: set DmaBufferAlignment according to CWG
>   EmbeddedPkg/PlatformPciIoDxe: add support for non-coherent DMA
> 
>  ArmPkg/Drivers/CpuDxe/CpuDxe.c                                                                |   4 +-
>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c                                          | 853 ++++++++++++++++++++
>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h                                          |  72 ++
>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c                                       | 271 +++++++
>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf                                     |  43 +
>  EmbeddedPkg/EmbeddedPkg.dec                                                                   |   2 +
>  EmbeddedPkg/EmbeddedPkg.dsc                                                                   |   3 +
>  EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h                              |  46 ++
>  EmbeddedPkg/Include/Protocol/PlatformPciIo.h                                                  |  74 ++
>  EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c   | 115 +++
>  EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf |  34 +
>  11 files changed, 1516 insertions(+), 1 deletion(-)
>  create mode 100644 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c
>  create mode 100644 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h
>  create mode 100644 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c
>  create mode 100644 EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf
>  create mode 100644 EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h
>  create mode 100644 EmbeddedPkg/Include/Protocol/PlatformPciIo.h
>  create mode 100644 EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c
>  create mode 100644 EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf
> 
> -- 
> 2.7.4
> 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 1/5] EmbeddedPkg: introduce platform PCI I/O protocol
  2016-10-31 18:13 ` [PATCH 1/5] EmbeddedPkg: introduce platform PCI I/O protocol Ard Biesheuvel
@ 2016-11-01 21:54   ` Leif Lindholm
  2016-11-02 13:29     ` Ard Biesheuvel
  0 siblings, 1 reply; 26+ messages in thread
From: Leif Lindholm @ 2016-11-01 21:54 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: edk2-devel

On Mon, Oct 31, 2016 at 06:13:06PM +0000, Ard Biesheuvel wrote:
> Introduce a protocol that can be exposed by a platform for devices that
> can be driven by a PCI driver, (e.g., AHCI, XHCI), but do not live on a
> PCI bus. This used to be called 'PCI emulation' but given that we only
> emulate the PCI config space and nothing else, it tends to be a bit
> confusing so this introduces the term 'platform PCI I/O' instead.
> 
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  EmbeddedPkg/EmbeddedPkg.dec                  |  1 +
>  EmbeddedPkg/Include/Protocol/PlatformPciIo.h | 74 ++++++++++++++++++++

OK, so perhaps I should have commented on this already on 0/5, but I
think this belongs in MdeModulePkg. The closest thing to an "embedded"
user of this code is Juno.

>  2 files changed, 75 insertions(+)
> 
> diff --git a/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec
> index 2c2cf41103c2..84a6f4d01077 100644
> --- a/EmbeddedPkg/EmbeddedPkg.dec
> +++ b/EmbeddedPkg/EmbeddedPkg.dec
> @@ -69,6 +69,7 @@ [Protocols.common]
>    gAndroidFastbootPlatformProtocolGuid =  { 0x524685a0, 0x89a0, 0x11e3, {0x9d, 0x4d, 0xbf, 0xa9, 0xf6, 0xa4, 0x03, 0x08}}
>    gUsbDeviceProtocolGuid =  { 0x021bd2ca, 0x51d2, 0x11e3, {0x8e, 0x56, 0xb7, 0x54, 0x17, 0xc7,  0x0b, 0x44 }}
>    gPlatformGpioProtocolGuid = { 0x52ce9845, 0x5af4, 0x43e2, {0xba, 0xfd, 0x23, 0x08, 0x12, 0x54, 0x7a, 0xc2 }}
> +  gPlatformPciIoProtocolGuid = { 0x0d51905b, 0xb77e, 0x452a, {0xa2, 0xc0, 0xec, 0xa0, 0xcc, 0x8d, 0x51, 0x4a }}
>  
>  [PcdsFeatureFlag.common]
>    gEmbeddedTokenSpaceGuid.PcdEmbeddedMacBoot|FALSE|BOOLEAN|0x00000001
> diff --git a/EmbeddedPkg/Include/Protocol/PlatformPciIo.h b/EmbeddedPkg/Include/Protocol/PlatformPciIo.h
> new file mode 100644
> index 000000000000..a7bd584049ac
> --- /dev/null
> +++ b/EmbeddedPkg/Include/Protocol/PlatformPciIo.h
> @@ -0,0 +1,74 @@
> +/** @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.
> +
> +**/
> +
> +#ifndef __PLATFORM_PCI_IO_H__
> +#define __PLATFORM_PCI_IO_H__
> +
> +#define PLATFORM_PCI_IO_PROTOCOL_GUID \
> +  { 0x0d51905b, 0xb77e, 0x452a, {0xa2, 0xc0, 0xec, 0xa0, 0xcc, 0x8d, 0x51, 0x4a } }
> +
> +//
> +// Protocol interface structure
> +//
> +typedef struct _PLATFORM_PCI_IO PLATFORM_PCI_IO;
> +
> +//
> +// Data Types
> +//
> +typedef enum {
> +  PlatformPciIoDeviceOhci,
> +  PlatformPciIoDeviceUhci,
> +  PlatformPciIoDeviceEhci,
> +  PlatformPciIoDeviceXhci,
> +  PlatformPciIoDeviceAhci,

SdMmc and Ufs?

> +  PlatformPciIoDeviceMax,
> +} PLATFORM_PCI_IO_DEVICE_TYPE;
> +
> +typedef enum {
> +  PlatformPciIoDmaCoherent,
> +  PlatformPciIoDmaNonCoherent,
> +  PlatformPciIoDmaMax,
> +} PLATFORM_PCI_IO_DMA_TYPE;
> +
> +//
> +// Function Prototypes
> +//
> +typedef
> +EFI_STATUS
> +(EFIAPI *PLATFORM_PCI_IO_INIT) (
> +  IN  PLATFORM_PCI_IO     *This
> +  );
> +
> +struct _PLATFORM_PCI_IO {
> +  //
> +  // The MMIO address of the device
> +  //
> +  EFI_PHYSICAL_ADDRESS          BaseAddress;
> +  //
> +  // The type of device
> +  //
> +  PLATFORM_PCI_IO_DEVICE_TYPE   DeviceType;
> +  //
> +  // Whether this device is DMA coherent
> +  //
> +  PLATFORM_PCI_IO_DMA_TYPE      DmaType;
> +  //
> +  // Initialization function for the device
> +  //
> +  PLATFORM_PCI_IO_INIT          Initialize;
> +};
> +
> +extern EFI_GUID gPlatformPciIoProtocolGuid;
> +
> +#endif
> -- 
> 2.7.4
> 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/5] EmbeddedPkg: introduce platform PCI I/O registration library
  2016-10-31 18:13 ` [PATCH 2/5] EmbeddedPkg: introduce platform PCI I/O registration library Ard Biesheuvel
@ 2016-11-01 21:57   ` Leif Lindholm
  2016-11-02 13:30     ` Ard Biesheuvel
  0 siblings, 1 reply; 26+ messages in thread
From: Leif Lindholm @ 2016-11-01 21:57 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: edk2-devel

On Mon, Oct 31, 2016 at 06:13:07PM +0000, Ard Biesheuvel wrote:
> This introduces the PlatformPciIoDeviceRegistrationLib library class and
> a default implementation to help platforms expose platform devices that
> may be driven by a PCI driver.
> 
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  EmbeddedPkg/EmbeddedPkg.dec                                                                   |   1 +
>  EmbeddedPkg/EmbeddedPkg.dsc                                                                   |   2 +
>  EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h                              |  46 ++++++++
>  EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c   | 115 ++++++++++++++++++++
>  EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf |  34 ++++++
>  5 files changed, 198 insertions(+)
> 
> diff --git a/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec
> index 84a6f4d01077..226036858880 100644
> --- a/EmbeddedPkg/EmbeddedPkg.dec
> +++ b/EmbeddedPkg/EmbeddedPkg.dec
> @@ -44,6 +44,7 @@ [LibraryClasses.common]
>    EblNetworkLib|Include/Library/EblNetworkLib.h
>    GdbSerialLib|Include/Library/GdbSerialLib.h
>    DebugAgentTimerLib|Include/Library/DebugAgentTimerLib.h
> +  PlatformPciIoDeviceRegistrationLib|Include/Library/PlatformPciIoDeviceRegistrationLib.h
>  
>  
>  [Guids.common]
> diff --git a/EmbeddedPkg/EmbeddedPkg.dsc b/EmbeddedPkg/EmbeddedPkg.dsc
> index eb7af800f0b2..d47c836379c9 100644
> --- a/EmbeddedPkg/EmbeddedPkg.dsc
> +++ b/EmbeddedPkg/EmbeddedPkg.dsc
> @@ -290,5 +290,7 @@ [Components.common]
>    EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf
>    EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf
>  
> +  EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf
> +
>  [Components.IA32, Components.X64, Components.IPF, Components.ARM]
>    EmbeddedPkg/GdbStub/GdbStub.inf
> diff --git a/EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h b/EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h
> new file mode 100644
> index 000000000000..07f163abc701
> --- /dev/null
> +++ b/EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h
> @@ -0,0 +1,46 @@
> +/** @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.
> +
> +**/
> +
> +#ifndef __PLATFORM_PCI_IO_DEVICE_REGISTRATION_LIB_H__
> +#define __PLATFORM_PCI_IO_DEVICE_REGISTRATION_LIB_H__
> +
> +#include <Protocol/PlatformPciIo.h>
> +
> +/**
> +  Register a platform device for PCI I/O protocol emulation
> +
> +  @param[in]      BaseAddress     The MMIO base address of the platform device
> +  @param[in]      DeviceType      The type of platform device
> +  @param[in]      DmaType         Whether the device is DMA coherent
> +  @param[in]      InitFunc        Initialization routine to be invoked when the
> +                                  device is enabled
> +  @param[in,out]  Handle          The handle onto which to install the platform
> +                                  PCI I/O protocol has been installed.
> +                                  If Handle is NULL or *Handle is NULL, a new
> +                                  handle will be allocated.
> +
> +  @retval EFI_SUCCESS             The registration succeeded.
> +  @retval other                   The registration failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PlatformPciIoRegisterDevice (
> +  IN      EFI_PHYSICAL_ADDRESS          BaseAddress,
> +  IN      PLATFORM_PCI_IO_DEVICE_TYPE   DeviceType,
> +  IN      PLATFORM_PCI_IO_DMA_TYPE      DmaType,
> +  IN      PLATFORM_PCI_IO_INIT          InitFunc,
> +  IN OUT  EFI_HANDLE                    *Handle OPTIONAL
> +  );
> +
> +#endif
> diff --git a/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c b/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c
> new file mode 100644
> index 000000000000..1ce5abb137df
> --- /dev/null
> +++ b/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c
> @@ -0,0 +1,115 @@
> +/** @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/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PlatformPciIoDeviceRegistrationLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +
> +#include <Protocol/DevicePath.h>
> +#include <Protocol/PlatformPciIo.h>
> +
> +#pragma pack (1)
> +typedef struct {
> +  VENDOR_DEVICE_PATH                  Vendor;
> +  UINT64                              BaseAddress;
> +  EFI_DEVICE_PATH_PROTOCOL            End;
> +} PLATFORM_PCI_IO_DEVICE_PATH;
> +
> +#pragma pack ()
> +
> +/**
> +  Register a platform device for PCI I/O protocol emulation
> +
> +  @param[in]      BaseAddress     The MMIO base address of the platform device
> +  @param[in]      DeviceType      The type of platform device
> +  @param[in]      DmaType         Whether the device is DMA coherent
> +  @param[in]      InitFunc        Initialization routine to be invoked when the
> +                                  device is enabled
> +  @param[in,out]  Handle          The handle onto which to install the platform
> +                                  PCI I/O protocol has been installed.
> +                                  If Handle is NULL or *Handle is NULL, a new
> +                                  handle will be allocated.
> +
> +  @retval EFI_SUCCESS             The registration succeeded.
> +  @retval other                   The registration failed.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PlatformPciIoRegisterDevice (
> +  IN      EFI_PHYSICAL_ADDRESS          BaseAddress,
> +  IN      PLATFORM_PCI_IO_DEVICE_TYPE   DeviceType,
> +  IN      PLATFORM_PCI_IO_DMA_TYPE      DmaType,
> +  IN      PLATFORM_PCI_IO_INIT          InitFunc,
> +  IN OUT  EFI_HANDLE                    *Handle
> +  )
> +{
> +  PLATFORM_PCI_IO               *Device;
> +  PLATFORM_PCI_IO_DEVICE_PATH   *DevicePath;
> +  EFI_HANDLE                    LocalHandle;
> +  EFI_STATUS                    Status;
> +
> +  if (DeviceType >= PlatformPciIoDeviceMax || DmaType >= PlatformPciIoDmaMax) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Handle == NULL) {
> +    Handle = &LocalHandle;
> +    LocalHandle = NULL;
> +  }
> +
> +  Device = (PLATFORM_PCI_IO *)AllocateZeroPool (sizeof *Device);
> +  if (Device == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Device->BaseAddress = BaseAddress;
> +  Device->DeviceType = DeviceType;
> +  Device->DmaType = DmaType;
> +  Device->Initialize = InitFunc;
> +
> +  DevicePath = (PLATFORM_PCI_IO_DEVICE_PATH *)CreateDeviceNode (
> +                                                HARDWARE_DEVICE_PATH,
> +                                                HW_VENDOR_DP,
> +                                                sizeof (*DevicePath));
> +  if (DevicePath == NULL) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto FreeDevice;
> +  }
> +
> +  CopyGuid (&DevicePath->Vendor.Guid, &gPlatformPciIoProtocolGuid);
> +  DevicePath->BaseAddress = BaseAddress;
> +
> +  SetDevicePathNodeLength (&DevicePath->Vendor,
> +    sizeof (*DevicePath) - sizeof (DevicePath->End));
> +  SetDevicePathEndNode (&DevicePath->End);
> +
> +  Status = gBS->InstallMultipleProtocolInterfaces (Handle,
> +                  &gPlatformPciIoProtocolGuid, Device,
> +                  &gEfiDevicePathProtocolGuid, DevicePath);
> +  if (EFI_ERROR (Status)) {
> +    goto FreeDevicePath;
> +  }
> +  return EFI_SUCCESS;
> +
> +FreeDevicePath:
> +  FreePool (DevicePath);
> +
> +FreeDevice:
> +  FreePool (Device);
> +
> +  return Status;
> +}
> diff --git a/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf b/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf
> new file mode 100644
> index 000000000000..282db3ab59ab
> --- /dev/null
> +++ b/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf
> @@ -0,0 +1,34 @@
> +# @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.
> +#
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010017

Not 0019?

> +  BASE_NAME                      = PlatformPciIoDeviceRegistrationLib
> +  FILE_GUID                      = 8802ae41-8184-49cb-8aec-62627cd7ceb4
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = PlatformPciIoDeviceRegistrationLib
> +
> +[Sources]
> +  PlatformPciIoDeviceRegistrationLib.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +
> +[LibraryClasses]
> +  DebugLib
> +  DevicePathLib
> +  UefiBootServicesTableLib
> +
> +[Protocols]
> +  gPlatformPciIoProtocolGuid
> -- 
> 2.7.4
> 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 3/5] EmbeddedPkg: implement generic platform PCI I/O driver
  2016-10-31 18:13 ` [PATCH 3/5] EmbeddedPkg: implement generic platform PCI I/O driver Ard Biesheuvel
@ 2016-11-01 22:22   ` Leif Lindholm
  2016-11-02 13:39     ` Ard Biesheuvel
  0 siblings, 1 reply; 26+ messages in thread
From: Leif Lindholm @ 2016-11-01 22:22 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: edk2-devel

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")

> 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.)

> 
> 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.biesheuvel@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)?

> +
> +  //
> +  // 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?

> +      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?

> +    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?

> +  //
> +  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?

> +  }
> +
> +  *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?

> +
> +  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?

> +    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?

> +  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?

> +    //
> +    // 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.

> +  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.

> +
> +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
> 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 4/5] ArmPkg/CpuDxe: set DmaBufferAlignment according to CWG
  2016-10-31 18:13 ` [PATCH 4/5] ArmPkg/CpuDxe: set DmaBufferAlignment according to CWG Ard Biesheuvel
@ 2016-11-01 22:32   ` Leif Lindholm
  2016-11-02 13:40     ` Ard Biesheuvel
  0 siblings, 1 reply; 26+ messages in thread
From: Leif Lindholm @ 2016-11-01 22:32 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: edk2-devel

On Mon, Oct 31, 2016 at 06:13:09PM +0000, Ard Biesheuvel wrote:
> The DmaBufferAlignment currently defaults to 4, which is dangerously
> small and may result in lost data on platform that perform non-coherent
> DMA. So instead, take the CWG value from the cache info registers.
> 
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  ArmPkg/Drivers/CpuDxe/CpuDxe.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
> index d089cb2d119f..ddc64fd255a0 100644
> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c
> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
> @@ -225,7 +225,7 @@ EFI_CPU_ARCH_PROTOCOL mCpu = {
>    CpuGetTimerValue,
>    CpuSetMemoryAttributes,
>    0,          // NumberOfTimers
> -  4,          // DmaBufferAlignment
> +  2048,       // DmaBufferAlignment
>  };
>  
>  EFI_STATUS
> @@ -239,6 +239,8 @@ CpuDxeInitialize (
>  
>    InitializeExceptions (&mCpu);
>  
> +  mCpu.DmaBufferAlignment = ArmCacheWritebackGranule ();
> +

Could we hide the internal structure of mCpu here by moving this to a
helper function and calling
  InitializeDma (&mCpu);
(or something)?

>    Status = gBS->InstallMultipleProtocolInterfaces (
>                  &mCpuHandle,
>                  &gEfiCpuArchProtocolGuid,           &mCpu,
> -- 
> 2.7.4
> 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 5/5] EmbeddedPkg/PlatformPciIoDxe: add support for non-coherent DMA
  2016-10-31 18:13 ` [PATCH 5/5] EmbeddedPkg/PlatformPciIoDxe: add support for non-coherent DMA Ard Biesheuvel
@ 2016-11-01 22:43   ` Leif Lindholm
  2016-11-02 13:43     ` Ard Biesheuvel
  0 siblings, 1 reply; 26+ messages in thread
From: Leif Lindholm @ 2016-11-01 22:43 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: edk2-devel

On Mon, Oct 31, 2016 at 06:13:10PM +0000, Ard Biesheuvel wrote:
> Add support for bounce buffering using uncached mappings when DMA mappings
> are not aligned to the CPU's DMA buffer alignment.

This description does not appear to match the subject line?
And the contents of the patch seems to do both.

Anyway, I'll pass on a proper technical review until my head is a bit
clearer, but a few comments/questions below.

> 
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c      | 204 ++++++++++++++++++++
>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h      |   5 +
>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c   |  17 +-
>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf |   2 +
>  4 files changed, 221 insertions(+), 7 deletions(-)
> 
> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c
> index 97ed19353347..658d096c73c1 100644
> --- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c
> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c
> @@ -15,6 +15,8 @@
>  
>  #include "PlatformPciIo.h"
>  
> +#include <Library/DxeServicesTableLib.h>
> +
>  #include <Protocol/PciRootBridgeIo.h>
>  
>  typedef struct {
> @@ -454,6 +456,201 @@ CoherentPciIoFreeBuffer (
>    return EFI_SUCCESS;
>  }
>  
> +STATIC
> +EFI_STATUS
> +NonCoherentPciIoFreeBuffer (
> +  IN  EFI_PCI_IO_PROTOCOL         *This,
> +  IN  UINTN                       Pages,
> +  IN  VOID                        *HostAddress
> +  )
> +{
> +  EFI_STATUS        Status;
> +
> +  Status = gDS->SetMemorySpaceAttributes (
> +                  (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
> +                  EFI_PAGES_TO_SIZE (Pages),
> +                  EFI_MEMORY_WB);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  FreePages (HostAddress, Pages);
> +  return EFI_SUCCESS;
> +}
> +
> +STATIC
> +EFI_STATUS
> +NonCoherentPciIoAllocateBuffer (
> +  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
> +  )
> +{
> +  EFI_STATUS        Status;
> +
> +  Status = CoherentPciIoAllocateBuffer (This, Type, MemoryType, Pages,
> +             HostAddress, Attributes);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Status = gDS->SetMemorySpaceAttributes (
> +                  (EFI_PHYSICAL_ADDRESS)(UINTN)*HostAddress,
> +                  EFI_PAGES_TO_SIZE (Pages),
> +                  EFI_MEMORY_WC);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Status = gCpu->FlushDataCache (
> +                   gCpu,
> +                   (EFI_PHYSICAL_ADDRESS)(UINTN)*HostAddress,
> +                   EFI_PAGES_TO_SIZE (Pages),
> +                   EfiCpuFlushTypeInvalidate);
> +  if (EFI_ERROR (Status)) {
> +    NonCoherentPciIoFreeBuffer (This, Pages, *HostAddress);
> +  }
> +  return Status;
> +}
> +
> +STATIC
> +EFI_STATUS
> +NonCoherentPciIoMap (
> +  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;
> +  UINTN                             AlignMask;
> +  VOID                              *AllocAddress;
> +  EFI_GCD_MEMORY_SPACE_DESCRIPTOR   GcdDescriptor;
> +  BOOLEAN                           UncachedMapping;
> +
> +  MapInfo = (PLATFORM_PCI_IO_MAP_INFO *)AllocatePool (sizeof *MapInfo);
> +  if (MapInfo == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  MapInfo->HostAddress = HostAddress;
> +  MapInfo->Operation = Operation;
> +  MapInfo->NumberOfBytes = *NumberOfBytes;
> +
> +  //
> +  // Bounce buffering is not possible for consistent mappings, so
> +  // check we are mapping a cached buffer for consistent DMA
> +  //
> +  if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
> +    Status = gDS->GetMemorySpaceDescriptor (
> +                    (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
> +                    &GcdDescriptor);
> +    if (!EFI_ERROR (Status)) {
> +      UncachedMapping = (GcdDescriptor.Attributes & EFI_MEMORY_WC) != 0;
> +    } else {
> +      UncachedMapping = FALSE;
> +    }
> +  }
> +
> +  //
> +  // If this device does not support 64-bit DMA addressing, we need to allocate
> +  // a bounce buffer and copy over the data if HostAddress >= 4 GB. We also need
> +  // to allocate a bounce buffer if the mapping is not aligned to the CPU's
> +  // DMA buffer alignment.
> +  //
> +  Dev = PLATFORM_PCI_IO_DEV_FROM_PCI_IO(This);
> +  AlignMask = gCpu->DmaBufferAlignment - 1;
> +  if (((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&
> +       (UINTN) HostAddress >= SIZE_4GB) ||
> +       ((((UINTN) HostAddress || *NumberOfBytes) & AlignMask) != 0 &&
> +        !UncachedMapping)) {
> +
> +    Status = NonCoherentPciIoAllocateBuffer (This, AllocateAnyPages,
> +               EfiBootServicesData, EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
> +               &AllocAddress, 0);
> +    if (EFI_ERROR (Status)) {
> +      goto FreeMapInfo;
> +    }
> +    MapInfo->AllocAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress;
> +    if (Operation == EfiPciIoOperationBusMasterRead) {
> +      gBS->CopyMem (AllocAddress, HostAddress, *NumberOfBytes);
> +    }
> +    *DeviceAddress = MapInfo->AllocAddress;
> +  } else {
> +    MapInfo->AllocAddress = 0;
> +    *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
> +
> +    //
> +    // We are not using a bounce buffer: the mapping is sufficiently
> +    // aligned to allow us to simply flush the caches. Note that cleaning
> +    // the caches is necessary for both data directions:
> +    // - for bus master read, we want the latest data to be present
> +    //   in main memory
> +    // - for bus master write, we don't want any stale dirty cachelines that
> +    //   may be written back unexpectedly, and clobber the data written to
> +    //   main memory by the device.
> +    //
> +    gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
> +            *NumberOfBytes, EfiCpuFlushTypeWriteBack);
> +  }
> +
> +  *Mapping = MapInfo;
> +  return EFI_SUCCESS;
> +
> +FreeMapInfo:
> +  FreePool (MapInfo);
> +
> +  return Status;
> +}
> +
> +STATIC
> +EFI_STATUS
> +NonCoherentPciIoUnmap (
> +  IN  EFI_PCI_IO_PROTOCOL          *This,
> +  IN  VOID                         *Mapping
> +  )
> +{
> +  PLATFORM_PCI_IO_MAP_INFO  *MapInfo;
> +
> +  if (Mapping == NULL) {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  MapInfo = Mapping;
> +  if (MapInfo->AllocAddress != 0) {
> +    //
> +    // We are using a bounce buffer: copy back the data if necessary,
> +    // and free the buffer.
> +    //
> +    if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
> +      gBS->CopyMem (MapInfo->HostAddress, (VOID *)MapInfo->AllocAddress,
> +             MapInfo->NumberOfBytes);
> +    }
> +    NonCoherentPciIoFreeBuffer (This,
> +      EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
> +      (VOID *)(UINTN)MapInfo->AllocAddress);
> +  } else {
> +    //
> +    // We are *not* using a bounce buffer: if this is a bus master write,
> +    // we have to invalidate the caches so the CPU will see the uncached
> +    // data written by the device.
> +    //
> +    if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
> +      gCpu->FlushDataCache (gCpu,
> +              (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,
> +              MapInfo->NumberOfBytes, EfiCpuFlushTypeInvalidate);
> +    }
> +  }
> +  FreePool (MapInfo);
> +  return EFI_SUCCESS;
> +}
>  
>  STATIC
>  EFI_STATUS
> @@ -646,4 +843,11 @@ InitializePciIoProtocol (
>  
>    // Copy protocol structure
>    CopyMem(&PlatformPciIoDev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);
> +
> +  if (PlatformPciIoDev->PlatformPciIo->DmaType == PlatformPciIoDmaNonCoherent) {
> +    PlatformPciIoDev->PciIo.AllocateBuffer = NonCoherentPciIoAllocateBuffer;
> +    PlatformPciIoDev->PciIo.FreeBuffer = NonCoherentPciIoFreeBuffer;
> +    PlatformPciIoDev->PciIo.Map = NonCoherentPciIoMap;
> +    PlatformPciIoDev->PciIo.Unmap = NonCoherentPciIoUnmap;
> +  }
>  }
> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h
> index 8fd8dc5e4a11..b7b792b85ae4 100644
> --- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h
> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h
> @@ -12,6 +12,8 @@
>  
>  **/
>  
> +#include <PiDxe.h>
> +
>  #include <Library/BaseMemoryLib.h>
>  #include <Library/DebugLib.h>
>  #include <Library/MemoryAllocationLib.h>
> @@ -20,6 +22,7 @@
>  
>  #include <IndustryStandard/Pci.h>
>  
> +#include <Protocol/Cpu.h>
>  #include <Protocol/PciIo.h>
>  #include <Protocol/PlatformPciIo.h>
>  
> @@ -28,6 +31,8 @@
>  #define PLATFORM_PCI_IO_DEV_FROM_PCI_IO(PciIoPointer) \
>            CR (PciIoPointer, PLATFORM_PCI_IO_DEV, PciIo, PLATFORM_PCI_IO_SIG)
>  
> +extern EFI_CPU_ARCH_PROTOCOL      *gCpu;
> +
>  typedef struct {
>    UINT32                  Signature;
>    //
> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c
> index 7f3306e7e891..fa4719686a6d 100644
> --- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c
> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c
> @@ -17,6 +17,8 @@
>  #include <Protocol/ComponentName.h>
>  #include <Protocol/DriverBinding.h>
>  
> +EFI_CPU_ARCH_PROTOCOL      *gCpu;
> +

Should this not really be pulled in from some header file?

Maybe including it straight from DxeMain.h isn't entirely kosher even
if this code does end up in MdeModulePkg, but surely the declaration
there should also be pulled in from somewhere under UefiCpuPkg/Include?

>  //
>  // Probe, start and stop functions of this driver, called by the DXE core for
>  // specific devices.
> @@ -60,13 +62,9 @@ PlatformPciIoDriverBindingSupported (
>    case PlatformPciIoDeviceEhci:
>    case PlatformPciIoDeviceXhci:
>    case PlatformPciIoDeviceAhci:
> -    //
> -    // Restricted to DMA coherent for now
> -    //
> -    if (PlatformPciIo->DmaType == PlatformPciIoDmaCoherent) {
> -      Status = EFI_SUCCESS;
> -      break;
> -    }
> +    Status = EFI_SUCCESS;
> +    break;
> +
>    default:
>      Status = EFI_UNSUPPORTED;
>    }
> @@ -257,6 +255,11 @@ PlatformPciIoDxeEntryPoint (
>    IN EFI_SYSTEM_TABLE *SystemTable
>    )
>  {
> +  EFI_STATUS      Status;
> +
> +  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
> +  ASSERT_EFI_ERROR(Status);
> +
>    return EfiLibInstallDriverBindingComponentName2 (
>             ImageHandle,
>             SystemTable,
> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf
> index 2b0baf06732c..670dcc5a9ff2 100644
> --- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf
> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf
> @@ -31,11 +31,13 @@ [Packages]
>  [LibraryClasses]
>    BaseMemoryLib
>    DebugLib
> +  DxeServicesTableLib
>    MemoryAllocationLib
>    UefiBootServicesTableLib
>    UefiDriverEntryPoint
>    UefiLib
>  
>  [Protocols]
> +  gEfiCpuArchProtocolGuid         ## CONSUMES
>    gEfiPciIoProtocolGuid           ## BY_START
>    gPlatformPciIoProtocolGuid      ## TO_START
> -- 
> 2.7.4
> 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 1/5] EmbeddedPkg: introduce platform PCI I/O protocol
  2016-11-01 21:54   ` Leif Lindholm
@ 2016-11-02 13:29     ` Ard Biesheuvel
  2016-11-02 15:42       ` Leif Lindholm
  0 siblings, 1 reply; 26+ messages in thread
From: Ard Biesheuvel @ 2016-11-02 13:29 UTC (permalink / raw)
  To: Leif Lindholm; +Cc: edk2-devel-01

On 1 November 2016 at 21:54, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Mon, Oct 31, 2016 at 06:13:06PM +0000, Ard Biesheuvel wrote:
>> Introduce a protocol that can be exposed by a platform for devices that
>> can be driven by a PCI driver, (e.g., AHCI, XHCI), but do not live on a
>> PCI bus. This used to be called 'PCI emulation' but given that we only
>> emulate the PCI config space and nothing else, it tends to be a bit
>> confusing so this introduces the term 'platform PCI I/O' instead.
>>
>> Contributed-under: TianoCore Contribution Agreement 1.0
>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> ---
>>  EmbeddedPkg/EmbeddedPkg.dec                  |  1 +
>>  EmbeddedPkg/Include/Protocol/PlatformPciIo.h | 74 ++++++++++++++++++++
>
> OK, so perhaps I should have commented on this already on 0/5, but I
> think this belongs in MdeModulePkg. The closest thing to an "embedded"
> user of this code is Juno.
>
>>  2 files changed, 75 insertions(+)
>>
>> diff --git a/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec
>> index 2c2cf41103c2..84a6f4d01077 100644
>> --- a/EmbeddedPkg/EmbeddedPkg.dec
>> +++ b/EmbeddedPkg/EmbeddedPkg.dec
>> @@ -69,6 +69,7 @@ [Protocols.common]
>>    gAndroidFastbootPlatformProtocolGuid =  { 0x524685a0, 0x89a0, 0x11e3, {0x9d, 0x4d, 0xbf, 0xa9, 0xf6, 0xa4, 0x03, 0x08}}
>>    gUsbDeviceProtocolGuid =  { 0x021bd2ca, 0x51d2, 0x11e3, {0x8e, 0x56, 0xb7, 0x54, 0x17, 0xc7,  0x0b, 0x44 }}
>>    gPlatformGpioProtocolGuid = { 0x52ce9845, 0x5af4, 0x43e2, {0xba, 0xfd, 0x23, 0x08, 0x12, 0x54, 0x7a, 0xc2 }}
>> +  gPlatformPciIoProtocolGuid = { 0x0d51905b, 0xb77e, 0x452a, {0xa2, 0xc0, 0xec, 0xa0, 0xcc, 0x8d, 0x51, 0x4a }}
>>
>>  [PcdsFeatureFlag.common]
>>    gEmbeddedTokenSpaceGuid.PcdEmbeddedMacBoot|FALSE|BOOLEAN|0x00000001
>> diff --git a/EmbeddedPkg/Include/Protocol/PlatformPciIo.h b/EmbeddedPkg/Include/Protocol/PlatformPciIo.h
>> new file mode 100644
>> index 000000000000..a7bd584049ac
>> --- /dev/null
>> +++ b/EmbeddedPkg/Include/Protocol/PlatformPciIo.h
>> @@ -0,0 +1,74 @@
>> +/** @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.
>> +
>> +**/
>> +
>> +#ifndef __PLATFORM_PCI_IO_H__
>> +#define __PLATFORM_PCI_IO_H__
>> +
>> +#define PLATFORM_PCI_IO_PROTOCOL_GUID \
>> +  { 0x0d51905b, 0xb77e, 0x452a, {0xa2, 0xc0, 0xec, 0xa0, 0xcc, 0x8d, 0x51, 0x4a } }
>> +
>> +//
>> +// Protocol interface structure
>> +//
>> +typedef struct _PLATFORM_PCI_IO PLATFORM_PCI_IO;
>> +
>> +//
>> +// Data Types
>> +//
>> +typedef enum {
>> +  PlatformPciIoDeviceOhci,
>> +  PlatformPciIoDeviceUhci,
>> +  PlatformPciIoDeviceEhci,
>> +  PlatformPciIoDeviceXhci,
>> +  PlatformPciIoDeviceAhci,
>
> SdMmc and Ufs?
>

Indeed. I have added both: SDHCI works in QEMU but I can't really test UFS.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/5] EmbeddedPkg: introduce platform PCI I/O registration library
  2016-11-01 21:57   ` Leif Lindholm
@ 2016-11-02 13:30     ` Ard Biesheuvel
  2016-11-02 15:39       ` Leif Lindholm
  2016-11-07 14:54       ` Evan Lloyd
  0 siblings, 2 replies; 26+ messages in thread
From: Ard Biesheuvel @ 2016-11-02 13:30 UTC (permalink / raw)
  To: Leif Lindholm; +Cc: edk2-devel-01

On 1 November 2016 at 21:57, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Mon, Oct 31, 2016 at 06:13:07PM +0000, Ard Biesheuvel wrote:
>> This introduces the PlatformPciIoDeviceRegistrationLib library class and
>> a default implementation to help platforms expose platform devices that
>> may be driven by a PCI driver.
>>
>> Contributed-under: TianoCore Contribution Agreement 1.0
>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> ---
>>  EmbeddedPkg/EmbeddedPkg.dec                                                                   |   1 +
>>  EmbeddedPkg/EmbeddedPkg.dsc                                                                   |   2 +
>>  EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h                              |  46 ++++++++
>>  EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c   | 115 ++++++++++++++++++++
>>  EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf |  34 ++++++
>>  5 files changed, 198 insertions(+)
>>
>> diff --git a/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec
>> index 84a6f4d01077..226036858880 100644
>> --- a/EmbeddedPkg/EmbeddedPkg.dec
>> +++ b/EmbeddedPkg/EmbeddedPkg.dec
>> @@ -44,6 +44,7 @@ [LibraryClasses.common]
>>    EblNetworkLib|Include/Library/EblNetworkLib.h
>>    GdbSerialLib|Include/Library/GdbSerialLib.h
>>    DebugAgentTimerLib|Include/Library/DebugAgentTimerLib.h
>> +  PlatformPciIoDeviceRegistrationLib|Include/Library/PlatformPciIoDeviceRegistrationLib.h
>>
>>
>>  [Guids.common]
>> diff --git a/EmbeddedPkg/EmbeddedPkg.dsc b/EmbeddedPkg/EmbeddedPkg.dsc
>> index eb7af800f0b2..d47c836379c9 100644
>> --- a/EmbeddedPkg/EmbeddedPkg.dsc
>> +++ b/EmbeddedPkg/EmbeddedPkg.dsc
>> @@ -290,5 +290,7 @@ [Components.common]
>>    EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf
>>    EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf
>>
>> +  EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf
>> +
>>  [Components.IA32, Components.X64, Components.IPF, Components.ARM]
>>    EmbeddedPkg/GdbStub/GdbStub.inf
>> diff --git a/EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h b/EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h
>> new file mode 100644
>> index 000000000000..07f163abc701
>> --- /dev/null
>> +++ b/EmbeddedPkg/Include/Library/PlatformPciIoDeviceRegistrationLib.h
>> @@ -0,0 +1,46 @@
>> +/** @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.
>> +
>> +**/
>> +
>> +#ifndef __PLATFORM_PCI_IO_DEVICE_REGISTRATION_LIB_H__
>> +#define __PLATFORM_PCI_IO_DEVICE_REGISTRATION_LIB_H__
>> +
>> +#include <Protocol/PlatformPciIo.h>
>> +
>> +/**
>> +  Register a platform device for PCI I/O protocol emulation
>> +
>> +  @param[in]      BaseAddress     The MMIO base address of the platform device
>> +  @param[in]      DeviceType      The type of platform device
>> +  @param[in]      DmaType         Whether the device is DMA coherent
>> +  @param[in]      InitFunc        Initialization routine to be invoked when the
>> +                                  device is enabled
>> +  @param[in,out]  Handle          The handle onto which to install the platform
>> +                                  PCI I/O protocol has been installed.
>> +                                  If Handle is NULL or *Handle is NULL, a new
>> +                                  handle will be allocated.
>> +
>> +  @retval EFI_SUCCESS             The registration succeeded.
>> +  @retval other                   The registration failed.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +PlatformPciIoRegisterDevice (
>> +  IN      EFI_PHYSICAL_ADDRESS          BaseAddress,
>> +  IN      PLATFORM_PCI_IO_DEVICE_TYPE   DeviceType,
>> +  IN      PLATFORM_PCI_IO_DMA_TYPE      DmaType,
>> +  IN      PLATFORM_PCI_IO_INIT          InitFunc,
>> +  IN OUT  EFI_HANDLE                    *Handle OPTIONAL
>> +  );
>> +
>> +#endif
>> diff --git a/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c b/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c
>> new file mode 100644
>> index 000000000000..1ce5abb137df
>> --- /dev/null
>> +++ b/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.c
>> @@ -0,0 +1,115 @@
>> +/** @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/BaseLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/DevicePathLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/PlatformPciIoDeviceRegistrationLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +
>> +#include <Protocol/DevicePath.h>
>> +#include <Protocol/PlatformPciIo.h>
>> +
>> +#pragma pack (1)
>> +typedef struct {
>> +  VENDOR_DEVICE_PATH                  Vendor;
>> +  UINT64                              BaseAddress;
>> +  EFI_DEVICE_PATH_PROTOCOL            End;
>> +} PLATFORM_PCI_IO_DEVICE_PATH;
>> +
>> +#pragma pack ()
>> +
>> +/**
>> +  Register a platform device for PCI I/O protocol emulation
>> +
>> +  @param[in]      BaseAddress     The MMIO base address of the platform device
>> +  @param[in]      DeviceType      The type of platform device
>> +  @param[in]      DmaType         Whether the device is DMA coherent
>> +  @param[in]      InitFunc        Initialization routine to be invoked when the
>> +                                  device is enabled
>> +  @param[in,out]  Handle          The handle onto which to install the platform
>> +                                  PCI I/O protocol has been installed.
>> +                                  If Handle is NULL or *Handle is NULL, a new
>> +                                  handle will be allocated.
>> +
>> +  @retval EFI_SUCCESS             The registration succeeded.
>> +  @retval other                   The registration failed.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +PlatformPciIoRegisterDevice (
>> +  IN      EFI_PHYSICAL_ADDRESS          BaseAddress,
>> +  IN      PLATFORM_PCI_IO_DEVICE_TYPE   DeviceType,
>> +  IN      PLATFORM_PCI_IO_DMA_TYPE      DmaType,
>> +  IN      PLATFORM_PCI_IO_INIT          InitFunc,
>> +  IN OUT  EFI_HANDLE                    *Handle
>> +  )
>> +{
>> +  PLATFORM_PCI_IO               *Device;
>> +  PLATFORM_PCI_IO_DEVICE_PATH   *DevicePath;
>> +  EFI_HANDLE                    LocalHandle;
>> +  EFI_STATUS                    Status;
>> +
>> +  if (DeviceType >= PlatformPciIoDeviceMax || DmaType >= PlatformPciIoDmaMax) {
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  if (Handle == NULL) {
>> +    Handle = &LocalHandle;
>> +    LocalHandle = NULL;
>> +  }
>> +
>> +  Device = (PLATFORM_PCI_IO *)AllocateZeroPool (sizeof *Device);
>> +  if (Device == NULL) {
>> +    return EFI_OUT_OF_RESOURCES;
>> +  }
>> +
>> +  Device->BaseAddress = BaseAddress;
>> +  Device->DeviceType = DeviceType;
>> +  Device->DmaType = DmaType;
>> +  Device->Initialize = InitFunc;
>> +
>> +  DevicePath = (PLATFORM_PCI_IO_DEVICE_PATH *)CreateDeviceNode (
>> +                                                HARDWARE_DEVICE_PATH,
>> +                                                HW_VENDOR_DP,
>> +                                                sizeof (*DevicePath));
>> +  if (DevicePath == NULL) {
>> +    Status = EFI_OUT_OF_RESOURCES;
>> +    goto FreeDevice;
>> +  }
>> +
>> +  CopyGuid (&DevicePath->Vendor.Guid, &gPlatformPciIoProtocolGuid);
>> +  DevicePath->BaseAddress = BaseAddress;
>> +
>> +  SetDevicePathNodeLength (&DevicePath->Vendor,
>> +    sizeof (*DevicePath) - sizeof (DevicePath->End));
>> +  SetDevicePathEndNode (&DevicePath->End);
>> +
>> +  Status = gBS->InstallMultipleProtocolInterfaces (Handle,
>> +                  &gPlatformPciIoProtocolGuid, Device,
>> +                  &gEfiDevicePathProtocolGuid, DevicePath);
>> +  if (EFI_ERROR (Status)) {
>> +    goto FreeDevicePath;
>> +  }
>> +  return EFI_SUCCESS;
>> +
>> +FreeDevicePath:
>> +  FreePool (DevicePath);
>> +
>> +FreeDevice:
>> +  FreePool (Device);
>> +
>> +  return Status;
>> +}
>> diff --git a/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf b/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf
>> new file mode 100644
>> index 000000000000..282db3ab59ab
>> --- /dev/null
>> +++ b/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf
>> @@ -0,0 +1,34 @@
>> +# @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.
>> +#
>> +
>> +[Defines]
>> +  INF_VERSION                    = 0x00010017
>
> Not 0019?
>

What can I say, I'm old school :-)

On the one hand, I'm happy to change it, but on the other hand, I
think it is good practice to expose the lowest version number you are
compatible with, in case anyone wants to backport this.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 3/5] EmbeddedPkg: implement generic platform PCI I/O driver
  2016-11-01 22:22   ` Leif Lindholm
@ 2016-11-02 13:39     ` Ard Biesheuvel
  2016-11-02 16:05       ` Leif Lindholm
  0 siblings, 1 reply; 26+ messages in thread
From: Ard Biesheuvel @ 2016-11-02 13:39 UTC (permalink / raw)
  To: Leif Lindholm; +Cc: edk2-devel-01

On 1 November 2016 at 22:22, Leif Lindholm <leif.lindholm@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.

>>
>> 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.biesheuvel@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?

>> +
>> +  //
>> +  // 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

>> +
>> +  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

>> +    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


>> +  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?

>> +
>> +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
>>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 4/5] ArmPkg/CpuDxe: set DmaBufferAlignment according to CWG
  2016-11-01 22:32   ` Leif Lindholm
@ 2016-11-02 13:40     ` Ard Biesheuvel
  2016-11-02 16:10       ` Leif Lindholm
  0 siblings, 1 reply; 26+ messages in thread
From: Ard Biesheuvel @ 2016-11-02 13:40 UTC (permalink / raw)
  To: Leif Lindholm; +Cc: edk2-devel-01

On 1 November 2016 at 22:32, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Mon, Oct 31, 2016 at 06:13:09PM +0000, Ard Biesheuvel wrote:
>> The DmaBufferAlignment currently defaults to 4, which is dangerously
>> small and may result in lost data on platform that perform non-coherent
>> DMA. So instead, take the CWG value from the cache info registers.
>>
>> Contributed-under: TianoCore Contribution Agreement 1.0
>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> ---
>>  ArmPkg/Drivers/CpuDxe/CpuDxe.c | 4 +++-
>>  1 file changed, 3 insertions(+), 1 deletion(-)
>>
>> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>> index d089cb2d119f..ddc64fd255a0 100644
>> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>> @@ -225,7 +225,7 @@ EFI_CPU_ARCH_PROTOCOL mCpu = {
>>    CpuGetTimerValue,
>>    CpuSetMemoryAttributes,
>>    0,          // NumberOfTimers
>> -  4,          // DmaBufferAlignment
>> +  2048,       // DmaBufferAlignment
>>  };
>>
>>  EFI_STATUS
>> @@ -239,6 +239,8 @@ CpuDxeInitialize (
>>
>>    InitializeExceptions (&mCpu);
>>
>> +  mCpu.DmaBufferAlignment = ArmCacheWritebackGranule ();
>> +
>
> Could we hide the internal structure of mCpu here by moving this to a
> helper function and calling
>   InitializeDma (&mCpu);
> (or something)?
>

We could, but why? The actual struct is defined 10 lines up


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 5/5] EmbeddedPkg/PlatformPciIoDxe: add support for non-coherent DMA
  2016-11-01 22:43   ` Leif Lindholm
@ 2016-11-02 13:43     ` Ard Biesheuvel
  2016-11-02 16:17       ` Leif Lindholm
  0 siblings, 1 reply; 26+ messages in thread
From: Ard Biesheuvel @ 2016-11-02 13:43 UTC (permalink / raw)
  To: Leif Lindholm; +Cc: edk2-devel-01

On 1 November 2016 at 22:43, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Mon, Oct 31, 2016 at 06:13:10PM +0000, Ard Biesheuvel wrote:
>> Add support for bounce buffering using uncached mappings when DMA mappings
>> are not aligned to the CPU's DMA buffer alignment.
>
> This description does not appear to match the subject line?
> And the contents of the patch seems to do both.
>

Yes, I was a bit sloppy with this one. The subject line needs to be
duplicated into the long log.

> Anyway, I'll pass on a proper technical review until my head is a bit
> clearer, but a few comments/questions below.
>
>>
>> Contributed-under: TianoCore Contribution Agreement 1.0
>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> ---
>>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c      | 204 ++++++++++++++++++++
>>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h      |   5 +
>>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c   |  17 +-
>>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf |   2 +
>>  4 files changed, 221 insertions(+), 7 deletions(-)
>>
>> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c
>> index 97ed19353347..658d096c73c1 100644
>> --- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c
>> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c
>> @@ -15,6 +15,8 @@
>>
>>  #include "PlatformPciIo.h"
>>
>> +#include <Library/DxeServicesTableLib.h>
>> +
>>  #include <Protocol/PciRootBridgeIo.h>
>>
>>  typedef struct {
>> @@ -454,6 +456,201 @@ CoherentPciIoFreeBuffer (
>>    return EFI_SUCCESS;
>>  }
>>
>> +STATIC
>> +EFI_STATUS
>> +NonCoherentPciIoFreeBuffer (
>> +  IN  EFI_PCI_IO_PROTOCOL         *This,
>> +  IN  UINTN                       Pages,
>> +  IN  VOID                        *HostAddress
>> +  )
>> +{
>> +  EFI_STATUS        Status;
>> +
>> +  Status = gDS->SetMemorySpaceAttributes (
>> +                  (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
>> +                  EFI_PAGES_TO_SIZE (Pages),
>> +                  EFI_MEMORY_WB);
>> +  if (EFI_ERROR (Status)) {
>> +    return Status;
>> +  }
>> +
>> +  FreePages (HostAddress, Pages);
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +NonCoherentPciIoAllocateBuffer (
>> +  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
>> +  )
>> +{
>> +  EFI_STATUS        Status;
>> +
>> +  Status = CoherentPciIoAllocateBuffer (This, Type, MemoryType, Pages,
>> +             HostAddress, Attributes);
>> +  if (EFI_ERROR (Status)) {
>> +    return Status;
>> +  }
>> +
>> +  Status = gDS->SetMemorySpaceAttributes (
>> +                  (EFI_PHYSICAL_ADDRESS)(UINTN)*HostAddress,
>> +                  EFI_PAGES_TO_SIZE (Pages),
>> +                  EFI_MEMORY_WC);
>> +  if (EFI_ERROR (Status)) {
>> +    return Status;
>> +  }
>> +
>> +  Status = gCpu->FlushDataCache (
>> +                   gCpu,
>> +                   (EFI_PHYSICAL_ADDRESS)(UINTN)*HostAddress,
>> +                   EFI_PAGES_TO_SIZE (Pages),
>> +                   EfiCpuFlushTypeInvalidate);
>> +  if (EFI_ERROR (Status)) {
>> +    NonCoherentPciIoFreeBuffer (This, Pages, *HostAddress);
>> +  }
>> +  return Status;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +NonCoherentPciIoMap (
>> +  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;
>> +  UINTN                             AlignMask;
>> +  VOID                              *AllocAddress;
>> +  EFI_GCD_MEMORY_SPACE_DESCRIPTOR   GcdDescriptor;
>> +  BOOLEAN                           UncachedMapping;
>> +
>> +  MapInfo = (PLATFORM_PCI_IO_MAP_INFO *)AllocatePool (sizeof *MapInfo);
>> +  if (MapInfo == NULL) {
>> +    return EFI_OUT_OF_RESOURCES;
>> +  }
>> +
>> +  MapInfo->HostAddress = HostAddress;
>> +  MapInfo->Operation = Operation;
>> +  MapInfo->NumberOfBytes = *NumberOfBytes;
>> +
>> +  //
>> +  // Bounce buffering is not possible for consistent mappings, so
>> +  // check we are mapping a cached buffer for consistent DMA
>> +  //
>> +  if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
>> +    Status = gDS->GetMemorySpaceDescriptor (
>> +                    (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
>> +                    &GcdDescriptor);
>> +    if (!EFI_ERROR (Status)) {
>> +      UncachedMapping = (GcdDescriptor.Attributes & EFI_MEMORY_WC) != 0;
>> +    } else {
>> +      UncachedMapping = FALSE;
>> +    }
>> +  }
>> +
>> +  //
>> +  // If this device does not support 64-bit DMA addressing, we need to allocate
>> +  // a bounce buffer and copy over the data if HostAddress >= 4 GB. We also need
>> +  // to allocate a bounce buffer if the mapping is not aligned to the CPU's
>> +  // DMA buffer alignment.
>> +  //
>> +  Dev = PLATFORM_PCI_IO_DEV_FROM_PCI_IO(This);
>> +  AlignMask = gCpu->DmaBufferAlignment - 1;
>> +  if (((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&
>> +       (UINTN) HostAddress >= SIZE_4GB) ||
>> +       ((((UINTN) HostAddress || *NumberOfBytes) & AlignMask) != 0 &&
>> +        !UncachedMapping)) {
>> +
>> +    Status = NonCoherentPciIoAllocateBuffer (This, AllocateAnyPages,
>> +               EfiBootServicesData, EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
>> +               &AllocAddress, 0);
>> +    if (EFI_ERROR (Status)) {
>> +      goto FreeMapInfo;
>> +    }
>> +    MapInfo->AllocAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress;
>> +    if (Operation == EfiPciIoOperationBusMasterRead) {
>> +      gBS->CopyMem (AllocAddress, HostAddress, *NumberOfBytes);
>> +    }
>> +    *DeviceAddress = MapInfo->AllocAddress;
>> +  } else {
>> +    MapInfo->AllocAddress = 0;
>> +    *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
>> +
>> +    //
>> +    // We are not using a bounce buffer: the mapping is sufficiently
>> +    // aligned to allow us to simply flush the caches. Note that cleaning
>> +    // the caches is necessary for both data directions:
>> +    // - for bus master read, we want the latest data to be present
>> +    //   in main memory
>> +    // - for bus master write, we don't want any stale dirty cachelines that
>> +    //   may be written back unexpectedly, and clobber the data written to
>> +    //   main memory by the device.
>> +    //
>> +    gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
>> +            *NumberOfBytes, EfiCpuFlushTypeWriteBack);
>> +  }
>> +
>> +  *Mapping = MapInfo;
>> +  return EFI_SUCCESS;
>> +
>> +FreeMapInfo:
>> +  FreePool (MapInfo);
>> +
>> +  return Status;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +NonCoherentPciIoUnmap (
>> +  IN  EFI_PCI_IO_PROTOCOL          *This,
>> +  IN  VOID                         *Mapping
>> +  )
>> +{
>> +  PLATFORM_PCI_IO_MAP_INFO  *MapInfo;
>> +
>> +  if (Mapping == NULL) {
>> +    return EFI_DEVICE_ERROR;
>> +  }
>> +
>> +  MapInfo = Mapping;
>> +  if (MapInfo->AllocAddress != 0) {
>> +    //
>> +    // We are using a bounce buffer: copy back the data if necessary,
>> +    // and free the buffer.
>> +    //
>> +    if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
>> +      gBS->CopyMem (MapInfo->HostAddress, (VOID *)MapInfo->AllocAddress,
>> +             MapInfo->NumberOfBytes);
>> +    }
>> +    NonCoherentPciIoFreeBuffer (This,
>> +      EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
>> +      (VOID *)(UINTN)MapInfo->AllocAddress);
>> +  } else {
>> +    //
>> +    // We are *not* using a bounce buffer: if this is a bus master write,
>> +    // we have to invalidate the caches so the CPU will see the uncached
>> +    // data written by the device.
>> +    //
>> +    if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
>> +      gCpu->FlushDataCache (gCpu,
>> +              (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,
>> +              MapInfo->NumberOfBytes, EfiCpuFlushTypeInvalidate);
>> +    }
>> +  }
>> +  FreePool (MapInfo);
>> +  return EFI_SUCCESS;
>> +}
>>
>>  STATIC
>>  EFI_STATUS
>> @@ -646,4 +843,11 @@ InitializePciIoProtocol (
>>
>>    // Copy protocol structure
>>    CopyMem(&PlatformPciIoDev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);
>> +
>> +  if (PlatformPciIoDev->PlatformPciIo->DmaType == PlatformPciIoDmaNonCoherent) {
>> +    PlatformPciIoDev->PciIo.AllocateBuffer = NonCoherentPciIoAllocateBuffer;
>> +    PlatformPciIoDev->PciIo.FreeBuffer = NonCoherentPciIoFreeBuffer;
>> +    PlatformPciIoDev->PciIo.Map = NonCoherentPciIoMap;
>> +    PlatformPciIoDev->PciIo.Unmap = NonCoherentPciIoUnmap;
>> +  }
>>  }
>> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h
>> index 8fd8dc5e4a11..b7b792b85ae4 100644
>> --- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h
>> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h
>> @@ -12,6 +12,8 @@
>>
>>  **/
>>
>> +#include <PiDxe.h>
>> +
>>  #include <Library/BaseMemoryLib.h>
>>  #include <Library/DebugLib.h>
>>  #include <Library/MemoryAllocationLib.h>
>> @@ -20,6 +22,7 @@
>>
>>  #include <IndustryStandard/Pci.h>
>>
>> +#include <Protocol/Cpu.h>
>>  #include <Protocol/PciIo.h>
>>  #include <Protocol/PlatformPciIo.h>
>>
>> @@ -28,6 +31,8 @@
>>  #define PLATFORM_PCI_IO_DEV_FROM_PCI_IO(PciIoPointer) \
>>            CR (PciIoPointer, PLATFORM_PCI_IO_DEV, PciIo, PLATFORM_PCI_IO_SIG)
>>
>> +extern EFI_CPU_ARCH_PROTOCOL      *gCpu;
>> +
>>  typedef struct {
>>    UINT32                  Signature;
>>    //
>> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c
>> index 7f3306e7e891..fa4719686a6d 100644
>> --- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c
>> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c
>> @@ -17,6 +17,8 @@
>>  #include <Protocol/ComponentName.h>
>>  #include <Protocol/DriverBinding.h>
>>
>> +EFI_CPU_ARCH_PROTOCOL      *gCpu;
>> +
>
> Should this not really be pulled in from some header file?
>

No. But it should be called mCpu not gCpu

> Maybe including it straight from DxeMain.h isn't entirely kosher even
> if this code does end up in MdeModulePkg, but surely the declaration
> there should also be pulled in from somewhere under UefiCpuPkg/Include?
>

It is simply a reference we hold to an architectural protocol, so it
is no different from any other driver that finds a protocol using
LocateProtocol and stashes the pointer.

>>  //
>>  // Probe, start and stop functions of this driver, called by the DXE core for
>>  // specific devices.
>> @@ -60,13 +62,9 @@ PlatformPciIoDriverBindingSupported (
>>    case PlatformPciIoDeviceEhci:
>>    case PlatformPciIoDeviceXhci:
>>    case PlatformPciIoDeviceAhci:
>> -    //
>> -    // Restricted to DMA coherent for now
>> -    //
>> -    if (PlatformPciIo->DmaType == PlatformPciIoDmaCoherent) {
>> -      Status = EFI_SUCCESS;
>> -      break;
>> -    }
>> +    Status = EFI_SUCCESS;
>> +    break;
>> +
>>    default:
>>      Status = EFI_UNSUPPORTED;
>>    }
>> @@ -257,6 +255,11 @@ PlatformPciIoDxeEntryPoint (
>>    IN EFI_SYSTEM_TABLE *SystemTable
>>    )
>>  {
>> +  EFI_STATUS      Status;
>> +
>> +  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
>> +  ASSERT_EFI_ERROR(Status);
>> +
>>    return EfiLibInstallDriverBindingComponentName2 (
>>             ImageHandle,
>>             SystemTable,
>> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf
>> index 2b0baf06732c..670dcc5a9ff2 100644
>> --- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf
>> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf
>> @@ -31,11 +31,13 @@ [Packages]
>>  [LibraryClasses]
>>    BaseMemoryLib
>>    DebugLib
>> +  DxeServicesTableLib
>>    MemoryAllocationLib
>>    UefiBootServicesTableLib
>>    UefiDriverEntryPoint
>>    UefiLib
>>
>>  [Protocols]
>> +  gEfiCpuArchProtocolGuid         ## CONSUMES
>>    gEfiPciIoProtocolGuid           ## BY_START
>>    gPlatformPciIoProtocolGuid      ## TO_START
>> --
>> 2.7.4
>>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/5] EmbeddedPkg: introduce platform PCI I/O registration library
  2016-11-02 13:30     ` Ard Biesheuvel
@ 2016-11-02 15:39       ` Leif Lindholm
  2016-11-07 14:54       ` Evan Lloyd
  1 sibling, 0 replies; 26+ messages in thread
From: Leif Lindholm @ 2016-11-02 15:39 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: edk2-devel-01, Andrew Fish, Kinney, Michael D

On Wed, Nov 02, 2016 at 01:30:22PM +0000, Ard Biesheuvel wrote:
> On 1 November 2016 at 21:57, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> > On Mon, Oct 31, 2016 at 06:13:07PM +0000, Ard Biesheuvel wrote:
> >> diff --git a/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf b/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf
> >> new file mode 100644
> >> index 000000000000..282db3ab59ab
> >> --- /dev/null
> >> +++ b/EmbeddedPkg/Library/PlatformPciIoDeviceRegistrationLib/PlatformPciIoDeviceRegistrationLib.inf
> >> @@ -0,0 +1,34 @@
> >> +# @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.
> >> +#
> >> +
> >> +[Defines]
> >> +  INF_VERSION                    = 0x00010017
> >
> > Not 0019?
> >
> 
> What can I say, I'm old school :-)
> 
> On the one hand, I'm happy to change it, but on the other hand, I
> think it is good practice to expose the lowest version number you are
> compatible with, in case anyone wants to backport this.

That's a good point - and something that would be useful to have
official guidelines for.

Andrew, Mike - what's your take on this? Should we have a recommended
"maximum INF_VERSION" for core protocols/libraries?

Regards,

Leif


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 1/5] EmbeddedPkg: introduce platform PCI I/O protocol
  2016-11-02 13:29     ` Ard Biesheuvel
@ 2016-11-02 15:42       ` Leif Lindholm
  0 siblings, 0 replies; 26+ messages in thread
From: Leif Lindholm @ 2016-11-02 15:42 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: edk2-devel-01, haojian.zhuang@linaro.org

On Wed, Nov 02, 2016 at 01:29:06PM +0000, Ard Biesheuvel wrote:
> >> +//
> >> +// Data Types
> >> +//
> >> +typedef enum {
> >> +  PlatformPciIoDeviceOhci,
> >> +  PlatformPciIoDeviceUhci,
> >> +  PlatformPciIoDeviceEhci,
> >> +  PlatformPciIoDeviceXhci,
> >> +  PlatformPciIoDeviceAhci,
> >
> > SdMmc and Ufs?
> >
> 
> Indeed. I have added both: SDHCI works in QEMU but I can't really test UFS.

Haojian - are you able to help out with testing UFS?

Regards,

Leif


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 3/5] EmbeddedPkg: implement generic platform PCI I/O driver
  2016-11-02 13:39     ` Ard Biesheuvel
@ 2016-11-02 16:05       ` Leif Lindholm
  0 siblings, 0 replies; 26+ messages in thread
From: Leif Lindholm @ 2016-11-02 16:05 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: edk2-devel-01

On Wed, Nov 02, 2016 at 01:39:26PM +0000, Ard Biesheuvel wrote:
> On 1 November 2016 at 22:22, Leif Lindholm <leif.lindholm@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.biesheuvel@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


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 4/5] ArmPkg/CpuDxe: set DmaBufferAlignment according to CWG
  2016-11-02 13:40     ` Ard Biesheuvel
@ 2016-11-02 16:10       ` Leif Lindholm
  2016-11-02 16:17         ` Ard Biesheuvel
  0 siblings, 1 reply; 26+ messages in thread
From: Leif Lindholm @ 2016-11-02 16:10 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: edk2-devel-01

On Wed, Nov 02, 2016 at 01:40:17PM +0000, Ard Biesheuvel wrote:
> On 1 November 2016 at 22:32, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> > On Mon, Oct 31, 2016 at 06:13:09PM +0000, Ard Biesheuvel wrote:
> >> The DmaBufferAlignment currently defaults to 4, which is dangerously
> >> small and may result in lost data on platform that perform non-coherent
> >> DMA. So instead, take the CWG value from the cache info registers.
> >>
> >> Contributed-under: TianoCore Contribution Agreement 1.0
> >> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> >> ---
> >>  ArmPkg/Drivers/CpuDxe/CpuDxe.c | 4 +++-
> >>  1 file changed, 3 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
> >> index d089cb2d119f..ddc64fd255a0 100644
> >> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c
> >> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
> >> @@ -225,7 +225,7 @@ EFI_CPU_ARCH_PROTOCOL mCpu = {
> >>    CpuGetTimerValue,
> >>    CpuSetMemoryAttributes,
> >>    0,          // NumberOfTimers
> >> -  4,          // DmaBufferAlignment
> >> +  2048,       // DmaBufferAlignment
> >>  };
> >>
> >>  EFI_STATUS
> >> @@ -239,6 +239,8 @@ CpuDxeInitialize (
> >>
> >>    InitializeExceptions (&mCpu);
> >>
> >> +  mCpu.DmaBufferAlignment = ArmCacheWritebackGranule ();
> >> +
> >
> > Could we hide the internal structure of mCpu here by moving this to a
> > helper function and calling
> >   InitializeDma (&mCpu);
> > (or something)?
> >
> 
> We could, but why? The actual struct is defined 10 lines up

It's just that it's the only place in this function we're prodding the
internals of the object directly. Messes slightly with my zen.
Not a strong opinion, just a preference.

/
    Leif




^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 4/5] ArmPkg/CpuDxe: set DmaBufferAlignment according to CWG
  2016-11-02 16:10       ` Leif Lindholm
@ 2016-11-02 16:17         ` Ard Biesheuvel
  2016-11-02 16:21           ` Leif Lindholm
  0 siblings, 1 reply; 26+ messages in thread
From: Ard Biesheuvel @ 2016-11-02 16:17 UTC (permalink / raw)
  To: Leif Lindholm; +Cc: edk2-devel-01

On 2 November 2016 at 16:10, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Wed, Nov 02, 2016 at 01:40:17PM +0000, Ard Biesheuvel wrote:
>> On 1 November 2016 at 22:32, Leif Lindholm <leif.lindholm@linaro.org> wrote:
>> > On Mon, Oct 31, 2016 at 06:13:09PM +0000, Ard Biesheuvel wrote:
>> >> The DmaBufferAlignment currently defaults to 4, which is dangerously
>> >> small and may result in lost data on platform that perform non-coherent
>> >> DMA. So instead, take the CWG value from the cache info registers.
>> >>
>> >> Contributed-under: TianoCore Contribution Agreement 1.0
>> >> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> >> ---
>> >>  ArmPkg/Drivers/CpuDxe/CpuDxe.c | 4 +++-
>> >>  1 file changed, 3 insertions(+), 1 deletion(-)
>> >>
>> >> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>> >> index d089cb2d119f..ddc64fd255a0 100644
>> >> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>> >> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>> >> @@ -225,7 +225,7 @@ EFI_CPU_ARCH_PROTOCOL mCpu = {
>> >>    CpuGetTimerValue,
>> >>    CpuSetMemoryAttributes,
>> >>    0,          // NumberOfTimers
>> >> -  4,          // DmaBufferAlignment
>> >> +  2048,       // DmaBufferAlignment
>> >>  };
>> >>
>> >>  EFI_STATUS
>> >> @@ -239,6 +239,8 @@ CpuDxeInitialize (
>> >>
>> >>    InitializeExceptions (&mCpu);
>> >>
>> >> +  mCpu.DmaBufferAlignment = ArmCacheWritebackGranule ();
>> >> +
>> >
>> > Could we hide the internal structure of mCpu here by moving this to a
>> > helper function and calling
>> >   InitializeDma (&mCpu);
>> > (or something)?
>> >
>>
>> We could, but why? The actual struct is defined 10 lines up
>
> It's just that it's the only place in this function we're prodding the
> internals of the object directly. Messes slightly with my zen.
> Not a strong opinion, just a preference.
>

Sure, if you want.

In fact, I will break this out as a separate patch, considering that
it fixes a serious bug.

So you are happy with the patch if I fold the following into it?

"""
--- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
@@ -228,6 +228,15 @@ EFI_CPU_ARCH_PROTOCOL mCpu = {
   2048,       // DmaBufferAlignment
 };

+STATIC
+VOID
+InitializeDma (
+  IN OUT  EFI_CPU_ARCH_PROTOCOL   *CpuArchProtocol
+  )
+{
+  CpuArchProtocol->DmaBufferAlignment = ArmCacheWritebackGranule ();
+}
+
 EFI_STATUS
 CpuDxeInitialize (
   IN EFI_HANDLE         ImageHandle,
@@ -239,7 +248,7 @@ CpuDxeInitialize (

   InitializeExceptions (&mCpu);

-  mCpu.DmaBufferAlignment = ArmCacheWritebackGranule ();
+  InitializeDma (&mCpu);

   Status = gBS->InstallMultipleProtocolInterfaces (
                 &mCpuHandle,
"""


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 5/5] EmbeddedPkg/PlatformPciIoDxe: add support for non-coherent DMA
  2016-11-02 13:43     ` Ard Biesheuvel
@ 2016-11-02 16:17       ` Leif Lindholm
  0 siblings, 0 replies; 26+ messages in thread
From: Leif Lindholm @ 2016-11-02 16:17 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: edk2-devel-01

On Wed, Nov 02, 2016 at 01:43:42PM +0000, Ard Biesheuvel wrote:
> On 1 November 2016 at 22:43, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> > On Mon, Oct 31, 2016 at 06:13:10PM +0000, Ard Biesheuvel wrote:
> >> Add support for bounce buffering using uncached mappings when DMA mappings
> >> are not aligned to the CPU's DMA buffer alignment.
> >
> > This description does not appear to match the subject line?
> > And the contents of the patch seems to do both.
> >
> 
> Yes, I was a bit sloppy with this one. The subject line needs to be
> duplicated into the long log.
> 
> > Anyway, I'll pass on a proper technical review until my head is a bit
> > clearer, but a few comments/questions below.
> >
> >>
> >> Contributed-under: TianoCore Contribution Agreement 1.0
> >> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> >> ---
> >>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c      | 204 ++++++++++++++++++++
> >>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h      |   5 +
> >>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c   |  17 +-
> >>  EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf |   2 +
> >>  4 files changed, 221 insertions(+), 7 deletions(-)
> >>
> >> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c
> >> index 97ed19353347..658d096c73c1 100644
> >> --- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c
> >> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.c
> >> @@ -15,6 +15,8 @@
> >>
> >>  #include "PlatformPciIo.h"
> >>
> >> +#include <Library/DxeServicesTableLib.h>
> >> +
> >>  #include <Protocol/PciRootBridgeIo.h>
> >>
> >>  typedef struct {
> >> @@ -454,6 +456,201 @@ CoherentPciIoFreeBuffer (
> >>    return EFI_SUCCESS;
> >>  }
> >>
> >> +STATIC
> >> +EFI_STATUS
> >> +NonCoherentPciIoFreeBuffer (
> >> +  IN  EFI_PCI_IO_PROTOCOL         *This,
> >> +  IN  UINTN                       Pages,
> >> +  IN  VOID                        *HostAddress
> >> +  )
> >> +{
> >> +  EFI_STATUS        Status;
> >> +
> >> +  Status = gDS->SetMemorySpaceAttributes (
> >> +                  (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
> >> +                  EFI_PAGES_TO_SIZE (Pages),
> >> +                  EFI_MEMORY_WB);
> >> +  if (EFI_ERROR (Status)) {
> >> +    return Status;
> >> +  }
> >> +
> >> +  FreePages (HostAddress, Pages);
> >> +  return EFI_SUCCESS;
> >> +}
> >> +
> >> +STATIC
> >> +EFI_STATUS
> >> +NonCoherentPciIoAllocateBuffer (
> >> +  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
> >> +  )
> >> +{
> >> +  EFI_STATUS        Status;
> >> +
> >> +  Status = CoherentPciIoAllocateBuffer (This, Type, MemoryType, Pages,
> >> +             HostAddress, Attributes);
> >> +  if (EFI_ERROR (Status)) {
> >> +    return Status;
> >> +  }
> >> +
> >> +  Status = gDS->SetMemorySpaceAttributes (
> >> +                  (EFI_PHYSICAL_ADDRESS)(UINTN)*HostAddress,
> >> +                  EFI_PAGES_TO_SIZE (Pages),
> >> +                  EFI_MEMORY_WC);
> >> +  if (EFI_ERROR (Status)) {
> >> +    return Status;
> >> +  }
> >> +
> >> +  Status = gCpu->FlushDataCache (
> >> +                   gCpu,
> >> +                   (EFI_PHYSICAL_ADDRESS)(UINTN)*HostAddress,
> >> +                   EFI_PAGES_TO_SIZE (Pages),
> >> +                   EfiCpuFlushTypeInvalidate);
> >> +  if (EFI_ERROR (Status)) {
> >> +    NonCoherentPciIoFreeBuffer (This, Pages, *HostAddress);
> >> +  }
> >> +  return Status;
> >> +}
> >> +
> >> +STATIC
> >> +EFI_STATUS
> >> +NonCoherentPciIoMap (
> >> +  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;
> >> +  UINTN                             AlignMask;
> >> +  VOID                              *AllocAddress;
> >> +  EFI_GCD_MEMORY_SPACE_DESCRIPTOR   GcdDescriptor;
> >> +  BOOLEAN                           UncachedMapping;
> >> +
> >> +  MapInfo = (PLATFORM_PCI_IO_MAP_INFO *)AllocatePool (sizeof *MapInfo);
> >> +  if (MapInfo == NULL) {
> >> +    return EFI_OUT_OF_RESOURCES;
> >> +  }
> >> +
> >> +  MapInfo->HostAddress = HostAddress;
> >> +  MapInfo->Operation = Operation;
> >> +  MapInfo->NumberOfBytes = *NumberOfBytes;
> >> +
> >> +  //
> >> +  // Bounce buffering is not possible for consistent mappings, so
> >> +  // check we are mapping a cached buffer for consistent DMA
> >> +  //
> >> +  if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
> >> +    Status = gDS->GetMemorySpaceDescriptor (
> >> +                    (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
> >> +                    &GcdDescriptor);
> >> +    if (!EFI_ERROR (Status)) {
> >> +      UncachedMapping = (GcdDescriptor.Attributes & EFI_MEMORY_WC) != 0;
> >> +    } else {
> >> +      UncachedMapping = FALSE;
> >> +    }
> >> +  }
> >> +
> >> +  //
> >> +  // If this device does not support 64-bit DMA addressing, we need to allocate
> >> +  // a bounce buffer and copy over the data if HostAddress >= 4 GB. We also need
> >> +  // to allocate a bounce buffer if the mapping is not aligned to the CPU's
> >> +  // DMA buffer alignment.
> >> +  //
> >> +  Dev = PLATFORM_PCI_IO_DEV_FROM_PCI_IO(This);
> >> +  AlignMask = gCpu->DmaBufferAlignment - 1;
> >> +  if (((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&
> >> +       (UINTN) HostAddress >= SIZE_4GB) ||
> >> +       ((((UINTN) HostAddress || *NumberOfBytes) & AlignMask) != 0 &&
> >> +        !UncachedMapping)) {
> >> +
> >> +    Status = NonCoherentPciIoAllocateBuffer (This, AllocateAnyPages,
> >> +               EfiBootServicesData, EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
> >> +               &AllocAddress, 0);
> >> +    if (EFI_ERROR (Status)) {
> >> +      goto FreeMapInfo;
> >> +    }
> >> +    MapInfo->AllocAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress;
> >> +    if (Operation == EfiPciIoOperationBusMasterRead) {
> >> +      gBS->CopyMem (AllocAddress, HostAddress, *NumberOfBytes);
> >> +    }
> >> +    *DeviceAddress = MapInfo->AllocAddress;
> >> +  } else {
> >> +    MapInfo->AllocAddress = 0;
> >> +    *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
> >> +
> >> +    //
> >> +    // We are not using a bounce buffer: the mapping is sufficiently
> >> +    // aligned to allow us to simply flush the caches. Note that cleaning
> >> +    // the caches is necessary for both data directions:
> >> +    // - for bus master read, we want the latest data to be present
> >> +    //   in main memory
> >> +    // - for bus master write, we don't want any stale dirty cachelines that
> >> +    //   may be written back unexpectedly, and clobber the data written to
> >> +    //   main memory by the device.
> >> +    //
> >> +    gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
> >> +            *NumberOfBytes, EfiCpuFlushTypeWriteBack);
> >> +  }
> >> +
> >> +  *Mapping = MapInfo;
> >> +  return EFI_SUCCESS;
> >> +
> >> +FreeMapInfo:
> >> +  FreePool (MapInfo);
> >> +
> >> +  return Status;
> >> +}
> >> +
> >> +STATIC
> >> +EFI_STATUS
> >> +NonCoherentPciIoUnmap (
> >> +  IN  EFI_PCI_IO_PROTOCOL          *This,
> >> +  IN  VOID                         *Mapping
> >> +  )
> >> +{
> >> +  PLATFORM_PCI_IO_MAP_INFO  *MapInfo;
> >> +
> >> +  if (Mapping == NULL) {
> >> +    return EFI_DEVICE_ERROR;
> >> +  }
> >> +
> >> +  MapInfo = Mapping;
> >> +  if (MapInfo->AllocAddress != 0) {
> >> +    //
> >> +    // We are using a bounce buffer: copy back the data if necessary,
> >> +    // and free the buffer.
> >> +    //
> >> +    if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
> >> +      gBS->CopyMem (MapInfo->HostAddress, (VOID *)MapInfo->AllocAddress,
> >> +             MapInfo->NumberOfBytes);
> >> +    }
> >> +    NonCoherentPciIoFreeBuffer (This,
> >> +      EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
> >> +      (VOID *)(UINTN)MapInfo->AllocAddress);
> >> +  } else {
> >> +    //
> >> +    // We are *not* using a bounce buffer: if this is a bus master write,
> >> +    // we have to invalidate the caches so the CPU will see the uncached
> >> +    // data written by the device.
> >> +    //
> >> +    if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
> >> +      gCpu->FlushDataCache (gCpu,
> >> +              (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,
> >> +              MapInfo->NumberOfBytes, EfiCpuFlushTypeInvalidate);
> >> +    }
> >> +  }
> >> +  FreePool (MapInfo);
> >> +  return EFI_SUCCESS;
> >> +}
> >>
> >>  STATIC
> >>  EFI_STATUS
> >> @@ -646,4 +843,11 @@ InitializePciIoProtocol (
> >>
> >>    // Copy protocol structure
> >>    CopyMem(&PlatformPciIoDev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);
> >> +
> >> +  if (PlatformPciIoDev->PlatformPciIo->DmaType == PlatformPciIoDmaNonCoherent) {
> >> +    PlatformPciIoDev->PciIo.AllocateBuffer = NonCoherentPciIoAllocateBuffer;
> >> +    PlatformPciIoDev->PciIo.FreeBuffer = NonCoherentPciIoFreeBuffer;
> >> +    PlatformPciIoDev->PciIo.Map = NonCoherentPciIoMap;
> >> +    PlatformPciIoDev->PciIo.Unmap = NonCoherentPciIoUnmap;
> >> +  }
> >>  }
> >> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h
> >> index 8fd8dc5e4a11..b7b792b85ae4 100644
> >> --- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h
> >> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIo.h
> >> @@ -12,6 +12,8 @@
> >>
> >>  **/
> >>
> >> +#include <PiDxe.h>
> >> +
> >>  #include <Library/BaseMemoryLib.h>
> >>  #include <Library/DebugLib.h>
> >>  #include <Library/MemoryAllocationLib.h>
> >> @@ -20,6 +22,7 @@
> >>
> >>  #include <IndustryStandard/Pci.h>
> >>
> >> +#include <Protocol/Cpu.h>
> >>  #include <Protocol/PciIo.h>
> >>  #include <Protocol/PlatformPciIo.h>
> >>
> >> @@ -28,6 +31,8 @@
> >>  #define PLATFORM_PCI_IO_DEV_FROM_PCI_IO(PciIoPointer) \
> >>            CR (PciIoPointer, PLATFORM_PCI_IO_DEV, PciIo, PLATFORM_PCI_IO_SIG)
> >>
> >> +extern EFI_CPU_ARCH_PROTOCOL      *gCpu;
> >> +
> >>  typedef struct {
> >>    UINT32                  Signature;
> >>    //
> >> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c
> >> index 7f3306e7e891..fa4719686a6d 100644
> >> --- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c
> >> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.c
> >> @@ -17,6 +17,8 @@
> >>  #include <Protocol/ComponentName.h>
> >>  #include <Protocol/DriverBinding.h>
> >>
> >> +EFI_CPU_ARCH_PROTOCOL      *gCpu;
> >> +
> >
> > Should this not really be pulled in from some header file?
> >
> 
> No. But it should be called mCpu not gCpu

Ah, that makes a lot more sense then, thanks.

I also confusingly added the comment here, rather than 15 lines
earlier where I was intending to.

/
    Leif
    
> > Maybe including it straight from DxeMain.h isn't entirely kosher even
> > if this code does end up in MdeModulePkg, but surely the declaration
> > there should also be pulled in from somewhere under UefiCpuPkg/Include?
> >
> 
> It is simply a reference we hold to an architectural protocol, so it
> is no different from any other driver that finds a protocol using
> LocateProtocol and stashes the pointer.

Right, as mCpu that makes complete sense.

> >>  //
> >>  // Probe, start and stop functions of this driver, called by the DXE core for
> >>  // specific devices.
> >> @@ -60,13 +62,9 @@ PlatformPciIoDriverBindingSupported (
> >>    case PlatformPciIoDeviceEhci:
> >>    case PlatformPciIoDeviceXhci:
> >>    case PlatformPciIoDeviceAhci:
> >> -    //
> >> -    // Restricted to DMA coherent for now
> >> -    //
> >> -    if (PlatformPciIo->DmaType == PlatformPciIoDmaCoherent) {
> >> -      Status = EFI_SUCCESS;
> >> -      break;
> >> -    }
> >> +    Status = EFI_SUCCESS;
> >> +    break;
> >> +
> >>    default:
> >>      Status = EFI_UNSUPPORTED;
> >>    }
> >> @@ -257,6 +255,11 @@ PlatformPciIoDxeEntryPoint (
> >>    IN EFI_SYSTEM_TABLE *SystemTable
> >>    )
> >>  {
> >> +  EFI_STATUS      Status;
> >> +
> >> +  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
> >> +  ASSERT_EFI_ERROR(Status);
> >> +
> >>    return EfiLibInstallDriverBindingComponentName2 (
> >>             ImageHandle,
> >>             SystemTable,
> >> diff --git a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf
> >> index 2b0baf06732c..670dcc5a9ff2 100644
> >> --- a/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf
> >> +++ b/EmbeddedPkg/Drivers/PlatformPciIoDxe/PlatformPciIoDxe.inf
> >> @@ -31,11 +31,13 @@ [Packages]
> >>  [LibraryClasses]
> >>    BaseMemoryLib
> >>    DebugLib
> >> +  DxeServicesTableLib
> >>    MemoryAllocationLib
> >>    UefiBootServicesTableLib
> >>    UefiDriverEntryPoint
> >>    UefiLib
> >>
> >>  [Protocols]
> >> +  gEfiCpuArchProtocolGuid         ## CONSUMES
> >>    gEfiPciIoProtocolGuid           ## BY_START
> >>    gPlatformPciIoProtocolGuid      ## TO_START
> >> --
> >> 2.7.4
> >>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 4/5] ArmPkg/CpuDxe: set DmaBufferAlignment according to CWG
  2016-11-02 16:17         ` Ard Biesheuvel
@ 2016-11-02 16:21           ` Leif Lindholm
  2016-11-02 16:23             ` Ard Biesheuvel
  0 siblings, 1 reply; 26+ messages in thread
From: Leif Lindholm @ 2016-11-02 16:21 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: edk2-devel-01

On Wed, Nov 02, 2016 at 04:17:03PM +0000, Ard Biesheuvel wrote:
> On 2 November 2016 at 16:10, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> > On Wed, Nov 02, 2016 at 01:40:17PM +0000, Ard Biesheuvel wrote:
> >> On 1 November 2016 at 22:32, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> >> > On Mon, Oct 31, 2016 at 06:13:09PM +0000, Ard Biesheuvel wrote:
> >> >> The DmaBufferAlignment currently defaults to 4, which is dangerously
> >> >> small and may result in lost data on platform that perform non-coherent
> >> >> DMA. So instead, take the CWG value from the cache info registers.
> >> >>
> >> >> Contributed-under: TianoCore Contribution Agreement 1.0
> >> >> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> >> >> ---
> >> >>  ArmPkg/Drivers/CpuDxe/CpuDxe.c | 4 +++-
> >> >>  1 file changed, 3 insertions(+), 1 deletion(-)
> >> >>
> >> >> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
> >> >> index d089cb2d119f..ddc64fd255a0 100644
> >> >> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c
> >> >> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
> >> >> @@ -225,7 +225,7 @@ EFI_CPU_ARCH_PROTOCOL mCpu = {
> >> >>    CpuGetTimerValue,
> >> >>    CpuSetMemoryAttributes,
> >> >>    0,          // NumberOfTimers
> >> >> -  4,          // DmaBufferAlignment
> >> >> +  2048,       // DmaBufferAlignment
> >> >>  };
> >> >>
> >> >>  EFI_STATUS
> >> >> @@ -239,6 +239,8 @@ CpuDxeInitialize (
> >> >>
> >> >>    InitializeExceptions (&mCpu);
> >> >>
> >> >> +  mCpu.DmaBufferAlignment = ArmCacheWritebackGranule ();
> >> >> +
> >> >
> >> > Could we hide the internal structure of mCpu here by moving this to a
> >> > helper function and calling
> >> >   InitializeDma (&mCpu);
> >> > (or something)?
> >> >
> >>
> >> We could, but why? The actual struct is defined 10 lines up
> >
> > It's just that it's the only place in this function we're prodding the
> > internals of the object directly. Messes slightly with my zen.
> > Not a strong opinion, just a preference.
> >
> 
> Sure, if you want.
> 
> In fact, I will break this out as a separate patch, considering that
> it fixes a serious bug.

Agreed.

> So you are happy with the patch if I fold the following into it?

Super happy - thanks!
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>

> 
> """
> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c
> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
> @@ -228,6 +228,15 @@ EFI_CPU_ARCH_PROTOCOL mCpu = {
>    2048,       // DmaBufferAlignment
>  };
> 
> +STATIC
> +VOID
> +InitializeDma (
> +  IN OUT  EFI_CPU_ARCH_PROTOCOL   *CpuArchProtocol
> +  )
> +{
> +  CpuArchProtocol->DmaBufferAlignment = ArmCacheWritebackGranule ();
> +}
> +
>  EFI_STATUS
>  CpuDxeInitialize (
>    IN EFI_HANDLE         ImageHandle,
> @@ -239,7 +248,7 @@ CpuDxeInitialize (
> 
>    InitializeExceptions (&mCpu);
> 
> -  mCpu.DmaBufferAlignment = ArmCacheWritebackGranule ();
> +  InitializeDma (&mCpu);
> 
>    Status = gBS->InstallMultipleProtocolInterfaces (
>                  &mCpuHandle,
> """


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 4/5] ArmPkg/CpuDxe: set DmaBufferAlignment according to CWG
  2016-11-02 16:21           ` Leif Lindholm
@ 2016-11-02 16:23             ` Ard Biesheuvel
  0 siblings, 0 replies; 26+ messages in thread
From: Ard Biesheuvel @ 2016-11-02 16:23 UTC (permalink / raw)
  To: Leif Lindholm; +Cc: edk2-devel-01

On 2 November 2016 at 16:21, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Wed, Nov 02, 2016 at 04:17:03PM +0000, Ard Biesheuvel wrote:
>> On 2 November 2016 at 16:10, Leif Lindholm <leif.lindholm@linaro.org> wrote:
>> > On Wed, Nov 02, 2016 at 01:40:17PM +0000, Ard Biesheuvel wrote:
>> >> On 1 November 2016 at 22:32, Leif Lindholm <leif.lindholm@linaro.org> wrote:
>> >> > On Mon, Oct 31, 2016 at 06:13:09PM +0000, Ard Biesheuvel wrote:
>> >> >> The DmaBufferAlignment currently defaults to 4, which is dangerously
>> >> >> small and may result in lost data on platform that perform non-coherent
>> >> >> DMA. So instead, take the CWG value from the cache info registers.
>> >> >>
>> >> >> Contributed-under: TianoCore Contribution Agreement 1.0
>> >> >> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> >> >> ---
>> >> >>  ArmPkg/Drivers/CpuDxe/CpuDxe.c | 4 +++-
>> >> >>  1 file changed, 3 insertions(+), 1 deletion(-)
>> >> >>
>> >> >> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>> >> >> index d089cb2d119f..ddc64fd255a0 100644
>> >> >> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>> >> >> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>> >> >> @@ -225,7 +225,7 @@ EFI_CPU_ARCH_PROTOCOL mCpu = {
>> >> >>    CpuGetTimerValue,
>> >> >>    CpuSetMemoryAttributes,
>> >> >>    0,          // NumberOfTimers
>> >> >> -  4,          // DmaBufferAlignment
>> >> >> +  2048,       // DmaBufferAlignment
>> >> >>  };
>> >> >>
>> >> >>  EFI_STATUS
>> >> >> @@ -239,6 +239,8 @@ CpuDxeInitialize (
>> >> >>
>> >> >>    InitializeExceptions (&mCpu);
>> >> >>
>> >> >> +  mCpu.DmaBufferAlignment = ArmCacheWritebackGranule ();
>> >> >> +
>> >> >
>> >> > Could we hide the internal structure of mCpu here by moving this to a
>> >> > helper function and calling
>> >> >   InitializeDma (&mCpu);
>> >> > (or something)?
>> >> >
>> >>
>> >> We could, but why? The actual struct is defined 10 lines up
>> >
>> > It's just that it's the only place in this function we're prodding the
>> > internals of the object directly. Messes slightly with my zen.
>> > Not a strong opinion, just a preference.
>> >
>>
>> Sure, if you want.
>>
>> In fact, I will break this out as a separate patch, considering that
>> it fixes a serious bug.
>
> Agreed.
>
>> So you are happy with the patch if I fold the following into it?
>
> Super happy - thanks!
> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
>

OK, pushed.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/5] EmbeddedPkg: introduce platform PCI I/O registration library
  2016-11-02 13:30     ` Ard Biesheuvel
  2016-11-02 15:39       ` Leif Lindholm
@ 2016-11-07 14:54       ` Evan Lloyd
  1 sibling, 0 replies; 26+ messages in thread
From: Evan Lloyd @ 2016-11-07 14:54 UTC (permalink / raw)
  To: ard.biesheuvel@linaro.org, Leif Lindholm; +Cc: edk2-devel-01



>-----Original Message-----
>From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
>Ard Biesheuvel
>Sent: 02 November 2016 13:30
>To: Leif Lindholm
>Cc: edk2-devel-01
>Subject: Re: [edk2] [PATCH 2/5] EmbeddedPkg: introduce platform PCI I/O
>registration library
>
>On 1 November 2016 at 21:57, Leif Lindholm <leif.lindholm@linaro.org>
>wrote:
>> On Mon, Oct 31, 2016 at 06:13:07PM +0000, Ard Biesheuvel wrote:
...
>>> +
>>> +[Defines]
>>> +  INF_VERSION                    = 0x00010017
>>
>> Not 0019?
>>
>
>What can I say, I'm old school :-)
>
>On the one hand, I'm happy to change it, but on the other hand, I
>think it is good practice to expose the lowest version number you are
>compatible with, in case anyone wants to backport this.

But the .INF spec very clearly says:
" All new EDK II INF files must include one of the following statements: INF_VERSION = 0x00010019 or INF_VERSION = 1.25 in this section, where the number varies according to the release of this specification."

>_______________________________________________
>edk2-devel mailing list
>edk2-devel@lists.01.org
>https://lists.01.org/mailman/listinfo/edk2-devel
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.


^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2016-11-07 14:54 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-10-31 18:13 [PATCH 0/5] EmbeddedPkg: generic support for reusing PCI drivers for platform devices Ard Biesheuvel
2016-10-31 18:13 ` [PATCH 1/5] EmbeddedPkg: introduce platform PCI I/O protocol Ard Biesheuvel
2016-11-01 21:54   ` Leif Lindholm
2016-11-02 13:29     ` Ard Biesheuvel
2016-11-02 15:42       ` Leif Lindholm
2016-10-31 18:13 ` [PATCH 2/5] EmbeddedPkg: introduce platform PCI I/O registration library Ard Biesheuvel
2016-11-01 21:57   ` Leif Lindholm
2016-11-02 13:30     ` Ard Biesheuvel
2016-11-02 15:39       ` Leif Lindholm
2016-11-07 14:54       ` Evan Lloyd
2016-10-31 18:13 ` [PATCH 3/5] EmbeddedPkg: implement generic platform PCI I/O driver Ard Biesheuvel
2016-11-01 22:22   ` Leif Lindholm
2016-11-02 13:39     ` Ard Biesheuvel
2016-11-02 16:05       ` Leif Lindholm
2016-10-31 18:13 ` [PATCH 4/5] ArmPkg/CpuDxe: set DmaBufferAlignment according to CWG Ard Biesheuvel
2016-11-01 22:32   ` Leif Lindholm
2016-11-02 13:40     ` Ard Biesheuvel
2016-11-02 16:10       ` Leif Lindholm
2016-11-02 16:17         ` Ard Biesheuvel
2016-11-02 16:21           ` Leif Lindholm
2016-11-02 16:23             ` Ard Biesheuvel
2016-10-31 18:13 ` [PATCH 5/5] EmbeddedPkg/PlatformPciIoDxe: add support for non-coherent DMA Ard Biesheuvel
2016-11-01 22:43   ` Leif Lindholm
2016-11-02 13:43     ` Ard Biesheuvel
2016-11-02 16:17       ` Leif Lindholm
2016-11-01 21:45 ` [PATCH 0/5] EmbeddedPkg: generic support for reusing PCI drivers for platform devices Leif Lindholm

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox