REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4466

This change provides additional functionalities to `ArmGicLib` to
manipulate pending interrupt related status. The added functions include:

- `ArmGicSetPendingInterrupt`
- `ArmGicClearPendingInterrupt`
- `ArmGicIsInterruptPending`

Cc: Leif Lindholm <quic_llind...@quicinc.com>
Cc: Ard Biesheuvel <ardb+tianoc...@kernel.org>
Cc: Sami Mujawar <sami.muja...@arm.com>

Signed-off-by: Kun Qin <ku...@microsoft.com>
---
 ArmPkg/Drivers/ArmGic/ArmGicLib.c  | 162 ++++++++++++++++++++
 ArmPkg/ArmPkg.ci.yaml              |   2 +
 ArmPkg/Include/Library/ArmGicLib.h |  49 ++++++
 3 files changed, 213 insertions(+)

diff --git a/ArmPkg/Drivers/ArmGic/ArmGicLib.c 
b/ArmPkg/Drivers/ArmGic/ArmGicLib.c
index 830d822d2c05..3844dc05e2af 100644
--- a/ArmPkg/Drivers/ArmGic/ArmGicLib.c
+++ b/ArmPkg/Drivers/ArmGic/ArmGicLib.c
@@ -33,6 +33,12 @@
 #define IPRIORITY_ADDRESS(base, offset)  ((base) +\
           ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDIPR + 4 * (offset))
 
+#define ISPENDR_ADDRESS(base, offset)  ((base) +\
+          ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISPENDR + 4 * (offset))
+
+#define ICPENDR_ADDRESS(base, offset)  ((base) +\
+          ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICPENDR + 4 * (offset))
+
 /**
  *
  * Return whether the Source interrupt index refers to a shared interrupt (SPI)
@@ -440,6 +446,162 @@ ArmGicIsInterruptEnabled (
   return ((Interrupts & (1 << RegShift)) != 0);
 }
 
+/**
+  Set an interrupt to pending state from GIC.
+
+  @param GicDistributorBase    Base address of platform GIC Distributor.
+  @param GicRedistributorBase  Base address of platform GIC Redistributor.
+  @param Source                Interrupt source ID.
+**/
+VOID
+EFIAPI
+ArmGicSetPendingInterrupt (
+  IN UINTN  GicDistributorBase,
+  IN UINTN  GicRedistributorBase,
+  IN UINTN  Source
+  )
+{
+  UINT32                 RegOffset;
+  UINTN                  RegShift;
+  ARM_GIC_ARCH_REVISION  Revision;
+  UINTN                  GicCpuRedistributorBase;
+
+  // Calculate enable register offset and bit position
+  RegOffset = (UINT32)(Source / 32);
+  RegShift  = Source % 32;
+
+  Revision = ArmGicGetSupportedArchRevision ();
+  if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
+      FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
+      SourceIsSpi (Source))
+  {
+    // Write set-pending register
+    MmioWrite32 (
+      GicDistributorBase + ARM_GIC_ICDSPR + (4 * RegOffset),
+      1 << RegShift
+      );
+  } else {
+    GicCpuRedistributorBase = GicGetCpuRedistributorBase (
+                                GicRedistributorBase,
+                                Revision
+                                );
+    if (GicCpuRedistributorBase == 0) {
+      ASSERT_EFI_ERROR (EFI_NOT_FOUND);
+      return;
+    }
+
+    // Write set-enable register
+    MmioWrite32 (
+      ISPENDR_ADDRESS (GicCpuRedistributorBase, RegOffset),
+      1 << RegShift
+      );
+  }
+}
+
+/**
+  Clear a pending interrupt from GIC.
+
+  @param GicDistributorBase    Base address of platform GIC Distributor.
+  @param GicRedistributorBase  Base address of platform GIC Redistributor.
+  @param Source                Interrupt source ID.
+**/
+VOID
+EFIAPI
+ArmGicClearPendingInterrupt (
+  IN UINTN  GicDistributorBase,
+  IN UINTN  GicRedistributorBase,
+  IN UINTN  Source
+  )
+{
+  UINT32                 RegOffset;
+  UINTN                  RegShift;
+  ARM_GIC_ARCH_REVISION  Revision;
+  UINTN                  GicCpuRedistributorBase;
+
+  // Calculate enable register offset and bit position
+  RegOffset = (UINT32)(Source / 32);
+  RegShift  = Source % 32;
+
+  Revision = ArmGicGetSupportedArchRevision ();
+  if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
+      FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
+      SourceIsSpi (Source))
+  {
+    // Write clear-enable register
+    MmioWrite32 (
+      GicDistributorBase + ARM_GIC_ICDICPR + (4 * RegOffset),
+      1 << RegShift
+      );
+  } else {
+    GicCpuRedistributorBase = GicGetCpuRedistributorBase (
+                                GicRedistributorBase,
+                                Revision
+                                );
+    if (GicCpuRedistributorBase == 0) {
+      return;
+    }
+
+    // Write clear-enable register
+    MmioWrite32 (
+      ICPENDR_ADDRESS (GicCpuRedistributorBase, RegOffset),
+      1 << RegShift
+      );
+  }
+}
+
+/**
+  Check if an interrupt is pending in GIC.
+
+  @param GicDistributorBase    Base address of platform GIC Distributor.
+  @param GicRedistributorBase  Base address of platform GIC Redistributor.
+  @param Source                Interrupt source ID.
+
+  @return BOOLEAN   TRUE if the interrupt is pending, FALSE otherwise.
+**/
+BOOLEAN
+EFIAPI
+ArmGicIsInterruptPending (
+  IN UINTN  GicDistributorBase,
+  IN UINTN  GicRedistributorBase,
+  IN UINTN  Source
+  )
+{
+  UINT32                 RegOffset;
+  UINTN                  RegShift;
+  ARM_GIC_ARCH_REVISION  Revision;
+  UINTN                  GicCpuRedistributorBase;
+  UINT32                 Interrupts;
+
+  // Calculate enable register offset and bit position
+  RegOffset = (UINT32)(Source / 32);
+  RegShift  = Source % 32;
+
+  Revision = ArmGicGetSupportedArchRevision ();
+  if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
+      FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
+      SourceIsSpi (Source))
+  {
+    Interrupts = MmioRead32 (
+                   GicDistributorBase + ARM_GIC_ICDSPR + (4 * RegOffset)
+                   );
+  } else {
+    GicCpuRedistributorBase = GicGetCpuRedistributorBase (
+                                GicRedistributorBase,
+                                Revision
+                                );
+    if (GicCpuRedistributorBase == 0) {
+      return 0;
+    }
+
+    // Read set-enable register
+    Interrupts = MmioRead32 (
+                   ISPENDR_ADDRESS (GicCpuRedistributorBase, RegOffset)
+                   );
+  }
+
+  return ((Interrupts & (1 << RegShift)) != 0);
+}
+
 VOID
 EFIAPI
 ArmGicDisableDistributor (
diff --git a/ArmPkg/ArmPkg.ci.yaml b/ArmPkg/ArmPkg.ci.yaml
index 8a8f738437d5..06e31498cf79 100644
--- a/ArmPkg/ArmPkg.ci.yaml
+++ b/ArmPkg/ArmPkg.ci.yaml
@@ -154,11 +154,13 @@
           "icdsgir",
           "icdspr",
           "icenabler",
+          "icpendr",
           "intid",
           "ipriority",
           "irouter",
           "isenabler",
           "ishst",
+          "ispendr",
           "istatus",
           "itargets",
           "lable",
diff --git a/ArmPkg/Include/Library/ArmGicLib.h 
b/ArmPkg/Include/Library/ArmGicLib.h
index 28d58f187d4f..83d52756d61a 100644
--- a/ArmPkg/Include/Library/ArmGicLib.h
+++ b/ArmPkg/Include/Library/ArmGicLib.h
@@ -78,6 +78,8 @@
 // GIC SGI & PPI Redistributor frame
 #define ARM_GICR_ISENABLER  0x0100      // Interrupt Set-Enable Registers
 #define ARM_GICR_ICENABLER  0x0180      // Interrupt Clear-Enable Registers
+#define ARM_GICR_ISPENDR    0x0200      // Interrupt Set-Pending Registers
+#define ARM_GICR_ICPENDR    0x0280      // Interrupt Clear-Pending Registers
 
 // GIC Cpu interface
 #define ARM_GIC_ICCICR   0x00         // CPU Interface Control Register
@@ -167,6 +169,53 @@ ArmGicDisableInterruptInterface (
   IN  UINTN  GicInterruptInterfaceBase
   );
 
+/**
+  Set an interrupt to pending state from GIC.
+
+  @param GicDistributorBase    Base address of platform GIC Distributor.
+  @param GicRedistributorBase  Base address of platform GIC Redistributor.
+  @param Source                Interrupt source ID.
+**/
+VOID
+EFIAPI
+ArmGicSetPendingInterrupt (
+  IN UINTN  GicDistributorBase,
+  IN UINTN  GicRedistributorBase,
+  IN UINTN  Source
+  );
+
+/**
+  Clear a pending interrupt from GIC.
+
+  @param GicDistributorBase    Base address of platform GIC Distributor.
+  @param GicRedistributorBase  Base address of platform GIC Redistributor.
+  @param Source                Interrupt source ID.
+**/
+VOID
+EFIAPI
+ArmGicClearPendingInterrupt (
+  IN UINTN  GicDistributorBase,
+  IN UINTN  GicRedistributorBase,
+  IN UINTN  Source
+  );
+
+/**
+  Check if an interrupt is pending in GIC.
+
+  @param GicDistributorBase    Base address of platform GIC Distributor.
+  @param GicRedistributorBase  Base address of platform GIC Redistributor.
+  @param Source                Interrupt source ID.
+
+  @return BOOLEAN   TRUE if the interrupt is pending, FALSE otherwise.
+**/
+BOOLEAN
+EFIAPI
+ArmGicIsInterruptPending (
+  IN UINTN  GicDistributorBase,
+  IN UINTN  GicRedistributorBase,
+  IN UINTN  Source
+  );
+
 VOID
 EFIAPI
 ArmGicEnableDistributor (
-- 
2.41.0.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#107190): https://edk2.groups.io/g/devel/message/107190
Mute This Topic: https://groups.io/mt/100337225/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to