aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/platform-interrupt-controller-API.rst18
-rw-r--r--drivers/arm/gic/v2/gicv2_main.c24
-rw-r--r--drivers/arm/gic/v3/gicv3_main.c22
-rw-r--r--include/drivers/arm/gicv2.h1
-rw-r--r--include/drivers/arm/gicv3.h1
-rw-r--r--include/lib/aarch32/arch_helpers.h1
-rw-r--r--include/lib/aarch64/arch_helpers.h1
-rw-r--r--include/plat/common/platform.h1
-rw-r--r--plat/common/plat_gicv2.c5
-rw-r--r--plat/common/plat_gicv3.c5
10 files changed, 79 insertions, 0 deletions
diff --git a/docs/platform-interrupt-controller-API.rst b/docs/platform-interrupt-controller-API.rst
index d5c1673399..795c085625 100644
--- a/docs/platform-interrupt-controller-API.rst
+++ b/docs/platform-interrupt-controller-API.rst
@@ -274,6 +274,24 @@ In case of ARM standard platforms using GIC, the implementation of the API
writes to the GIC *Clear Pending Register* to clear the interrupt pending
status, and inserts barrier to make memory updates visible afterwards.
+Function: unsigned int plat_ic_set_priority_mask(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Return : int
+
+This API should set the priority mask (first parameter) in the interrupt
+controller such that only interrupts of higher priority than the supplied one
+may be signalled to the PE. The API should return the current priority value
+that it's overwriting.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+inserts to order memory updates before updating mask, then writes to the GIC
+*Priority Mask Register*, and make sure memory updates are visible before
+potential trigger due to mask update.
+
----
*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c
index eab4c3bfed..59b6632329 100644
--- a/drivers/arm/gic/v2/gicv2_main.c
+++ b/drivers/arm/gic/v2/gicv2_main.c
@@ -476,3 +476,27 @@ void gicv2_set_interrupt_pending(unsigned int id)
dsbishst();
gicd_set_ispendr(driver_data->gicd_base, id);
}
+
+/*******************************************************************************
+ * This function sets the PMR register with the supplied value. Returns the
+ * original PMR.
+ ******************************************************************************/
+unsigned int gicv2_set_pmr(unsigned int mask)
+{
+ unsigned int old_mask;
+
+ assert(driver_data);
+ assert(driver_data->gicc_base);
+
+ old_mask = gicc_read_pmr(driver_data->gicc_base);
+
+ /*
+ * Order memory updates w.r.t. PMR write, and ensure they're visible
+ * before potential out of band interrupt trigger because of PMR update.
+ */
+ dmbishst();
+ gicc_write_pmr(driver_data->gicc_base, mask);
+ dsbishst();
+
+ return old_mask;
+}
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index 43dd77f126..0f50f6d763 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -1089,3 +1089,25 @@ void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num)
gicd_set_ispendr(gicv3_driver_data->gicd_base, id);
}
}
+
+/*******************************************************************************
+ * This function sets the PMR register with the supplied value. Returns the
+ * original PMR.
+ ******************************************************************************/
+unsigned int gicv3_set_pmr(unsigned int mask)
+{
+ unsigned int old_mask;
+
+ old_mask = read_icc_pmr_el1();
+
+ /*
+ * Order memory updates w.r.t. PMR write, and ensure they're visible
+ * before potential out of band interrupt trigger because of PMR update.
+ * PMR system register writes are self-synchronizing, so no ISB required
+ * thereafter.
+ */
+ dsbishst();
+ write_icc_pmr_el1(mask);
+
+ return old_mask;
+}
diff --git a/include/drivers/arm/gicv2.h b/include/drivers/arm/gicv2.h
index bc2822ee1d..9b8510aabe 100644
--- a/include/drivers/arm/gicv2.h
+++ b/include/drivers/arm/gicv2.h
@@ -174,6 +174,7 @@ void gicv2_raise_sgi(int sgi_num, int proc_num);
void gicv2_set_spi_routing(unsigned int id, int proc_num);
void gicv2_set_interrupt_pending(unsigned int id);
void gicv2_clear_interrupt_pending(unsigned int id);
+unsigned int gicv2_set_pmr(unsigned int mask);
#endif /* __ASSEMBLY__ */
#endif /* __GICV2_H__ */
diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h
index 09d6d80848..95b6e3bb9b 100644
--- a/include/drivers/arm/gicv3.h
+++ b/include/drivers/arm/gicv3.h
@@ -389,6 +389,7 @@ void gicv3_set_spi_routing(unsigned int id, unsigned int irm,
u_register_t mpidr);
void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num);
void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num);
+unsigned int gicv3_set_pmr(unsigned int mask);
#endif /* __ASSEMBLY__ */
#endif /* __GICV3_H__ */
diff --git a/include/lib/aarch32/arch_helpers.h b/include/lib/aarch32/arch_helpers.h
index c8caea2867..469e9b0d05 100644
--- a/include/lib/aarch32/arch_helpers.h
+++ b/include/lib/aarch32/arch_helpers.h
@@ -213,6 +213,7 @@ DEFINE_SYSOP_TYPE_FUNC(dmb, ld)
DEFINE_SYSOP_TYPE_FUNC(dsb, ish)
DEFINE_SYSOP_TYPE_FUNC(dsb, ishst)
DEFINE_SYSOP_TYPE_FUNC(dmb, ish)
+DEFINE_SYSOP_TYPE_FUNC(dmb, ishst)
DEFINE_SYSOP_FUNC(isb)
void __dead2 smc(uint32_t r0, uint32_t r1, uint32_t r2, uint32_t r3,
diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h
index b880497ce6..03110fd5a8 100644
--- a/include/lib/aarch64/arch_helpers.h
+++ b/include/lib/aarch64/arch_helpers.h
@@ -204,6 +204,7 @@ DEFINE_SYSOP_TYPE_FUNC(dmb, ld)
DEFINE_SYSOP_TYPE_FUNC(dsb, ish)
DEFINE_SYSOP_TYPE_FUNC(dsb, ishst)
DEFINE_SYSOP_TYPE_FUNC(dmb, ish)
+DEFINE_SYSOP_TYPE_FUNC(dmb, ishst)
DEFINE_SYSOP_FUNC(isb)
uint32_t get_afflvl_shift(uint32_t);
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index ab5d68ed5c..f03a3997af 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -87,6 +87,7 @@ void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
u_register_t mpidr);
void plat_ic_set_interrupt_pending(unsigned int id);
void plat_ic_clear_interrupt_pending(unsigned int id);
+unsigned int plat_ic_set_priority_mask(unsigned int mask);
/*******************************************************************************
* Optional common functions (may be overridden)
diff --git a/plat/common/plat_gicv2.c b/plat/common/plat_gicv2.c
index 646049489e..05fabcab1d 100644
--- a/plat/common/plat_gicv2.c
+++ b/plat/common/plat_gicv2.c
@@ -272,3 +272,8 @@ void plat_ic_clear_interrupt_pending(unsigned int id)
{
gicv2_clear_interrupt_pending(id);
}
+
+unsigned int plat_ic_set_priority_mask(unsigned int mask)
+{
+ return gicv2_set_pmr(mask);
+}
diff --git a/plat/common/plat_gicv3.c b/plat/common/plat_gicv3.c
index e5bf014d28..52ceb6a7ca 100644
--- a/plat/common/plat_gicv3.c
+++ b/plat/common/plat_gicv3.c
@@ -266,6 +266,11 @@ void plat_ic_clear_interrupt_pending(unsigned int id)
assert(id >= MIN_PPI_ID);
gicv3_clear_interrupt_pending(id, plat_my_core_pos());
}
+
+unsigned int plat_ic_set_priority_mask(unsigned int mask)
+{
+ return gicv3_set_pmr(mask);
+}
#endif
#ifdef IMAGE_BL32