/******************************************************************************* ** 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"); } } /******************************************************************************/ /******************************************************************************/ /******************************************************************************/