Skip to content

Commit

Permalink
PciBusDxe: New PCI Express feature Relax Ordering
Browse files Browse the repository at this point in the history
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2313

The code changes are made to enable the configuration of PCI Express
feature Relax Ordering (OR), that enables the PCI function to initiate
requests if it does not require strong write ordering for its transact-
ions; as per the PCI Express Base Specification 4 Revision 1.

The code changes are made to configure only those PCI devices which are
requested by platform for override, through the new PCI Express Platform
protocol interface for device-specific policies.

Signed-off-by: Ashraf Javeed <ashraf.javeed@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
  • Loading branch information
ashrafj committed Feb 7, 2020
1 parent 91e85bd commit 27d11f3
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 1 deletion.
4 changes: 4 additions & 0 deletions MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,12 @@ struct _PCI_IO_DEVICE {
// This field is used to support this case.
//
UINT16 BridgeIoAlignment;
//
// PCI Express features setup flags
//
UINT8 SetupMPS;
UINT8 SetupMRRS;
PCI_FEATURE_POLICY SetupRO;
};

#define PCI_IO_DEVICE_FROM_PCI_IO_THIS(a) \
Expand Down
70 changes: 70 additions & 0 deletions MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.c
Original file line number Diff line number Diff line change
Expand Up @@ -381,3 +381,73 @@ ProgramMaxReadReqSize (
return Status;
}

/**
Overrides the PCI Device Control register Relax Order register field; if
the hardware value is different than the intended value.
@param PciDevice A pointer to the PCI_IO_DEVICE instance.
@retval EFI_SUCCESS The data was read from or written to the PCI device.
@retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
valid for the PCI configuration header of the PCI controller.
@retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
**/
EFI_STATUS
ProgramRelaxOrder (
IN PCI_IO_DEVICE *PciDevice,
IN VOID *PciExFeatureConfiguration
)
{
PCI_REG_PCIE_DEVICE_CONTROL PcieDev;
UINT32 Offset;
EFI_STATUS Status;
EFI_TPL OldTpl;

PcieDev.Uint16 = 0;
Offset = PciDevice->PciExpressCapabilityOffset +
OFFSET_OF (PCI_CAPABILITY_PCIEXP, DeviceControl);
Status = PciDevice->PciIo.Pci.Read (
&PciDevice->PciIo,
EfiPciIoWidthUint16,
Offset,
1,
&PcieDev.Uint16
);
ASSERT (Status == EFI_SUCCESS);

if (PciDevice->SetupRO.Override
&& PcieDev.Bits.RelaxedOrdering != PciDevice->SetupRO.Act
) {
PcieDev.Bits.RelaxedOrdering = PciDevice->SetupRO.Act;
DEBUG (( DEBUG_INFO, "RO=%d,", PciDevice->SetupRO.Act));

//
// Raise TPL to high level to disable timer interrupt while the write operation completes
//
OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);

Status = PciDevice->PciIo.Pci.Write (
&PciDevice->PciIo,
EfiPciIoWidthUint16,
Offset,
1,
&PcieDev.Uint16
);
//
// Restore TPL to its original level
//
gBS->RestoreTPL (OldTpl);

if (!EFI_ERROR(Status)) {
PciDevice->PciExpressCapabilityStructure.DeviceControl.Uint16 = PcieDev.Uint16;
} else {
ReportPciWriteError (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, Offset);
}
} else {
DEBUG (( DEBUG_INFO, "No RO,", PciDevice->SetupRO.Act));
}

return Status;
}

18 changes: 18 additions & 0 deletions MdeModulePkg/Bus/Pci/PciBusDxe/PciExpressFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,22 @@ ProgramMaxReadReqSize (
IN VOID *PciExFeatureConfiguration
);

/**
Overrides the PCI Device Control register Relax Order register field; if
the hardware value is different than the intended value.
@param PciDevice A pointer to the PCI_IO_DEVICE instance.
@retval EFI_SUCCESS The data was read from or written to the PCI device.
@retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
valid for the PCI configuration header of the PCI controller.
@retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
**/
EFI_STATUS
ProgramRelaxOrder (
IN PCI_IO_DEVICE *PciDevice,
IN VOID *PciExFeatureConfiguration
);

#endif
5 changes: 4 additions & 1 deletion MdeModulePkg/Bus/Pci/PciBusDxe/PciFeatureSupport.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ EFI_PCI_EXPRESS_PLATFORM_POLICY mPciExpressPlatformPolicy = {
//
// support for PCI Express feature - Relax Order
//
FALSE,
TRUE,
//
// support for PCI Express feature - No-Snoop
//
Expand Down Expand Up @@ -113,6 +113,9 @@ PCI_EXPRESS_FEATURE_INITIALIZATION_POINT mPciExpressFeatureInitializationList[]
},
{
PciExpressFeatureProgramPhase, PciExpressMrrs, ProgramMaxReadReqSize
},
{
PciExpressFeatureProgramPhase, PciExpressRelaxOrder, ProgramRelaxOrder
}
};

Expand Down
61 changes: 61 additions & 0 deletions MdeModulePkg/Bus/Pci/PciBusDxe/PciPlatformSupport.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,45 @@ SetDevicePolicyPciExpressMrrs (
}
}

/**
Routine to set the device-specific policy for the PCI feature Relax Ordering
@param RelaxOrder value corresponding to data type EFI_PCI_EXPRESS_RELAX_ORDER
@param PciDevice A pointer to PCI_IO_DEVICE
**/
VOID
SetDevicePolicyPciExpressRo (
IN EFI_PCI_EXPRESS_RELAX_ORDER RelaxOrder,
OUT PCI_IO_DEVICE *PciDevice
)
{
//
// implementation specific rules for the usage of PCI_FEATURE_POLICY members
// exclusively for the PCI Feature Relax Ordering (RO)
//
// .Override = 0 to skip this PCI feature RO for the PCI device
// .Override = 1 to program this RO PCI feature
// .Act = 1 to enable the RO in the PCI device
// .Act = 0 to disable the RO in the PCI device
//
switch (RelaxOrder) {
case EFI_PCI_EXPRESS_RO_AUTO:
PciDevice->SetupRO.Override = 0;
break;
case EFI_PCI_EXPRESS_RO_DISABLE:
PciDevice->SetupRO.Override = 1;
PciDevice->SetupRO.Act = 0;
break;
case EFI_PCI_EXPRESS_RO_ENABLE:
PciDevice->SetupRO.Override = 1;
PciDevice->SetupRO.Act = 1;
break;
default:
PciDevice->SetupRO.Override = 0;
break;
}
}

/**
Generic routine to setup the PCI features as per its predetermined defaults.
**/
Expand All @@ -170,6 +209,8 @@ SetupDefaultPciExpressDevicePolicy (
PciDevice->SetupMRRS = EFI_PCI_EXPRESS_NOT_APPLICABLE;
}

PciDevice->SetupRO.Override = 0;

}

/**
Expand Down Expand Up @@ -259,6 +300,15 @@ GetPciExpressDevicePolicy (
} else {
PciDevice->SetupMRRS = EFI_PCI_EXPRESS_NOT_APPLICABLE;
}
//
// set device specific policy for Relax Ordering
//
if (mPciExpressPlatformPolicy.RelaxOrder) {
SetDevicePolicyPciExpressRo (PciExpressDevicePolicy.DeviceCtlRelaxOrder, PciDevice);
} else {
PciDevice->SetupRO.Override = 0;
}


DEBUG ((
DEBUG_INFO,
Expand Down Expand Up @@ -438,6 +488,17 @@ PciExpressPlatformNotifyDeviceState (
} else {
PciExDeviceConfiguration.DeviceCtlMRRS = EFI_PCI_EXPRESS_NOT_APPLICABLE;
}
//
// get the device-specific state for the PCIe Relax Order feature
//
if (mPciExpressPlatformPolicy.RelaxOrder) {
PciExDeviceConfiguration.DeviceCtlRelaxOrder = PciDevice->PciExpressCapabilityStructure.DeviceControl.Bits.RelaxedOrdering
? EFI_PCI_EXPRESS_RO_ENABLE
: EFI_PCI_EXPRESS_RO_DISABLE;
} else {
PciExDeviceConfiguration.DeviceCtlRelaxOrder = EFI_PCI_EXPRESS_NOT_APPLICABLE;
}


if (mPciExPlatformProtocol != NULL) {
return mPciExPlatformProtocol->NotifyDeviceState (
Expand Down

0 comments on commit 27d11f3

Please sign in to comment.