Commit 8db978b5 authored by Jeenu Viswambharan's avatar Jeenu Viswambharan
Browse files

GIC: Add API to raise secure SGI



API documentation updated.

Change-Id: I129725059299af6cc612bafa8d74817f779d7c4f
Signed-off-by: default avatarJeenu Viswambharan <jeenu.viswambharan@arm.com>
parent 74dce7fa
......@@ -200,6 +200,23 @@ For GICv2:
``INTR_TYPE_S_EL1`` maps to Group 0. Otherwise, ``INTR_TYPE_EL3`` maps to
Group 0 interrupt.
Function: void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target); [optional]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
Argument : int
Argument : u_register_t
Return : void
This API should raise an EL3 SGI. The first parameter, ``sgi_num``, specifies
the ID of the SGI. The second parameter, ``target``, must be the MPIDR of the
target PE.
In case of ARM standard platforms using GIC, the implementation of the API
inserts barrier to make memory updates visible before raising SGI, then writes
to appropriate *SGI Register* in order to raise the EL3 SGI.
----
*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
......@@ -368,3 +368,38 @@ void gicv2_set_interrupt_type(unsigned int id, unsigned int type)
}
spin_unlock(&gic_lock);
}
/*******************************************************************************
* This function raises the specified SGI to requested targets.
*
* The proc_num parameter must be the linear index of the target PE in the
* system.
******************************************************************************/
void gicv2_raise_sgi(int sgi_num, int proc_num)
{
unsigned int sgir_val, target;
assert(driver_data);
assert(proc_num < GICV2_MAX_TARGET_PE);
assert(driver_data->gicd_base);
/*
* Target masks array must have been supplied, and the core position
* should be valid.
*/
assert(driver_data->target_masks);
assert(proc_num < driver_data->target_masks_num);
/* Don't raise SGI if the mask hasn't been populated */
target = driver_data->target_masks[proc_num];
assert(target != 0);
sgir_val = GICV2_SGIR_VALUE(SGIR_TGT_SPECIFIC, target, sgi_num);
/*
* Ensure that any shared variable updates depending on out of band
* interrupt trigger are observed before raising SGI.
*/
dsbishst();
gicd_write_sgir(driver_data->gicd_base, sgir_val);
}
......@@ -31,6 +31,14 @@ static inline unsigned int gicd_read_pidr2(uintptr_t base)
return mmio_read_32(base + GICD_PIDR2_GICV2);
}
/*******************************************************************************
* GIC Distributor interface accessors for writing entire registers
******************************************************************************/
static inline void gicd_write_sgir(uintptr_t base, unsigned int val)
{
mmio_write_32(base + GICD_SGIR, val);
}
/*******************************************************************************
* GIC CPU interface accessors for reading entire registers
******************************************************************************/
......
......@@ -960,3 +960,42 @@ void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
spin_unlock(&gic_lock);
}
}
/*******************************************************************************
* This function raises the specified Secure Group 0 SGI.
*
* The target parameter must be a valid MPIDR in the system.
******************************************************************************/
void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target)
{
unsigned int tgt, aff3, aff2, aff1, aff0;
uint64_t sgi_val;
/* Verify interrupt number is in the SGI range */
assert((sgi_num >= MIN_SGI_ID) && (sgi_num < MIN_PPI_ID));
/* Extract affinity fields from target */
aff0 = MPIDR_AFFLVL0_VAL(target);
aff1 = MPIDR_AFFLVL1_VAL(target);
aff2 = MPIDR_AFFLVL2_VAL(target);
aff3 = MPIDR_AFFLVL3_VAL(target);
/*
* Make target list from affinity 0, and ensure GICv3 SGI can target
* this PE.
*/
assert(aff0 < GICV3_MAX_SGI_TARGETS);
tgt = BIT(aff0);
/* Raise SGI to PE specified by its affinity */
sgi_val = GICV3_SGIR_VALUE(aff3, aff2, aff1, sgi_num, SGIR_IRM_TO_AFF,
tgt);
/*
* Ensure that any shared variable updates depending on out of band
* interrupt trigger are observed before raising SGI.
*/
dsbishst();
write_icc_sgi0r_el1(sgi_val);
isb();
}
......@@ -36,6 +36,19 @@
#define CPENDSGIR_SHIFT 2
#define SPENDSGIR_SHIFT CPENDSGIR_SHIFT
#define SGIR_TGTLSTFLT_SHIFT 24
#define SGIR_TGTLSTFLT_MASK 0x3
#define SGIR_TGTLST_SHIFT 16
#define SGIR_TGTLST_MASK 0xff
#define SGIR_INTID_MASK 0xf
#define SGIR_TGT_SPECIFIC 0
#define GICV2_SGIR_VALUE(tgt_lst_flt, tgt, intid) \
((((tgt_lst_flt) & SGIR_TGTLSTFLT_MASK) << SGIR_TGTLSTFLT_SHIFT) | \
(((tgt) & SGIR_TGTLST_MASK) << SGIR_TGTLST_SHIFT) | \
((intid) & SGIR_INTID_MASK))
/*******************************************************************************
* GICv2 specific CPU interface register offsets and constants.
******************************************************************************/
......@@ -157,6 +170,7 @@ void gicv2_enable_interrupt(unsigned int id);
void gicv2_disable_interrupt(unsigned int id);
void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority);
void gicv2_set_interrupt_type(unsigned int id, unsigned int type);
void gicv2_raise_sgi(int sgi_num, int proc_num);
#endif /* __ASSEMBLY__ */
#endif /* __GICV2_H__ */
......@@ -24,6 +24,9 @@
/* Constant to categorize LPI interrupt */
#define MIN_LPI_ID 8192
/* GICv3 can only target up to 16 PEs with SGI */
#define GICV3_MAX_SGI_TARGETS 16
/*******************************************************************************
* GICv3 specific Distributor interface register offsets and constants.
******************************************************************************/
......@@ -165,6 +168,27 @@
#define IAR1_EL1_INTID_SHIFT 0
#define IAR1_EL1_INTID_MASK 0xffffff
/* ICC SGI macros */
#define SGIR_TGT_MASK 0xffff
#define SGIR_AFF1_SHIFT 16
#define SGIR_INTID_SHIFT 24
#define SGIR_INTID_MASK 0xf
#define SGIR_AFF2_SHIFT 32
#define SGIR_IRM_SHIFT 40
#define SGIR_IRM_MASK 0x1
#define SGIR_AFF3_SHIFT 48
#define SGIR_AFF_MASK 0xf
#define SGIR_IRM_TO_AFF 0
#define GICV3_SGIR_VALUE(aff3, aff2, aff1, intid, irm, tgt) \
((((uint64_t) (aff3) & SGIR_AFF_MASK) << SGIR_AFF3_SHIFT) | \
(((uint64_t) (irm) & SGIR_IRM_MASK) << SGIR_IRM_SHIFT) | \
(((uint64_t) (aff2) & SGIR_AFF_MASK) << SGIR_AFF2_SHIFT) | \
(((intid) & SGIR_INTID_MASK) << SGIR_INTID_SHIFT) | \
(((aff1) & SGIR_AFF_MASK) << SGIR_AFF1_SHIFT) | \
((tgt) & SGIR_TGT_MASK))
/*****************************************************************************
* GICv3 ITS registers and constants
*****************************************************************************/
......@@ -357,6 +381,7 @@ void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
unsigned int priority);
void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
unsigned int group);
void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target);
#endif /* __ASSEMBLY__ */
#endif /* __GICV3_H__ */
......@@ -44,6 +44,7 @@
(((mpidr) >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK)
#define MPIDR_AFFLVL2_VAL(mpidr) \
(((mpidr) >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK)
#define MPIDR_AFFLVL3_VAL(mpidr) 0
/*
* The MPIDR_MAX_AFFLVL count starts from 0. Take care to
......
......@@ -266,6 +266,7 @@ DEFINE_COPROCR_RW_FUNCS(icc_iar0_el1, ICC_IAR0)
DEFINE_COPROCR_RW_FUNCS(icc_iar1_el1, ICC_IAR1)
DEFINE_COPROCR_RW_FUNCS(icc_eoir0_el1, ICC_EOIR0)
DEFINE_COPROCR_RW_FUNCS(icc_eoir1_el1, ICC_EOIR1)
DEFINE_COPROCR_RW_FUNCS_64(icc_sgi0r_el1, ICC_SGI0R_EL1_64)
DEFINE_COPROCR_RW_FUNCS(hdcr, HDCR)
DEFINE_COPROCR_RW_FUNCS(cnthp_ctl, CNTHP_CTL)
......@@ -325,4 +326,7 @@ DEFINE_DCOP_PARAM_FUNC(cvac, DCCMVAC)
#define read_ctr_el0() read_ctr()
#define write_icc_sgi0r_el1(_v) \
write64_icc_sgi0r_el1(_v)
#endif /* __ARCH_HELPERS_H__ */
......@@ -77,6 +77,7 @@
#define ICC_IAR1_EL1 S3_0_c12_c12_0
#define ICC_EOIR0_EL1 S3_0_c12_c8_1
#define ICC_EOIR1_EL1 S3_0_c12_c12_1
#define ICC_SGI0R_EL1 S3_0_c12_c11_7
/*******************************************************************************
* Generic timer memory mapped registers & offsets
......
......@@ -322,6 +322,7 @@ DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar0_el1, ICC_IAR0_EL1)
DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar1_el1, ICC_IAR1_EL1)
DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir0_el1, ICC_EOIR0_EL1)
DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir1_el1, ICC_EOIR1_EL1)
DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_sgi0r_el1, ICC_SGI0R_EL1)
#define IS_IN_EL(x) \
......
......@@ -82,6 +82,7 @@ void plat_ic_enable_interrupt(unsigned int id);
int plat_ic_has_interrupt_type(unsigned int type);
void plat_ic_set_interrupt_type(unsigned int id, unsigned int type);
void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority);
void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target);
/*******************************************************************************
* Optional common functions (may be overridden)
......
......@@ -7,6 +7,7 @@
#include <gic_common.h>
#include <gicv2.h>
#include <interrupt_mgmt.h>
#include <platform.h>
/*
* The following platform GIC functions are weakly defined. They
......@@ -29,6 +30,7 @@
#pragma weak plat_ic_disable_interrupt
#pragma weak plat_ic_set_interrupt_priority
#pragma weak plat_ic_set_interrupt_type
#pragma weak plat_ic_raise_el3_sgi
/*
* This function returns the highest priority pending interrupt at
......@@ -220,3 +222,21 @@ void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
gicv2_set_interrupt_type(id, gicv2_type);
}
void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
{
#if GICV2_G0_FOR_EL3
int id;
/* Target must be a valid MPIDR in the system */
id = plat_core_pos_by_mpidr(target);
assert(id >= 0);
/* Verify that this is a secure SGI */
assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3);
gicv2_raise_sgi(sgi_num, id);
#else
assert(0);
#endif
}
......@@ -35,6 +35,7 @@
#pragma weak plat_ic_disable_interrupt
#pragma weak plat_ic_set_interrupt_priority
#pragma weak plat_ic_set_interrupt_type
#pragma weak plat_ic_raise_el3_sgi
CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) &&
(INTR_TYPE_NS == INTR_GROUP1NS) &&
......@@ -217,6 +218,17 @@ void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
{
gicv3_set_interrupt_type(id, plat_my_core_pos(), type);
}
void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
{
/* Target must be a valid MPIDR in the system */
assert(plat_core_pos_by_mpidr(target) >= 0);
/* Verify that this is a secure EL3 SGI */
assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3);
gicv3_raise_secure_g0_sgi(sgi_num, target);
}
#endif
#ifdef IMAGE_BL32
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment