android_kernel_modules_leno.../debug_tools/vtunedk/src/eventmux.c

365 lines
10 KiB
C

/*COPYRIGHT**
Copyright (C) 2005-2014 Intel Corporation. All Rights Reserved.
This file is part of SEP Development Kit
SEP Development Kit is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
SEP Development Kit is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SEP Development Kit; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
As a special exception, you may use this file as part of a free software
library without restriction. Specifically, if other files instantiate
templates or use macros or inline functions from this file, or you compile
this file and link it with other files to produce an executable, this
file does not by itself cause the resulting executable to be covered by
the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
**COPYRIGHT*/
#include "lwpmudrv_defines.h"
#include <linux/version.h>
#include <linux/jiffies.h>
#include <linux/time.h>
#include <linux/percpu.h>
#include "lwpmudrv_types.h"
#include "rise_errors.h"
#include "lwpmudrv_ecb.h"
#include "lwpmudrv_struct.h"
#include "lwpmudrv.h"
#include "control.h"
static PVOID em_tables = NULL;
static size_t em_tables_size = 0;
/* ------------------------------------------------------------------------- */
/*!
* @fn VOID eventmux_Allocate_Groups (
* VOID *params
* )
*
* @brief Allocate memory need to support event multiplexing
*
* @param params - pointer to a S32 that holds the size of buffer to allocate
*
* @return NONE
*
* <I>Special Notes:</I>
* Allocate the memory needed to save different group counters
* Called via the parallel control mechanism
*/
static VOID
eventmux_Allocate_Groups (
PVOID params
)
{
U32 this_cpu;
S32 alloc_size = *(S32 *)params;
CPU_STATE cpu_state;
preempt_disable();
this_cpu = CONTROL_THIS_CPU();
cpu_state = &pcb[this_cpu];
preempt_enable();
CPU_STATE_em_tables(cpu_state) = em_tables + (alloc_size * this_cpu);
}
/* ------------------------------------------------------------------------- */
/*!
* @fn VOID eventmux_Deallocate_Groups (
* VOID *params
* )
*
* @brief Free the scratch memory need to support event multiplexing
*
* @param params - pointer to NULL
*
* @return NONE
*
* <I>Special Notes:</I>
* Free the memory needed to save different group counters
* Called via the parallel control mechanism
*/
static VOID
eventmux_Deallocate_Groups (
PVOID params
)
{
U32 this_cpu;
CPU_STATE cpu_state;
preempt_disable();
this_cpu = CONTROL_THIS_CPU();
cpu_state = &pcb[this_cpu];
preempt_enable();
CPU_STATE_em_tables(cpu_state) = NULL;
return;
}
/* ------------------------------------------------------------------------- */
/*!
* @fn VOID eventmux_Timer_Callback_Thread (
* )
*
* @brief Stop all the timer threads and terminate them
*
* @param none
*
* @return NONE
*
* <I>Special Notes:</I>
* timer routine - The event multiplexing happens here.
*/
static VOID
eventmux_Timer_Callback_Thread (
unsigned long arg
)
{
U32 this_cpu;
CPU_STATE pcpu;
preempt_disable();
this_cpu = CONTROL_THIS_CPU();
pcpu = &pcb[this_cpu];
preempt_enable();
if (CPU_STATE_em_tables(pcpu) == NULL) {
return;
}
dispatch->swap_group(TRUE);
CPU_STATE_em_timer(pcpu)->expires = jiffies+arg;
add_timer(CPU_STATE_em_timer(pcpu));
}
/* ------------------------------------------------------------------------- */
/*!
* @fn VOID eventmux_Prepare_Timer_Threads (
* VOID
* )
*
* @brief Stop all the timer threads and terminate them
*
* @param NONE
*
* @return NONE
*
* <I>Special Notes:</I>
* Set up the timer threads to prepare for event multiplexing.
* Do not start the threads as yet
*/
static VOID
eventmux_Prepare_Timer_Threads (
PVOID arg
)
{
CPU_STATE pcpu;
// initialize and set up the timer for all cpus
// Do not start the timer as yet.
preempt_disable();
pcpu = &pcb[CONTROL_THIS_CPU()];
preempt_enable();
CPU_STATE_em_timer(pcpu) = (struct timer_list*)CONTROL_Allocate_Memory(sizeof(struct timer_list));
if (CPU_STATE_em_timer(pcpu) == NULL) {
SEP_PRINT_ERROR("eventmux_Prepare_Timer_Threads skipped pcpu=NULL\n")
return;
}
init_timer(CPU_STATE_em_timer(pcpu));
}
/* ------------------------------------------------------------------------- */
/*!
* @fn VOID eventmux_Cancel_Timers (
* VOID
* )
*
* @brief Stop all the timer threads and terminate them
*
* @param NONE
*
* @return NONE
*
* <I>Special Notes:</I>
* Cancel all the timer threads that have been started
*/
static VOID
eventmux_Cancel_Timers (
VOID
)
{
CPU_STATE pcpu;
S32 i;
/*
* Cancel the timer for all active CPUs
*/
for (i=0; i < GLOBAL_STATE_active_cpus(driver_state); i++) {
pcpu = &pcb[i];
del_timer_sync(CPU_STATE_em_timer(pcpu));
}
}
/* ------------------------------------------------------------------------- */
/*!
* @fn VOID eventmux_Start_Timers (
* long unsigned arg
* )
*
* @brief Start the timer on a single cpu
*
* @param delay interval time in jiffies
*
* @return NONE
*
* <I>Special Notes:</I>
* start the timer on a single cpu
* Call from each cpu to get cpu affinity for Timer_Callback_Thread
*/
static VOID
eventmux_Start_Timers(
PVOID arg
)
{
CPU_STATE pcpu;
preempt_disable();
pcpu = &pcb[CONTROL_THIS_CPU()];
preempt_enable();
CPU_STATE_em_timer(pcpu)->function = eventmux_Timer_Callback_Thread;
CPU_STATE_em_timer(pcpu)->data = (unsigned long)arg;
CPU_STATE_em_timer(pcpu)->expires = jiffies+(unsigned long)arg;
add_timer(CPU_STATE_em_timer(pcpu));
}
/* ------------------------------------------------------------------------- */
/*!
* @fn VOID EVENTMUX_Start (
* EVENT_CONFIG ec
* )
*
* @brief Start the timers and enable all the threads
*
* @param ec - Event Configuration
*
* @return NONE
*
* <I>Special Notes:</I>
* if event multiplexing has been enabled, set up the time slices and
* start the timer threads for all the timers
*/
extern VOID
EVENTMUX_Start (
EVENT_CONFIG ec
)
{
unsigned long delay;
if (EVENT_CONFIG_mode(ec) != EM_TIMER_BASED ||
EVENT_CONFIG_num_groups(ec) == 1) {
return;
}
/*
* notice we want to use group 0's time slice for the initial timer
*/
delay = msecs_to_jiffies(EVENT_CONFIG_em_factor(ec));
SEP_PRINT_DEBUG("EVENTMUX_Start: delay is %lu jiffies\n", delay);
/*
* Start the timer for all cpus
*/
CONTROL_Invoke_Parallel(eventmux_Start_Timers, (PVOID)delay);
}
/* ------------------------------------------------------------------------- */
/*!
* @fn VOID EVENTMUX_Initialize (
* EVENT_CONFIG ec
* )
*
* @brief Initialize the event multiplexing module
*
* @param ec - Event Configuration
*
* @return NONE
*
* <I>Special Notes:</I>
* if event multiplexing has been enabled,
* then allocate the memory needed to save and restore all the counter data
* set up the timers needed, but do not start them
*/
extern VOID
EVENTMUX_Initialize (
EVENT_CONFIG ec
)
{
S32 size_of_vector;
if (EVENT_CONFIG_mode(ec) == EM_DISABLED ||
EVENT_CONFIG_num_groups(ec) == 1) {
return;
}
size_of_vector = EVENT_CONFIG_num_groups(ec) *
EVENT_CONFIG_max_gp_events(ec) *
sizeof(S64);
em_tables_size = GLOBAL_STATE_num_cpus(driver_state) * size_of_vector;
em_tables = CONTROL_Allocate_Memory(em_tables_size);
CONTROL_Invoke_Parallel(eventmux_Allocate_Groups,
(VOID *)&(size_of_vector));
if (EVENT_CONFIG_mode(ec) == EM_TIMER_BASED) {
CONTROL_Invoke_Parallel(eventmux_Prepare_Timer_Threads, NULL);
}
}
/* ------------------------------------------------------------------------- */
/*!
* @fn VOID EVENTMUX_Destroy (
* EVENT_CONFIG ec
* )
*
* @brief Clean up the event multiplexing threads
*
* @param ec - Event Configuration
*
* @return NONE
*
* <I>Special Notes:</I>
* if event multiplexing has been enabled, then stop and cancel all the timers
* free up all the memory that is associated with EM
*/
extern VOID
EVENTMUX_Destroy (
EVENT_CONFIG ec
)
{
if (ec == NULL) {
return;
}
if (EVENT_CONFIG_mode(ec) == EM_DISABLED ||
EVENT_CONFIG_num_groups(ec) == 1) {
return;
}
if (EVENT_CONFIG_mode(ec) == EM_TIMER_BASED) {
eventmux_Cancel_Timers();
}
em_tables = CONTROL_Free_Memory(em_tables);
em_tables_size = 0;
CONTROL_Invoke_Parallel(eventmux_Deallocate_Groups, (VOID *)(size_t)0);
}