GICv3: ITS architectural save and restore helpers
authorSoby Mathew <soby.mathew@arm.com>
Tue, 18 Jul 2017 15:12:45 +0000 (16:12 +0100)
committerSoby Mathew <soby.mathew@arm.com>
Thu, 5 Oct 2017 15:47:53 +0000 (16:47 +0100)
This patch adds functions to save and restore GICv3 ITS registers during
system suspend. Please note that the power management of GIC ITS is
implementation defined. These functions only implements the
architectural part of the ITS power management and they do not restore
memory structures or register content required to support ITS. Even if
the ITS implementation stores structures in memory, an implementation
defined power down sequence is likely to be required to flush some
internal ITS caches to memory. If such implementation defined sequence
is not followed, the platform must ensure that the ITS is not power
gated during system suspend.

Change-Id: I5f31e5541975aa7dcaab69b0b7f67583c0e27678
Signed-off-by: Soby Mathew <soby.mathew@arm.com>
Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
drivers/arm/gic/v3/gicv3_main.c
drivers/arm/gic/v3/gicv3_private.h
include/drivers/arm/gicv3.h

index 83bf430f4684c4caeeb9c8ff469b92e2e05ab8c8..7282bdc451e1923c83a01e8d552be6bbcf36b70b 100644 (file)
@@ -428,6 +428,74 @@ unsigned int gicv3_get_interrupt_type(unsigned int id,
        return INTR_GROUP0;
 }
 
+/*****************************************************************************
+ * Function to save and disable the GIC ITS register context. The power
+ * management of GIC ITS is implementation-defined and this function doesn't
+ * save any memory structures required to support ITS. As the sequence to save
+ * this state is implementation defined, it should be executed in platform
+ * specific code. Calling this function alone and then powering down the GIC and
+ * ITS without implementing the aforementioned platform specific code will
+ * corrupt the ITS state.
+ *
+ * This function must be invoked after the GIC CPU interface is disabled.
+ *****************************************************************************/
+void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx)
+{
+       int i;
+
+       assert(gicv3_driver_data);
+       assert(IS_IN_EL3());
+       assert(its_ctx);
+       assert(gits_base);
+
+       its_ctx->gits_ctlr = gits_read_ctlr(gits_base);
+
+       /* Disable the ITS */
+       gits_write_ctlr(gits_base, its_ctx->gits_ctlr &
+                                       (~GITS_CTLR_ENABLED_BIT));
+
+       /* Wait for quiescent state */
+       gits_wait_for_quiescent_bit(gits_base);
+
+       its_ctx->gits_cbaser = gits_read_cbaser(gits_base);
+       its_ctx->gits_cwriter = gits_read_cwriter(gits_base);
+
+       for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++)
+               its_ctx->gits_baser[i] = gits_read_baser(gits_base, i);
+}
+
+/*****************************************************************************
+ * Function to restore the GIC ITS register context. The power
+ * management of GIC ITS is implementation defined and this function doesn't
+ * restore any memory structures required to support ITS. The assumption is
+ * that these structures are in memory and are retained during system suspend.
+ *
+ * This must be invoked before the GIC CPU interface is enabled.
+ *****************************************************************************/
+void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx)
+{
+       int i;
+
+       assert(gicv3_driver_data);
+       assert(IS_IN_EL3());
+       assert(its_ctx);
+       assert(gits_base);
+
+       /* Assert that the GITS is disabled and quiescent */
+       assert((gits_read_ctlr(gits_base) & GITS_CTLR_ENABLED_BIT) == 0);
+       assert((gits_read_ctlr(gits_base) & GITS_CTLR_QUIESCENT_BIT) == 1);
+
+       gits_write_cbaser(gits_base, its_ctx->gits_cbaser);
+       gits_write_cwriter(gits_base, its_ctx->gits_cwriter);
+
+       for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++)
+               gits_write_baser(gits_base, i, its_ctx->gits_baser[i]);
+
+       /* Restore the ITS CTLR but leave the ITS disabled */
+       gits_write_ctlr(gits_base, its_ctx->gits_ctlr &
+                       (~GITS_CTLR_ENABLED_BIT));
+}
+
 /*****************************************************************************
  * Function to save the GIC Redistributor register context. This function
  * must be invoked after CPU interface disable and prior to Distributor save.
index 7224e0675d447c257f70da5b4aab5987b60c7074..59298edf2de1aa9e515b77794b4b6edd0a70950f 100644 (file)
@@ -314,4 +314,60 @@ static inline void gicr_write_pendbaser(uintptr_t base, unsigned int val)
        mmio_write_32(base + GICR_PENDBASER, val);
 }
 
+/*******************************************************************************
+ * GIC ITS functions to read and write entire ITS registers.
+ ******************************************************************************/
+static inline uint32_t gits_read_ctlr(uintptr_t base)
+{
+       return mmio_read_32(base + GITS_CTLR);
+}
+
+static inline void gits_write_ctlr(uintptr_t base, unsigned int val)
+{
+       mmio_write_32(base + GITS_CTLR, val);
+}
+
+static inline uint64_t gits_read_cbaser(uintptr_t base)
+{
+       return mmio_read_64(base + GITS_CBASER);
+}
+
+static inline void gits_write_cbaser(uintptr_t base, uint64_t val)
+{
+       mmio_write_32(base + GITS_CBASER, val);
+}
+
+static inline uint64_t gits_read_cwriter(uintptr_t base)
+{
+       return mmio_read_64(base + GITS_CWRITER);
+}
+
+static inline void gits_write_cwriter(uintptr_t base, uint64_t val)
+{
+       mmio_write_32(base + GITS_CWRITER, val);
+}
+
+static inline uint64_t gits_read_baser(uintptr_t base, unsigned int its_table_id)
+{
+       assert(its_table_id < 8);
+       return mmio_read_64(base + GITS_BASER + (8 * its_table_id));
+}
+
+static inline void gits_write_baser(uintptr_t base, unsigned int its_table_id, uint64_t val)
+{
+       assert(its_table_id < 8);
+       mmio_write_64(base + GITS_BASER + (8 * its_table_id), val);
+}
+
+/*
+ * Wait for Quiescent bit when GIC ITS is disabled
+ */
+static inline void gits_wait_for_quiescent_bit(uintptr_t gits_base)
+{
+       assert(!(gits_read_ctlr(gits_base) & GITS_CTLR_ENABLED_BIT));
+       while ((gits_read_ctlr(gits_base) & GITS_CTLR_QUIESCENT_BIT) == 0)
+               ;
+}
+
+
 #endif /* __GICV3_PRIVATE_H__ */
index d20421d285b70cc7c15918702c80c8a8865e0883..c52fe4833fa943ca40deac97529df6377ee5879c 100644 (file)
 #define IAR1_EL1_INTID_SHIFT           0
 #define IAR1_EL1_INTID_MASK            0xffffff
 
+/*****************************************************************************
+ * GICv3 ITS registers and constants
+ *****************************************************************************/
+
+#define GITS_CTLR                      0x0
+#define GITS_IIDR                      0x4
+#define GITS_TYPER                     0x8
+#define GITS_CBASER                    0x80
+#define GITS_CWRITER                   0x88
+#define GITS_CREADR                    0x90
+#define GITS_BASER                     0x100
+
+/* GITS_CTLR bit definitions */
+#define GITS_CTLR_ENABLED_BIT          1
+#define GITS_CTLR_QUIESCENT_SHIFT      31
+#define GITS_CTLR_QUIESCENT_BIT                (1U << GITS_CTLR_QUIESCENT_SHIFT)
+
 #ifndef __ASSEMBLY__
 
 #include <gic_common.h>
@@ -293,6 +310,16 @@ typedef struct gicv3_dist_ctx {
        uint32_t gicd_nsacr[GICD_NUM_REGS(NSACR)];
 } gicv3_dist_ctx_t;
 
+typedef struct gicv3_its_ctx {
+       /* 64 bits registers */
+       uint64_t gits_cbaser;
+       uint64_t gits_cwriter;
+       uint64_t gits_baser[8];
+
+       /* 32 bits registers */
+       uint32_t gits_ctlr;
+} gicv3_its_ctx_t;
+
 /*******************************************************************************
  * GICv3 EL3 driver API
  ******************************************************************************/
@@ -319,6 +346,8 @@ void gicv3_distif_post_restore(unsigned int proc_num);
 void gicv3_distif_pre_save(unsigned int proc_num);
 void gicv3_rdistif_init_restore(unsigned int proc_num, const gicv3_redist_ctx_t * const rdist_ctx);
 void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ctx);
+void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx);
+void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx);
 
 #endif /* __ASSEMBLY__ */
 #endif /* __GICV3_H__ */