1019 lines
29 KiB
C

/*******************************************************************************
** This file is provided under a dual BSD/GPLv2 license. When using or
** redistributing this file, you may do so under either license.
**
** GPL LICENSE SUMMARY
**
** Copyright (c) 2013 Intel Corporation All Rights Reserved
**
** This program is free software; you can redistribute it and/or modify it under
** the terms of version 2 of the GNU General Public License as published by the
** Free Software Foundation.
**
** This program 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
** this program; if not, write to the Free Software Foundation, Inc.,
** 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
** The full GNU General Public License is included in this distribution in the
** file called LICENSE.GPL.
**
** BSD LICENSE
**
** Copyright (c) 2013 Intel Corporation All Rights Reserved
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice, this
** list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice,
** this list of conditions and the following disclaimer in the documentation
** and/or other materials provided with the distribution.
** * Neither the name of Intel Corporation nor the names of its contributors may
** be used to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
** POSSIBILITY OF SUCH DAMAGE.
**
*******************************************************************************/
#include "esif_lf.h"
#include "esif_lf_action.h"
#include "esif_ipc.h"
#include "esif_queue.h"
#include "esif_hash_table.h"
#ifdef ESIF_ATTR_OS_WINDOWS
/*
* The Windows banned-API check header must be included after all other headers,
* or issues can be identified against Windows SDK/DDK included headers which we
* have no control over.
*/
#define _SDL_BANNED_RECOMMENDED
#include "win\banned.h"
#endif
#define ESIF_DEBUG_MODULE ESIF_DEBUG_MOD_ELF
#define INIT_DEBUG 0
#define LF_DEBUG 1
#define DECODE_DEBUG 2
#define EVENT_DEBUG 3
#define ESIF_TRACE_DYN_INIT(format, ...) \
ESIF_TRACE_DYN(ESIF_DEBUG_MOD_ELF, INIT_DEBUG, format, ##__VA_ARGS__)
#define ESIF_TRACE_DYN_LF(format, ...) \
ESIF_TRACE_DYN(ESIF_DEBUG_MOD_ELF, LF_DEBUG, format, ##__VA_ARGS__)
#define ESIF_TRACE_DYN_DECODE(format, ...) \
ESIF_TRACE_DYN(ESIF_DEBUG_MOD_ELF, DECODE_DEBUG, format, ##__VA_ARGS__)
#define ESIF_TRACE_DYN_EVENT(format, ...) \
ESIF_TRACE_DYN(ESIF_DEBUG_MOD_ELF, EVENT_DEBUG, format, ##__VA_ARGS__)
/* List of Init/Exit Functions to be called during esif_lf_init/exit */
typedef enum esif_rc (*esif_init_callback)(void);
typedef void (*esif_exit_callback)(void);
struct esif_init_module {
esif_init_callback init_func;
esif_exit_callback exit_func;
u32 started;
};
static struct esif_init_module esif_initializers[] = {
{esif_lf_pm_init, esif_lf_pm_exit}, /* Always First */
{esif_action_acpi_init, esif_action_acpi_exit},
{esif_action_code_init, esif_action_code_exit},
{esif_action_const_init, esif_action_const_exit},
{esif_action_mmio_init, esif_action_mmio_exit},
{esif_action_msr_init, esif_action_msr_exit},
{esif_action_systemio_init, esif_action_systemio_exit},
{esif_action_var_init, esif_action_var_exit},
{esif_action_mbi_init, esif_action_mbi_exit},
{esif_data_init, esif_data_exit},
{esif_queue_init, esif_queue_exit},
{esif_event_init, esif_event_exit},
{esif_link_list_init, esif_link_list_exit},
{esif_hash_table_init, esif_hash_table_exit},
{esif_dsp_init, esif_dsp_exit},
{esif_command_init, esif_command_exit} /* Always Last */
};
static enum esif_rc esif_start_initializers(void);
static void esif_stop_initializers(void);
/*
*******************************************************************************
** PRIVATE
*******************************************************************************
*/
#define GFX_DTS_TEMPERATURE_MAX 207
#define GFX_DTS_TEMPERATURE_MIN 127
#define GFX_DEGREE_TEMPERATURE_MAX 90
#define GFX_DEGREE_TEMPERATURE_MIN 10
/*
* DTS to Degree Celcius conversion with respect to table below.
* Example : Temperature in Degree for DTS temperature of 157 will be calcuate
* as DTSToCelcius(157) = ((GFX_DEGREE_TEMPERATRUE_MIN == 10)+
* ((GFX_DTS_TEMPERATRUE_MAX == 207)- (degreeTemp == 157))) = 60, which is
* correct in table below.
* Example :
* DTSToCelcius(180) = ((GFX_DEGREE_TEMPERATRUE_MIN == 10)+
* ((GFX_DTS_TEMPERATRUE_MAX == 207)- (degreeTemp == 180))) = 37, which is
* correct in table below.
*/
#define DTS_TO_CELCIUS(temp) ((GFX_DEGREE_TEMPERATURE_MIN) + \
((GFX_DTS_TEMPERATURE_MAX)-(temp)))
/*
* Thermistor xform example
* 1. Input EC is 586, output Kelvin is 3055
* 2. Input Kelvin in 3055, output EC is 586
*
* Lookup LPAT ACPI object = {{type, tempK}, {type, rawVal}} = {
* ...
* {{INT64, 2891}, {UINT64, 668}},
* {{INT64, 3031}, {UINT64, 612}}, <-- tempK[0], raw[0]
* {{INT64, 3081}, {UINT64, 560}}, <-- tempK[1], raw[1]
* {{INT64, 3131}, {UINT64, 508}},
* ... }
* Algorithm
* FP = (tempK[1] - tempK[0]) / (raw[0] - raw[1])
* = ( 3081 - 3031 ) / ( 612 - 560 )
* = 0.096153
*
* Kernel lacks of floating point, so make FP 1K bigger to keep precision.
* FP = FP * 1K = 961
*
* Kelvin = tempK[0] + ((raw[0] - input_EC) * FP ) / 1K
* = 3031 + (( 612 - 586 ) * 961) / 1K
* = 3031 + 24
* = 3055
#
* EC = raw[0] - ((input_K - tempK[0]) * 1K) / FP
* = 612 - ((3055 - 3031 ) * 1K) / 961
* = 615 - 26
* = 586
*
*/
static u32 esif_xform_lpat(int input, struct esif_lp_dsp *dsp_ptr,
enum esif_temperature_type input_type)
{
u8 *var_ptr = (u8 *) dsp_ptr->table;
long long temp[2] = {0, 0};
long long raw[2] = {0, 0};
long long fp = 0;
long long output = 0;
int i = 0;
int num_lpat = 0;
if (input_type != ESIF_TEMP_THERMISTOR && input_type != ESIF_TEMP_DECIK)
return 0;
/*
* VS 2012 doesn't support "typeof(((type *)0)->memb *)" generic type,
* so we can only use (long long *) instead.
*/
#define ESIF_VAR union esif_data_variant
#define var_offset(type, memb) ((size_t)&((type *)0)->memb)
#define var_sizeof(type, memb) (sizeof((type *)0)->memb)
#define val_var_offset(ptr, type, memb) *(long long *) \
(ptr + var_offset(type, memb))
#define next_val_var_offset(ptr, type, all_memb, memb) *(long long *) \
(ptr + var_offset(type, memb) + var_sizeof(type, all_memb))
if (0 == dsp_ptr->table_size)
goto exit;
num_lpat = dsp_ptr->table_size / sizeof(union esif_data_variant);
for (i=0; i < ((num_lpat/2) - 1); i++) {
temp[0] = val_var_offset(var_ptr, ESIF_VAR, integer.value);
raw[0] = next_val_var_offset(var_ptr, ESIF_VAR, integer,
integer.value);
/* Next element */
var_ptr += 2 * var_sizeof(ESIF_VAR, integer);
temp[1] = val_var_offset(var_ptr, ESIF_VAR, integer.value);
raw[1] = next_val_var_offset(var_ptr, ESIF_VAR, integer,
integer.value);
switch (input_type) {
case ESIF_TEMP_THERMISTOR:
/* Out of boundry check - too small */
if (i == 0 && input > raw[0])
goto exit;
/* LPAT entry lookup */
if (input <= raw[0] && input >= raw[1])
goto comp;
break;
case ESIF_TEMP_DECIK:
if (i == 0 && input < temp[0])
goto exit;
if (input >= temp[0] && input <= temp[1])
goto comp;
break;
default:
goto exit;
}
}
/* Out of boundry check - too large */
goto exit;
comp:
/* FP = 1K * ((temp1 - temp0) / (raw0 - raw1)) */
fp = (temp[1] - temp[0]) * 1000;
do_div(fp, (raw[0] - raw[1]));
switch (input_type) {
case ESIF_TEMP_THERMISTOR:
/* K = temp0 + ((raw0 - EC) * FP) / 1K */
output = (raw[0] - input) * fp;
do_div(output, 1000);
output = temp[0] - output;
break;
case ESIF_TEMP_DECIK:
/* EC = raw0 - ((K - temp0) * 1K) / FP */
output = (input - temp[0]) * 1000;
do_div(output, fp);
output = raw[0] - output;
break;
default:
break;
}
exit:
ESIF_TRACE_DYN_TEMP("%s: input %d dsp.table_size %u num_plat %d "
"LPAT {temp0 %u, raw0 %u}, {temp1 %u, raw1 %u} output %llu\n",
ESIF_FUNC, input, dsp_ptr->table_size, num_lpat,
(u32)temp[0], (u32)raw[0], (u32)temp[1], (u32)raw[1], output);
return (u32) output;
}
/* DTS Counter | Temperature
* Value | Degree Celcius
* 127 | 90
* 137 | 80
* 147 | 70
* 157 | 60
* 167 | 50
* 177 | 40
* 187 | 30
* 197 | 20
* 207 | 10
*/
static enum esif_rc esif_xform_temp(
const enum esif_temperature_type type,
esif_temp_t *temp_ptr,
const enum esif_action_type action,
const struct esif_lp_dsp *dsp_ptr,
const struct esif_lp_primitive *primitive_ptr,
const struct esif_lp *lp_ptr
)
{
enum esif_rc rc = ESIF_OK;
enum esif_temperature_type temp_in_type = type;
enum esif_temperature_type temp_out_type = type;
struct esif_cpc_algorithm *algo_ptr = dsp_ptr->get_algorithm(
dsp_ptr,
action);
enum esif_primitive_opcode opcode = primitive_ptr->opcode;
esif_temp_t temp_in;
esif_temp_t temp_out;
if (algo_ptr == NULL)
return ESIF_E_NEED_ALGORITHM;
temp_in = *temp_ptr;
temp_out = *temp_ptr;
switch (algo_ptr->temp_xform) {
case ESIF_ALGORITHM_TYPE_TEMP_DECIK:
/* Convert Temp before/after ACPI action
* For Get:
* From reading from APCI device driver in Kelvin
* To normalized temp (C) back to user response buffer
* For Set:
* From user request buffer in Kelvin or Celsius
* To Kelvin passing to ACPI device driver to set
*/
ESIF_TRACE_DYN_TEMP(
"%s: using algorithm DeciK (%s), for ACPI temp\n",
ESIF_FUNC,
esif_algorithm_type_str(algo_ptr->temp_xform));
if (opcode == ESIF_PRIMITIVE_OP_GET) {
temp_in_type = ESIF_TEMP_DECIK;
temp_out_type = type;
/* Normalized from Kelvin */
esif_convert_temp(temp_in_type, temp_out_type,
&temp_out);
} else {/* ESIF_PRIMITIVE_OP_SET */
temp_in_type = type;
temp_out_type = ESIF_TEMP_DECIK;
/* Normalized to Kelvin */
esif_convert_temp(temp_in_type, temp_out_type,
&temp_out);
}
break;
case ESIF_ALGORITHM_TYPE_TEMP_TJMAX_CORE:
{
/* LIFU Get TJMAX from GET_PROC_TJ_MAX */
const struct esif_lp_domain *lpd_ptr = NULL;
u32 tjmax = 0;
/*
* TjMax Only Lives In Doman 0 (D0) Level, If Found,
* Assign Tjmax, Or Use A Default Value (TODO:100??)
*/
lpd_ptr = &lp_ptr->domains[0];
tjmax = (lpd_ptr->temp_tjmax) ? lpd_ptr->temp_tjmax : 100;
ESIF_TRACE_DYN_TEMP(
"%s: using algorithm Tjmax %d %s, cached Tjmax %d,"
" for CORE MSR temp\n",
ESIF_FUNC,
tjmax,
esif_algorithm_type_str(algo_ptr->temp_xform),
lpd_ptr->temp_tjmax);
if (opcode == ESIF_PRIMITIVE_OP_GET) {
temp_out = (temp_out > tjmax) ? 0 : tjmax - temp_out;
temp_in_type = ESIF_TEMP_C;
temp_out_type = type;
esif_convert_temp(temp_in_type, temp_out_type,
&temp_out);
} else {
temp_in_type = type;
temp_out_type = ESIF_TEMP_C;
esif_convert_temp(temp_in_type, temp_out_type,
&temp_out);
temp_out = (temp_out > tjmax) ? 0 : tjmax - temp_out;
}
break;
}
case ESIF_ALGORITHM_TYPE_TEMP_PCH_CORE:
{
ESIF_TRACE_DYN_TEMP(
"%s: using algorithm %s, for PCH MMIO temp\n",
ESIF_FUNC,
esif_algorithm_type_str(algo_ptr->temp_xform));
if (opcode == ESIF_PRIMITIVE_OP_GET) {
temp_out = (temp_out / 2) - 50;
temp_in_type = ESIF_TEMP_C;
temp_out_type = type;
esif_convert_temp(temp_in_type, temp_out_type,
&temp_out);
} else {
temp_in_type = type;
temp_out_type = ESIF_TEMP_C;
esif_convert_temp(temp_in_type, temp_out_type,
&temp_out);
temp_out = (temp_out / 2) - 50;
}
break;
}
case ESIF_ALGORITHM_TYPE_TEMP_TJMAX_ATOM:
{
const struct esif_lp_domain *lpd_ptr = NULL;
u32 tjmax = 0;
/*
* TjMax Only Lives In Doman 0 (D0) Level, If Found,
* Assign Tjmax, Or Use A Default Value (TODO:100??)
*/
lpd_ptr = &lp_ptr->domains[0];
tjmax = (lpd_ptr->temp_tjmax) ? lpd_ptr->temp_tjmax : 100;
ESIF_TRACE_DYN_TEMP(
"%s: using algorithm %s tjmax %d, cached tjmax %d, for ATOM MSR temp\n",
ESIF_FUNC,
esif_algorithm_type_str(algo_ptr->temp_xform),
tjmax,
lpd_ptr->temp_tjmax);
if (opcode == ESIF_PRIMITIVE_OP_GET) {
u32 temp = 0;
/* Algorithm taken from 7.0 DPTF Code */
/* This will read the current temperature from MSR.
* Please refer BWG for details. Valid temp. range is
* -20 deg to 90 deg.
*/
temp = ((temp_out >> 16) & 0x007F);
/*
* Bit 4 is set OR Bit 31 is not set --- indicates above
* 90 deg temperature
*/
if ((temp_out & 0x10) ||
((temp_out & 0x80000000) == 0x0)) {
temp_out = tjmax + temp;
} else {
temp_out = tjmax - temp;
}
temp_in_type = ESIF_TEMP_C;
temp_out_type = type;
esif_convert_temp(temp_in_type, temp_out_type,
&temp_out);
} else {
temp_in_type = type;
temp_out_type = ESIF_TEMP_C;
esif_convert_temp(temp_in_type, temp_out_type,
&temp_out);
}
break;
}
case ESIF_ALGORITHM_TYPE_TEMP_DTS_ATOM:
{
u32 tjmax = dsp_ptr->get_temp_tc1(dsp_ptr, action);
ESIF_TRACE_DYN_TEMP(
"%s: using algorithm %s, tjmax %d for ATOM\n",
ESIF_FUNC,
esif_algorithm_type_str(algo_ptr->temp_xform),
tjmax);
if (opcode == ESIF_PRIMITIVE_OP_GET) {
temp_out = DTS_TO_CELCIUS(temp_out) + tjmax - 90;
temp_in_type = ESIF_TEMP_C;
temp_out_type = type;
esif_convert_temp(temp_in_type, temp_out_type,
&temp_out);
} else {/* ESIF_PRIMITIVE_OP_SET */
temp_in_type = type;
temp_out_type = ESIF_TEMP_C;
esif_convert_temp(temp_in_type, temp_out_type,
&temp_out);
}
break;
}
case ESIF_ALGORITHM_TYPE_TEMP_NONE:
ESIF_TRACE_DYN_TEMP(
"%s: using algorithm none (%s), for Code and "
"Konst temp\n",
ESIF_FUNC,
esif_algorithm_type_str(algo_ptr->temp_xform));
if (opcode == ESIF_PRIMITIVE_OP_GET) {
temp_in_type = ESIF_TEMP_C;
temp_out_type = type;
esif_convert_temp(temp_in_type, temp_out_type,
&temp_out);
} else {/* ESIF_PRIMITIVE_OP_SET */
temp_in_type = type;
temp_out_type = ESIF_TEMP_C;
esif_convert_temp(temp_in_type, temp_out_type,
&temp_out);
}
break;
case ESIF_ALGORITHM_TYPE_TEMP_LPAT:
ESIF_TRACE_DYN_TEMP(
"%s: using algorithm %s temp_in %u\n", ESIF_FUNC,
esif_algorithm_type_str(algo_ptr->temp_xform),
temp_in);
if (opcode == ESIF_PRIMITIVE_OP_GET) {
temp_out = esif_xform_lpat(temp_in, lp_ptr->dsp_ptr,
ESIF_TEMP_THERMISTOR);
temp_in_type = ESIF_TEMP_DECIK;
temp_out_type = type;
esif_convert_temp(temp_in_type, temp_out_type,
&temp_out);
} else { /*ESIF_PRIMITIVE_OP_SET */
temp_in_type = type;
temp_out_type = ESIF_TEMP_DECIK;
/* Normalized to Kelvin */
esif_convert_temp(temp_in_type, temp_out_type,
&temp_out);
temp_out = esif_xform_lpat(temp_in, lp_ptr->dsp_ptr,
ESIF_TEMP_DECIK);
}
break;
default:
ESIF_TRACE_DYN_POWER(
"%s: Unknown algorithm (%s) to xform temp\n",
ESIF_FUNC,
esif_algorithm_type_str(algo_ptr->temp_xform));
rc = ESIF_E_UNSUPPORTED_ALGORITHM;
}
ESIF_TRACE_DYN_TEMP("%s: IN temp %u %s(%d)\n", ESIF_FUNC, temp_in,
esif_temperature_type_desc(
temp_in_type), temp_in_type);
ESIF_TRACE_DYN_TEMP("%s: OUT temp %u %s(%d)\n", ESIF_FUNC, temp_out,
esif_temperature_type_desc(
temp_out_type), temp_out_type);
*temp_ptr = temp_out;
return rc;
}
/* Power Transform */
static enum esif_rc esif_xform_power(
const enum esif_power_unit_type type,
esif_power_t *power_ptr,
const enum esif_action_type action,
const struct esif_lp_dsp *dsp_ptr,
const enum esif_primitive_opcode opcode
)
{
enum esif_power_unit_type power_in_type = type;
enum esif_power_unit_type power_out_type = type;
enum esif_rc rc = ESIF_OK;
struct esif_cpc_algorithm *algo_ptr = NULL;
esif_power_t power_in;
esif_power_t power_out;
algo_ptr = dsp_ptr->get_algorithm(dsp_ptr, action);
if (algo_ptr == NULL)
return ESIF_E_NEED_ALGORITHM;
power_in = *power_ptr;
power_out = *power_ptr;
switch (algo_ptr->power_xform) {
case ESIF_ALGORITHM_TYPE_POWER_DECIW:
ESIF_TRACE_DYN_POWER(
"%s: using algorithm DeciW (%s), for ACPI power\n",
ESIF_FUNC,
esif_algorithm_type_str(algo_ptr->power_xform));
if (opcode == ESIF_PRIMITIVE_OP_GET) {
/* Tenths Of A Watt To Milli Watts */
power_in_type = ESIF_POWER_DECIW;
power_out_type = type;
/* Normalized from DeciW */
esif_convert_power(power_in_type,
power_out_type,
&power_out);
} else {
/* Milli Watts To Tenths Of A Watt */
power_in_type = type;
power_out_type = ESIF_POWER_DECIW;
/* Normalized to DeciW */
esif_convert_power(power_in_type,
power_out_type,
&power_out);
}
break;
case ESIF_ALGORITHM_TYPE_POWER_MILLIW:
ESIF_TRACE_DYN_POWER(
"%s: using algorithm MillW (%s), for Code and Konst power\n",
ESIF_FUNC,
esif_algorithm_type_str(algo_ptr->power_xform));
if (opcode == ESIF_PRIMITIVE_OP_GET) {
power_in_type = ESIF_POWER_MILLIW;
power_out_type = type;
esif_convert_power(power_in_type,
power_out_type,
&power_out);
} else {
/* Milli Watts To Tenths Of A Watt */
power_in_type = type;
power_out_type = ESIF_POWER_MILLIW;
esif_convert_power(power_in_type,
power_out_type,
&power_out);
}
break;
case ESIF_ALGORITHM_TYPE_POWER_UNIT_ATOM:
/*
* Power 1mw * (2 ^ RAPL_POWER_UNIT)
* RAPL_POWER_UNIT = 5 example 1mw * (2 ^5) = 32mw
*/
ESIF_TRACE_DYN_POWER(
"%s: using algorithm %s, for hardware power\n",
ESIF_FUNC,
esif_algorithm_type_str(algo_ptr->power_xform));
/* Hardware */
if (opcode == ESIF_PRIMITIVE_OP_GET) {
power_in_type = ESIF_POWER_UNIT_ATOM;
power_out_type = type;
/* Normalized from hardware */
esif_convert_power(power_in_type,
power_out_type,
&power_out);
} else {
power_in_type = type;
power_out_type = ESIF_POWER_UNIT_ATOM;
/* Normalized to hardware */
esif_convert_power(power_in_type,
power_out_type,
&power_out);
}
break;
case ESIF_ALGORITHM_TYPE_POWER_UNIT_CORE:
/*
* Power 1000mw / (2 ^ RAPL_POWER_UNIT)
* RAPL_POWER_LIMIT = 3 example 1000mw / (2 ^3) = 125mw
*/
ESIF_TRACE_DYN_POWER(
"%s: using algorithm %s, for hardware power\n",
ESIF_FUNC,
esif_algorithm_type_str(algo_ptr->power_xform));
/* Hardware */
if (opcode == ESIF_PRIMITIVE_OP_GET) {
power_in_type = ESIF_POWER_UNIT_CORE;
power_out_type = type;
/* Normalized from hardware */
esif_convert_power(power_in_type,
power_out_type,
&power_out);
} else {
/* Milliwatts To hardware */
power_in_type = type;
power_out_type = ESIF_POWER_UNIT_CORE;
/* Normalized to OctaW */
esif_convert_power(power_in_type,
power_out_type,
&power_out);
}
break;
case ESIF_ALGORITHM_TYPE_POWER_NONE:
/* No algorithm specified, do not perform any xform */
ESIF_TRACE_DYN_POWER(
"%s: using algorithm NONE (%s), no xform performed\n",
ESIF_FUNC,
esif_algorithm_type_str(algo_ptr->power_xform));
break;
default:
ESIF_TRACE_DYN_POWER(
"%s: Unknown algorithm (%s) to xform power\n",
ESIF_FUNC,
esif_algorithm_type_str(algo_ptr->power_xform));
rc = ESIF_E_UNSUPPORTED_ALGORITHM;
}
ESIF_TRACE_DYN_POWER("%s: IN power %u %s(%d)\n", ESIF_FUNC, power_in,
esif_power_unit_desc(power_in_type),
power_in_type);
ESIF_TRACE_DYN_POWER("%s: OUT power %u %s(%d)\n", ESIF_FUNC, power_out,
esif_power_unit_desc(
power_out_type), power_out_type);
*power_ptr = power_out;
return rc;
}
/* Execute Xform Function */
enum esif_rc esif_execute_xform_func(
const struct esif_lp *lp_ptr,
const struct esif_lp_primitive *primitive_ptr,
const enum esif_action_type action,
const enum esif_data_type data_type,
u64 *temp_ptr
)
{
enum esif_rc rc = ESIF_E_XFORM_NOT_AVAILABLE;
switch (data_type) {
case ESIF_DATA_TEMPERATURE:
if (lp_ptr->xform_temp != NULL)
rc = lp_ptr->xform_temp(NORMALIZE_TEMP_TYPE,
(esif_temp_t *) temp_ptr,
action,
lp_ptr->dsp_ptr,
primitive_ptr,
lp_ptr);
break;
case ESIF_DATA_POWER:
if (lp_ptr->xform_power != NULL)
rc = lp_ptr->xform_power(NORMALIZE_POWER_UNIT_TYPE,
(esif_power_t *) temp_ptr,
action,
lp_ptr->dsp_ptr,
primitive_ptr->opcode);
break;
default:
rc = ESIF_E_UNSUPPORTED_ACTION_TYPE;
break;
}
return rc;
}
/*
*******************************************************************************
** PUBLIC
*******************************************************************************
*/
/* ESIF Stats */
struct esif_memory_stats g_memstat = {0};
esif_ccb_lock_t g_memstat_lock;
/* ESIF Memory */
struct esif_ccb_mempool *g_mempool[ESIF_MEMPOOL_TYPE_MAX] = {0};
esif_ccb_lock_t g_mempool_lock;
struct esif_ccb_memtype *g_memtype[ESIF_MEMTYPE_TYPE_MAX] = {0};
esif_ccb_lock_t g_memtype_lock;
/* Register Participant */
enum esif_rc esif_lf_register_participant(struct esif_participant_iface *pi_ptr)
{
enum esif_rc rc = ESIF_OK;
struct esif_lp *lp_ptr = NULL;
ESIF_TRACE_DYN_LF("Register Send_Event Handler\n");
ESIF_TRACE_DYN_DECODE(
"Version: %d\n"
"GUID: %08x.%08x.%08x.%08x\n"
"Enumerator: %s(%d)\n"
"Flags: %08x\n"
"Name: %s\n"
"Driver Name: %s\n"
"Device Name: %s\n"
"Device Path: %s\n"
"ACPI Device: %s\n"
"ACPI Scope: %s\n"
"ACPI UID: %s\n"
"ACPI Type: %x\n"
"PCI Vendor: %x\n"
"PCI Device: %x\n"
"PCI Bus: %x\n"
"PCI Bus Device: %x\n"
"PCI Function: %x\n"
"PCI Revision: %x\n"
"PCI Class: %x\n"
"PCI SubClass: %x\n"
"PCI ProgIF: %x\n",
pi_ptr->version,
*((int *)&pi_ptr->class_guid[0]),
*((int *)&pi_ptr->class_guid[4]),
*((int *)&pi_ptr->class_guid[8]),
*((int *)&pi_ptr->class_guid[12]),
esif_participant_enum_str(pi_ptr->enumerator),
pi_ptr->enumerator,
pi_ptr->flags,
pi_ptr->name,
pi_ptr->driver_name,
pi_ptr->device_name,
pi_ptr->device_path,
pi_ptr->acpi_device,
pi_ptr->acpi_scope,
pi_ptr->acpi_uid,
pi_ptr->acpi_type,
pi_ptr->pci_vendor,
pi_ptr->pci_device,
pi_ptr->pci_bus,
pi_ptr->pci_bus_device,
pi_ptr->pci_function,
pi_ptr->pci_revision,
pi_ptr->pci_class,
pi_ptr->pci_sub_class,
pi_ptr->pci_prog_if);
lp_ptr = esif_lf_pm_lp_create(pi_ptr);
if (NULL == lp_ptr) {
rc = ESIF_E_NO_CREATE;
goto exit;
}
pi_ptr->send_event = esif_lf_event;
lp_ptr->xform_temp = esif_xform_temp;
lp_ptr->xform_power = esif_xform_power;
/* Transition State To Registering Next State Need DSP */
rc = esif_lf_pm_lp_set_state(lp_ptr,
ESIF_PM_PARTICIPANT_STATE_REGISTERING);
if (ESIF_OK != rc)
goto exit;
/* Notify Upper Framework */
rc = esif_lf_event(pi_ptr, ESIF_EVENT_PARTICIPANT_CREATE, 'NA', NULL);
if (ESIF_OK != rc)
goto exit;
/* Notify Driver */
pi_ptr->recv_event(ESIF_EVENT_PARTICIPANT_CREATE, 'NA', NULL);
if (ESIF_OK != rc)
goto exit;
exit:
return rc;
}
/* Unregister All Participants */
void esif_lf_unregister_all_participants()
{
u8 i = 0;
struct esif_participant_iface *pi_ptr = NULL;
for (i = 0; i < MAX_PARTICIPANT_ENTRY; i++) {
pi_ptr = esif_lf_pm_pi_get_by_instance_id(i);
if (pi_ptr != NULL)
esif_lf_unregister_participant(pi_ptr);
}
}
/* Unregister Participant */
enum esif_rc esif_lf_unregister_participant(
struct esif_participant_iface *pi_ptr)
{
enum esif_rc rc = ESIF_OK;
struct esif_lp *lp_ptr = esif_lf_pm_lp_get_by_pi(pi_ptr);
if (NULL == lp_ptr) {
rc = ESIF_E_PARTICIPANT_NOT_FOUND;
goto exit;
}
if (NULL != lp_ptr->dsp_ptr)
esif_dsp_unload(lp_ptr);
ESIF_TRACE_DYN_LF("instance %d.\n", lp_ptr->instance);
/* Notify Upper Framework */
rc = esif_lf_event(lp_ptr->pi_ptr,
ESIF_EVENT_PARTICIPANT_UNREGISTER,
'NA',
NULL);
if (ESIF_OK != rc)
goto exit;
esif_lf_pm_lp_remove(lp_ptr);
exit:
return rc;
}
/* Optional Low-Level ESIF LF OS Init.
* Call before any esif_ccb_malloc, esif_lf_init, or threads created
*/
static unsigned int os_init_count = 0;
void esif_lf_os_init()
{
if (!os_init_count) {
esif_ccb_lock_init(&g_memstat_lock);
os_init_count = 1;
} else {
os_init_count++;
}
}
/* Optional Low-Level ESIF LF OS Exit.
* Call after all esif_ccb_free, esif_lf_init, and threads exit
*/
void esif_lf_os_exit()
{
if (os_init_count) {
os_init_count--;
} else {
esif_ccb_lock_uninit(&g_memstat_lock);
os_init_count = 0;
}
}
/* Start all Initializers, Stopping and aborting all on first Error */
static enum esif_rc esif_start_initializers()
{
enum esif_rc rc = ESIF_OK;
int initializer_count = sizeof(esif_initializers) / sizeof(struct esif_init_module);
int j;
for (j = 0; j < initializer_count; j++) {
rc = (*esif_initializers[j].init_func)();
if (rc != ESIF_OK) {
esif_stop_initializers();
break;
}
esif_initializers[j].started = 1;
}
return rc;
}
/* Stop all Initializers that have been Started */
static void esif_stop_initializers()
{
int initializer_count = sizeof(esif_initializers) / sizeof(struct esif_init_module);
int j;
/* Stop in reverse order */
for (j = initializer_count-1; j >= 0; j--) {
if (esif_initializers[j].started) {
(*esif_initializers[j].exit_func)();
esif_initializers[j].started = 0;
}
}
}
/* ESIF LF Init */
enum esif_rc esif_lf_init(u32 debug_mask)
{
enum esif_rc rc = ESIF_OK;
esif_lf_os_init();
esif_ccb_mempool_init_tracking();
esif_ccb_memtype_init_tracking();
/* Static Debug Table */
esif_debug_init_module_categories();
if (0 != debug_mask) {
/* Modules */
esif_debug_set_modules(debug_mask);
/* CPC */
esif_debug_set_module_category(ESIF_DEBUG_MOD_CPC,
ESIF_TRACE_CATEGORY_DEFAULT |
0xff);
/* DSP */
esif_debug_set_module_category(ESIF_DEBUG_MOD_DSP,
ESIF_TRACE_CATEGORY_DEFAULT |
0xff);
}
ESIF_TRACE_DYN_INIT("%s: Initialize Eco-System Independent Framework\n",
ESIF_FUNC);
/* Call all Init functions listed in esif_initializers. Abort on 1st Error */
rc = esif_start_initializers();
return rc;
}
/* ESIF LF Exit */
void esif_lf_exit(void)
{
esif_lf_unregister_all_participants();
/* Call all Exit functions listed in esif_initializers */
esif_stop_initializers();
esif_ccb_mempool_uninit_tracking();
esif_ccb_memtype_uninit_tracking();
esif_lf_os_exit();
ESIF_TRACE_DYN_INIT("%s: Exit Eco-System Independent Framework\n",
ESIF_FUNC);
ESIF_TRACE_DEBUG("\nDUMP Memory Stats:\n"
"-----------------------\n");
ESIF_TRACE_DEBUG("MemAllocs: %d\n", g_memstat.allocs);
ESIF_TRACE_DEBUG("MemFrees: %d\n", g_memstat.frees);
ESIF_TRACE_DEBUG("MemInuse: %d\n",
g_memstat.allocs - g_memstat.frees);
ESIF_TRACE_DEBUG("MemPoolAllocs: %d\n", g_memstat.memPoolAllocs);
ESIF_TRACE_DEBUG("MemPoolFrees: %d\n", g_memstat.memPoolFrees);
ESIF_TRACE_DEBUG("MemPoolInuse: %d\n",
g_memstat.memPoolAllocs - g_memstat.memPoolFrees);
ESIF_TRACE_DEBUG("MemPoolObjAllocs: %d\n", g_memstat.memPoolObjAllocs);
ESIF_TRACE_DEBUG("MemPoolObjFrees: %d\n", g_memstat.memPoolObjFrees);
ESIF_TRACE_DEBUG("MemPoolObjInuse: %d\n",
g_memstat.memPoolObjAllocs -
g_memstat.memPoolObjFrees);
ESIF_TRACE_DEBUG("MemTypeAllocs: %d\n", g_memstat.memTypeAllocs);
ESIF_TRACE_DEBUG("MemTypeFrees: %d\n", g_memstat.memTypeFrees);
ESIF_TRACE_DEBUG("MemTypeInuse: %d\n",
g_memstat.memTypeAllocs - g_memstat.memTypeFrees);
ESIF_TRACE_DEBUG("MemTypeObjAllocs: %d\n", g_memstat.memTypeObjAllocs);
ESIF_TRACE_DEBUG("MemTypeObjFrees: %d\n", g_memstat.memTypeObjFrees);
ESIF_TRACE_DEBUG("MemTypeObjInuse: %d\n\n",
g_memstat.memTypeObjAllocs -
g_memstat.memTypeObjFrees);
if (0 != (g_memstat.allocs - g_memstat.frees)) {
ESIF_TRACE_DEBUG(
"!!!!!!!! POTENTIAL MEMORY LEAK DETECTED !!!!!!!!\n\n");
}
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/