// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2003-2020, Intel Corporation. All rights reserved.
* Intel Management Engine Interface (Intel MEI) Linux driver
*/
#include <linux/export.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/mei.h>
#include "mei_dev.h"
#include "hbm.h"
#include "client.h"
static const char *mei_hbm_status_str(enum mei_hbm_status status)
{
#define MEI_HBM_STATUS(status) case MEI_HBMS_##status: return #status
switch (status) {
MEI_HBM_STATUS(SUCCESS);
MEI_HBM_STATUS(CLIENT_NOT_FOUND);
MEI_HBM_STATUS(ALREADY_EXISTS);
MEI_HBM_STATUS(REJECTED);
MEI_HBM_STATUS(INVALID_PARAMETER);
MEI_HBM_STATUS(NOT_ALLOWED);
MEI_HBM_STATUS(ALREADY_STARTED);
MEI_HBM_STATUS(NOT_STARTED);
default: return "unknown";
}
#undef MEI_HBM_STATUS
};
static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)
{
#define MEI_CL_CS(status) case MEI_CL_CONN_##status: return #status
switch (status) {
MEI_CL_CS(SUCCESS);
MEI_CL_CS(NOT_FOUND);
MEI_CL_CS(ALREADY_STARTED);
MEI_CL_CS(OUT_OF_RESOURCES);
MEI_CL_CS(MESSAGE_SMALL);
MEI_CL_CS(NOT_ALLOWED);
default: return "unknown";
}
#undef MEI_CL_CCS
}
const char *mei_hbm_state_str(enum mei_hbm_state state)
{
#define MEI_HBM_STATE(state) case MEI_HBM_##state: return #state
switch (state) {
MEI_HBM_STATE(IDLE);
MEI_HBM_STATE(STARTING);
MEI_HBM_STATE(STARTED);
MEI_HBM_STATE(DR_SETUP);
MEI_HBM_STATE(ENUM_CLIENTS);
MEI_HBM_STATE(CLIENT_PROPERTIES);
MEI_HBM_STATE(STOPPED);
default:
return "unknown";
}
#undef MEI_HBM_STATE
}
/**
* mei_cl_conn_status_to_errno - convert client connect response
* status to error code
*
* @status: client connect response status
*
* Return: corresponding error code
*/
static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)
{
switch (status) {
case MEI_CL_CONN_SUCCESS: return 0;
case MEI_CL_CONN_NOT_FOUND: return -ENOTTY;
case MEI_CL_CONN_ALREADY_STARTED: return -EBUSY;
case MEI_CL_CONN_OUT_OF_RESOURCES: return -EBUSY;
case MEI_CL_CONN_MESSAGE_SMALL: return -EINVAL;
case MEI_CL_CONN_NOT_ALLOWED: return -EBUSY;
default: return -EINVAL;
}
}
/**
* mei_hbm_write_message - wrapper for sending hbm messages.
*
* @dev: mei device
* @hdr: mei header
* @data: payload
*/
static inline int mei_hbm_write_message(struct mei_device *dev,
struct mei_msg_hdr *hdr,
const void *data)
{
return mei_write_message(dev, hdr, sizeof(*hdr), data, hdr->length);
}
/**
* mei_hbm_idle - set hbm to idle state
*
* @dev: the device structure
*/
void mei_hbm_idle(struct mei_device *dev)
{
dev->init_clients_timer = 0;
dev->hbm_state = MEI_HBM_IDLE;
}
/**
* mei_hbm_reset - reset hbm counters and book keeping data structurs
*
* @dev: the device structure
*/
void mei_hbm_reset(struct mei_device *dev)
{
mei_me_cl_rm_all(dev);
mei_hbm_idle(dev);
}
/**
* mei_hbm_hdr - construct hbm header
*
* @mei_hdr: hbm header
* @length: payload length
*/
static inline void mei_hbm_hdr(struct mei_msg_hdr *mei_hdr, size_t length)
{
memset(mei_hdr, 0, sizeof(*mei_hdr));
mei_hdr->length = length;
mei_hdr->msg_complete = 1;
}
/**
* mei_hbm_cl_hdr - construct client hbm header
*
* @cl: client
* @hbm_cmd: host bus message command
* @buf: buffer for cl header
* @len: buffer length
*/
static inline
void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
{
struct mei_hbm_cl_cmd *cmd = buf;
memset(cmd, 0, len);
cmd->hbm_cmd = hbm_cmd;
cmd->host_addr = mei_cl_host_addr(cl);
cmd->me_addr = mei_cl_me_id(cl);
}
/**
* mei_hbm_cl_write - write simple hbm client message
*
* @dev: the device structure
* @cl: client
* @hbm_cmd: host bus message command
* @buf: message buffer
* @len: buffer length
*
* Return: 0 on success, <0 on failure.
*/
static inline int mei_hbm_cl_write(struct mei_device *dev, struct mei_cl *cl,
u8 hbm_cmd, void *buf, size_t len)
{
struct mei_msg_hdr mei_hdr;
mei_hbm_hdr(&mei_hdr, len);
mei_hbm_cl_hdr(cl, hbm_cmd, buf, len);
return mei_hbm_write_message(dev, &mei_hdr, buf);
}
/**
* mei_hbm_cl_addr_equal - check if the client's and
* the message address match
*
* @cl: client
* @cmd: hbm client message
*
* Return: true if addresses are the same
*/
static inline
bool mei_hbm_cl_addr_equal(struct mei_cl *cl, struct mei_hbm_cl_cmd *cmd)
{
return mei_cl_host_addr(cl) == cmd->host_addr &&
mei_cl_me_id(cl) == cmd->me_addr;
}
/**
* mei_hbm_cl_find_by_cmd - find recipient client
*
* @dev: the device structure
* @buf: a buffer with hbm cl command
*
* Return: the recipient
|