diff mbox series

[edk2,edk2-platforms,v2] Silicon/Socionext/SynQuacer: implement menu option to set max PCIe speed

Message ID 20180125153119.27596-1-ard.biesheuvel@linaro.org
State Superseded
Headers show
Series [edk2,edk2-platforms,v2] Silicon/Socionext/SynQuacer: implement menu option to set max PCIe speed | expand

Commit Message

Ard Biesheuvel Jan. 25, 2018, 3:31 p.m. UTC
Add menu options to the SynQuacer Platform menu screen to limit the
maximum PCIe link speed for each slot individually. This may be useful
to work around potential PCIe issues.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

---
v2:
Make the speed limit per-slot instead of per-RC. That does make this
implementation more specific to DeveloperBox than it was before, but
given the special knowledge about the on-board ASM1184e switch and the
need for enabling spread-spectrum on the ASM1061, we're already past the
point where PlatformDxe is a generic SynQuacer driver, and we may need to
move it into Platform/Socionext (and clone it for each platform) in the
future.

 Platform/Socionext/DeveloperBox/DeveloperBox.dsc                                                     |   2 +
 Platform/Socionext/SynQuacerEvalBoard/SynQuacerEvalBoard.dsc                                         |   2 +
 Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c                                                |  24 ++++-
 Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.c                                        | 107 ++++++++++++++++++++
 Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.h                                        |  13 +++
 Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.inf                                      |  11 ++
 Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxeHii.uni                                   |  29 ++++++
 Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxeHii.vfr                                   |  69 +++++++++++++
 Silicon/Socionext/SynQuacer/Include/Guid/SynQuacerPlatformFormSet.h                                  |  23 +++++
 Silicon/Socionext/SynQuacer/Include/Platform/Pcie.h                                                  |   5 +
 Silicon/Socionext/SynQuacer/Include/Platform/VarStore.h                                              |  29 ++++++
 Silicon/Socionext/SynQuacer/Library/SynQuacerPciHostBridgeLib/SynQuacerPciHostBridgeLib.inf          |   2 +
 Silicon/Socionext/SynQuacer/Library/SynQuacerPciHostBridgeLib/SynQuacerPciHostBridgeLibConstructor.c |  35 ++++++-
 Silicon/Socionext/SynQuacer/SynQuacer.dec                                                            |   5 +
 14 files changed, 349 insertions(+), 7 deletions(-)

-- 
2.11.0

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Comments

Leif Lindholm Jan. 25, 2018, 5:04 p.m. UTC | #1
On Thu, Jan 25, 2018 at 03:31:19PM +0000, Ard Biesheuvel wrote:
> Add menu options to the SynQuacer Platform menu screen to limit the

> maximum PCIe link speed for each slot individually. This may be useful

> to work around potential PCIe issues.

> 

> Contributed-under: TianoCore Contribution Agreement 1.1

> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---

> v2:

> Make the speed limit per-slot instead of per-RC. That does make this

> implementation more specific to DeveloperBox than it was before, but

> given the special knowledge about the on-board ASM1184e switch and the

> need for enabling spread-spectrum on the ASM1061, we're already past the

> point where PlatformDxe is a generic SynQuacer driver, and we may need to

> move it into Platform/Socionext (and clone it for each platform) in the

> future.

> 

>  Platform/Socionext/DeveloperBox/DeveloperBox.dsc                                                     |   2 +

>  Platform/Socionext/SynQuacerEvalBoard/SynQuacerEvalBoard.dsc                                         |   2 +

>  Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c                                                |  24 ++++-

>  Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.c                                        | 107 ++++++++++++++++++++

>  Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.h                                        |  13 +++

>  Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.inf                                      |  11 ++

>  Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxeHii.uni                                   |  29 ++++++

>  Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxeHii.vfr                                   |  69 +++++++++++++

>  Silicon/Socionext/SynQuacer/Include/Guid/SynQuacerPlatformFormSet.h                                  |  23 +++++

>  Silicon/Socionext/SynQuacer/Include/Platform/Pcie.h                                                  |   5 +

>  Silicon/Socionext/SynQuacer/Include/Platform/VarStore.h                                              |  29 ++++++

>  Silicon/Socionext/SynQuacer/Library/SynQuacerPciHostBridgeLib/SynQuacerPciHostBridgeLib.inf          |   2 +

>  Silicon/Socionext/SynQuacer/Library/SynQuacerPciHostBridgeLib/SynQuacerPciHostBridgeLibConstructor.c |  35 ++++++-

>  Silicon/Socionext/SynQuacer/SynQuacer.dec                                                            |   5 +

>  14 files changed, 349 insertions(+), 7 deletions(-)

> 

> diff --git a/Platform/Socionext/DeveloperBox/DeveloperBox.dsc b/Platform/Socionext/DeveloperBox/DeveloperBox.dsc

> index 86685d1dec3b..2d46b4515749 100644

> --- a/Platform/Socionext/DeveloperBox/DeveloperBox.dsc

> +++ b/Platform/Socionext/DeveloperBox/DeveloperBox.dsc

> @@ -405,6 +405,8 @@ [PcdsDynamicExDefault.common.DEFAULT]

>  [PcdsDynamicHii]

>    gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|L"Timeout"|gEfiGlobalVariableGuid|0x0|30

>  

> +  gSynQuacerTokenSpaceGuid.PcdPlatformSettings|L"SynQuacerPlatformSettings"|gSynQuacerPlatformFormSetGuid|0x0|0x0|NV,BS

> +

>  [PcdsDynamicDefault]

>    gArmTokenSpaceGuid.PcdSystemMemoryBase|0x0000000000000000

>    gArmTokenSpaceGuid.PcdSystemMemorySize|0xFFFFFFFFFFFFFFFF

> diff --git a/Platform/Socionext/SynQuacerEvalBoard/SynQuacerEvalBoard.dsc b/Platform/Socionext/SynQuacerEvalBoard/SynQuacerEvalBoard.dsc

> index b4b9239143bc..263b6454ff72 100644

> --- a/Platform/Socionext/SynQuacerEvalBoard/SynQuacerEvalBoard.dsc

> +++ b/Platform/Socionext/SynQuacerEvalBoard/SynQuacerEvalBoard.dsc

> @@ -397,6 +397,8 @@ [PcdsDynamicExDefault.common.DEFAULT]

>  [PcdsDynamicHii]

>    gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|L"Timeout"|gEfiGlobalVariableGuid|0x0|30

>  

> +  gSynQuacerTokenSpaceGuid.PcdPlatformSettings|L"SynQuacerPlatformSettings"|gSynQuacerPlatformFormSetGuid|0x0|0x0|NV,BS

> +

>  [PcdsDynamicDefault]

>    gArmTokenSpaceGuid.PcdSystemMemoryBase|0x0000000000000000

>    gArmTokenSpaceGuid.PcdSystemMemorySize|0xFFFFFFFFFFFFFFFF

> diff --git a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c

> index 9af3dd942cdd..4e1b4a6f9080 100644

> --- a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c

> +++ b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c

> @@ -45,6 +45,11 @@ RetrainAsm1184eDownstreamPort (

>    EFI_STATUS                Status;

>    PCIE_CAP                  Cap;

>    PCI_REG_PCIE_LINK_CONTROL LinkControl;

> +  UINTN                     SegmentNumber;

> +  UINTN                     BusNumber;

> +  UINTN                     DeviceNumber;

> +  UINTN                     FunctionNumber;

> +  UINTN                     Location;

>  

>    //

>    // The upstream and downstream ports share the same PID/VID, so check

> @@ -64,8 +69,23 @@ RetrainAsm1184eDownstreamPort (

>      return;

>    }

>  

> -  DEBUG ((DEBUG_INFO, "%a: retraining ASM118x downstream PCIe port\n",

> -    __FUNCTION__));

> +  Status = PciIo->GetLocation (PciIo, &SegmentNumber, &BusNumber, &DeviceNumber,

> +                    &FunctionNumber);

> +  ASSERT_EFI_ERROR (Status);

> +

> +  Location = SYNQUACER_PCI_LOCATION (SegmentNumber, BusNumber, DeviceNumber);

> +  if ((Location == SYNQUACER_PCI_SLOT0_LOCATION &&

> +       mHiiSettings->PcieSlot0MaxSpeed == PCIE_MAX_SPEED_GEN1) ||

> +      (Location == SYNQUACER_PCI_SLOT1_LOCATION &&

> +       mHiiSettings->PcieSlot1MaxSpeed == PCIE_MAX_SPEED_GEN1) ||

> +      (Location == SYNQUACER_PCI_SLOT2_LOCATION &&

> +       mHiiSettings->PcieSlot2MaxSpeed == PCIE_MAX_SPEED_GEN1)) {


Having discussed with Ard on IRC, this looks to me like exactly the
kind of thing you would want to be able to have a static inline
function in a header file, due to it being a SoC-specific operation
also needed in a different module further down in this patch. (And
turning it into a library would be substantial overkill.)

Since that would currently be banned by the coding style, I have asked
Ard to replace this pattern with a switch statement instead, to
improve readability.

But I think I will bring this topic up for discussion at the spring
plugfest.

/
    Leif
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
diff mbox series

Patch

diff --git a/Platform/Socionext/DeveloperBox/DeveloperBox.dsc b/Platform/Socionext/DeveloperBox/DeveloperBox.dsc
index 86685d1dec3b..2d46b4515749 100644
--- a/Platform/Socionext/DeveloperBox/DeveloperBox.dsc
+++ b/Platform/Socionext/DeveloperBox/DeveloperBox.dsc
@@ -405,6 +405,8 @@  [PcdsDynamicExDefault.common.DEFAULT]
 [PcdsDynamicHii]
   gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|L"Timeout"|gEfiGlobalVariableGuid|0x0|30
 
+  gSynQuacerTokenSpaceGuid.PcdPlatformSettings|L"SynQuacerPlatformSettings"|gSynQuacerPlatformFormSetGuid|0x0|0x0|NV,BS
+
 [PcdsDynamicDefault]
   gArmTokenSpaceGuid.PcdSystemMemoryBase|0x0000000000000000
   gArmTokenSpaceGuid.PcdSystemMemorySize|0xFFFFFFFFFFFFFFFF
diff --git a/Platform/Socionext/SynQuacerEvalBoard/SynQuacerEvalBoard.dsc b/Platform/Socionext/SynQuacerEvalBoard/SynQuacerEvalBoard.dsc
index b4b9239143bc..263b6454ff72 100644
--- a/Platform/Socionext/SynQuacerEvalBoard/SynQuacerEvalBoard.dsc
+++ b/Platform/Socionext/SynQuacerEvalBoard/SynQuacerEvalBoard.dsc
@@ -397,6 +397,8 @@  [PcdsDynamicExDefault.common.DEFAULT]
 [PcdsDynamicHii]
   gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|L"Timeout"|gEfiGlobalVariableGuid|0x0|30
 
+  gSynQuacerTokenSpaceGuid.PcdPlatformSettings|L"SynQuacerPlatformSettings"|gSynQuacerPlatformFormSetGuid|0x0|0x0|NV,BS
+
 [PcdsDynamicDefault]
   gArmTokenSpaceGuid.PcdSystemMemoryBase|0x0000000000000000
   gArmTokenSpaceGuid.PcdSystemMemorySize|0xFFFFFFFFFFFFFFFF
diff --git a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c
index 9af3dd942cdd..4e1b4a6f9080 100644
--- a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c
+++ b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c
@@ -45,6 +45,11 @@  RetrainAsm1184eDownstreamPort (
   EFI_STATUS                Status;
   PCIE_CAP                  Cap;
   PCI_REG_PCIE_LINK_CONTROL LinkControl;
+  UINTN                     SegmentNumber;
+  UINTN                     BusNumber;
+  UINTN                     DeviceNumber;
+  UINTN                     FunctionNumber;
+  UINTN                     Location;
 
   //
   // The upstream and downstream ports share the same PID/VID, so check
@@ -64,8 +69,23 @@  RetrainAsm1184eDownstreamPort (
     return;
   }
 
-  DEBUG ((DEBUG_INFO, "%a: retraining ASM118x downstream PCIe port\n",
-    __FUNCTION__));
+  Status = PciIo->GetLocation (PciIo, &SegmentNumber, &BusNumber, &DeviceNumber,
+                    &FunctionNumber);
+  ASSERT_EFI_ERROR (Status);
+
+  Location = SYNQUACER_PCI_LOCATION (SegmentNumber, BusNumber, DeviceNumber);
+  if ((Location == SYNQUACER_PCI_SLOT0_LOCATION &&
+       mHiiSettings->PcieSlot0MaxSpeed == PCIE_MAX_SPEED_GEN1) ||
+      (Location == SYNQUACER_PCI_SLOT1_LOCATION &&
+       mHiiSettings->PcieSlot1MaxSpeed == PCIE_MAX_SPEED_GEN1) ||
+      (Location == SYNQUACER_PCI_SLOT2_LOCATION &&
+       mHiiSettings->PcieSlot2MaxSpeed == PCIE_MAX_SPEED_GEN1)) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "%a: retraining ASM118x downstream PCIe port at %04x:%02x:%02x to Gen2\n",
+    __FUNCTION__, SegmentNumber, BusNumber, DeviceNumber));
 
   Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16,
                         ASM118x_PCIE_LINK_CONTROL_OFFSET, 1, &LinkControl);
diff --git a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.c b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.c
index 91c1b66ea1f8..b60607d05861 100644
--- a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.c
+++ b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.c
@@ -14,6 +14,36 @@ 
 
 #include "PlatformDxe.h"
 
+UINT64                            mHiiSettingsVal;
+SYNQUACER_PLATFORM_VARSTORE_DATA  *mHiiSettings;
+
+typedef struct {
+  VENDOR_DEVICE_PATH              VendorDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL        End;
+} HII_VENDOR_DEVICE_PATH;
+
+STATIC HII_VENDOR_DEVICE_PATH     mPlatformDxeHiiVendorDevicePath = {
+  {
+    {
+      HARDWARE_DEVICE_PATH,
+      HW_VENDOR_DP,
+      {
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+      }
+    },
+    SYNQUACER_PLATFORM_FORMSET_GUID
+  },
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    {
+      (UINT8) (END_DEVICE_PATH_LENGTH),
+      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+    }
+  }
+};
+
 STATIC EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR mNetsecDesc[] = {
   {
     ACPI_ADDRESS_SPACE_DESCRIPTOR,                    // Desc
@@ -144,6 +174,77 @@  SmmuEnableCoherentDma (
     SMMU_SCR0_SHCFG_INNER | SMMU_SCR0_MTCFG | SMMU_SCR0_MEMATTR_INNER_OUTER_WB);
 }
 
+STATIC
+EFI_STATUS
+InstallHiiPages (
+  VOID
+  )
+{
+  EFI_STATUS                      Status;
+  EFI_HII_HANDLE                  HiiHandle;
+  EFI_HANDLE                      DriverHandle;
+
+  DriverHandle = NULL;
+  Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle,
+                  &gEfiDevicePathProtocolGuid,
+                  &mPlatformDxeHiiVendorDevicePath,
+                  NULL);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  HiiHandle = HiiAddPackages (&gSynQuacerPlatformFormSetGuid,
+                              DriverHandle,
+                              PlatformDxeStrings,
+                              PlatformDxeHiiBin,
+                              NULL);
+
+  if (HiiHandle == NULL) {
+    gBS->UninstallMultipleProtocolInterfaces (DriverHandle,
+           &gEfiDevicePathProtocolGuid,
+           &mPlatformDxeHiiVendorDevicePath,
+           NULL);
+    return EFI_OUT_OF_RESOURCES;
+  }
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EnableSettingsForm (
+  VOID
+  )
+{
+  EFI_STATUS                        Status;
+  UINTN                             VarSize;
+  SYNQUACER_PLATFORM_VARSTORE_DATA  Settings;
+
+  VarSize = sizeof (Settings);
+  Status = gRT->GetVariable (SYNQUACER_PLATFORM_VARIABLE_NAME,
+                  &gSynQuacerPlatformFormSetGuid, NULL, &VarSize, &Settings);
+  if (Status == EFI_NOT_FOUND) {
+    //
+    // Variable does not exist yet - create it
+    //
+    SetMem (&Settings, sizeof (Settings), 0);
+    Status = gRT->SetVariable (SYNQUACER_PLATFORM_VARIABLE_NAME,
+                    &gSynQuacerPlatformFormSetGuid,
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                    sizeof (Settings), &Settings);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_WARN, "%a: EfiSetVariable failed - %r\n", __FUNCTION__,
+        Status));
+      return Status;
+    }
+  } else if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_WARN, "%a: EfiGetVariable failed - %r\n", __FUNCTION__,
+      Status));
+    return Status;
+  }
+
+  return InstallHiiPages ();
+}
+
 EFI_STATUS
 EFIAPI
 PlatformDxeEntryPoint (
@@ -156,6 +257,9 @@  PlatformDxeEntryPoint (
   UINTN                           DtbSize;
   EFI_HANDLE                      Handle;
 
+  mHiiSettingsVal = PcdGet64 (PcdPlatformSettings);
+  mHiiSettings = (SYNQUACER_PLATFORM_VARSTORE_DATA *)&mHiiSettingsVal;
+
   Dtb = NULL;
   Status = DtPlatformLoadDtb (&Dtb, &DtbSize);
   if (!EFI_ERROR (Status)) {
@@ -197,5 +301,8 @@  PlatformDxeEntryPoint (
   Status = RegisterPcieNotifier ();
   ASSERT_EFI_ERROR (Status);
 
+  Status = EnableSettingsForm ();
+  ASSERT_EFI_ERROR (Status);
+
   return EFI_SUCCESS;
 }
diff --git a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.h b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.h
index d1dad2a3eace..53898b5828d4 100644
--- a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.h
+++ b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.h
@@ -16,18 +16,31 @@ 
 #define __PLATFORM_DXE_H__
 
 #include <PiDxe.h>
+#include <Guid/SynQuacerPlatformFormSet.h>
 #include <IndustryStandard/Pci.h>
 #include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
 #include <Library/DtPlatformDtbLoaderLib.h>
+#include <Library/HiiLib.h>
 #include <Library/IoLib.h>
 #include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
 #include <Platform/MemoryMap.h>
+#include <Platform/Pcie.h>
+#include <Platform/VarStore.h>
 #include <Protocol/NonDiscoverableDevice.h>
 #include <Protocol/PciIo.h>
 
+extern UINT8                             PlatformDxeHiiBin[];
+extern UINT8                             PlatformDxeStrings[];
+
+extern UINT64                            mHiiSettingsVal;
+extern SYNQUACER_PLATFORM_VARSTORE_DATA  *mHiiSettings;
+
 EFI_STATUS
 EFIAPI
 RegisterPcieNotifier (
diff --git a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.inf b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.inf
index f075957d7456..de21ba33df75 100644
--- a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.inf
+++ b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.inf
@@ -25,6 +25,8 @@  [Defines]
 [Sources]
   Pci.c
   PlatformDxe.c
+  PlatformDxeHii.uni
+  PlatformDxeHii.vfr
 
 [Packages]
   EmbeddedPkg/EmbeddedPkg.dec
@@ -37,18 +39,24 @@  [Packages]
 [LibraryClasses]
   BaseMemoryLib
   DebugLib
+  DevicePathLib
   DtPlatformDtbLoaderLib
+  HiiLib
   IoLib
   MemoryAllocationLib
+  PcdLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
   UefiLib
+  UefiRuntimeServicesTableLib
 
 [Guids]
+  gEfiHiiPlatformSetupFormsetGuid
   gFdtTableGuid
   gNetsecNonDiscoverableDeviceGuid
   gSynQuacerNonDiscoverableI2cMasterGuid
   gSynQuacerNonDiscoverableRuntimeI2cMasterGuid
+  gSynQuacerPlatformFormSetGuid
 
 [Protocols]
   gEdkiiNonDiscoverableDeviceProtocolGuid         ## PRODUCES
@@ -59,5 +67,8 @@  [FixedPcd]
   gSynQuacerTokenSpaceGuid.PcdNetsecEepromBase
   gSynQuacerTokenSpaceGuid.PcdNetsecPhyAddress
 
+[Pcd]
+  gSynQuacerTokenSpaceGuid.PcdPlatformSettings
+
 [Depex]
   TRUE
diff --git a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxeHii.uni b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxeHii.uni
new file mode 100644
index 000000000000..b274d12ed2c6
--- /dev/null
+++ b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxeHii.uni
@@ -0,0 +1,29 @@ 
+/** @file
+*
+*  Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+*
+*  This program and the accompanying materials are licensed and made available
+*  under the terms and conditions of the BSD License which accompanies this
+*  distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#langdef en-US  "English"
+
+#string STR_FORM_SET_TITLE             #language en-US "SynQuacer Platform Settings"
+#string STR_FORM_SET_TITLE_HELP        #language en-US "Press <Enter> to set platform specific options."
+
+#string STR_MAIN_FORM_TITLE            #language en-US "SynQuacer Platform Settings"
+#string STR_NULL_STRING                #language en-US ""
+
+#string STR_PCIE0_MAX_SPEED_PROMPT     #language en-US "PCIe x4 slot max speed"
+#string STR_PCIE1_MAX_SPEED_PROMPT     #language en-US "PCIe x1 slot 1 max speed"
+#string STR_PCIE2_MAX_SPEED_PROMPT     #language en-US "PCIe x1 slot 2 max speed"
+#string STR_PCIE_MAX_SPEED_HELP        #language en-US "The maximum speed the PCIe downstream port is allowed to negotiate"
+
+#string STR_PCIE_MAX_SPEED_UNLIMITED   #language en-US "Unlimited"
+#string STR_PCIE_MAX_SPEED_GEN1        #language en-US "Gen1 (2.5 GT/s)"
diff --git a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxeHii.vfr b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxeHii.vfr
new file mode 100644
index 000000000000..52f554b61e3c
--- /dev/null
+++ b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxeHii.vfr
@@ -0,0 +1,69 @@ 
+/** @file
+*
+*  Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+*
+*  This program and the accompanying materials are licensed and made available
+*  under the terms and conditions of the BSD License which accompanies this
+*  distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/SynQuacerPlatformFormSet.h>
+#include <Platform/VarStore.h>
+
+//
+// EFI Variable attributes
+//
+#define EFI_VARIABLE_NON_VOLATILE       0x00000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
+#define EFI_VARIABLE_RUNTIME_ACCESS     0x00000004
+#define EFI_VARIABLE_READ_ONLY          0x00000008
+
+formset
+  guid      = SYNQUACER_PLATFORM_FORMSET_GUID,
+  title     = STRING_TOKEN(STR_FORM_SET_TITLE),
+  help      = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
+  classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+  efivarstore SYNQUACER_PLATFORM_VARSTORE_DATA,
+    attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,  // EFI variable attributes
+    name  = SynQuacerPlatformSettings,
+    guid  = SYNQUACER_PLATFORM_FORMSET_GUID;
+
+  form formid = 0x1000,
+    title  = STRING_TOKEN(STR_MAIN_FORM_TITLE);
+
+    oneof varid = SynQuacerPlatformSettings.PcieSlot0MaxSpeed,
+        prompt      = STRING_TOKEN(STR_PCIE0_MAX_SPEED_PROMPT),
+        help        = STRING_TOKEN(STR_PCIE_MAX_SPEED_HELP),
+        flags       = NUMERIC_SIZE_1 | INTERACTIVE | RESET_REQUIRED,
+        option text = STRING_TOKEN(STR_PCIE_MAX_SPEED_UNLIMITED), value = PCIE_MAX_SPEED_UNLIMITED, flags = DEFAULT;
+        option text = STRING_TOKEN(STR_PCIE_MAX_SPEED_GEN1), value = PCIE_MAX_SPEED_GEN1, flags = 0;
+    endoneof;
+
+    oneof varid = SynQuacerPlatformSettings.PcieSlot1MaxSpeed,
+        prompt      = STRING_TOKEN(STR_PCIE1_MAX_SPEED_PROMPT),
+        help        = STRING_TOKEN(STR_PCIE_MAX_SPEED_HELP),
+        flags       = NUMERIC_SIZE_1 | INTERACTIVE | RESET_REQUIRED,
+        option text = STRING_TOKEN(STR_PCIE_MAX_SPEED_UNLIMITED), value = PCIE_MAX_SPEED_UNLIMITED, flags = DEFAULT;
+        option text = STRING_TOKEN(STR_PCIE_MAX_SPEED_GEN1), value = PCIE_MAX_SPEED_GEN1, flags = 0;
+    endoneof;
+
+    oneof varid = SynQuacerPlatformSettings.PcieSlot2MaxSpeed,
+        prompt      = STRING_TOKEN(STR_PCIE2_MAX_SPEED_PROMPT),
+        help        = STRING_TOKEN(STR_PCIE_MAX_SPEED_HELP),
+        flags       = NUMERIC_SIZE_1 | INTERACTIVE | RESET_REQUIRED,
+        option text = STRING_TOKEN(STR_PCIE_MAX_SPEED_UNLIMITED), value = PCIE_MAX_SPEED_UNLIMITED, flags = DEFAULT;
+        option text = STRING_TOKEN(STR_PCIE_MAX_SPEED_GEN1), value = PCIE_MAX_SPEED_GEN1, flags = 0;
+    endoneof;
+
+    subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+  endform;
+
+endformset;
diff --git a/Silicon/Socionext/SynQuacer/Include/Guid/SynQuacerPlatformFormSet.h b/Silicon/Socionext/SynQuacer/Include/Guid/SynQuacerPlatformFormSet.h
new file mode 100644
index 000000000000..9a70bb873056
--- /dev/null
+++ b/Silicon/Socionext/SynQuacer/Include/Guid/SynQuacerPlatformFormSet.h
@@ -0,0 +1,23 @@ 
+/** @file
+*
+*  Copyright (c) 2017, Linaro Limited. All rights reserved.
+*
+*  This program and the accompanying materials are licensed and made available
+*  under the terms and conditions of the BSD License which accompanies this
+*  distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef __SYNQUACER_PLATFORM_FORMSET_H__
+#define __SYNQUACER_PLATFORM_FORMSET_H__
+
+#define SYNQUACER_PLATFORM_FORMSET_GUID  \
+  { 0xe9cd576a, 0xaf9a, 0x4d41, { 0xbf, 0x1a, 0x29, 0xe1, 0xbc, 0x99, 0x99, 0x54 } }
+
+extern EFI_GUID gSynQuacerPlatformFormSetGuid;
+
+#endif
diff --git a/Silicon/Socionext/SynQuacer/Include/Platform/Pcie.h b/Silicon/Socionext/SynQuacer/Include/Platform/Pcie.h
index d2a3f9acbf49..ee2357be9a06 100644
--- a/Silicon/Socionext/SynQuacer/Include/Platform/Pcie.h
+++ b/Silicon/Socionext/SynQuacer/Include/Platform/Pcie.h
@@ -60,4 +60,9 @@ 
 #define SYNQUACER_PCI_SEG1_MMIO64_MAX       0x3fffffffff
 #define SYNQUACER_PCI_SEG1_MMIO64_SIZE      0x100000000
 
+#define SYNQUACER_PCI_LOCATION(s,b,d)       (((s) << 16) | ((b) << 8) | (d))
+#define SYNQUACER_PCI_SLOT0_LOCATION        SYNQUACER_PCI_LOCATION(1, 0, 0)
+#define SYNQUACER_PCI_SLOT1_LOCATION        SYNQUACER_PCI_LOCATION(0, 1, 7)
+#define SYNQUACER_PCI_SLOT2_LOCATION        SYNQUACER_PCI_LOCATION(0, 1, 3)
+
 #endif
diff --git a/Silicon/Socionext/SynQuacer/Include/Platform/VarStore.h b/Silicon/Socionext/SynQuacer/Include/Platform/VarStore.h
new file mode 100644
index 000000000000..5944613e7465
--- /dev/null
+++ b/Silicon/Socionext/SynQuacer/Include/Platform/VarStore.h
@@ -0,0 +1,29 @@ 
+/** @file
+
+  Copyright (c) 2017, 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 __VARSTORE_H__
+#define __VARSTORE_H__
+
+#define SYNQUACER_PLATFORM_VARIABLE_NAME  L"SynQuacerPlatformSettings"
+
+#define PCIE_MAX_SPEED_UNLIMITED          0x0
+#define PCIE_MAX_SPEED_GEN1               0x1
+
+typedef struct {
+  UINT8         PcieSlot0MaxSpeed;
+  UINT8         PcieSlot1MaxSpeed;
+  UINT8         PcieSlot2MaxSpeed;
+  UINT8         Reserved[5];
+} SYNQUACER_PLATFORM_VARSTORE_DATA;
+
+#endif
diff --git a/Silicon/Socionext/SynQuacer/Library/SynQuacerPciHostBridgeLib/SynQuacerPciHostBridgeLib.inf b/Silicon/Socionext/SynQuacer/Library/SynQuacerPciHostBridgeLib/SynQuacerPciHostBridgeLib.inf
index 27fcba034418..e475529eaf58 100644
--- a/Silicon/Socionext/SynQuacer/Library/SynQuacerPciHostBridgeLib/SynQuacerPciHostBridgeLib.inf
+++ b/Silicon/Socionext/SynQuacer/Library/SynQuacerPciHostBridgeLib/SynQuacerPciHostBridgeLib.inf
@@ -45,6 +45,7 @@  [LibraryClasses]
   DebugLib
   DevicePathLib
   MemoryAllocationLib
+  PcdLib
   UefiBootServicesTableLib
 
 [FixedPcd]
@@ -52,3 +53,4 @@  [FixedPcd]
 
 [Pcd]
   gSynQuacerTokenSpaceGuid.PcdPcieEnableMask
+  gSynQuacerTokenSpaceGuid.PcdPlatformSettings
diff --git a/Silicon/Socionext/SynQuacer/Library/SynQuacerPciHostBridgeLib/SynQuacerPciHostBridgeLibConstructor.c b/Silicon/Socionext/SynQuacer/Library/SynQuacerPciHostBridgeLib/SynQuacerPciHostBridgeLibConstructor.c
index bea40e3dcfe8..976963026f7b 100644
--- a/Silicon/Socionext/SynQuacer/Library/SynQuacerPciHostBridgeLib/SynQuacerPciHostBridgeLibConstructor.c
+++ b/Silicon/Socionext/SynQuacer/Library/SynQuacerPciHostBridgeLib/SynQuacerPciHostBridgeLibConstructor.c
@@ -18,9 +18,11 @@ 
 #include <Library/ArmLib.h>
 #include <Library/DebugLib.h>
 #include <Library/IoLib.h>
+#include <Library/PcdLib.h>
 #include <Library/PciHostBridgeLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Platform/Pcie.h>
+#include <Platform/VarStore.h>
 #include <Protocol/PciHostBridgeResourceAllocation.h>
 
 #define IATU_VIEWPORT_OFF                                   0x900
@@ -268,7 +270,8 @@  PciInitControllerPost (
   IN  EFI_PHYSICAL_ADDRESS    DbiBase,
   IN  EFI_PHYSICAL_ADDRESS    ConfigBase,
   IN  EFI_PHYSICAL_ADDRESS    IoMemBase,
-  IN  CONST PCI_ROOT_BRIDGE   *RootBridge
+  IN  CONST PCI_ROOT_BRIDGE   *RootBridge,
+  IN  BOOLEAN                 EnableGen2Speed
   )
 {
   // 4: Set Bifurcation  1=disable  4=able
@@ -312,8 +315,10 @@  PciInitControllerPost (
                                           EFI_PCI_COMMAND_MEMORY_SPACE |
                                           EFI_PCI_COMMAND_BUS_MASTER);
 
-  // Force link speed change to Gen2 at link up
-  MmioOr32 (DbiBase + GEN2_CONTROL_OFF, DIRECT_SPEED_CHANGE);
+  if (EnableGen2Speed) {
+    // Force link speed change to Gen2 at link up
+    MmioOr32 (DbiBase + GEN2_CONTROL_OFF, DIRECT_SPEED_CHANGE);
+  }
 
   // Region 0: MMIO32 range
   ConfigureWindow (DbiBase, 0,
@@ -392,7 +397,14 @@  SynQuacerPciHostBridgeLibConstructor (
   IN EFI_SYSTEM_TABLE *SystemTable
   )
 {
-  UINTN               Idx;
+  UINTN                             Idx;
+  UINT64                            SettingsVal;
+  SYNQUACER_PLATFORM_VARSTORE_DATA  *Settings;
+  BOOLEAN                           EnableGen2Speed;
+  UINTN                             Location;
+
+  SettingsVal = PcdGet64 (PcdPlatformSettings);
+  Settings = (SYNQUACER_PLATFORM_VARSTORE_DATA *)&SettingsVal;
 
   for (Idx = 0; Idx < ARRAY_SIZE (mBaseAddresses); Idx++) {
     if (PcdGet8 (PcdPcieEnableMask) & (1 << Idx)) {
@@ -409,12 +421,25 @@  SynQuacerPciHostBridgeLibConstructor (
   gBS->Stall (150 * 1000);
 
   for (Idx = 0; Idx < ARRAY_SIZE (mBaseAddresses); Idx++) {
+    Location = SYNQUACER_PCI_LOCATION (Idx, 0, 0);
+    if ((Location == SYNQUACER_PCI_SLOT0_LOCATION &&
+         Settings->PcieSlot0MaxSpeed == PCIE_MAX_SPEED_GEN1) ||
+        (Location == SYNQUACER_PCI_SLOT1_LOCATION &&
+         Settings->PcieSlot1MaxSpeed == PCIE_MAX_SPEED_GEN1) ||
+        (Location == SYNQUACER_PCI_SLOT2_LOCATION &&
+         Settings->PcieSlot2MaxSpeed == PCIE_MAX_SPEED_GEN1)) {
+      EnableGen2Speed = FALSE;
+    } else {
+      EnableGen2Speed = TRUE;
+    }
+
     if (PcdGet8 (PcdPcieEnableMask) & (1 << Idx)) {
       PciInitControllerPost (mBaseAddresses[Idx].ExsBase,
                              mBaseAddresses[Idx].DbiBase,
                              mBaseAddresses[Idx].ConfigBase,
                              mBaseAddresses[Idx].IoMemBase,
-                             &mPciRootBridges[Idx]);
+                             &mPciRootBridges[Idx],
+                             EnableGen2Speed);
     }
   }
 
diff --git a/Silicon/Socionext/SynQuacer/SynQuacer.dec b/Silicon/Socionext/SynQuacer/SynQuacer.dec
index 76529e3c2164..eb4fc4ace2f7 100644
--- a/Silicon/Socionext/SynQuacer/SynQuacer.dec
+++ b/Silicon/Socionext/SynQuacer/SynQuacer.dec
@@ -27,6 +27,8 @@  [Guids]
 
   gSynQuacerPlatformDxeFileGuid = { 0xac422cc1, 0xd916, 0x489a, { 0xb1, 0x65, 0x53, 0x6f, 0xdf, 0xc6, 0x33, 0xc2 } }
 
+  gSynQuacerPlatformFormSetGuid = { 0xe9cd576a, 0xaf9a, 0x4d41, { 0xbf, 0x1a, 0x29, 0xe1, 0xbc, 0x99, 0x99, 0x54 } }
+
 [Ppis]
   gSynQuacerDramInfoPpiGuid = { 0x3e1d7356, 0xdda4, 0x4b1a, { 0x93, 0x46, 0xbf, 0x89, 0x1c, 0x86, 0x46, 0xcc } }
 
@@ -45,3 +47,6 @@  [PcdsFixedAtBuild]
 [PcdsPatchableInModule, PcdsDynamic]
   # Enable both RC #0 and RC #1 by default
   gSynQuacerTokenSpaceGuid.PcdPcieEnableMask|0x3|UINT8|0x00000007
+
+[PcdsDynamic]
+  gSynQuacerTokenSpaceGuid.PcdPlatformSettings|0x0|UINT64|0x00000008