Files
Chromebook-Device-Nyan-NVID…/drivers/platform/x86/intel_dptf/esif_lf_primitive.c
2025-04-06 23:50:55 -05:00

479 lines
14 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_primitive.h"
#include "esif_lf_action.h"
#include "esif_ipc.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
/* Debug Logging Defintions */
#define INIT_DEBUG 0 /* Init Debug */
#define PRIMITIVE_DEBUG 1 /* Primitive Debug */
#define DECODE_DEBUG 2 /* Decode Debug */
#define PRIMITIVE_DEBUG_DSP 3 /* Debug DSP */
#define ESIF_TRACE_DYN_INIT(format, ...) \
ESIF_TRACE_DYN(ESIF_DEBUG_MOD_PRIMITIVE, INIT_DEBUG, \
format, ##__VA_ARGS__)
#define ESIF_TRACE_DYN_PRIM(format, ...) \
ESIF_TRACE_DYN(ESIF_DEBUG_MOD_PRIMITIVE, PRIMITIVE_DEBUG, \
format, ##__VA_ARGS__)
#define ESIF_TRACE_DYN_DECODE(format, ...) \
ESIF_TRACE_DYN(ESIF_DEBUG_MOD_PRIMITIVE, DECODE_DEBUG, \
format, ##__VA_ARGS__)
#define ESIF_TRACE_DYN_PRIM_DPF(format, ...) \
ESIF_TRACE_DYN(ESIF_DEBUG_MOD_PRIMITIVE, PRIMITIVE_DEBUG_DSP, \
format, ##__VA_ARGS__)
/*
******************************************************************************
* PRIVATE
******************************************************************************
*/
/* u16 To String */
static char *esif_primitive_domain_str(
u16 domain,
char *str_ptr
)
{
esif_ccb_memcpy(str_ptr, &domain, 2); /* Two Byte String */
*(str_ptr + 2) = 0; /* Null Terminate */
return str_ptr;
}
/* u32 To String */
static char *esif_action_acpi_str(
u32 method,
char *str_ptr
)
{
esif_ccb_memcpy(str_ptr, &method, 4); /* Four Byte String */
*(str_ptr + 4) = 0; /* Null Terminate */
return str_ptr;
}
/* Print Action */
static void esif_action_dump(struct esif_lp_action *action_ptr)
{
/* Done this way to fix compiler warning in release build */
char tmp[8];
tmp[0] = '\0';
/* First action that succeeds wins */
ESIF_TRACE_DYN_DECODE(
"ACTION TYPE P1 P2 "
"P3 P4 P5\n"
"----------------------------- ---------- ---------- "
"---------- ---------- ----------\n"
"%-25s(%02d) 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
esif_action_type_str(action_ptr->type),
action_ptr->type,
action_ptr->get_p1_u32(action_ptr),
action_ptr->get_p2_u32(action_ptr),
action_ptr->get_p3_u32(action_ptr),
action_ptr->get_p4_u32(action_ptr),
action_ptr->get_p5_u32(action_ptr));
if (ESIF_ACTION_ACPI == action_ptr->type) {
ESIF_TRACE_DYN_DECODE("ACPI Method: %s\n",
esif_action_acpi_str(action_ptr->get_p1_u32(action_ptr),
tmp));
} else if (ESIF_ACTION_KODE == action_ptr->type) {
ESIF_TRACE_DYN_DECODE("Code Method: %s\n",
esif_action_acpi_str(action_ptr->get_p1_u32(action_ptr),
tmp));
}
return;
}
static enum esif_rc esif_lf_primitive_get_and_execute_action(
struct esif_lp_primitive *primitive_ptr,
struct esif_lp *lp_ptr,
const struct esif_data *req_data_ptr,
struct esif_data *rsp_data_ptr,
u8 action
)
{
enum esif_rc rc = ESIF_OK;
struct esif_lp_action *action_ptr = NULL;
if (NULL == lp_ptr) {
rc = ESIF_E_PARAMETER_IS_NULL;
goto exit;
}
action_ptr = lp_ptr->dsp_ptr->get_action(lp_ptr->dsp_ptr,
primitive_ptr,
action);
if (NULL == action_ptr) {
rc = ESIF_E_PRIMITIVE_NOT_FOUND_IN_DSP;
goto exit;
}
esif_action_dump(action_ptr);
/* Have Action Now Execute */
rc = esif_execute_action(lp_ptr,
primitive_ptr,
action_ptr,
(struct esif_data *)req_data_ptr,
rsp_data_ptr);
ESIF_TRACE_DYN_PRIM("%s: PRIMITIVE ACTION(%d) return type: %s(%d)\n",
ESIF_FUNC, action, esif_rc_str(rc), rc);
exit:
if (action_ptr != NULL)
esif_ccb_free(action_ptr);
return rc;
}
/*
******************************************************************************
* PUBLIC
******************************************************************************
*/
/*
* Execute IPC Primitive
* Gets primitive data from IPC structure, looks up the participatn associated
* with the primitive, and then executes the primitive. After execution,
* sets the response data in the primitive for return to caller.
*/
struct esif_ipc *esif_execute_ipc_primitive(struct esif_ipc *ipc_ptr)
{
enum esif_rc rc = ESIF_OK;
struct esif_lp *lp_ptr = NULL;
struct esif_ipc_primitive *primitive_ptr =
(struct esif_ipc_primitive *)(ipc_ptr + 1);
u8 *data_ptr = (u8 *)primitive_ptr + sizeof(*primitive_ptr);
u32 data_size = 0;
struct esif_data req_data = {
primitive_ptr->req_data_type,
data_ptr + primitive_ptr->req_data_offset,
primitive_ptr->req_data_len,
0
};
struct esif_data rsp_data = {
primitive_ptr->rsp_data_type,
data_ptr + primitive_ptr->rsp_data_offset,
primitive_ptr->rsp_data_len,
0
};
/* Done this way to fix compiler warning in release build */
char tmp[8];
tmp[0] = '\0';
data_size = ipc_ptr->data_len - sizeof(*primitive_ptr);
if(((primitive_ptr->req_data_offset + primitive_ptr->req_data_len) >
data_size) ||
((primitive_ptr->rsp_data_offset + primitive_ptr->rsp_data_len) >
data_size)) {
rc = ESIF_E_NEED_LARGER_BUFFER;
goto exit;
}
ESIF_TRACE_DYN_PRIM("%s: PRIMITIVE Received:\n", ESIF_FUNC);
ESIF_TRACE_DYN_DECODE(
" Version: %d\n"
" Primitive: %s(%d)\n"
" Primitive Domain: %s(%d)\n"
" Primitive Instance: %d\n"
" Source Type/ID: %s/%d\n"
" Destination Type/ID: %s/%d\n"
" Action Hint: %s(%d)\n"
" Payload Length: %d\n"
" Request Data Type: %s(%d)\n"
" Request Data Offset: %d\n"
" Request Data Length: %d\n"
" Response Data Type: %s(%d)\n"
" Response Data Offset: %d\n"
" Response Data Length: %d\n",
(int)primitive_ptr->version,
esif_primitive_str((enum esif_primitive_type)primitive_ptr->id),
(int)primitive_ptr->id,
esif_primitive_domain_str(primitive_ptr->domain, tmp),
(int)primitive_ptr->domain,
(int)primitive_ptr->instance,
esif_primitive_src_str(primitive_ptr->src_id),
(int)primitive_ptr->src_id,
esif_primitive_dst_str(primitive_ptr->dst_id),
(int)primitive_ptr->dst_id,
esif_action_type_str(primitive_ptr->kern_action),
(int)primitive_ptr->kern_action,
(int)primitive_ptr->payload_len,
esif_data_type_str(primitive_ptr->req_data_type),
(int)primitive_ptr->req_data_type,
(int)primitive_ptr->req_data_offset,
(int)primitive_ptr->req_data_len,
esif_data_type_str(primitive_ptr->rsp_data_type),
(int)primitive_ptr->rsp_data_type,
(int)primitive_ptr->rsp_data_offset,
(int)primitive_ptr->rsp_data_len);
/* Lookup the requsted participant instance */
lp_ptr = esif_lf_pm_lp_get_by_instance_id(primitive_ptr->dst_id);
if (NULL == lp_ptr) {
rc = ESIF_E_PRIMITIVE_DST_UNAVAIL;
} else {
struct esif_primitive_tuple tuple = {
(u16)primitive_ptr->id,
primitive_ptr->domain,
primitive_ptr->instance
};
/*
* 5th param - user specified action, or all actions (if NULL)
*/
rc = esif_execute_primitive(lp_ptr,
&tuple,
&req_data,
&rsp_data,
&primitive_ptr->kern_action);
}
primitive_ptr->return_code = rc;
/* Update Response Data Length and Type (May be Changed) */
primitive_ptr->rsp_data_type = rsp_data.type;
primitive_ptr->rsp_data_len = rsp_data.data_len;
ESIF_TRACE_DYN_PRIM("%s:\n"
" PRIMITIVE Return: %s(%d)\n"
" Response Data Type: %s(%d)\n"
" Buffer Length: %d\n"
" Data Length : %d\n",
ESIF_FUNC, esif_rc_str(rc), rc,
esif_data_type_str(primitive_ptr->rsp_data_type),
rsp_data.type, rsp_data.data_len,
rsp_data.data_len);
exit:
return ipc_ptr;
}
/* Execute Primitive */
enum esif_rc esif_execute_primitive(
struct esif_lp *lp_ptr,
const struct esif_primitive_tuple *tuple_ptr,
const struct esif_data *req_data_ptr,
struct esif_data *rsp_data_ptr,
const u16 *action_index_ptr
)
{
enum esif_rc rc = ESIF_OK;
struct esif_lp_primitive *primitive_ptr = NULL;
u8 action = 0;
/* Done this way to fix compiler warning in release build */
char tmp[8];
tmp[0] = '\0';
/* Special load our DSP */
if (ESIF_DATA_DSP == req_data_ptr->type) {
ESIF_TRACE_DYN_PRIM_DPF("%s: Load DSP buf=%p size=%d\n",
ESIF_FUNC,
req_data_ptr->buf_ptr,
req_data_ptr->buf_len);
/* Unload? */
if (NULL != lp_ptr->dsp_ptr && 0 == req_data_ptr->buf_len) {
ESIF_TRACE_DYN_PRIM_DPF("%s: Unload DSP %p\n",
ESIF_FUNC,
lp_ptr->dsp_ptr);
esif_dsp_unload(lp_ptr);
rc = ESIF_OK;
goto exit;
}
/* Reload? */
if (lp_ptr->dsp_ptr != NULL) {
ESIF_TRACE_DYN_PRIM_DPF(
"%s: Reload DSP buf=%p size=%d\n",
ESIF_FUNC,
req_data_ptr->buf_ptr,
req_data_ptr->buf_len);
esif_dsp_unload(lp_ptr);
}
rc = esif_dsp_load(lp_ptr, req_data_ptr);
goto exit;
}
/* Can't continue without DSP! */
if (NULL == lp_ptr->dsp_ptr) {
rc = ESIF_E_NEED_DSP;
goto exit;
}
/* Free Me! */
primitive_ptr = lp_ptr->dsp_ptr->get_primitive(lp_ptr->dsp_ptr,
tuple_ptr);
if (NULL == primitive_ptr) {
rc = ESIF_E_PRIMITIVE_NOT_FOUND_IN_DSP;
goto exit;
}
if (ESIF_PM_PARTICIPANT_STATE_REGISTERED != esif_lf_pm_lp_get_state(lp_ptr)) {
rc = ESIF_E_PRIMITIVE_DST_UNAVAIL;
goto exit;
}
ESIF_TRACE_DYN_PRIM("%s: PRIMITIVE Lookup Found in DSP (%s)\n",
ESIF_FUNC, lp_ptr->dsp_ptr->get_code(lp_ptr->dsp_ptr));
ESIF_TRACE_DYN_DECODE(" Primitive: %s(%d)\n"
" Primitive Domain: %s(%d)\n"
" Primitive Instance: %d\n"
" Opcode: %s(%d)\n"
" Actions: %d\n",
esif_primitive_str((enum esif_primitive_type)
primitive_ptr->tuple.id),
(int)primitive_ptr->tuple.id,
esif_primitive_domain_str(primitive_ptr->tuple.domain, tmp),
(int)primitive_ptr->tuple.domain,
(int)primitive_ptr->tuple.instance,
esif_primitive_opcode_str(primitive_ptr->opcode),
(int)primitive_ptr->opcode,
(int)primitive_ptr->action_count);
/* Have Action Specified */
if (NULL != action_index_ptr) {
rc = esif_lf_primitive_get_and_execute_action(primitive_ptr,
lp_ptr,
req_data_ptr,
rsp_data_ptr,
(u8) *action_index_ptr);
goto exit;
}
/* No action specified, so call actions one by one until one fires */
for (action = 0; action < primitive_ptr->action_count; action++) {
rc = esif_lf_primitive_get_and_execute_action(primitive_ptr,
lp_ptr,
req_data_ptr,
rsp_data_ptr,
action);
if ((ESIF_OK == rc) ||
(ESIF_E_NEED_LARGER_BUFFER == rc) ||
(ESIF_E_PRIMITIVE_NOT_FOUND_IN_DSP == rc)) {
break;
}
}
exit:
if (primitive_ptr)
esif_ccb_free(primitive_ptr);
return rc;
}
/*
* Simple helper function to execute a primitive that takes no special
* parameters.
*/
enum esif_rc esif_get_simple_primitive(
struct esif_lp *lp_ptr,
u16 id,
u16 domain,
u16 instance,
enum esif_data_type esif_type,
void *buffer_ptr,
u32 buffer_size
)
{
enum esif_rc rc = ESIF_OK;
struct esif_primitive_tuple tuple_get = {id, domain, instance};
struct esif_data esif_void = {ESIF_DATA_VOID, NULL, 0, 0};
struct esif_data esif_return = {esif_type,
buffer_ptr,
buffer_size,
buffer_size};
if ((NULL == lp_ptr) || (NULL == buffer_ptr)) {
rc = ESIF_E_PARAMETER_IS_NULL;
goto exit;
}
rc = esif_execute_primitive(lp_ptr,
&tuple_get,
&esif_void, &esif_return,
NULL);
exit:
return rc;
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/