tzc400: add support for interrupts

A new function tzc400_it_handler() is created to manage TZC400
interrupts. The required helpers to read and clear interrupts are added
as well.
In case DEBUG is enabled, more information about the faulty access
(address, NSAID, type of access) is displayed.

Change-Id: Ie9ab1c199a8f12b2c9472d7120efbdf35711284a
Signed-off-by: Yann Gautier <yann.gautier@st.com>
This commit is contained in:
Yann Gautier 2019-02-15 16:45:48 +01:00 committed by Yann Gautier
parent e84ca57130
commit 34c1a1a43c
2 changed files with 103 additions and 5 deletions

View File

@ -10,6 +10,7 @@
#include <common/debug.h>
#include <drivers/arm/tzc400.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include "tzc_common_private.h"
@ -70,6 +71,77 @@ DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(400, 400)
DEFINE_TZC_COMMON_CONFIGURE_REGION0(400)
DEFINE_TZC_COMMON_CONFIGURE_REGION(400)
static void _tzc400_clear_it(uintptr_t base, uint32_t filter)
{
mmio_write_32(base + INT_CLEAR, BIT_32(filter));
}
static uint32_t _tzc400_get_int_by_filter(uintptr_t base, uint32_t filter)
{
return mmio_read_32(base + INT_STATUS) & BIT_32(filter);
}
#if DEBUG
static unsigned long _tzc400_get_fail_address(uintptr_t base, uint32_t filter)
{
unsigned long fail_address;
fail_address = mmio_read_32(base + FAIL_ADDRESS_LOW_OFF +
(filter * FILTER_OFFSET));
#ifdef __aarch64__
fail_address += (unsigned long)mmio_read_32(base + FAIL_ADDRESS_HIGH_OFF +
(filter * FILTER_OFFSET)) << 32;
#endif
return fail_address;
}
static uint32_t _tzc400_get_fail_id(uintptr_t base, uint32_t filter)
{
return mmio_read_32(base + FAIL_ID + (filter * FILTER_OFFSET));
}
static uint32_t _tzc400_get_fail_control(uintptr_t base, uint32_t filter)
{
return mmio_read_32(base + FAIL_CONTROL_OFF + (filter * FILTER_OFFSET));
}
static void _tzc400_dump_fail_filter(uintptr_t base, uint32_t filter)
{
uint32_t control_fail;
uint32_t fail_id;
unsigned long address_fail;
address_fail = _tzc400_get_fail_address(base, filter);
ERROR("Illegal access to 0x%lx:\n", address_fail);
fail_id = _tzc400_get_fail_id(base, filter);
ERROR("\tFAIL_ID = 0x%x\n", fail_id);
control_fail = _tzc400_get_fail_control(base, filter);
if (((control_fail & BIT_32(FAIL_CONTROL_NS_SHIFT)) >> FAIL_CONTROL_NS_SHIFT) ==
FAIL_CONTROL_NS_NONSECURE) {
ERROR("\tNon-Secure\n");
} else {
ERROR("\tSecure\n");
}
if (((control_fail & BIT_32(FAIL_CONTROL_PRIV_SHIFT)) >> FAIL_CONTROL_PRIV_SHIFT) ==
FAIL_CONTROL_PRIV_PRIV) {
ERROR("\tPrivilege\n");
} else {
ERROR("\tUnprivilege\n");
}
if (((control_fail & BIT_32(FAIL_CONTROL_DIR_SHIFT)) >> FAIL_CONTROL_DIR_SHIFT) ==
FAIL_CONTROL_DIR_WRITE) {
ERROR("\tWrite\n");
} else {
ERROR("\tRead\n");
}
}
#endif /* DEBUG */
static unsigned int _tzc400_get_gate_keeper(uintptr_t base,
unsigned int filter)
{
@ -108,11 +180,6 @@ void tzc400_set_action(unsigned int action)
assert(tzc400.base != 0U);
assert(action <= TZC_ACTION_ERR_INT);
/*
* - Currently no handler is provided to trap an error via interrupt
* or exception.
* - The interrupt action has not been tested.
*/
_tzc400_write_action(tzc400.base, action);
}
@ -245,3 +312,31 @@ void tzc400_disable_filters(void)
for (filter = 0; filter < tzc400.num_filters; filter++)
_tzc400_set_gate_keeper(tzc400.base, filter, 0);
}
int tzc400_it_handler(void)
{
uint32_t filter;
uint32_t filter_it_pending = tzc400.num_filters;
assert(tzc400.base != 0U);
for (filter = 0U; filter < tzc400.num_filters; filter++) {
if (_tzc400_get_int_by_filter(tzc400.base, filter) != 0U) {
filter_it_pending = filter;
break;
}
}
if (filter_it_pending == tzc400.num_filters) {
ERROR("TZC-400: No interrupt pending!\n");
return -1;
}
#if DEBUG
_tzc400_dump_fail_filter(tzc400.base, filter_it_pending);
#endif
_tzc400_clear_it(tzc400.base, filter_it_pending);
return 0;
}

View File

@ -90,6 +90,8 @@
#define TZC_400_REGION_SIZE U(0x20)
#define TZC_400_ACTION_OFF U(0x4)
#define FILTER_OFFSET U(0x10)
#ifndef __ASSEMBLER__
#include <cdefs.h>
@ -110,6 +112,7 @@ void tzc400_configure_region(unsigned int filters,
void tzc400_set_action(unsigned int action);
void tzc400_enable_filters(void);
void tzc400_disable_filters(void);
int tzc400_it_handler(void);
static inline void tzc_init(uintptr_t base)
{