You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
4.9 KiB
169 lines
4.9 KiB
/* |
|
* Copyright (c) 2015 Intel Corporation |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
/** |
|
* @file |
|
* @brief Kernel event logger support. |
|
*/ |
|
|
|
|
|
#include <misc/kernel_event_logger.h> |
|
#include <misc/util.h> |
|
#include <init.h> |
|
#include <nano_private.h> |
|
#include <kernel_event_logger_arch.h> |
|
|
|
uint32_t _sys_k_event_logger_buffer[CONFIG_KERNEL_EVENT_LOGGER_BUFFER_SIZE]; |
|
|
|
#ifdef CONFIG_KERNEL_EVENT_LOGGER_CONTEXT_SWITCH |
|
void *_collector_fiber; |
|
#endif |
|
|
|
#ifdef CONFIG_KERNEL_EVENT_LOGGER_SLEEP |
|
uint32_t _sys_k_event_logger_sleep_start_time; |
|
#endif |
|
|
|
|
|
/** |
|
* @brief Initialize the kernel event logger system. |
|
* |
|
* @details Initialize the ring buffer and the sync semaphore. |
|
* |
|
* @return No return value. |
|
*/ |
|
static int _sys_k_event_logger_init(struct device *arg) |
|
{ |
|
ARG_UNUSED(arg); |
|
|
|
sys_event_logger_init(&sys_k_event_logger, _sys_k_event_logger_buffer, |
|
CONFIG_KERNEL_EVENT_LOGGER_BUFFER_SIZE); |
|
|
|
return 0; |
|
} |
|
DEVICE_INIT(kernel_event_logger_0, "", _sys_k_event_logger_init, |
|
NULL, NULL, |
|
NANOKERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); |
|
|
|
|
|
void sys_k_event_logger_put_timed(uint16_t event_id) |
|
{ |
|
uint32_t data[1]; |
|
|
|
data[0] = sys_tick_get_32(); |
|
|
|
sys_event_logger_put(&sys_k_event_logger, event_id, data, |
|
ARRAY_SIZE(data)); |
|
} |
|
|
|
#ifdef CONFIG_KERNEL_EVENT_LOGGER_CONTEXT_SWITCH |
|
void _sys_k_event_logger_context_switch(void) |
|
{ |
|
extern tNANO _nanokernel; |
|
uint32_t data[2]; |
|
|
|
extern void _sys_event_logger_put_non_preemptible( |
|
struct event_logger *logger, |
|
uint16_t event_id, |
|
uint32_t *event_data, |
|
uint8_t data_size); |
|
|
|
/* if the kernel event logger has not been initialized, we do nothing */ |
|
if (sys_k_event_logger.ring_buf.buf == NULL) { |
|
return; |
|
} |
|
|
|
if (_collector_fiber != _nanokernel.current) { |
|
data[0] = sys_tick_get_32(); |
|
data[1] = (uint32_t)_nanokernel.current; |
|
|
|
/* |
|
* The mechanism we use to log the kernel events uses a sync semaphore |
|
* to inform that there are available events to be collected. The |
|
* context switch event can be triggered from a task. When we |
|
* signal a semaphore from a task and a fiber is waiting for |
|
* that semaphore, a context switch is generated immediately. Due to |
|
* the fact that we register the context switch event while the context |
|
* switch is being processed, a new context switch can be generated |
|
* before the kernel finishes processing the current context switch. We |
|
* need to prevent this because the kernel is not able to handle it. |
|
* The _sem_give_non_preemptible function does not trigger a context |
|
* switch when we signal the semaphore from any type of thread. Using |
|
* _sys_event_logger_put_non_preemptible function, that internally uses |
|
* _sem_give_non_preemptible function for signaling the sync semaphore, |
|
* allow us registering the context switch event without triggering any |
|
* new context switch during the process. |
|
*/ |
|
_sys_event_logger_put_non_preemptible(&sys_k_event_logger, |
|
KERNEL_EVENT_LOGGER_CONTEXT_SWITCH_EVENT_ID, data, |
|
ARRAY_SIZE(data)); |
|
} |
|
} |
|
|
|
void sys_k_event_logger_register_as_collector(void) |
|
{ |
|
_collector_fiber = _nanokernel.current; |
|
} |
|
#endif /* CONFIG_KERNEL_EVENT_LOGGER_CONTEXT_SWITCH */ |
|
|
|
|
|
#ifdef CONFIG_KERNEL_EVENT_LOGGER_INTERRUPT |
|
void _sys_k_event_logger_interrupt(void) |
|
{ |
|
uint32_t data[2]; |
|
|
|
/* if the kernel event logger has not been initialized, we do nothing */ |
|
if (sys_k_event_logger.ring_buf.buf == NULL) { |
|
return; |
|
} |
|
|
|
data[0] = sys_tick_get_32(); |
|
data[1] = _sys_current_irq_key_get(); |
|
|
|
sys_k_event_logger_put(KERNEL_EVENT_LOGGER_INTERRUPT_EVENT_ID, data, |
|
ARRAY_SIZE(data)); |
|
} |
|
#endif /* CONFIG_KERNEL_EVENT_LOGGER_INTERRUPT */ |
|
|
|
|
|
#ifdef CONFIG_KERNEL_EVENT_LOGGER_SLEEP |
|
void _sys_k_event_logger_enter_sleep(void) |
|
{ |
|
_sys_k_event_logger_sleep_start_time = sys_cycle_get_32(); |
|
} |
|
|
|
void _sys_k_event_logger_exit_sleep(void) |
|
{ |
|
uint32_t data[3]; |
|
|
|
if (_sys_k_event_logger_sleep_start_time != 0) { |
|
data[0] = sys_tick_get_32(); |
|
data[1] = (sys_cycle_get_32() - _sys_k_event_logger_sleep_start_time) |
|
/ sys_clock_hw_cycles_per_tick; |
|
/* register the cause of exiting sleep mode */ |
|
data[2] = _sys_current_irq_key_get(); |
|
|
|
/* |
|
* if _sys_k_event_logger_sleep_start_time is different to zero, means |
|
* that the CPU was sleeping, so we reset it to identify that the event |
|
* was processed and that any the next interrupt is no awaing the CPU. |
|
*/ |
|
_sys_k_event_logger_sleep_start_time = 0; |
|
|
|
sys_k_event_logger_put(KERNEL_EVENT_LOGGER_SLEEP_EVENT_ID, data, |
|
ARRAY_SIZE(data)); |
|
} |
|
} |
|
#endif /* CONFIG_KERNEL_EVENT_LOGGER_SLEEP */
|
|
|