public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Omkar Anand Kulkarni" <omkar.kulkarni@arm.com>
To: devel@edk2.groups.io
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>,
	Leif Lindholm <leif@nuviainc.com>,
	Sami Mujawar <sami.mujawar@arm.com>,
	Jiewen Yao <jiewen.yao@intel.com>
Subject: [edk2-platforms][PATCH 1/6] Platform/ARM: Add DMC-620 RAS error handling driver
Date: Fri, 30 Oct 2020 14:11:51 +0530	[thread overview]
Message-ID: <20201030084156.8291-2-omkar.kulkarni@arm.com> (raw)
In-Reply-To: <20201030084156.8291-1-omkar.kulkarni@arm.com>

DMC-620 memory controller improves system reliability by generating
interrupts on detecting ECC errors on the data. Add a initial DMC-620 MM
driver that implements a MMI handler for handling single-bit ECC error
events originating from the DRAM.

The driver implements the HEST error source descriptor protocol in order
to publish the GHES error source descriptor for single-bit DRAM errors.
The GHES error source descriptor that is published is of type 'memory
error'. A GHES error source descriptor is pub;lished for each instances
if the DMC-620 controller in the system.

The driver registers a MMI handler for handling 1-bit DRAM ECC error
events. The MMI handler, when invoked, reads the DMC-620 error record
registers and populates the EFI_PLATFORM_MEMORY_ERROR_DATA type error
section information structure with the corresponding information read
from the error record registers.

Co-authored-by: Thomas Abraham <thomas.abraham@arm.com>
Signed-off-by: Omkar Anand Kulkarni <omkar.kulkarni@arm.com>
---
 Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.dec              |  28 ++
 Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.inf              |  59 +++
 Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.h                | 209 +++++++++++
 Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.c                | 379 ++++++++++++++++++++
 Platform/ARM/Drivers/Dmc620Mm/Dmc620MmErrorSourceInfo.c | 191 ++++++++++
 5 files changed, 866 insertions(+)

diff --git a/Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.dec b/Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.dec
new file mode 100644
index 000000000000..2caa28879c35
--- /dev/null
+++ b/Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.dec
@@ -0,0 +1,28 @@
+#/** @file
+#
+#  Copyright (c) 2020, ARM Limited. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+  DEC_SPECIFICATION              = 0x0001001A
+  PACKAGE_NAME                   = Dmc620Mm
+  PACKAGE_GUID                   = 94110B10-8E72-42A0-8963-D2B57FCF0F38
+  PACKAGE_VERSION                = 0.1
+
+[Guids]
+  gDmc620MmTokenSpaceGuid = {0xc305f72a, 0xd10d, 0x45e8, { 0x81, 0x78, 0x51, 0x8b, 0x78, 0x62, 0x77, 0x79 } }
+  gArmDmcEventHandlerGuid = { 0x5ef0afd5, 0xe01a, 0x4c30, { 0x86, 0x19, 0x45, 0x46, 0x26, 0x91, 0x80, 0x98 }}
+
+[PcdsFixedAtBuild.common]
+  gDmc620MmTokenSpaceGuid.PcdDmc620NumCtrl|2|UINT32|0x00000001
+  gDmc620MmTokenSpaceGuid.PcdDmc620RegisterBase|0x4E000000|UINT64|0x00000002
+  gDmc620MmTokenSpaceGuid.PcdDmc620CtrlSize|0x100000|UINT32|0x00000003
+  gDmc620MmTokenSpaceGuid.PcdDmc620CorrectableErrorThreshold|10|UINT32|0x00000004
+  gDmc620MmTokenSpaceGuid.PcdDmc620ErrSourceCount|1|UINT32|0x00000005
+  gDmc620MmTokenSpaceGuid.PcdDmc620DramErrorSdeiEventBase|0|UINT32|0x00000006
+  gDmc620MmTokenSpaceGuid.PcdDmc620DramOneBitErrorDataBase|0|UINT64|0x00000007
+  gDmc620MmTokenSpaceGuid.PcdDmc620DramOneBitErrorDataSize|0|UINT64|0x00000008
+  gDmc620MmTokenSpaceGuid.PcdDmc620DramOneBitErrorSourceId|0|UINT16|0x00000009
diff --git a/Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.inf b/Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.inf
new file mode 100644
index 000000000000..02c8107467aa
--- /dev/null
+++ b/Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.inf
@@ -0,0 +1,59 @@
+## @file
+#  StandaloneMM driver for the DMC620 Memory Controller.
+#
+#  Copyright (c) 2020, ARM Limited. All rights reserved.
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001A
+  BASE_NAME                      = StandaloneMmDmc620Driver
+  FILE_GUID                      = CB53ACD9-A1A1-43B3-A638-AC74DA5D9DA2
+  MODULE_TYPE                    = MM_STANDALONE
+  VERSION_STRING                 = 1.0
+  PI_SPECIFICATION_VERSION       = 0x00010032
+  ENTRY_POINT                    = Dmc620MmDriverInitialize
+
+[Sources]
+  Dmc620Mm.c
+  Dmc620MmErrorSourceInfo.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  edk2-platforms/Platform/ARM/ARM.dec
+  Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+  StandaloneMmDriverEntryPoint
+  DebugLib
+  ArmSvcLib
+  ArmLib
+  BaseMemoryLib
+
+[Protocols]
+  gMmHestErrorSourceDescProtocolGuid      ##PRODUCES
+
+[FixedPcd]
+  gArmPlatformTokenSpaceGuid.PcdGhesGenericErrorDataMmBufferBase
+  gArmPlatformTokenSpaceGuid.PcdGhesGenericErrorDataMmBufferSize
+
+  gDmc620MmTokenSpaceGuid.PcdDmc620NumCtrl
+  gDmc620MmTokenSpaceGuid.PcdDmc620RegisterBase
+  gDmc620MmTokenSpaceGuid.PcdDmc620CtrlSize
+  gDmc620MmTokenSpaceGuid.PcdDmc620CorrectableErrorThreshold
+  gDmc620MmTokenSpaceGuid.PcdDmc620ErrSourceCount
+  gDmc620MmTokenSpaceGuid.PcdDmc620DramErrorSdeiEventBase
+  gDmc620MmTokenSpaceGuid.PcdDmc620DramOneBitErrorDataBase
+  gDmc620MmTokenSpaceGuid.PcdDmc620DramOneBitErrorDataSize
+  gDmc620MmTokenSpaceGuid.PcdDmc620DramOneBitErrorSourceId
+
+[Guids]
+  gArmDmcEventHandlerGuid
+
+[Depex]
+  TRUE
diff --git a/Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.h b/Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.h
new file mode 100644
index 000000000000..36d4b5c6be0b
--- /dev/null
+++ b/Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.h
@@ -0,0 +1,209 @@
+/** @file
+  DMC-620 memory controller register defines, macros and structres used by
+  the DMC-620 StandaloneMM driver.
+
+  Copyright (c) 2020, ARM Limited. All rights reserved.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef DMC620_MM_DRIVER_H_
+#define DMC620_MM_DRIVER_H_
+
+#include <Base.h>
+#include <Guid/Cper.h>
+#include <IndustryStandard/Acpi.h>
+
+#include <Library/ArmLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+
+#include <Protocol/HestErrorSourceInfo.h>
+
+// DMC-620  memory controller status register field values and masks
+#define DMC620_MEMC_STATUS_MEMC_STATUS_MASK           (0x00000007)
+#define DMC620_MEMC_STATUS_MEMC_STATUS_READY          (0x3)
+
+// DMC-620 memory controller command register
+#define DMC620_MEMC_CMD_MEMC_CMD_EXECUTE_DRAIN        (0x5)
+
+// DMC-620 memory controller Err Record 1/2 Status register bit masks
+#define DMC620_ERR_STATUS_MV                          (0x04000000)
+#define DMC620_ERR_STATUS_AV                          (0x80000000)
+
+// DMC-620 memory controller DRAM error record (Err1/2) Misc 0 register fields
+#define DMC620_ERR_MISC0_COLUMN_MASK                  (0x000003FF)
+#define DMC620_ERR_MISC0_ROW_MASK                     (0x0FFFFC00)
+#define DMC620_ERR_MISC0_ROW_SHIFT                    (10)
+#define DMC620_ERR_MISC0_RANK_MASK                    (0x70000000)
+#define DMC620_ERR_MISC0_RANK_SHIFT                   (28)
+#define DMC620_ERR_MISC0_VAILD                        (0x80000000)
+
+// DMC-620 memory controller DRAM error record (Err1/2) Misc 1 register fields
+#define DMC620_ERR_MISC1_VAILD                        (0x80000000)
+#define DMC620_ERR_MISC1_BANK_MASK                    (0x0000000F)
+
+// DMC-620 memory controller ErrGsr register bit masks
+#define DMC620_DRAM_ECC_CORRECTED_FH                  (BIT0 << 1)
+
+//
+// Macro to initialize the HEST GHESv2 Notification structure.
+//
+#define ARM_PLATFORM_ACPI_6_3_GHES_NOTIFICATION_STRUCT_INIT(Type,  \
+        PollInterval, EventId) {                                    \
+  Type,                                                             \
+  sizeof (EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_STRUCTURE),      \
+  {0, 0, 0, 0, 0, 0, 0}, /* ConfigurationWriteEnable */             \
+  PollInterval,                                                     \
+  EventId,                                                          \
+  0,           /* Poll Interval Threshold Value  */                 \
+  0,           /* Poll Interval Threshold Window */                 \
+  0,           /* Error Threshold Value          */                 \
+  0            /* Error Threshold Window         */                 \
+}
+
+//
+// Macro to initialize the HEST GHESv2 Error Status and Read Ack register.
+//
+#define ARM_PLATFORM_ACPI_6_3_GHES_GENERIC_ADDRESS_STRUCT_INIT(Address) {   \
+  0,        /* UINT8 Address Space ID */   \
+  64,       /* Register Bit Width     */   \
+  0,        /* Register Bit Offset    */   \
+  4,        /* Access Size            */   \
+  Address   /* CPER/Read Ack Addr     */   \
+}
+
+//#pragma pack(1)
+
+//
+// DMC-620 memory controller register definitions
+//
+typedef struct {
+  UINT32 MemcStatus;
+  UINT32 MemcConfig;
+  UINT32 MemcCmd;
+  UINT32 Reserved [0x1BD];
+  UINT32 Err0Fr;
+  UINT32 Reserved1;
+  UINT32 Err0Ctlr0;
+  UINT32 Err0Ctlr1;
+  UINT32 Err0Status;
+  UINT8  Reserved2[0x740 - 0x714];
+  UINT32 Err1Fr;
+  UINT32 Reserved3;
+  UINT32 Err1Ctlr;
+  UINT32 Reserved4;
+  UINT32 Err1Status;
+  UINT32 Reserved5;
+  UINT32 Err1Addr0;
+  UINT32 Err1Addr1;
+  UINT32 Err1Misc0;
+  UINT32 Err1Misc1;
+  UINT32 Err1Misc2;
+  UINT32 Err1Misc3;
+  UINT32 Err1Misc4;
+  UINT32 Err1Misc5;
+  UINT8  Reserved6[0x780 - 0x778];
+  UINT32 Err2Fr;
+  UINT32 Reserved7;
+  UINT32 Err2Ctlr;
+  UINT32 Reserved8;
+  UINT32 Err2Status;
+  UINT32 Reserved9;
+  UINT32 Err2Addr0;
+  UINT32 Err2Addr1;
+  UINT32 Err2Misc0;
+  UINT32 Err2Misc1;
+  UINT32 Err2Misc2;
+  UINT32 Err2Misc3;
+  UINT32 Err2Misc4;
+  UINT32 Err2Misc5;
+  UINT8  Reserved10[0x7c0 - 0x7b8];
+  //UINT32 Reserved11[0x58];
+  UINT32 Reserved15[0x14];//hack
+  UINT32 Err4Status;
+  UINT32 Reserved16[0x43];//hack
+  UINT32 Errgsr;
+} DMC620_REGS_TYPE;
+
+//
+// DMC-620 memory controller error record register definition
+//
+typedef struct {
+  UINT32 ErrFr;
+  UINT32 Reserved;
+  UINT32 ErrCtlr;
+  UINT32 Reserved1;
+  UINT32 ErrStatus;
+  UINT32 Reserved2;
+  UINT32 ErrAddr0;
+  UINT32 ErrAddr1;
+  UINT32 ErrMisc0;
+  UINT32 ErrMisc1;
+  UINT32 ErrMisc2;
+  UINT32 ErrMisc3;
+  UINT32 ErrMisc4;
+  UINT32 ErrMisc5;
+  UINT8  Reserved3[0x780 - 0x778];
+} DMC620_ERR_REGS_TYPE;
+
+//#pragma pack()
+
+//
+// List of supported error sources by DMC-620 memory controller
+//
+typedef enum {
+  DramEccCfh = 0,
+  DramEccFh,
+  ChiFh,
+  SramEccCfh,
+  SramEccFh,
+  DmcErrRecovery
+} DMC_ERR_SOURCES;
+
+/**
+  MMI handler implementing the HEST error source desc protocol.
+
+  Returns the error source descriptor information for all DMC(s) error sources and
+  also returns its count and length.
+
+  @param[in]  This   Pointer for this protocol
+
+  @param[out] Buffer HEST error source descriptor Information
+                     buffer.
+  @param[out] ErrorSourcesLength Total length of Error Source Descriptors
+  @param[out] ErrorSourceCount   Total number of supported error sources.
+
+  @retval EFI_SUCCESS           Buffer has valid Error Source descriptor information.
+  @retval EFI_INVALID_PARAMETER Buffer is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+DmcErrorSourceDescInfoGet (
+  IN  MM_HEST_ERROR_SOURCE_DESC_PROTOCOL *This,
+  OUT VOID                               **Buffer,
+  OUT UINTN                              *ErrorSourcesLength,
+  OUT UINTN                              *ErrorSourcesCount
+  );
+
+/**
+  Allow reporting of supported DMC-620 error sources
+
+  Install the Hest Error Source Descriptor protocol handler to allow publishing
+  of the supported DMC-620 memory controller error sources.
+
+  @param[in] MmSystemTable Pointer to System table.
+
+  @retval EFI_SUCCESS           Protocol installation successful.
+  @retval EFI_INVALID_PARAMETER Invalid system table parameter.
+
+**/
+
+EFI_STATUS
+Dmc620InstallErrorSourceDescProtocol (
+  IN EFI_MM_SYSTEM_TABLE *MmSystemTable
+  );
+
+#endif // DMC620_MM_DRIVER_H_
diff --git a/Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.c b/Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.c
new file mode 100644
index 000000000000..ee669085abea
--- /dev/null
+++ b/Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.c
@@ -0,0 +1,379 @@
+/** @file
+  DMC 620 Memory Controller error handling (Standalone MM) driver
+
+  Supports Single Bit DRAM error handling for multiple DMC 620 instances.
+  On a error event, publishes the CPER error record of Memory type.
+
+  Copyright (c) 2020, ARM Limited. All rights reserved.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Dmc620Mm.h>
+
+/**
+  Drain DMC-620 controller of any transactions.
+
+  Performs pending direct_command operations and updates the register values
+  with the next (new) values. The new values will be considered when the
+  DMC moves to ready state.
+
+  @param [in] DmcCtrl Pointer to DMC620_x control registers
+
+  @retval NONE.
+
+**/
+STATIC
+VOID
+Dmc620DrainController (
+  IN DMC620_REGS_TYPE *DmcCtrl
+  )
+{
+  UINT32  MemcStatus;
+
+  MmioWrite32 ((UINTN)&DmcCtrl->MemcCmd, DMC620_MEMC_CMD_MEMC_CMD_EXECUTE_DRAIN);
+
+  do {
+    MemcStatus = MmioRead32 ((UINTN)&DmcCtrl->MemcStatus);
+  } while ((MemcStatus & DMC620_MEMC_STATUS_MEMC_STATUS_MASK) !=
+              DMC620_MEMC_STATUS_MEMC_STATUS_READY);
+}
+
+/**
+  Helper function to handle the DMC-620 DRAM errors.
+
+  Reads the DRAM error record registers. Creates a CPER error record of type
+  'Memory Error' and populates it with DRAM error record registers.
+
+  @param[in] DmcCtrl               A pointer to DMC620 control registers.
+  @param[in] DmcInstance           DMC instance which raised the RAS event.
+  @param[in] ErrRecType            A type of the DMC error record.
+  @param[in] ErrorBlockBaseAddress Unique address for populating the error block
+                                   status for given DMC error source.
+
+  @return NONE.
+
+**/
+STATIC
+VOID
+Dmc620HandleDramError (
+  IN DMC620_REGS_TYPE *DmcCtrl,
+  IN UINTN            DmcInstance,
+  IN UINTN            ErrRecType,
+  IN UINTN            ErrorBlockBaseAddress
+  )
+{
+  EFI_ACPI_6_3_GENERIC_ERROR_DATA_ENTRY_STRUCTURE *ErrBlockSectionDesc;
+  EFI_ACPI_6_3_GENERIC_ERROR_STATUS_STRUCTURE     *ErrBlockStatusHeaderData;
+  EFI_PLATFORM_MEMORY_ERROR_DATA                  MemorySectionInfo = {0};
+  DMC620_ERR_REGS_TYPE                            *ErrRecord;
+  EFI_GUID                                        SectionType;
+  UINT32                                          ResetReg;
+  VOID                                            *ErrBlockSectionData;
+  UINTN                                           *ErrorStatusRegister;
+  UINTN                                           *ReadAckRegister;
+  UINTN                                           *ErrStatusBlock;
+  UINTN                                           ErrStatus;
+  UINTN                                           ErrAddr0;
+  UINTN                                           ErrAddr1;
+  UINTN                                           ErrMisc0;
+  UINTN                                           ErrMisc1;
+  UINT8                                           CorrectedError;
+
+  //
+  // Check the type of DRAM error (1-bit or 2-bit) and accordingly select
+  // error record to use.
+  //
+  if (ErrRecType == DMC620_DRAM_ECC_CORRECTED_FH) {
+    DEBUG ((DEBUG_INFO, "DRAM ECC Corrected Fault (1-Bit ECC error) \n"));
+    ErrRecord = (DMC620_ERR_REGS_TYPE *)&DmcCtrl->Err1Fr;
+    CorrectedError = 1;
+  }
+  else {
+    DEBUG ((DEBUG_INFO, "DRAM ECC Fault Handling (2-bit ECC error)\n"));
+    ErrRecord = (DMC620_ERR_REGS_TYPE *)&DmcCtrl->Err2Fr;
+    CorrectedError = 0;
+  }
+
+  // Read most recent DRAM error record registers.
+  do {
+    ErrStatus = MmioRead32 ((UINTN)&ErrRecord->ErrStatus);
+    ErrAddr0  = MmioRead32 ((UINTN)&ErrRecord->ErrAddr0);
+    ErrAddr1  = MmioRead32 ((UINTN)&ErrRecord->ErrAddr1);
+    ErrMisc0  = MmioRead32 ((UINTN)&ErrRecord->ErrMisc0);
+    ErrMisc1  = MmioRead32 ((UINTN)&ErrRecord->ErrMisc1);
+
+    // Clear the status register so that new error records are populated.
+    ResetReg = MmioRead32 ((UINTN)&ErrRecord->ErrStatus);
+    MmioWrite32 ((UINTN)&ErrRecord->ErrStatus, ResetReg);
+    Dmc620DrainController (DmcCtrl);
+  } while (MmioRead32 ((UINTN)&ErrRecord->ErrStatus));
+
+  ErrStatus = MmioRead32 ((UINTN)&DmcCtrl->Err4Status);//hack
+
+  // 
+  // Get Physical address of DRAM error from Address register and populate
+  // Memory Error Section.
+  //
+  if (ErrStatus & DMC620_ERR_STATUS_AV) {
+    DEBUG ((DEBUG_INFO, "DRAM Error: Address_0 : 0x%x Address_1 : 0x%x\n",
+                        ErrAddr0, ErrAddr1));
+    // 
+    // Populate Memory CPER section with DRAM error address (48 bits) and
+    // address mask fields.
+    //
+    MemorySectionInfo.ValidFields |= EFI_PLATFORM_MEMORY_PHY_ADDRESS_MASK_VALID;
+    MemorySectionInfo.PhysicalAddressMask = 0xFFFFFFFFFFFF;
+    MemorySectionInfo.ValidFields |= EFI_PLATFORM_MEMORY_PHY_ADDRESS_VALID;
+    MemorySectionInfo.PhysicalAddress = (ErrAddr1 << 32) | ErrAddr0;
+  }
+
+  //
+  // Read the Error Record Misc registers and populate relevant fields in
+  // Memory error section.
+  //
+  // Read DRAM MISC0 register and populate the Memory Error Section.
+  if ((ErrStatus & DMC620_ERR_STATUS_MV)
+      && (ErrMisc0 & DMC620_ERR_MISC0_VAILD))
+  {
+    // Populate Memory Error Section wih DRAM column information.
+    MemorySectionInfo.ValidFields |= EFI_PLATFORM_MEMORY_COLUMN_VALID;
+    MemorySectionInfo.Column = ErrMisc0 & DMC620_ERR_MISC0_COLUMN_MASK;
+
+    //
+    // Populate Memory Error Section with DRAM row information.
+    // Row bits (bit 16 and 17) are to be filled as extended.
+    //
+    MemorySectionInfo.ValidFields |=
+      EFI_PLATFORM_MEMORY_ERROR_EXTENDED_ROW_BIT_16_17_VALID;
+    MemorySectionInfo.Row =
+      (ErrMisc0 & DMC620_ERR_MISC0_ROW_MASK) >> DMC620_ERR_MISC0_ROW_SHIFT;
+    MemorySectionInfo.Extended =
+      (ErrMisc0 & DMC620_ERR_MISC0_ROW_MASK) >> (DMC620_ERR_MISC0_ROW_SHIFT + 16);
+
+    // Populate Memory Error Section wih DRAM rank information.
+    MemorySectionInfo.ValidFields |= EFI_PLATFORM_MEMORY_ERROR_RANK_NUM_VALID;
+    MemorySectionInfo.RankNum = (ErrMisc0 & DMC620_ERR_MISC0_RANK_MASK) >>
+      DMC620_ERR_MISC0_RANK_SHIFT;
+  }
+
+  // Read DRAM MISC1 register and populate the Memory Error Section.
+  if ((ErrStatus & DMC620_ERR_STATUS_MV)
+      && (ErrMisc1 & DMC620_ERR_MISC1_VAILD))
+  {
+    MemorySectionInfo.ValidFields |= EFI_PLATFORM_MEMORY_BANK_VALID;
+    MemorySectionInfo.Bank = (ErrMisc1 & DMC620_ERR_MISC1_BANK_MASK);
+  }
+
+  //
+  // Misc registers 2..5 are not used and convey only the error counter
+  // information. They are cleared as they do not contribute in Error
+  // Record creation.
+  //
+  if (ErrStatus & DMC620_ERR_STATUS_MV) {
+    ResetReg = 0x0;
+    MmioWrite32 ((UINTN)&ErrRecord->ErrMisc2, ResetReg);
+    MmioWrite32 ((UINTN)&ErrRecord->ErrMisc3, ResetReg);
+    MmioWrite32 ((UINTN)&ErrRecord->ErrMisc4, ResetReg);
+    MmioWrite32 ((UINTN)&ErrRecord->ErrMisc5, ResetReg);
+  }
+
+  //
+  // Reset error records Status register for recording new DRAM error syndrome
+  // information.
+  //
+  ResetReg = MmioRead32 ((UINTN)&ErrRecord->ErrStatus);
+  MmioWrite32 ((UINTN)&ErrRecord->ErrStatus, ResetReg);
+  Dmc620DrainController (DmcCtrl);
+
+  ErrStatus = 0;//hack
+  ResetReg = MmioRead32 ((UINTN)&DmcCtrl->Err4Status);
+  MmioWrite32 ((UINTN)&DmcCtrl->Err4Status, ResetReg);
+  Dmc620DrainController (DmcCtrl);
+
+  //
+  // Allocate memory for Error Acknowledge register, Error Status register and
+  // Error status block data.
+  //
+  ReadAckRegister = (UINTN *)ErrorBlockBaseAddress;
+  ErrorStatusRegister = (UINTN *)ErrorBlockBaseAddress + 1;
+  ErrStatusBlock = (UINTN *)ErrorStatusRegister + 1;
+
+  // Initialize Error Status Register with Error Status Block address.
+  *ErrorStatusRegister = (UINTN)ErrStatusBlock;
+
+  //
+  // Locate Block Status Header base address and populate it with Error Status
+  // Block Header information.
+  //
+  ErrBlockStatusHeaderData = (EFI_ACPI_6_3_GENERIC_ERROR_STATUS_STRUCTURE *)
+                             ErrStatusBlock;
+  *ErrBlockStatusHeaderData =
+    (EFI_ACPI_6_3_GENERIC_ERROR_STATUS_STRUCTURE) {
+      .BlockStatus = {
+        .UncorrectableErrorValid     = ((CorrectedError == 0) ? 0:1),
+        .CorrectableErrorValid       = ((CorrectedError == 1) ? 1:0),
+        .MultipleUncorrectableErrors = 0x0,
+        .MultipleCorrectableErrors   = 0x0,
+        .ErrorDataEntryCount         = 0x1
+       },
+      .RawDataOffset = (sizeof(EFI_ACPI_6_3_GENERIC_ERROR_STATUS_STRUCTURE) +
+                       sizeof(EFI_ACPI_6_3_GENERIC_ERROR_DATA_ENTRY_STRUCTURE)),
+      .RawDataLength = 0,
+      .DataLength = (sizeof(EFI_ACPI_6_3_GENERIC_ERROR_DATA_ENTRY_STRUCTURE) +
+                    sizeof(EFI_PLATFORM_MEMORY_ERROR_DATA)),
+      .ErrorSeverity = ((CorrectedError == 1) ?
+		      EFI_ACPI_6_3_ERROR_SEVERITY_CORRECTED:
+                                         EFI_ACPI_6_3_ERROR_SEVERITY_FATAL),
+    };
+
+  //
+  // Locate Section Descriptor base address and populate Error Status Section
+  // Descriptor data.
+  //
+  ErrBlockSectionDesc = (EFI_ACPI_6_3_GENERIC_ERROR_DATA_ENTRY_STRUCTURE *)
+                        (ErrBlockStatusHeaderData + 1);
+  *ErrBlockSectionDesc =
+    (EFI_ACPI_6_3_GENERIC_ERROR_DATA_ENTRY_STRUCTURE) {
+      .ErrorSeverity = ((CorrectedError == 1) ?
+		         EFI_ACPI_6_3_ERROR_SEVERITY_CORRECTED:
+                         EFI_ACPI_6_3_ERROR_SEVERITY_FATAL),
+      .Revision = EFI_ACPI_6_3_GENERIC_ERROR_DATA_ENTRY_REVISION,
+      .ValidationBits = 0,
+      .Flags = 0,
+      .ErrorDataLength = sizeof (EFI_PLATFORM_MEMORY_ERROR_DATA),
+      .FruId = {0},
+      .FruText = {0},
+      .Timestamp = {0},
+    };
+  SectionType = (EFI_GUID) EFI_ERROR_SECTION_PLATFORM_MEMORY_GUID;
+  CopyGuid ((EFI_GUID *)ErrBlockSectionDesc->SectionType, &SectionType);
+
+  // Locate Section base address and populate Memory Error Section data.
+  ErrBlockSectionData = (VOID *)(ErrBlockSectionDesc + 1);
+  CopyMem (
+    ErrBlockSectionData,
+    (VOID *)&MemorySectionInfo,
+    sizeof (EFI_PLATFORM_MEMORY_ERROR_DATA)
+    );
+}
+
+/**
+  DMC620 RAS event handler.
+
+  Mutiple DMC error processing support. Current implementation handles the DRAM
+  ECC errors.
+
+  @param[in] DispatchHandle      The unique handle assigned to this handler by
+                                 MmiHandlerRegister().
+  @param[in] Context             Points to an optional handler context which
+                                 was specified when the handler was registered.
+  @param[in, out] CommBuffer     A pointer to a collection of data in memory that
+                                 will be conveyed from a non-MM environment into
+                                 an MM environment.
+  @param[in, out] CommBufferSize The size of the CommBuffer.
+
+  @retval EFI_SUCCESS Event handler successful.
+  @retval Other       Failure of event handler.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+Dmc620ErrorEventHandler (
+  IN     EFI_HANDLE DispatchHandle,
+  IN     CONST VOID *Context,       OPTIONAL
+  IN OUT VOID       *CommBuffer,    OPTIONAL
+  IN OUT UINTN      *CommBufferSize OPTIONAL
+  )
+{
+  DMC620_REGS_TYPE *DmcCtrl;
+  UINTN            DmcIdx;
+  UINTN            ErrGsr;
+
+  // DMC instance which raised RAS error event.
+  DmcIdx = *(UINTN *)CommBuffer;
+  // Base address of the DMC instance.
+  DmcCtrl = (DMC620_REGS_TYPE *)(FixedPcdGet64 (PcdDmc620RegisterBase) +
+            (FixedPcdGet64 (PcdDmc620CtrlSize) * DmcIdx));
+
+  DEBUG ((
+    DEBUG_INFO,
+    "DMC error event raised for DMC: %d with DmcBaseAddr: 0x%x \n",
+    DmcIdx, (UINTN)DmcCtrl
+    ));
+
+  ErrGsr = MmioRead32 ((UINTN)&DmcCtrl->Errgsr);
+  ErrGsr = 0x2; //HACK
+
+  if (ErrGsr & DMC620_DRAM_ECC_CORRECTED_FH) {
+    // Handle corrected 1-bit DRAM ECC error.
+    Dmc620HandleDramError (
+      DmcCtrl,
+      DmcIdx,
+      DMC620_DRAM_ECC_CORRECTED_FH,
+      FixedPcdGet64 (PcdDmc620DramOneBitErrorDataBase) +
+        (FixedPcdGet64 (PcdDmc620DramOneBitErrorDataSize) * DmcIdx));
+  } else {
+    // ToDo: Add support for other DMC620 error sources.
+    DEBUG ((DEBUG_ERROR, "Unsupported DMC-620 error reported, ignoring\n"));
+  }
+
+  // No data to send using the MM communication buffer so clear the comm buffer
+  // size.
+  *CommBufferSize = 0;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Initialize function for the driver.
+
+  Registers MMI handlers to process RAS events on DMC and installs required
+  protocols to publish the error source descriptors.
+
+  @param[in] ImageHandle Handle to image.
+  @param[in] SystemTable Pointer to System table.
+
+  @retval EFI_SUCCESS On successful installation of RAS handlers for DMC.
+  @retval Other       Failure in installing RAS handlers for DMC.
+
+**/
+EFI_STATUS
+EFIAPI
+Dmc620MmDriverInitialize (
+  IN EFI_HANDLE          ImageHandle,
+  IN EFI_MM_SYSTEM_TABLE *SystemTable
+  )
+{
+  EFI_MM_SYSTEM_TABLE *mMmst;
+  EFI_STATUS          Status;
+  EFI_HANDLE          DispatchHandle;
+
+  ASSERT (SystemTable != NULL);
+  mMmst = SystemTable;
+
+  // Register RAS event MMI handlers.
+  Status = mMmst->MmiHandlerRegister (
+                    Dmc620ErrorEventHandler,
+                    &gArmDmcEventHandlerGuid,
+                    &DispatchHandle
+                     );
+  if (EFI_ERROR(Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "Registration failed for DMC RAS event handler, Status:%r\n",
+      Status
+      ));
+
+     return Status;
+  }
+
+  // Installs the HEST error source descriptor protocol.
+  Status = Dmc620InstallErrorSourceDescProtocol (SystemTable);
+  if (EFI_ERROR(Status)) {
+    mMmst->MmiHandlerUnRegister (DispatchHandle);
+  }
+
+  return Status;
+}
diff --git a/Platform/ARM/Drivers/Dmc620Mm/Dmc620MmErrorSourceInfo.c b/Platform/ARM/Drivers/Dmc620Mm/Dmc620MmErrorSourceInfo.c
new file mode 100644
index 000000000000..b7cc6368a2a4
--- /dev/null
+++ b/Platform/ARM/Drivers/Dmc620Mm/Dmc620MmErrorSourceInfo.c
@@ -0,0 +1,191 @@
+/** @file
+  DMC-620 Memory Controller HEST error source descriptors
+
+  Implements the HEST Error Source Descriptor protocol. Publishes the Error
+  Sources supported using the GHESv2 type error source descriptor.
+
+  Copyright (c) 2020, ARM Limited. All rights reserved.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Dmc620Mm.h>
+
+/**
+  Populate the DRAM Error Source Descriptor.
+
+  Populate DMC-620 DRAM error source descriptor as a GHESv2 type in the HEST
+  table. The error source descriptor is populate with appropriate values
+  based on the instance number of DMC-620.
+
+  @param[in]  DmcIdx      Instance number of the DMC-620.
+  @param[in]  ErrorDesc   HEST error source descriptor Information
+
+**/
+STATIC
+VOID
+EFIAPI
+Dmc620SetupDramErrorDescriptor (
+  IN  EFI_ACPI_6_3_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE *ErrorDesc,
+  IN  UINTN     DmcIdx
+  )
+{
+  UINTN  ErrorBlockData;
+ 
+  //
+  // Address of reserved memory for the error status block that will be used
+  // to hold the information about the DRAM error.
+  //
+  ErrorBlockData = FixedPcdGet64 (PcdDmc620DramOneBitErrorDataBase) +
+                     (FixedPcdGet64 (PcdDmc620DramOneBitErrorDataSize) * DmcIdx);
+
+  // Populate the DRAM error descriptor.
+  *ErrorDesc =
+    (EFI_ACPI_6_3_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE) {
+      .Type = EFI_ACPI_6_3_GENERIC_HARDWARE_ERROR_VERSION_2,
+      .SourceId = FixedPcdGet16 (PcdDmc620DramOneBitErrorSourceId) + DmcIdx,
+      .RelatedSourceId = 0xFFFF,
+      .Flags = 0,
+      .Enabled = 1,
+      .NumberOfRecordsToPreAllocate = 1,
+      .MaxSectionsPerRecord = 1,
+      .MaxRawDataLength = sizeof (EFI_PLATFORM_MEMORY_ERROR_DATA),
+      .ErrorStatusAddress =
+        ARM_PLATFORM_ACPI_6_3_GHES_GENERIC_ADDRESS_STRUCT_INIT (
+          (ErrorBlockData + 8)
+          ),
+      .NotificationStructure =
+        ARM_PLATFORM_ACPI_6_3_GHES_NOTIFICATION_STRUCT_INIT (
+          EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_SOFTWARE_DELEGATED_EXCEPTION,
+          0,
+          FixedPcdGet32 (PcdDmc620DramErrorSdeiEventBase) + DmcIdx
+          ),
+      .ErrorStatusBlockLength =
+	sizeof (EFI_ACPI_6_3_GENERIC_ERROR_STATUS_STRUCTURE) +
+	sizeof (EFI_ACPI_6_3_GENERIC_ERROR_DATA_ENTRY_STRUCTURE) +
+	sizeof (EFI_PLATFORM_MEMORY_ERROR_DATA),
+      .ReadAckRegister =
+        ARM_PLATFORM_ACPI_6_3_GHES_GENERIC_ADDRESS_STRUCT_INIT (ErrorBlockData),
+      .ReadAckPreserve = 0,
+      .ReadAckWrite = 0
+      };
+}
+
+/**
+  MMI handler implementing the HEST error source descriptor protocol.
+
+  Returns the error source descriptor information for all DMC(s) error sources
+  and also returns its count and length. Computes base addresses for each
+  supported error source and populate the global context with the base address
+  information.
+
+  @param[in]  This               Pointer for this protocol.
+  @param[out] Buffer             HEST error source descriptor Information
+                                 buffer.
+  @param[out] ErrorSourcesLength Total length of Error Source Descriptors
+  @param[out] ErrorSourceCount   Total number of supported error spurces.
+
+  @retval EFI_SUCCESS            Buffer has valid Error Source descriptor
+                                 information.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+Dmc620ErrorSourceDescInfoGet (
+  IN  MM_HEST_ERROR_SOURCE_DESC_PROTOCOL *This,
+  OUT VOID                               **Buffer,
+  OUT UINTN                              *ErrorSourcesLength,
+  OUT UINTN                              *ErrorSourcesCount
+  )
+{
+  EFI_ACPI_6_3_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE *ErrorDescriptor;
+  UINTN                                                          DmcIdx;
+
+  //
+  // Update the error source length and error source count for error sources
+  // supported by all DMCs.
+  //
+  *ErrorSourcesLength =
+    FixedPcdGet64 (PcdDmc620NumCtrl) *
+    FixedPcdGet64 (PcdDmc620ErrSourceCount) *
+    sizeof(EFI_ACPI_6_3_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE);
+  *ErrorSourcesCount = FixedPcdGet64 (PcdDmc620NumCtrl) *
+                         FixedPcdGet64 (PcdDmc620ErrSourceCount);
+
+  //
+  // If 'Buffer' is NULL, this invocation of the protocol handler is to
+  // determine the total size of all the error source descriptor instances.
+  //
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Buffer to be updated with error source descriptor(s) information.
+  ErrorDescriptor =
+    (EFI_ACPI_6_3_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE *)*Buffer;
+
+  //
+  // Populate the available error source descriptor for all the DMC-620
+  // instances.
+  //
+  for (DmcIdx = 0; DmcIdx < FixedPcdGet64 (PcdDmc620NumCtrl); DmcIdx++)
+  {
+    // Add the one-bit DRAM error source descriptor. 
+    Dmc620SetupDramErrorDescriptor(ErrorDescriptor, DmcIdx);
+    ErrorDescriptor++;
+  }
+
+  return EFI_SUCCESS;
+}
+
+//
+// DMC-620 MM_HEST_ERROR_SOURCE_DESC_PROTOCOL protocol instance.
+//
+STATIC MM_HEST_ERROR_SOURCE_DESC_PROTOCOL mDmc620ErrorSourceDesc = {
+  Dmc620ErrorSourceDescInfoGet
+};
+
+/**
+  Allow reporting of supported DMC-620 error sources
+
+  Install the Hest Error Source Descriptor protocol handler to allow publishing
+  of the supported DMC-620 memory controller error sources.
+
+  @param[in] MmSystemTable Pointer to System table.
+
+  @retval EFI_SUCCESS           Protocol installation successful.
+  @retval EFI_INVALID_PARAMETER Invalid system table parameter.
+
+**/
+EFI_STATUS
+Dmc620InstallErrorSourceDescProtocol (
+  IN EFI_MM_SYSTEM_TABLE *MmSystemTable
+  )
+{
+  EFI_HANDLE mDmcHandle = NULL;
+  EFI_STATUS Status;
+
+  // Check if the MmSystemTable is initialized.
+  if (MmSystemTable == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Install HEST error source descriptor protocol for DMC(s).
+  Status = MmSystemTable->MmInstallProtocolInterface (
+                            &mDmcHandle,
+                            &gMmHestErrorSourceDescProtocolGuid,
+                            EFI_NATIVE_INTERFACE,
+                            &mDmc620ErrorSourceDesc
+                            );
+  if (EFI_ERROR(Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "Failed installing HEST error source descriptor protocol, status: %r\n",
+      Status
+      ));
+  }
+
+  return Status;
+}
-- 
2.17.1


  reply	other threads:[~2020-10-30  8:42 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-30  8:41 [edk2-platforms][PATCH 0/6] Platform/ARM/Sgi: Add DMC620 1-bit ECC error handling Omkar Anand Kulkarni
2020-10-30  8:41 ` Omkar Anand Kulkarni [this message]
2020-10-30  8:41 ` [edk2-platforms][PATCH 2/6] Platform/ARM/Sgi: Install SDEI ACPI table Omkar Anand Kulkarni
2020-10-30  8:41 ` [edk2-platforms][PATCH 3/6] Platform/Arm/Sgi: Install HEST " Omkar Anand Kulkarni
2020-10-30  8:41 ` [edk2-platforms][PATCH 4/6] Platform/Arm/Sgi: define memory region for GHES error status block Omkar Anand Kulkarni
2020-10-30  8:41 ` [edk2-platforms][PATCH 5/6] Platform/Arm/Sgi: dmc-620 firmware-first error handling Omkar Anand Kulkarni
2020-10-30  8:41 ` [edk2-platforms][PATCH 6/6] Platform/Arm/Sgi575: Define values for ACPI table header Omkar Anand Kulkarni

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201030084156.8291-2-omkar.kulkarni@arm.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox