Adds support for CXL driver. The present solution supports -
Discovering PCIe device with CXL and DOE capbility.
Execute DOE operation to fetch CDAT structures, which holds
information about remote CXL Memory region and it's attributes.
Also installs a Protocol, which can be used by platform modules
to fetch the details about remote memory.
Signed-off-by: Sayanta Pattanayak <sayanta.pattanayak@...>
---
Platform/ARM/Drivers/CxlDxe/CxlDxe.dec | 21 +
Platform/ARM/Drivers/CxlDxe/CxlDxe.inf | 48 ++
Platform/ARM/Drivers/CxlDxe/CxlDxe.h | 156 ++++++
Platform/ARM/Include/Protocol/Cxl.h | 57 +++
Platform/ARM/Drivers/CxlDxe/CxlDxe.c | 530 ++++++++++++++++++++
5 files changed, 812 insertions(+)
diff --git a/Platform/ARM/Drivers/CxlDxe/CxlDxe.dec b/Platform/ARM/Driver=
s/CxlDxe/CxlDxe.dec
new file mode 100644
index 0000000000..d2ebc5ca61
--- /dev/null
+++ b/Platform/ARM/Drivers/CxlDxe/CxlDxe.dec
@@ -0,0 +1,21 @@
+#/** @file
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+ DEC_SPECIFICATION =3D 0x0001001B
+ PACKAGE_NAME =3D CxlDxe
+ PACKAGE_GUID =3D cbeba70a-4351-4ff6-a074-6854337b39b=
e
+ PACKAGE_VERSION =3D 0.1
+
+[Guids.common]
+ gArmRemoteCxlMemDescriptorGuid =3D { 0x29e54f5e, 0x365a, 0x4235, { 0xb=
a, 0x62, 0xc8, 0x32, 0xd7, 0x66, 0x08, 0x52 } }
+
+[Protocols]
+ gCxlPlatformProtocolGuid =3D { 0x88c7bb9c, 0x6175, 0x4bfb, { 0x96, 0x4=
0, 0xd2, 0x53, 0xd3, 0xd8, 0x7c, 0x17 } }
+
+[Includes.common]
+ Platform/ARM/Include
diff --git a/Platform/ARM/Drivers/CxlDxe/CxlDxe.inf b/Platform/ARM/Driver=
s/CxlDxe/CxlDxe.inf
new file mode 100644
index 0000000000..8bf130d1c5
--- /dev/null
+++ b/Platform/ARM/Drivers/CxlDxe/CxlDxe.inf
@@ -0,0 +1,48 @@
+## @file
+# Discovers CXL capable device and reads out device properties.
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION =3D 0x0001001B
+ BASE_NAME =3D CxlDxe
+ FILE_GUID =3D 29e54f5e-365a-4235-ba62-c832d766085=
2
+ MODULE_TYPE =3D DXE_DRIVER
+ VERSION_STRING =3D 1.0
+ ENTRY_POINT =3D CxlDxeEntryPoint
+
+[Sources.common]
+ CxlDxe.c
+
+[Guids]
+ gArmRemoteCxlMemDescriptorGuid
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ ArmPkg/ArmPkg.dec
+ Platform/ARM/ARM.dec
+ Platform/ARM/Drivers/CxlDxe/CxlDxe.dec
+
+[LibraryClasses]
+ ArmMmuLib
+ ArmLib
+ BaseLib
+ DebugLib
+ DevicePathLib
+ DxeServicesTableLib
+ HobLib
+ PcdLib
+ UefiDriverEntryPoint
+
+[Protocols]
+ gEfiPciIoProtocolGuid ##CONSUMES
+ gCxlPlatformProtocolGuid ## PRODUCES
+
+[FixedPcd]
+
+[Depex]
+ gEfiPciEnumerationCompleteProtocolGuid
diff --git a/Platform/ARM/Drivers/CxlDxe/CxlDxe.h b/Platform/ARM/Drivers/=
CxlDxe/CxlDxe.h
new file mode 100644
index 0000000000..58e143c9bd
--- /dev/null
+++ b/Platform/ARM/Drivers/CxlDxe/CxlDxe.h
@@ -0,0 +1,156 @@
+/** @file
+ CXL driver file.
+
+ Defines CXL specific structures and macros.
+
+ Copyright (c) 2022, Arm Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Specification Reference:
+ - CXL Specificiation Revision 3.0, Version 0.7
+**/
+
+#define PCIE_EXTENDED_CAP_OFFSET 0x100
+#define PCIE_EXTENDED_CAP_ID_MASK 0xFFFF
+#define PCIE_EXTENDED_NEXT_CAP_OFFSET_MASK 0xFFF
+#define PCIE_EXTENDED_NEXT_CAP_OFFSET_SHIFT 20
+
+#define PCIE_EXT_CAP_DOE_ID 0x2E
+
+#define PCIE_EXTENDED_CAP_NEXT(n) ((n)>>(PCIE_EXTENDED_NEXT_CAP_OFFSET_=
SHIFT))
+#define IS_CXL_DVSEC(n) (((n)&(0xFFFF)) =3D=3D 0x1E98)
+
+#define DOE_DATA_OBJECT_VID 0x0000ffff
+#define DOE_DATA_OBJECT_TYPE 0x00ff0000
+#define DOE_DATA_OBJECT_LENGTH 0x0003ffff
+
+#define CXL_DOE_TABLE_ENTRY_HANDLE 0xffff0000
+
+#define CXL_DOE_TABLE_ENTRY_HANDLE_LAST 0xffff
+
+#define DVSEC_CXL_VENDOR_ID 0x1E98
+
+#define DOE_DATA_OBJ_HEADER_1 0x0
+#define DOE_DATA_OBJ_HEADER_2 0x4
+
+#define DOE_CAPABILITIES_REG 0x4
+#define DOE_CONTROL_REG 0x8
+#define DOE_STATUS_REG 0xC
+#define DOE_WRITE_DATA_MAILBOX_REG 0x10
+#define DOE_READ_DATA_MAILBOX_REG 0x14
+
+#define DOE_STAT_DOE_BUSY 0x1
+#define DOE_STAT_DATA_OBJ_READY ((0x1) << 31)
+#define DOE_CTRL_DOE_GO ((0x1) << 31)
+
+#define IS_DOE_SUPPORTED(n) \
+ (((n)&(PCIE_EXTENDED_CAP_ID_MASK))=3D=3D(PCIE_EXT_CAP_DOE_ID))
+
+typedef enum {
+ PCIE_EXT_CAP_HEADER,
+ PCIE_DVSEC_HEADER_1,
+ PCIE_DVSEC_HEADER_2,
+ PCIE_DVSEC_HEADER_MAX
+} PCIE_DVSEC_HEADER_ENUM;
+
+/**
+ * Data Object Header
+ *
+ * Data Object Exchange(DOE) Header1 and Header2 put together.
+ * Reference taken from PCI-SIG ECN and
+ * CXL Specification (Revision 3.0, Version 0.7).
+**/
+typedef struct {
+ UINT16 VendorId;
+ UINT8 DataObjType;
+ UINT8 Reserved;
+ UINT32 Length;
+} DOE_HEADER;
+
+#define DOE_DATA_OBJ_TYPE_COMPLIANCE 0x0
+#define DOE_DATA_OBJ_TYPE_CDAT 0x2
+
+/**
+ * DOE read request data
+ *
+ * DOE read request data structure. For CXL DOE requests are made
+ * to read CDAT tables.
+ * Reference taken from CXL Specification (Revision 3.0, Version 0.7).
+**/
+typedef struct {
+ DOE_HEADER Header;
+ UINT8 ReqCode;
+ UINT8 TableType;
+ UINT16 EntryHandle;
+} CXL_CDAT_READ_ENTRY_REQ;
+
+#define CXL_CDAT_DOE_ENTRYHANDLE_LAST_ENTRY 0xFFFF
+
+/* Size in DW(4 Bytes) */
+#define CDAT_READ_ENTRY_REQ_SIZE 3
+
+/**
+ * DOE read response data
+ *
+ * DOE read response data structure. For CXL, DOE responses hold
+ * information about CDAT tables.
+ * Reference taken from CXL Specification (Revision 3.0, Version 0.7).
+**/
+typedef struct {
+ DOE_HEADER Header;
+ UINT8 RspCode;
+ UINT8 TableType;
+ UINT16 EntryHandle;
+ UINT32 CdatTable[32];
+} CXL_CDAT_READ_ENTRY_RESP;
+
+/* Size in DW(4 Bytes) */
+#define CDAT_READ_ENTRY_RESP_SIZE 3
+
+/**
+ * Coherent Device Attribute Table(CDAT) Header
+ *
+ * CDAT header, which is followed by variable number of CDAT structures=
.
+ * Reference taken from CDAT Specification (Revision 1.02).
+**/
+typedef struct {
+ UINT32 Length;
+ UINT8 Revision;
+ UINT8 Checksum;
+ UINT8 Reserved[6];
+ UINT32 Sequence;
+} CDAT_TABLE_HEADER;
+
+/* Size in DW(4 Bytes) */
+#define CDAT_TABLE_HEADER_SIZE 4
+
+/**
+ * Device Scoped Memory Affinity Structure (DSMAS)
+ *
+ * DSMAS returns Device Physical Address(DPA) range and it's attributes=
.
+ * Reference taken from CDAT Specification (Revision 1.02).
+**/
+typedef struct {
+ UINT8 Type;
+ UINT8 Reserved_1;
+ UINT16 Length;
+ UINT8 DsmadHandle;
+ UINT8 Flags;
+ UINT16 Reserved_2;
+ UINT64 DpaBase;
+ UINT64 DpaLength;
+} CDAT_DSMAS;
+
+/* Size in DW(4 Bytes) */
+#define CDAT_STRUCTURE_DSMAS_SIZE 6
+
+typedef enum {
+ CDAT_STRUCTURE_DSMAS,
+ CDAT_STRUCTURE_DSLBIS,
+ CDAT_STRUCTURE_DSMSCIS,
+ CDAT_STRUCTURE_DSIS,
+ CDAT_STRUCTURE_DSEMTS,
+ CDAT_STRUCTURE_SSLBIS,
+ CDAT_STRUCTURE_COUNT
+} CDAT_STRUCTURE_TYPE;
+
diff --git a/Platform/ARM/Include/Protocol/Cxl.h b/Platform/ARM/Include/P=
rotocol/Cxl.h
new file mode 100644
index 0000000000..7dd7c87894
--- /dev/null
+++ b/Platform/ARM/Include/Protocol/Cxl.h
@@ -0,0 +1,57 @@
+/** @file
+ Interface API of CXL Platform protocol.
+
+ Declares the CXL Platform protocol interfaces, which are used by other
+ platform drivers for collecting information regarding discovered remot=
e
+ memory nodes.
+
+ Copyright (c) 2022, Arm Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+/** Remote memory details
+ *
+ * Remote memory region address in device address space and length of =
the
+ * region. These informations are passed using ACPI tables, where addr=
essbase
+ * will be mapped to Host system address space.
+**/
+typedef struct {
+ UINT64 DpaAddress; /// Remote memory base in device address spac=
e
+ UINT64 DpaLength; /// Remote memory length lower bytes
+} REMOTE_MEMORY_CONFIG;
+
+/**
+ Update Remote memory information
+
+ Update the Remote memory details, Base address and Length, for number =
of
+ Remote memory nodes discovered from the CXL devices.
+
+ @param[out] RemoteMem Array for updating Remote memory config.
+ @param[in,out] MemCount Number of supported remote memory nodes.
+
+ @retval EFI_SUCCES Memory is updated successfully
+**/
+typedef
+EFI_STATUS
+(EFIAPI *CXL_GET_REMOTE_MEM) (
+ OUT REMOTE_MEMORY_CONFIG *RemoteMem,
+ IN OUT UINT32 *MemCount
+ );
+
+/**
+ Return number of remote memory nodes discovered from CXL Mem devices.
+
+ @retval UINT32 Number of supported remote memory nodes.
+**/
+typedef UINT32 (EFIAPI *CXL_GET_REMOTE_MEM_COUNT) (VOID);
+
+/**
+ * CXL Platform Protocol
+ *
+ * This protocol enables platform drivers to get number of memory range=
count
+ * and associated memory configurations.
+**/
+typedef struct {
+ CXL_GET_REMOTE_MEM CxlGetRemoteMem;
+ CXL_GET_REMOTE_MEM_COUNT CxlGetRemoteMemCount;
+} CXL_PLATFORM_PROTOCOL;
diff --git a/Platform/ARM/Drivers/CxlDxe/CxlDxe.c b/Platform/ARM/Drivers/=
CxlDxe/CxlDxe.c
new file mode 100644
index 0000000000..71ec5c0662
--- /dev/null
+++ b/Platform/ARM/Drivers/CxlDxe/CxlDxe.c
@@ -0,0 +1,530 @@
+/** @file
+ Discovers CXL capable device and reads out device capabilities.
+
+ This driver locates PciIo Protocol and discovers PCIe devices with CXL=
.Mem
+ capability. If a device with CXL.Mem capability is found then DOE capa=
bility
+ is looked for. Once DOE capability is found, CDAT structures are fetch=
ed from
+ the respective device.
+ It also installs CXL Platform portocol, which can be used by other
+ Platform drivers for capturing remote memory configurations and attrib=
utes.
+
+ Copyright (c) 2022, Arm Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Specification Reference:
+ - CXL Specificiation Revision 3.0, Version 0.7, Chapter 8.1.11
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Protocol/Cxl.h>
+#include <Protocol/PciIo.h>
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Pci22.h>
+
+#include "CxlDxe.h"
+
+STATIC UINT32 RemoteMemCount;
+//TODO: For now considered maximum 5 remote memory ranges.
+// In future it will be made dynamic.
+STATIC REMOTE_MEMORY_CONFIG RemoteMemConfig[5];
+
+/**
+ Check whether device is ready to receive new data through DOE request.
+
+ @param[in] Pci PCI IO Protocol handle.
+ @param[in] DoeBase Base offset of DOE status registers in PCIe device
+ config space.
+
+ @retval EFI_SUCCESS Successful read operation.
+ @retval Other Device not ready or failed to check device stat=
us.
+**/
+STATIC
+EFI_STATUS
+IsDoeBusy (
+ IN EFI_PCI_IO_PROTOCOL *Pci,
+ IN UINT32 DoeBase
+ )
+{
+ EFI_STATUS Status;
+ UINT32 DoeStatVal;
+
+ Status =3D Pci->Pci.Read (Pci, EfiPciIoWidthUint32, DoeBase, 1, &DoeSt=
atVal);
+ if (EFI_ERROR (Status))
+ return Status;
+
+ if (DoeStatVal & DOE_STAT_DOE_BUSY)
+ return EFI_ALREADY_STARTED;
+
+ return Status;
+}
+
+/**
+ Read out CDAT structure data for host memory configuration.
+
+ From the DOE response data, various CDAT structure data are filtered o=
ut
+ for host platform configuration.
+
+ @param[in] DoeRespCdatDat Response data from DOE operation.
+ @param[in] Length DOE response data length in bytes.
+**/
+STATIC
+VOID
+UpdateCdatData (
+ IN UINT32 *DoeRespCdatData,
+ IN UINT16 Length
+ )
+{
+ UINT32 Index;
+ CDAT_DSMAS *Dsmas;
+
+ // Skipping the CDAT header.
+ Index =3D CDAT_TABLE_HEADER_SIZE;
+
+ while (Index < Length) {
+ switch (DoeRespCdatData[Index] & 0xff) {
+ case CDAT_STRUCTURE_DSMAS:
+ Dsmas =3D (CDAT_DSMAS *) (& (DoeRespCdatData [Index]));
+ RemoteMemConfig[RemoteMemCount].DpaAddress =3D Dsmas->DpaBase;
+ RemoteMemConfig[RemoteMemCount].DpaLength =3D Dsmas->DpaLength;
+ RemoteMemCount ++;
+ Index +=3D CDAT_STRUCTURE_DSMAS_SIZE;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return;
+}
+
+/**
+ Receive DOE response.
+
+ For CXL, DOE responses carry CDAT structures that hold information abo=
ut
+ remote memory ranges and it's attributes.
+ System firmware polls the Data Object Ready bit and, provided it is Se=
t, reads
+ data from the DOE Read Data Mailbox and writes 1 to the DOE Read Data =
Mailbox
+ to indicate a successful read, a DWORD at a time until the entire DOE =
Response
+ is read. Data Object Header2 holds number of DW to be transferred for
+ capturing the entire DOE response.
+
+ @param[in] Pci PCI IO Protocol handle.
+ @param[in] DoeBase Base offset of DOE registers in PCIe device c=
onfig
+ space.
+ @param[out] EntryHandle Value of next entry in table. For CXL, table =
type
+ is CDAT.
+
+ @retval EFI_SUCCESS Successful receiving of DOE response.
+ @retval Other Failed receiving of DOE response.
+**/
+STATIC
+EFI_STATUS
+DoeReceiveResponse (
+ IN EFI_PCI_IO_PROTOCOL *Pci,
+ IN UINT32 DoeBase,
+ OUT UINT16 *EntryHandle
+ )
+{
+ EFI_STATUS Status;
+ UINT32 DoeReadMbData =3D 1;
+ UINT32 DoeRespCdatData[15] =3D {};
+ UINT32 DoeStat;
+ UINT32 Index =3D 0;
+ UINT16 Length;
+ UINT64 Reg;
+ UINT32 Val;
+
+ Reg =3D DoeBase + DOE_STATUS_REG;
+ Status =3D Pci->Pci.Read ( Pci, EfiPciIoWidthUint32, Reg, 1, &DoeStat)=
;
+ if (EFI_ERROR (Status))
+ return Status;
+
+ if ((DoeStat & DOE_STAT_DATA_OBJ_READY) !=3D 0) {
+ Index =3D 0;
+ Reg =3D DoeBase + DOE_READ_DATA_MAILBOX_REG;
+
+ // Read the DOE header.
+ Status =3D Pci->Pci.Read (Pci, EfiPciIoWidthUint32, Reg, 1, &Val);
+ if (EFI_ERROR (Status))
+ return Status;
+
+ // Write 1 to DOE Read Data Mailbox to indicate successful Read.
+ Status =3D Pci->Pci.Write (Pci, EfiPciIoWidthUint32, Reg, 1, &DoeRea=
dMbData);
+ if (EFI_ERROR (Status))
+ return Status;
+
+ // Read the DOE Header 2 for data length.
+ Status =3D Pci->Pci.Read (Pci, EfiPciIoWidthUint32, Reg, 1, &Val);
+ if (EFI_ERROR (Status))
+ return Status;
+
+ Length =3D Val & DOE_DATA_OBJECT_LENGTH;
+ if (Length < 2) {
+ DEBUG ((DEBUG_ERROR, " DOE data read error\n"));
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ // Write 1 to DOE Read Data Mailbox to indicate successful Read.
+ Status =3D Pci->Pci.Write (Pci, EfiPciIoWidthUint32, Reg, 1, &DoeRea=
dMbData);
+ if (EFI_ERROR (Status))
+ return Status;
+
+ // Read DOE read entry response header.
+ Status =3D Pci->Pci.Read (Pci, EfiPciIoWidthUint32, Reg, 1, &Val);
+ if (EFI_ERROR (Status))
+ return Status;
+
+ *EntryHandle =3D ((Val & CXL_DOE_TABLE_ENTRY_HANDLE) >> 16);
+ // Write 1 to DOE Read Data Mailbox to indicate successful Read.
+ Status =3D Pci->Pci.Write (Pci, EfiPciIoWidthUint32, Reg, 1, &DoeRea=
dMbData);
+ if (EFI_ERROR (Status))
+ return Status;
+
+ Length -=3D 3;
+ while (Index < Length) {
+ Status =3D Pci->Pci.Read (Pci, EfiPciIoWidthUint32, Reg, 1, &Val);
+ if (EFI_ERROR (Status))
+ return Status;
+
+ DoeRespCdatData[Index] =3D Val;
+ Index++;
+ // Write 1 to DOE Read Data Mailbox to indicate successful Read.
+ Status =3D Pci->Pci.Write (
+ Pci,
+ EfiPciIoWidthUint32,
+ Reg,
+ 1,
+ &DoeReadMbData
+ );
+ if (EFI_ERROR (Status))
+ return Status;
+ }
+
+ UpdateCdatData (DoeRespCdatData, Length);
+ }
+
+ return Status;
+}
+
+/**
+ Make DOE request to fetch CDAT structures and receive DOE response.
+
+ This function requests for DOE objects and receives response for the s=
ame.
+ The steps include -
+ 1. System firmware checks that the DOE Busy bit is Clear.
+ 2. System firmware writes entire data object a DWORD(4 Bytes) at a tim=
e via
+ DOE Write Data Mailbox register.
+ 3. System firmware writes 1b to the DOE Go bit.
+ 4. The DOE instance consumes the DOE request from the DOE mailbox.
+ 5. The DOE instance generates a DOE Response and Sets Data Object Read=
y bit.
+ 6. System firmware polls the Data Object Ready bit and, provided it is=
Set,
+ reads data from the DOE Read Data Mailbox and writes 1 to the DOE R=
ead
+ Data Mailbox to indicate a successful read, a DWORD at a time until=
the
+ entire DOE Response is read.
+ 7: DOE requests are made until response for last CDAT table entry is r=
eceived.
+
+ @param[in] Pci PCI IO Protocol handle.
+ @param[in] DoeBase Base offset of DOE registers in PCIe device config=
space.
+
+ @retval EFI_SUCCESS Successful DOE request and response receive.
+ @retval Other Failed DOE request or response receive.
+**/
+STATIC
+EFI_STATUS
+SendDoeCommand (
+ IN EFI_PCI_IO_PROTOCOL *Pci,
+ IN UINT32 DoeBase
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Val;
+ UINT64 Reg;
+ CXL_CDAT_READ_ENTRY_REQ CxlDoeReq;
+ UINT32 Index =3D 0;
+
+ // CDAT DOE Request header & Read entry request object.
+ CxlDoeReq.Header.VendorId =3D DVSEC_CXL_VENDOR_ID;
+ CxlDoeReq.Header.DataObjType =3D DOE_DATA_OBJ_TYPE_CDAT;
+ CxlDoeReq.Header.Length =3D CDAT_READ_ENTRY_REQ_SIZE;
+
+ // 0 indicates this a request to read.
+ CxlDoeReq.ReqCode =3D 0;
+
+ // 0 indicates table type as CDAT.
+ CxlDoeReq.TableType =3D 0;
+
+ // 0 represents very first entry in the table.
+ CxlDoeReq.EntryHandle =3D 0;
+
+ Reg =3D DoeBase + DOE_WRITE_DATA_MAILBOX_REG;
+
+ do {
+ Status =3D IsDoeBusy (Pci, DoeBase + DOE_STATUS_REG);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Device busy or DOE request can't be made\n"))=
;
+ return Status;
+ }
+
+ while (Index < CDAT_READ_ENTRY_REQ_SIZE) {
+ Val =3D *((UINT32 *) (&CxlDoeReq) + Index);
+ Status =3D Pci->Pci.Write (Pci, EfiPciIoWidthUint32, Reg, 1, &Val)=
;
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Error while making DOE request\n"));
+ return Status;
+ }
+ Index++;
+ }
+
+ Reg =3D DoeBase + DOE_CONTROL_REG;
+ Status =3D Pci->Pci.Read (Pci, EfiPciIoWidthUint32, Reg, 1, &Val);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Error while reading DOE control reg\n"));
+ return Status;
+ }
+
+ Val |=3D DOE_CTRL_DOE_GO;
+ Status =3D Pci->Pci.Write (Pci, EfiPciIoWidthUint32, Reg, 1, &Val);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Error while writing into DOE control reg\n"))=
;
+ return Status;
+ }
+
+ Status =3D DoeReceiveResponse (Pci, DoeBase, &CxlDoeReq.EntryHandle)=
;
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Error while receiving DOE response\n"));
+ return Status;
+ }
+ } while (CxlDoeReq.EntryHandle < CXL_DOE_TABLE_ENTRY_HANDLE_LAST);
+
+ return Status;
+}
+
+/**
+ Return number of remote memory nodes discovered from CXL Mem devices.
+
+ @retval UINT32 Number of supported remote memory nodes
+**/
+STATIC UINT32 EFIAPI CxlGetRemoteMemCount (VOID)
+{
+ return RemoteMemCount;
+}
+
+/**
+ Update Remote memory information
+
+ Update the Remote memory details, Base address and Length, for number =
of
+ Remote memory nodes discovered from the CXL devices. If the update req=
uest
+ for number of memory nodes is more than maximum remote memory nodes, t=
hen
+ MemCount is modified to number of maximum remote memory nodes.
+
+ @param[out] RemoteMem Array for updating Remote memory config.
+ @param[in,out] MemCount Number of supported remote memory nodes.
+
+ @retval EFI_SUCCES Memory is updated successfully
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CxlGetRemoteMem (
+ OUT REMOTE_MEMORY_CONFIG *RemoteMemInfo,
+ IN OUT UINT32 *MemCount
+ )
+{
+
+ if ((*MemCount) > RemoteMemCount) {
+ DEBUG ((DEBUG_WARN, "Requested for more than max. Remote Memory node=
\n"));
+ *MemCount =3D RemoteMemCount;
+ }
+
+ CopyMem (
+ RemoteMemInfo,
+ RemoteMemConfig,
+ sizeof (REMOTE_MEMORY_CONFIG) * (*MemCount)
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Installs the CXL platform protocol.
+
+ CXL platform protocol has interfaces for providing CXL mem device
+ configurations. A Platform driver can fetch such configurations
+ using these protocl interfaces.
+
+ @retval EFI_SUCCESS On successful installation of protocol interfaces=
.
+ @retval Other On failure of protocol installation.
+**/
+STATIC
+EFI_STATUS
+CxlInstallProtocol (VOID)
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *CxlPlatformHandle;
+ CXL_PLATFORM_PROTOCOL *CxlPlatformProtocol;
+
+ CxlPlatformHandle =3D (EFI_HANDLE *) AllocateZeroPool (sizeof(EFI_HAND=
LE));
+
+ CxlPlatformProtocol =3D (CXL_PLATFORM_PROTOCOL *) AllocateZeroPool (
+ sizeof(CXL_PLATFORM_=
PROTOCOL)
+ );
+ if (!CxlPlatformProtocol) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "CxlInstallProtocol: Failed to allocate memory for CxlPlatformProt=
ocol\n"
+ ));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CxlPlatformProtocol->CxlGetRemoteMem =3D CxlGetRemoteMem;
+ CxlPlatformProtocol->CxlGetRemoteMemCount =3D CxlGetRemoteMemCount;
+
+ Status =3D gBS->InstallProtocolInterface (
+ CxlPlatformHandle,
+ &gCxlPlatformProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ CxlPlatformProtocol
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "CxlInstallProtocol: Failed to install CxlPlatformProtocol: 0x%08x=
\n",
+ Status
+ ));
+
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "Installed protocol: %p\n", CxlPlatformProtocol));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry point for CXL DXE.
+
+ This Dxe depends on gEfiPciEnumerationCompleteProtocolGuid. It locates
+ PciIo Protocol and discovers PCIe devices with CXL.Mem capability. If =
a
+ device with CXL.Mem capability is found then DOE capability is looked =
for.
+ After that, CXL.Mem device configurations are fetched, and thereafter =
CXL
+ Platform portocol is installed.
+
+ @param[in] ImageHandle Handle to the Efi image.
+ @param[in] SystemTable A pointer to the Efi System Table.
+
+ @retval EFI_SUCCESS On successful execution of mentioned functionliti=
es.
+ @retval Other On failure.
+**/
+EFI_STATUS
+EFIAPI
+CxlDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *Pci;
+ UINTN Seg, Bus, Dev, Func;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount, Index;
+ UINT32 ExtCapOffset, NextExtCapOffset;
+ UINT32 NextDoeExtCapOffset;
+ UINT32 PcieExtCapAndDvsecHeader[3];
+ UINT32 PcieExtCapHeader;
+
+ Status =3D gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to locate any PciIo protocols\n"));
+ return Status;
+ }
+
+ for (Index =3D 0; Index < HandleCount; Index++) {
+ Status =3D gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&Pci
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to get Pci handle\n"));
+ return Status;
+ }
+
+ Pci->GetLocation (Pci, &Seg, &Bus, &Dev, &Func);
+ NextExtCapOffset =3D PCIE_EXTENDED_CAP_OFFSET;
+
+ do {
+ ExtCapOffset =3D NextExtCapOffset;
+ Status =3D Pci->Pci.Read (
+ Pci,
+ EfiPciIoWidthUint32,
+ ExtCapOffset,
+ PCIE_DVSEC_HEADER_MAX,
+ PcieExtCapAndDvsecHeader
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to read PCI IO for Ext. capability\=
n"));
+ return Status;
+ }
+
+ /* Check whether this is a CXL device */
+ if (IS_CXL_DVSEC(PcieExtCapAndDvsecHeader[PCIE_DVSEC_HEADER_1])) {
+ DEBUG ((DEBUG_INFO, "Found CXL Device\n"));
+
+ NextDoeExtCapOffset =3D PCIE_EXTENDED_CAP_OFFSET;
+ do {
+ ExtCapOffset =3D NextDoeExtCapOffset;
+ Status =3D Pci->Pci.Read (
+ Pci,
+ EfiPciIoWidthUint32,
+ ExtCapOffset,
+ 1,
+ &PcieExtCapHeader
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to read PCI Ext. capability\n")=
);
+ return Status;
+ }
+
+ if (IS_DOE_SUPPORTED (PcieExtCapHeader)) {
+ DEBUG ((DEBUG_INFO, "Found DOE Capability\n"));
+ Status =3D SendDoeCommand (Pci, ExtCapOffset);
+
+ if (EFI_ERROR (Status))
+ return Status;
+
+ NextExtCapOffset =3D 0;
+ break;
+ }
+
+ NextDoeExtCapOffset =3D PCIE_EXTENDED_CAP_NEXT (PcieExtCapHead=
er);
+ } while(NextDoeExtCapOffset);
+
+ Status =3D CxlInstallProtocol();
+ if (EFI_ERROR (Status))
+ return Status;
+ }
+
+ NextExtCapOffset =3D PCIE_EXTENDED_CAP_NEXT (
+ PcieExtCapAndDvsecHeader[PCIE_EXT_CAP_HEADER]
+ );
+
+ } while (NextExtCapOffset);
+ }
+
+ return EFI_SUCCESS;
+}
--=20
2.17.1