18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2003-2020, Intel Corporation. All rights reserved.
48c2ecf20Sopenharmony_ci * Intel Management Engine Interface (Intel MEI) Linux driver
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include <linux/export.h>
78c2ecf20Sopenharmony_ci#include <linux/sched.h>
88c2ecf20Sopenharmony_ci#include <linux/wait.h>
98c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/mei.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "mei_dev.h"
158c2ecf20Sopenharmony_ci#include "hbm.h"
168c2ecf20Sopenharmony_ci#include "client.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic const char *mei_hbm_status_str(enum mei_hbm_status status)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci#define MEI_HBM_STATUS(status) case MEI_HBMS_##status: return #status
218c2ecf20Sopenharmony_ci	switch (status) {
228c2ecf20Sopenharmony_ci	MEI_HBM_STATUS(SUCCESS);
238c2ecf20Sopenharmony_ci	MEI_HBM_STATUS(CLIENT_NOT_FOUND);
248c2ecf20Sopenharmony_ci	MEI_HBM_STATUS(ALREADY_EXISTS);
258c2ecf20Sopenharmony_ci	MEI_HBM_STATUS(REJECTED);
268c2ecf20Sopenharmony_ci	MEI_HBM_STATUS(INVALID_PARAMETER);
278c2ecf20Sopenharmony_ci	MEI_HBM_STATUS(NOT_ALLOWED);
288c2ecf20Sopenharmony_ci	MEI_HBM_STATUS(ALREADY_STARTED);
298c2ecf20Sopenharmony_ci	MEI_HBM_STATUS(NOT_STARTED);
308c2ecf20Sopenharmony_ci	default: return "unknown";
318c2ecf20Sopenharmony_ci	}
328c2ecf20Sopenharmony_ci#undef MEI_HBM_STATUS
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci#define MEI_CL_CS(status) case MEI_CL_CONN_##status: return #status
388c2ecf20Sopenharmony_ci	switch (status) {
398c2ecf20Sopenharmony_ci	MEI_CL_CS(SUCCESS);
408c2ecf20Sopenharmony_ci	MEI_CL_CS(NOT_FOUND);
418c2ecf20Sopenharmony_ci	MEI_CL_CS(ALREADY_STARTED);
428c2ecf20Sopenharmony_ci	MEI_CL_CS(OUT_OF_RESOURCES);
438c2ecf20Sopenharmony_ci	MEI_CL_CS(MESSAGE_SMALL);
448c2ecf20Sopenharmony_ci	MEI_CL_CS(NOT_ALLOWED);
458c2ecf20Sopenharmony_ci	default: return "unknown";
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci#undef MEI_CL_CCS
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ciconst char *mei_hbm_state_str(enum mei_hbm_state state)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci#define MEI_HBM_STATE(state) case MEI_HBM_##state: return #state
538c2ecf20Sopenharmony_ci	switch (state) {
548c2ecf20Sopenharmony_ci	MEI_HBM_STATE(IDLE);
558c2ecf20Sopenharmony_ci	MEI_HBM_STATE(STARTING);
568c2ecf20Sopenharmony_ci	MEI_HBM_STATE(STARTED);
578c2ecf20Sopenharmony_ci	MEI_HBM_STATE(DR_SETUP);
588c2ecf20Sopenharmony_ci	MEI_HBM_STATE(ENUM_CLIENTS);
598c2ecf20Sopenharmony_ci	MEI_HBM_STATE(CLIENT_PROPERTIES);
608c2ecf20Sopenharmony_ci	MEI_HBM_STATE(STOPPED);
618c2ecf20Sopenharmony_ci	default:
628c2ecf20Sopenharmony_ci		return "unknown";
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci#undef MEI_HBM_STATE
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci/**
688c2ecf20Sopenharmony_ci * mei_cl_conn_status_to_errno - convert client connect response
698c2ecf20Sopenharmony_ci * status to error code
708c2ecf20Sopenharmony_ci *
718c2ecf20Sopenharmony_ci * @status: client connect response status
728c2ecf20Sopenharmony_ci *
738c2ecf20Sopenharmony_ci * Return: corresponding error code
748c2ecf20Sopenharmony_ci */
758c2ecf20Sopenharmony_cistatic int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	switch (status) {
788c2ecf20Sopenharmony_ci	case MEI_CL_CONN_SUCCESS:          return 0;
798c2ecf20Sopenharmony_ci	case MEI_CL_CONN_NOT_FOUND:        return -ENOTTY;
808c2ecf20Sopenharmony_ci	case MEI_CL_CONN_ALREADY_STARTED:  return -EBUSY;
818c2ecf20Sopenharmony_ci	case MEI_CL_CONN_OUT_OF_RESOURCES: return -EBUSY;
828c2ecf20Sopenharmony_ci	case MEI_CL_CONN_MESSAGE_SMALL:    return -EINVAL;
838c2ecf20Sopenharmony_ci	case MEI_CL_CONN_NOT_ALLOWED:      return -EBUSY;
848c2ecf20Sopenharmony_ci	default:                           return -EINVAL;
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/**
898c2ecf20Sopenharmony_ci * mei_hbm_write_message - wrapper for sending hbm messages.
908c2ecf20Sopenharmony_ci *
918c2ecf20Sopenharmony_ci * @dev: mei device
928c2ecf20Sopenharmony_ci * @hdr: mei header
938c2ecf20Sopenharmony_ci * @data: payload
948c2ecf20Sopenharmony_ci */
958c2ecf20Sopenharmony_cistatic inline int mei_hbm_write_message(struct mei_device *dev,
968c2ecf20Sopenharmony_ci					struct mei_msg_hdr *hdr,
978c2ecf20Sopenharmony_ci					const void *data)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	return mei_write_message(dev, hdr, sizeof(*hdr), data, hdr->length);
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/**
1038c2ecf20Sopenharmony_ci * mei_hbm_idle - set hbm to idle state
1048c2ecf20Sopenharmony_ci *
1058c2ecf20Sopenharmony_ci * @dev: the device structure
1068c2ecf20Sopenharmony_ci */
1078c2ecf20Sopenharmony_civoid mei_hbm_idle(struct mei_device *dev)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	dev->init_clients_timer = 0;
1108c2ecf20Sopenharmony_ci	dev->hbm_state = MEI_HBM_IDLE;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/**
1148c2ecf20Sopenharmony_ci * mei_hbm_reset - reset hbm counters and book keeping data structurs
1158c2ecf20Sopenharmony_ci *
1168c2ecf20Sopenharmony_ci * @dev: the device structure
1178c2ecf20Sopenharmony_ci */
1188c2ecf20Sopenharmony_civoid mei_hbm_reset(struct mei_device *dev)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	mei_me_cl_rm_all(dev);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	mei_hbm_idle(dev);
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci/**
1268c2ecf20Sopenharmony_ci * mei_hbm_hdr - construct hbm header
1278c2ecf20Sopenharmony_ci *
1288c2ecf20Sopenharmony_ci * @mei_hdr: hbm header
1298c2ecf20Sopenharmony_ci * @length: payload length
1308c2ecf20Sopenharmony_ci */
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic inline void mei_hbm_hdr(struct mei_msg_hdr *mei_hdr, size_t length)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	memset(mei_hdr, 0, sizeof(*mei_hdr));
1358c2ecf20Sopenharmony_ci	mei_hdr->length = length;
1368c2ecf20Sopenharmony_ci	mei_hdr->msg_complete = 1;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci/**
1408c2ecf20Sopenharmony_ci * mei_hbm_cl_hdr - construct client hbm header
1418c2ecf20Sopenharmony_ci *
1428c2ecf20Sopenharmony_ci * @cl: client
1438c2ecf20Sopenharmony_ci * @hbm_cmd: host bus message command
1448c2ecf20Sopenharmony_ci * @buf: buffer for cl header
1458c2ecf20Sopenharmony_ci * @len: buffer length
1468c2ecf20Sopenharmony_ci */
1478c2ecf20Sopenharmony_cistatic inline
1488c2ecf20Sopenharmony_civoid mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct mei_hbm_cl_cmd *cmd = buf;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	memset(cmd, 0, len);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	cmd->hbm_cmd = hbm_cmd;
1558c2ecf20Sopenharmony_ci	cmd->host_addr = mei_cl_host_addr(cl);
1568c2ecf20Sopenharmony_ci	cmd->me_addr = mei_cl_me_id(cl);
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci/**
1608c2ecf20Sopenharmony_ci * mei_hbm_cl_write - write simple hbm client message
1618c2ecf20Sopenharmony_ci *
1628c2ecf20Sopenharmony_ci * @dev: the device structure
1638c2ecf20Sopenharmony_ci * @cl: client
1648c2ecf20Sopenharmony_ci * @hbm_cmd: host bus message command
1658c2ecf20Sopenharmony_ci * @buf: message buffer
1668c2ecf20Sopenharmony_ci * @len: buffer length
1678c2ecf20Sopenharmony_ci *
1688c2ecf20Sopenharmony_ci * Return: 0 on success, <0 on failure.
1698c2ecf20Sopenharmony_ci */
1708c2ecf20Sopenharmony_cistatic inline int mei_hbm_cl_write(struct mei_device *dev, struct mei_cl *cl,
1718c2ecf20Sopenharmony_ci				   u8 hbm_cmd, void *buf, size_t len)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	struct mei_msg_hdr mei_hdr;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	mei_hbm_hdr(&mei_hdr, len);
1768c2ecf20Sopenharmony_ci	mei_hbm_cl_hdr(cl, hbm_cmd, buf, len);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	return mei_hbm_write_message(dev, &mei_hdr, buf);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci/**
1828c2ecf20Sopenharmony_ci * mei_hbm_cl_addr_equal - check if the client's and
1838c2ecf20Sopenharmony_ci *	the message address match
1848c2ecf20Sopenharmony_ci *
1858c2ecf20Sopenharmony_ci * @cl: client
1868c2ecf20Sopenharmony_ci * @cmd: hbm client message
1878c2ecf20Sopenharmony_ci *
1888c2ecf20Sopenharmony_ci * Return: true if addresses are the same
1898c2ecf20Sopenharmony_ci */
1908c2ecf20Sopenharmony_cistatic inline
1918c2ecf20Sopenharmony_cibool mei_hbm_cl_addr_equal(struct mei_cl *cl, struct mei_hbm_cl_cmd *cmd)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	return  mei_cl_host_addr(cl) == cmd->host_addr &&
1948c2ecf20Sopenharmony_ci		mei_cl_me_id(cl) == cmd->me_addr;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci/**
1988c2ecf20Sopenharmony_ci * mei_hbm_cl_find_by_cmd - find recipient client
1998c2ecf20Sopenharmony_ci *
2008c2ecf20Sopenharmony_ci * @dev: the device structure
2018c2ecf20Sopenharmony_ci * @buf: a buffer with hbm cl command
2028c2ecf20Sopenharmony_ci *
2038c2ecf20Sopenharmony_ci * Return: the recipient client or NULL if not found
2048c2ecf20Sopenharmony_ci */
2058c2ecf20Sopenharmony_cistatic inline
2068c2ecf20Sopenharmony_cistruct mei_cl *mei_hbm_cl_find_by_cmd(struct mei_device *dev, void *buf)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct mei_hbm_cl_cmd *cmd = (struct mei_hbm_cl_cmd *)buf;
2098c2ecf20Sopenharmony_ci	struct mei_cl *cl;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	list_for_each_entry(cl, &dev->file_list, link)
2128c2ecf20Sopenharmony_ci		if (mei_hbm_cl_addr_equal(cl, cmd))
2138c2ecf20Sopenharmony_ci			return cl;
2148c2ecf20Sopenharmony_ci	return NULL;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci/**
2198c2ecf20Sopenharmony_ci * mei_hbm_start_wait - wait for start response message.
2208c2ecf20Sopenharmony_ci *
2218c2ecf20Sopenharmony_ci * @dev: the device structure
2228c2ecf20Sopenharmony_ci *
2238c2ecf20Sopenharmony_ci * Return: 0 on success and < 0 on failure
2248c2ecf20Sopenharmony_ci */
2258c2ecf20Sopenharmony_ciint mei_hbm_start_wait(struct mei_device *dev)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	int ret;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	if (dev->hbm_state > MEI_HBM_STARTING)
2308c2ecf20Sopenharmony_ci		return 0;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	mutex_unlock(&dev->device_lock);
2338c2ecf20Sopenharmony_ci	ret = wait_event_timeout(dev->wait_hbm_start,
2348c2ecf20Sopenharmony_ci			dev->hbm_state != MEI_HBM_STARTING,
2358c2ecf20Sopenharmony_ci			mei_secs_to_jiffies(MEI_HBM_TIMEOUT));
2368c2ecf20Sopenharmony_ci	mutex_lock(&dev->device_lock);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if (ret == 0 && (dev->hbm_state <= MEI_HBM_STARTING)) {
2398c2ecf20Sopenharmony_ci		dev->hbm_state = MEI_HBM_IDLE;
2408c2ecf20Sopenharmony_ci		dev_err(dev->dev, "waiting for mei start failed\n");
2418c2ecf20Sopenharmony_ci		return -ETIME;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci	return 0;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci/**
2478c2ecf20Sopenharmony_ci * mei_hbm_start_req - sends start request message.
2488c2ecf20Sopenharmony_ci *
2498c2ecf20Sopenharmony_ci * @dev: the device structure
2508c2ecf20Sopenharmony_ci *
2518c2ecf20Sopenharmony_ci * Return: 0 on success and < 0 on failure
2528c2ecf20Sopenharmony_ci */
2538c2ecf20Sopenharmony_ciint mei_hbm_start_req(struct mei_device *dev)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	struct mei_msg_hdr mei_hdr;
2568c2ecf20Sopenharmony_ci	struct hbm_host_version_request req;
2578c2ecf20Sopenharmony_ci	int ret;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	mei_hbm_reset(dev);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	mei_hbm_hdr(&mei_hdr, sizeof(req));
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	/* host start message */
2648c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(req));
2658c2ecf20Sopenharmony_ci	req.hbm_cmd = HOST_START_REQ_CMD;
2668c2ecf20Sopenharmony_ci	req.host_version.major_version = HBM_MAJOR_VERSION;
2678c2ecf20Sopenharmony_ci	req.host_version.minor_version = HBM_MINOR_VERSION;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	dev->hbm_state = MEI_HBM_IDLE;
2708c2ecf20Sopenharmony_ci	ret = mei_hbm_write_message(dev, &mei_hdr, &req);
2718c2ecf20Sopenharmony_ci	if (ret) {
2728c2ecf20Sopenharmony_ci		dev_err(dev->dev, "version message write failed: ret = %d\n",
2738c2ecf20Sopenharmony_ci			ret);
2748c2ecf20Sopenharmony_ci		return ret;
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	dev->hbm_state = MEI_HBM_STARTING;
2788c2ecf20Sopenharmony_ci	dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
2798c2ecf20Sopenharmony_ci	mei_schedule_stall_timer(dev);
2808c2ecf20Sopenharmony_ci	return 0;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci/**
2848c2ecf20Sopenharmony_ci * mei_hbm_dma_setup_req() - setup DMA request
2858c2ecf20Sopenharmony_ci * @dev: the device structure
2868c2ecf20Sopenharmony_ci *
2878c2ecf20Sopenharmony_ci * Return: 0 on success and < 0 on failure
2888c2ecf20Sopenharmony_ci */
2898c2ecf20Sopenharmony_cistatic int mei_hbm_dma_setup_req(struct mei_device *dev)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct mei_msg_hdr mei_hdr;
2928c2ecf20Sopenharmony_ci	struct hbm_dma_setup_request req;
2938c2ecf20Sopenharmony_ci	unsigned int i;
2948c2ecf20Sopenharmony_ci	int ret;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	mei_hbm_hdr(&mei_hdr, sizeof(req));
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(req));
2998c2ecf20Sopenharmony_ci	req.hbm_cmd = MEI_HBM_DMA_SETUP_REQ_CMD;
3008c2ecf20Sopenharmony_ci	for (i = 0; i < DMA_DSCR_NUM; i++) {
3018c2ecf20Sopenharmony_ci		phys_addr_t paddr;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci		paddr = dev->dr_dscr[i].daddr;
3048c2ecf20Sopenharmony_ci		req.dma_dscr[i].addr_hi = upper_32_bits(paddr);
3058c2ecf20Sopenharmony_ci		req.dma_dscr[i].addr_lo = lower_32_bits(paddr);
3068c2ecf20Sopenharmony_ci		req.dma_dscr[i].size = dev->dr_dscr[i].size;
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	mei_dma_ring_reset(dev);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	ret = mei_hbm_write_message(dev, &mei_hdr, &req);
3128c2ecf20Sopenharmony_ci	if (ret) {
3138c2ecf20Sopenharmony_ci		dev_err(dev->dev, "dma setup request write failed: ret = %d.\n",
3148c2ecf20Sopenharmony_ci			ret);
3158c2ecf20Sopenharmony_ci		return ret;
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	dev->hbm_state = MEI_HBM_DR_SETUP;
3198c2ecf20Sopenharmony_ci	dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
3208c2ecf20Sopenharmony_ci	mei_schedule_stall_timer(dev);
3218c2ecf20Sopenharmony_ci	return 0;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci/**
3258c2ecf20Sopenharmony_ci * mei_hbm_capabilities_req - request capabilities
3268c2ecf20Sopenharmony_ci *
3278c2ecf20Sopenharmony_ci * @dev: the device structure
3288c2ecf20Sopenharmony_ci *
3298c2ecf20Sopenharmony_ci * Return: 0 on success and < 0 on failure
3308c2ecf20Sopenharmony_ci */
3318c2ecf20Sopenharmony_cistatic int mei_hbm_capabilities_req(struct mei_device *dev)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct mei_msg_hdr mei_hdr;
3348c2ecf20Sopenharmony_ci	struct hbm_capability_request req;
3358c2ecf20Sopenharmony_ci	int ret;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	mei_hbm_hdr(&mei_hdr, sizeof(req));
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(req));
3408c2ecf20Sopenharmony_ci	req.hbm_cmd = MEI_HBM_CAPABILITIES_REQ_CMD;
3418c2ecf20Sopenharmony_ci	if (dev->hbm_f_vt_supported)
3428c2ecf20Sopenharmony_ci		req.capability_requested[0] = HBM_CAP_VT;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	ret = mei_hbm_write_message(dev, &mei_hdr, &req);
3458c2ecf20Sopenharmony_ci	if (ret) {
3468c2ecf20Sopenharmony_ci		dev_err(dev->dev,
3478c2ecf20Sopenharmony_ci			"capabilities request write failed: ret = %d.\n", ret);
3488c2ecf20Sopenharmony_ci		return ret;
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	dev->hbm_state = MEI_HBM_CAP_SETUP;
3528c2ecf20Sopenharmony_ci	dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
3538c2ecf20Sopenharmony_ci	mei_schedule_stall_timer(dev);
3548c2ecf20Sopenharmony_ci	return 0;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci/**
3588c2ecf20Sopenharmony_ci * mei_hbm_enum_clients_req - sends enumeration client request message.
3598c2ecf20Sopenharmony_ci *
3608c2ecf20Sopenharmony_ci * @dev: the device structure
3618c2ecf20Sopenharmony_ci *
3628c2ecf20Sopenharmony_ci * Return: 0 on success and < 0 on failure
3638c2ecf20Sopenharmony_ci */
3648c2ecf20Sopenharmony_cistatic int mei_hbm_enum_clients_req(struct mei_device *dev)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	struct mei_msg_hdr mei_hdr;
3678c2ecf20Sopenharmony_ci	struct hbm_host_enum_request req;
3688c2ecf20Sopenharmony_ci	int ret;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* enumerate clients */
3718c2ecf20Sopenharmony_ci	mei_hbm_hdr(&mei_hdr, sizeof(req));
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(req));
3748c2ecf20Sopenharmony_ci	req.hbm_cmd = HOST_ENUM_REQ_CMD;
3758c2ecf20Sopenharmony_ci	req.flags |= dev->hbm_f_dc_supported ? MEI_HBM_ENUM_F_ALLOW_ADD : 0;
3768c2ecf20Sopenharmony_ci	req.flags |= dev->hbm_f_ie_supported ?
3778c2ecf20Sopenharmony_ci			  MEI_HBM_ENUM_F_IMMEDIATE_ENUM : 0;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	ret = mei_hbm_write_message(dev, &mei_hdr, &req);
3808c2ecf20Sopenharmony_ci	if (ret) {
3818c2ecf20Sopenharmony_ci		dev_err(dev->dev, "enumeration request write failed: ret = %d.\n",
3828c2ecf20Sopenharmony_ci			ret);
3838c2ecf20Sopenharmony_ci		return ret;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci	dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
3868c2ecf20Sopenharmony_ci	dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
3878c2ecf20Sopenharmony_ci	mei_schedule_stall_timer(dev);
3888c2ecf20Sopenharmony_ci	return 0;
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci/**
3928c2ecf20Sopenharmony_ci * mei_hbm_me_cl_add - add new me client to the list
3938c2ecf20Sopenharmony_ci *
3948c2ecf20Sopenharmony_ci * @dev: the device structure
3958c2ecf20Sopenharmony_ci * @res: hbm property response
3968c2ecf20Sopenharmony_ci *
3978c2ecf20Sopenharmony_ci * Return: 0 on success and -ENOMEM on allocation failure
3988c2ecf20Sopenharmony_ci */
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic int mei_hbm_me_cl_add(struct mei_device *dev,
4018c2ecf20Sopenharmony_ci			     struct hbm_props_response *res)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	struct mei_me_client *me_cl;
4048c2ecf20Sopenharmony_ci	const uuid_le *uuid = &res->client_properties.protocol_name;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	mei_me_cl_rm_by_uuid(dev, uuid);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	me_cl = kzalloc(sizeof(*me_cl), GFP_KERNEL);
4098c2ecf20Sopenharmony_ci	if (!me_cl)
4108c2ecf20Sopenharmony_ci		return -ENOMEM;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	mei_me_cl_init(me_cl);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	me_cl->props = res->client_properties;
4158c2ecf20Sopenharmony_ci	me_cl->client_id = res->me_addr;
4168c2ecf20Sopenharmony_ci	me_cl->tx_flow_ctrl_creds = 0;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	mei_me_cl_add(dev, me_cl);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	return 0;
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci/**
4248c2ecf20Sopenharmony_ci * mei_hbm_add_cl_resp - send response to fw on client add request
4258c2ecf20Sopenharmony_ci *
4268c2ecf20Sopenharmony_ci * @dev: the device structure
4278c2ecf20Sopenharmony_ci * @addr: me address
4288c2ecf20Sopenharmony_ci * @status: response status
4298c2ecf20Sopenharmony_ci *
4308c2ecf20Sopenharmony_ci * Return: 0 on success and < 0 on failure
4318c2ecf20Sopenharmony_ci */
4328c2ecf20Sopenharmony_cistatic int mei_hbm_add_cl_resp(struct mei_device *dev, u8 addr, u8 status)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	struct mei_msg_hdr mei_hdr;
4358c2ecf20Sopenharmony_ci	struct hbm_add_client_response resp;
4368c2ecf20Sopenharmony_ci	int ret;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "adding client response\n");
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	mei_hbm_hdr(&mei_hdr, sizeof(resp));
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	memset(&resp, 0, sizeof(resp));
4438c2ecf20Sopenharmony_ci	resp.hbm_cmd = MEI_HBM_ADD_CLIENT_RES_CMD;
4448c2ecf20Sopenharmony_ci	resp.me_addr = addr;
4458c2ecf20Sopenharmony_ci	resp.status  = status;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	ret = mei_hbm_write_message(dev, &mei_hdr, &resp);
4488c2ecf20Sopenharmony_ci	if (ret)
4498c2ecf20Sopenharmony_ci		dev_err(dev->dev, "add client response write failed: ret = %d\n",
4508c2ecf20Sopenharmony_ci			ret);
4518c2ecf20Sopenharmony_ci	return ret;
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci/**
4558c2ecf20Sopenharmony_ci * mei_hbm_fw_add_cl_req - request from the fw to add a client
4568c2ecf20Sopenharmony_ci *
4578c2ecf20Sopenharmony_ci * @dev: the device structure
4588c2ecf20Sopenharmony_ci * @req: add client request
4598c2ecf20Sopenharmony_ci *
4608c2ecf20Sopenharmony_ci * Return: 0 on success and < 0 on failure
4618c2ecf20Sopenharmony_ci */
4628c2ecf20Sopenharmony_cistatic int mei_hbm_fw_add_cl_req(struct mei_device *dev,
4638c2ecf20Sopenharmony_ci			      struct hbm_add_client_request *req)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	int ret;
4668c2ecf20Sopenharmony_ci	u8 status = MEI_HBMS_SUCCESS;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct hbm_add_client_request) !=
4698c2ecf20Sopenharmony_ci			sizeof(struct hbm_props_response));
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	ret = mei_hbm_me_cl_add(dev, (struct hbm_props_response *)req);
4728c2ecf20Sopenharmony_ci	if (ret)
4738c2ecf20Sopenharmony_ci		status = !MEI_HBMS_SUCCESS;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	if (dev->dev_state == MEI_DEV_ENABLED)
4768c2ecf20Sopenharmony_ci		schedule_work(&dev->bus_rescan_work);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	return mei_hbm_add_cl_resp(dev, req->me_addr, status);
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci/**
4828c2ecf20Sopenharmony_ci * mei_hbm_cl_notify_req - send notification request
4838c2ecf20Sopenharmony_ci *
4848c2ecf20Sopenharmony_ci * @dev: the device structure
4858c2ecf20Sopenharmony_ci * @cl: a client to disconnect from
4868c2ecf20Sopenharmony_ci * @start: true for start false for stop
4878c2ecf20Sopenharmony_ci *
4888c2ecf20Sopenharmony_ci * Return: 0 on success and -EIO on write failure
4898c2ecf20Sopenharmony_ci */
4908c2ecf20Sopenharmony_ciint mei_hbm_cl_notify_req(struct mei_device *dev,
4918c2ecf20Sopenharmony_ci			  struct mei_cl *cl, u8 start)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	struct mei_msg_hdr mei_hdr;
4958c2ecf20Sopenharmony_ci	struct hbm_notification_request req;
4968c2ecf20Sopenharmony_ci	int ret;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	mei_hbm_hdr(&mei_hdr, sizeof(req));
4998c2ecf20Sopenharmony_ci	mei_hbm_cl_hdr(cl, MEI_HBM_NOTIFY_REQ_CMD, &req, sizeof(req));
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	req.start = start;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	ret = mei_hbm_write_message(dev, &mei_hdr, &req);
5048c2ecf20Sopenharmony_ci	if (ret)
5058c2ecf20Sopenharmony_ci		dev_err(dev->dev, "notify request failed: ret = %d\n", ret);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	return ret;
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci/**
5118c2ecf20Sopenharmony_ci *  notify_res_to_fop - convert notification response to the proper
5128c2ecf20Sopenharmony_ci *      notification FOP
5138c2ecf20Sopenharmony_ci *
5148c2ecf20Sopenharmony_ci * @cmd: client notification start response command
5158c2ecf20Sopenharmony_ci *
5168c2ecf20Sopenharmony_ci * Return:  MEI_FOP_NOTIFY_START or MEI_FOP_NOTIFY_STOP;
5178c2ecf20Sopenharmony_ci */
5188c2ecf20Sopenharmony_cistatic inline enum mei_cb_file_ops notify_res_to_fop(struct mei_hbm_cl_cmd *cmd)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	struct hbm_notification_response *rs =
5218c2ecf20Sopenharmony_ci		(struct hbm_notification_response *)cmd;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	return mei_cl_notify_req2fop(rs->start);
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci/**
5278c2ecf20Sopenharmony_ci * mei_hbm_cl_notify_start_res - update the client state according
5288c2ecf20Sopenharmony_ci *       notify start response
5298c2ecf20Sopenharmony_ci *
5308c2ecf20Sopenharmony_ci * @dev: the device structure
5318c2ecf20Sopenharmony_ci * @cl: mei host client
5328c2ecf20Sopenharmony_ci * @cmd: client notification start response command
5338c2ecf20Sopenharmony_ci */
5348c2ecf20Sopenharmony_cistatic void mei_hbm_cl_notify_start_res(struct mei_device *dev,
5358c2ecf20Sopenharmony_ci					struct mei_cl *cl,
5368c2ecf20Sopenharmony_ci					struct mei_hbm_cl_cmd *cmd)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	struct hbm_notification_response *rs =
5398c2ecf20Sopenharmony_ci		(struct hbm_notification_response *)cmd;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	cl_dbg(dev, cl, "hbm: notify start response status=%d\n", rs->status);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	if (rs->status == MEI_HBMS_SUCCESS ||
5448c2ecf20Sopenharmony_ci	    rs->status == MEI_HBMS_ALREADY_STARTED) {
5458c2ecf20Sopenharmony_ci		cl->notify_en = true;
5468c2ecf20Sopenharmony_ci		cl->status = 0;
5478c2ecf20Sopenharmony_ci	} else {
5488c2ecf20Sopenharmony_ci		cl->status = -EINVAL;
5498c2ecf20Sopenharmony_ci	}
5508c2ecf20Sopenharmony_ci}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci/**
5538c2ecf20Sopenharmony_ci * mei_hbm_cl_notify_stop_res - update the client state according
5548c2ecf20Sopenharmony_ci *       notify stop response
5558c2ecf20Sopenharmony_ci *
5568c2ecf20Sopenharmony_ci * @dev: the device structure
5578c2ecf20Sopenharmony_ci * @cl: mei host client
5588c2ecf20Sopenharmony_ci * @cmd: client notification stop response command
5598c2ecf20Sopenharmony_ci */
5608c2ecf20Sopenharmony_cistatic void mei_hbm_cl_notify_stop_res(struct mei_device *dev,
5618c2ecf20Sopenharmony_ci				       struct mei_cl *cl,
5628c2ecf20Sopenharmony_ci				       struct mei_hbm_cl_cmd *cmd)
5638c2ecf20Sopenharmony_ci{
5648c2ecf20Sopenharmony_ci	struct hbm_notification_response *rs =
5658c2ecf20Sopenharmony_ci		(struct hbm_notification_response *)cmd;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	cl_dbg(dev, cl, "hbm: notify stop response status=%d\n", rs->status);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	if (rs->status == MEI_HBMS_SUCCESS ||
5708c2ecf20Sopenharmony_ci	    rs->status == MEI_HBMS_NOT_STARTED) {
5718c2ecf20Sopenharmony_ci		cl->notify_en = false;
5728c2ecf20Sopenharmony_ci		cl->status = 0;
5738c2ecf20Sopenharmony_ci	} else {
5748c2ecf20Sopenharmony_ci		/* TODO: spec is not clear yet about other possible issues */
5758c2ecf20Sopenharmony_ci		cl->status = -EINVAL;
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci/**
5808c2ecf20Sopenharmony_ci * mei_hbm_cl_notify - signal notification event
5818c2ecf20Sopenharmony_ci *
5828c2ecf20Sopenharmony_ci * @dev: the device structure
5838c2ecf20Sopenharmony_ci * @cmd: notification client message
5848c2ecf20Sopenharmony_ci */
5858c2ecf20Sopenharmony_cistatic void mei_hbm_cl_notify(struct mei_device *dev,
5868c2ecf20Sopenharmony_ci			      struct mei_hbm_cl_cmd *cmd)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	struct mei_cl *cl;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	cl = mei_hbm_cl_find_by_cmd(dev, cmd);
5918c2ecf20Sopenharmony_ci	if (cl)
5928c2ecf20Sopenharmony_ci		mei_cl_notify(cl);
5938c2ecf20Sopenharmony_ci}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci/**
5968c2ecf20Sopenharmony_ci * mei_hbm_prop_req - request property for a single client
5978c2ecf20Sopenharmony_ci *
5988c2ecf20Sopenharmony_ci * @dev: the device structure
5998c2ecf20Sopenharmony_ci * @start_idx: client index to start search
6008c2ecf20Sopenharmony_ci *
6018c2ecf20Sopenharmony_ci * Return: 0 on success and < 0 on failure
6028c2ecf20Sopenharmony_ci */
6038c2ecf20Sopenharmony_cistatic int mei_hbm_prop_req(struct mei_device *dev, unsigned long start_idx)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	struct mei_msg_hdr mei_hdr;
6068c2ecf20Sopenharmony_ci	struct hbm_props_request req;
6078c2ecf20Sopenharmony_ci	unsigned long addr;
6088c2ecf20Sopenharmony_ci	int ret;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	addr = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, start_idx);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	/* We got all client properties */
6138c2ecf20Sopenharmony_ci	if (addr == MEI_CLIENTS_MAX) {
6148c2ecf20Sopenharmony_ci		dev->hbm_state = MEI_HBM_STARTED;
6158c2ecf20Sopenharmony_ci		mei_host_client_init(dev);
6168c2ecf20Sopenharmony_ci		return 0;
6178c2ecf20Sopenharmony_ci	}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	mei_hbm_hdr(&mei_hdr, sizeof(req));
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(req));
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	req.hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
6248c2ecf20Sopenharmony_ci	req.me_addr = addr;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	ret = mei_hbm_write_message(dev, &mei_hdr, &req);
6278c2ecf20Sopenharmony_ci	if (ret) {
6288c2ecf20Sopenharmony_ci		dev_err(dev->dev, "properties request write failed: ret = %d\n",
6298c2ecf20Sopenharmony_ci			ret);
6308c2ecf20Sopenharmony_ci		return ret;
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
6348c2ecf20Sopenharmony_ci	mei_schedule_stall_timer(dev);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	return 0;
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci/**
6408c2ecf20Sopenharmony_ci * mei_hbm_pg - sends pg command
6418c2ecf20Sopenharmony_ci *
6428c2ecf20Sopenharmony_ci * @dev: the device structure
6438c2ecf20Sopenharmony_ci * @pg_cmd: the pg command code
6448c2ecf20Sopenharmony_ci *
6458c2ecf20Sopenharmony_ci * Return: -EIO on write failure
6468c2ecf20Sopenharmony_ci *         -EOPNOTSUPP if the operation is not supported by the protocol
6478c2ecf20Sopenharmony_ci */
6488c2ecf20Sopenharmony_ciint mei_hbm_pg(struct mei_device *dev, u8 pg_cmd)
6498c2ecf20Sopenharmony_ci{
6508c2ecf20Sopenharmony_ci	struct mei_msg_hdr mei_hdr;
6518c2ecf20Sopenharmony_ci	struct hbm_power_gate req;
6528c2ecf20Sopenharmony_ci	int ret;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	if (!dev->hbm_f_pg_supported)
6558c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	mei_hbm_hdr(&mei_hdr, sizeof(req));
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(req));
6608c2ecf20Sopenharmony_ci	req.hbm_cmd = pg_cmd;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	ret = mei_hbm_write_message(dev, &mei_hdr, &req);
6638c2ecf20Sopenharmony_ci	if (ret)
6648c2ecf20Sopenharmony_ci		dev_err(dev->dev, "power gate command write failed.\n");
6658c2ecf20Sopenharmony_ci	return ret;
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mei_hbm_pg);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci/**
6708c2ecf20Sopenharmony_ci * mei_hbm_stop_req - send stop request message
6718c2ecf20Sopenharmony_ci *
6728c2ecf20Sopenharmony_ci * @dev: mei device
6738c2ecf20Sopenharmony_ci *
6748c2ecf20Sopenharmony_ci * Return: -EIO on write failure
6758c2ecf20Sopenharmony_ci */
6768c2ecf20Sopenharmony_cistatic int mei_hbm_stop_req(struct mei_device *dev)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	struct mei_msg_hdr mei_hdr;
6798c2ecf20Sopenharmony_ci	struct hbm_host_stop_request req;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	mei_hbm_hdr(&mei_hdr, sizeof(req));
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(req));
6848c2ecf20Sopenharmony_ci	req.hbm_cmd = HOST_STOP_REQ_CMD;
6858c2ecf20Sopenharmony_ci	req.reason = DRIVER_STOP_REQUEST;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	return mei_hbm_write_message(dev, &mei_hdr, &req);
6888c2ecf20Sopenharmony_ci}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci/**
6918c2ecf20Sopenharmony_ci * mei_hbm_cl_flow_control_req - sends flow control request.
6928c2ecf20Sopenharmony_ci *
6938c2ecf20Sopenharmony_ci * @dev: the device structure
6948c2ecf20Sopenharmony_ci * @cl: client info
6958c2ecf20Sopenharmony_ci *
6968c2ecf20Sopenharmony_ci * Return: -EIO on write failure
6978c2ecf20Sopenharmony_ci */
6988c2ecf20Sopenharmony_ciint mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	struct hbm_flow_control req;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	cl_dbg(dev, cl, "sending flow control\n");
7038c2ecf20Sopenharmony_ci	return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD,
7048c2ecf20Sopenharmony_ci				&req, sizeof(req));
7058c2ecf20Sopenharmony_ci}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci/**
7088c2ecf20Sopenharmony_ci * mei_hbm_add_single_tx_flow_ctrl_creds - adds single buffer credentials.
7098c2ecf20Sopenharmony_ci *
7108c2ecf20Sopenharmony_ci * @dev: the device structure
7118c2ecf20Sopenharmony_ci * @fctrl: flow control response bus message
7128c2ecf20Sopenharmony_ci *
7138c2ecf20Sopenharmony_ci * Return: 0 on success, < 0 otherwise
7148c2ecf20Sopenharmony_ci */
7158c2ecf20Sopenharmony_cistatic int mei_hbm_add_single_tx_flow_ctrl_creds(struct mei_device *dev,
7168c2ecf20Sopenharmony_ci						 struct hbm_flow_control *fctrl)
7178c2ecf20Sopenharmony_ci{
7188c2ecf20Sopenharmony_ci	struct mei_me_client *me_cl;
7198c2ecf20Sopenharmony_ci	int rets;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	me_cl = mei_me_cl_by_id(dev, fctrl->me_addr);
7228c2ecf20Sopenharmony_ci	if (!me_cl) {
7238c2ecf20Sopenharmony_ci		dev_err(dev->dev, "no such me client %d\n", fctrl->me_addr);
7248c2ecf20Sopenharmony_ci		return -ENOENT;
7258c2ecf20Sopenharmony_ci	}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	if (WARN_ON(me_cl->props.single_recv_buf == 0)) {
7288c2ecf20Sopenharmony_ci		rets = -EINVAL;
7298c2ecf20Sopenharmony_ci		goto out;
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	me_cl->tx_flow_ctrl_creds++;
7338c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n",
7348c2ecf20Sopenharmony_ci		fctrl->me_addr, me_cl->tx_flow_ctrl_creds);
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	rets = 0;
7378c2ecf20Sopenharmony_ciout:
7388c2ecf20Sopenharmony_ci	mei_me_cl_put(me_cl);
7398c2ecf20Sopenharmony_ci	return rets;
7408c2ecf20Sopenharmony_ci}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci/**
7438c2ecf20Sopenharmony_ci * mei_hbm_cl_flow_control_res - flow control response from me
7448c2ecf20Sopenharmony_ci *
7458c2ecf20Sopenharmony_ci * @dev: the device structure
7468c2ecf20Sopenharmony_ci * @fctrl: flow control response bus message
7478c2ecf20Sopenharmony_ci */
7488c2ecf20Sopenharmony_cistatic void mei_hbm_cl_tx_flow_ctrl_creds_res(struct mei_device *dev,
7498c2ecf20Sopenharmony_ci					       struct hbm_flow_control *fctrl)
7508c2ecf20Sopenharmony_ci{
7518c2ecf20Sopenharmony_ci	struct mei_cl *cl;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	if (!fctrl->host_addr) {
7548c2ecf20Sopenharmony_ci		/* single receive buffer */
7558c2ecf20Sopenharmony_ci		mei_hbm_add_single_tx_flow_ctrl_creds(dev, fctrl);
7568c2ecf20Sopenharmony_ci		return;
7578c2ecf20Sopenharmony_ci	}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	cl = mei_hbm_cl_find_by_cmd(dev, fctrl);
7608c2ecf20Sopenharmony_ci	if (cl) {
7618c2ecf20Sopenharmony_ci		cl->tx_flow_ctrl_creds++;
7628c2ecf20Sopenharmony_ci		cl_dbg(dev, cl, "flow control creds = %d.\n",
7638c2ecf20Sopenharmony_ci				cl->tx_flow_ctrl_creds);
7648c2ecf20Sopenharmony_ci	}
7658c2ecf20Sopenharmony_ci}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci/**
7698c2ecf20Sopenharmony_ci * mei_hbm_cl_disconnect_req - sends disconnect message to fw.
7708c2ecf20Sopenharmony_ci *
7718c2ecf20Sopenharmony_ci * @dev: the device structure
7728c2ecf20Sopenharmony_ci * @cl: a client to disconnect from
7738c2ecf20Sopenharmony_ci *
7748c2ecf20Sopenharmony_ci * Return: -EIO on write failure
7758c2ecf20Sopenharmony_ci */
7768c2ecf20Sopenharmony_ciint mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
7778c2ecf20Sopenharmony_ci{
7788c2ecf20Sopenharmony_ci	struct hbm_client_connect_request req;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD,
7818c2ecf20Sopenharmony_ci				&req, sizeof(req));
7828c2ecf20Sopenharmony_ci}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci/**
7858c2ecf20Sopenharmony_ci * mei_hbm_cl_disconnect_rsp - sends disconnect respose to the FW
7868c2ecf20Sopenharmony_ci *
7878c2ecf20Sopenharmony_ci * @dev: the device structure
7888c2ecf20Sopenharmony_ci * @cl: a client to disconnect from
7898c2ecf20Sopenharmony_ci *
7908c2ecf20Sopenharmony_ci * Return: -EIO on write failure
7918c2ecf20Sopenharmony_ci */
7928c2ecf20Sopenharmony_ciint mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl)
7938c2ecf20Sopenharmony_ci{
7948c2ecf20Sopenharmony_ci	struct hbm_client_connect_response resp;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD,
7978c2ecf20Sopenharmony_ci				&resp, sizeof(resp));
7988c2ecf20Sopenharmony_ci}
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci/**
8018c2ecf20Sopenharmony_ci * mei_hbm_cl_disconnect_res - update the client state according
8028c2ecf20Sopenharmony_ci *       disconnect response
8038c2ecf20Sopenharmony_ci *
8048c2ecf20Sopenharmony_ci * @dev: the device structure
8058c2ecf20Sopenharmony_ci * @cl: mei host client
8068c2ecf20Sopenharmony_ci * @cmd: disconnect client response host bus message
8078c2ecf20Sopenharmony_ci */
8088c2ecf20Sopenharmony_cistatic void mei_hbm_cl_disconnect_res(struct mei_device *dev, struct mei_cl *cl,
8098c2ecf20Sopenharmony_ci				      struct mei_hbm_cl_cmd *cmd)
8108c2ecf20Sopenharmony_ci{
8118c2ecf20Sopenharmony_ci	struct hbm_client_connect_response *rs =
8128c2ecf20Sopenharmony_ci		(struct hbm_client_connect_response *)cmd;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	cl_dbg(dev, cl, "hbm: disconnect response status=%d\n", rs->status);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	if (rs->status == MEI_CL_DISCONN_SUCCESS)
8178c2ecf20Sopenharmony_ci		cl->state = MEI_FILE_DISCONNECT_REPLY;
8188c2ecf20Sopenharmony_ci	cl->status = 0;
8198c2ecf20Sopenharmony_ci}
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci/**
8228c2ecf20Sopenharmony_ci * mei_hbm_cl_connect_req - send connection request to specific me client
8238c2ecf20Sopenharmony_ci *
8248c2ecf20Sopenharmony_ci * @dev: the device structure
8258c2ecf20Sopenharmony_ci * @cl: a client to connect to
8268c2ecf20Sopenharmony_ci *
8278c2ecf20Sopenharmony_ci * Return: -EIO on write failure
8288c2ecf20Sopenharmony_ci */
8298c2ecf20Sopenharmony_ciint mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
8308c2ecf20Sopenharmony_ci{
8318c2ecf20Sopenharmony_ci	struct hbm_client_connect_request req;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD,
8348c2ecf20Sopenharmony_ci				&req, sizeof(req));
8358c2ecf20Sopenharmony_ci}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci/**
8388c2ecf20Sopenharmony_ci * mei_hbm_cl_connect_res - update the client state according
8398c2ecf20Sopenharmony_ci *        connection response
8408c2ecf20Sopenharmony_ci *
8418c2ecf20Sopenharmony_ci * @dev: the device structure
8428c2ecf20Sopenharmony_ci * @cl: mei host client
8438c2ecf20Sopenharmony_ci * @cmd: connect client response host bus message
8448c2ecf20Sopenharmony_ci */
8458c2ecf20Sopenharmony_cistatic void mei_hbm_cl_connect_res(struct mei_device *dev, struct mei_cl *cl,
8468c2ecf20Sopenharmony_ci				   struct mei_hbm_cl_cmd *cmd)
8478c2ecf20Sopenharmony_ci{
8488c2ecf20Sopenharmony_ci	struct hbm_client_connect_response *rs =
8498c2ecf20Sopenharmony_ci		(struct hbm_client_connect_response *)cmd;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	cl_dbg(dev, cl, "hbm: connect response status=%s\n",
8528c2ecf20Sopenharmony_ci			mei_cl_conn_status_str(rs->status));
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	if (rs->status == MEI_CL_CONN_SUCCESS)
8558c2ecf20Sopenharmony_ci		cl->state = MEI_FILE_CONNECTED;
8568c2ecf20Sopenharmony_ci	else {
8578c2ecf20Sopenharmony_ci		cl->state = MEI_FILE_DISCONNECT_REPLY;
8588c2ecf20Sopenharmony_ci		if (rs->status == MEI_CL_CONN_NOT_FOUND) {
8598c2ecf20Sopenharmony_ci			mei_me_cl_del(dev, cl->me_cl);
8608c2ecf20Sopenharmony_ci			if (dev->dev_state == MEI_DEV_ENABLED)
8618c2ecf20Sopenharmony_ci				schedule_work(&dev->bus_rescan_work);
8628c2ecf20Sopenharmony_ci		}
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci	cl->status = mei_cl_conn_status_to_errno(rs->status);
8658c2ecf20Sopenharmony_ci}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci/**
8688c2ecf20Sopenharmony_ci * mei_hbm_cl_res - process hbm response received on behalf
8698c2ecf20Sopenharmony_ci *         an client
8708c2ecf20Sopenharmony_ci *
8718c2ecf20Sopenharmony_ci * @dev: the device structure
8728c2ecf20Sopenharmony_ci * @rs:  hbm client message
8738c2ecf20Sopenharmony_ci * @fop_type: file operation type
8748c2ecf20Sopenharmony_ci */
8758c2ecf20Sopenharmony_cistatic void mei_hbm_cl_res(struct mei_device *dev,
8768c2ecf20Sopenharmony_ci			   struct mei_hbm_cl_cmd *rs,
8778c2ecf20Sopenharmony_ci			   enum mei_cb_file_ops fop_type)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	struct mei_cl *cl;
8808c2ecf20Sopenharmony_ci	struct mei_cl_cb *cb, *next;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	cl = NULL;
8838c2ecf20Sopenharmony_ci	list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list, list) {
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci		cl = cb->cl;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci		if (cb->fop_type != fop_type)
8888c2ecf20Sopenharmony_ci			continue;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci		if (mei_hbm_cl_addr_equal(cl, rs)) {
8918c2ecf20Sopenharmony_ci			list_del_init(&cb->list);
8928c2ecf20Sopenharmony_ci			break;
8938c2ecf20Sopenharmony_ci		}
8948c2ecf20Sopenharmony_ci	}
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	if (!cl)
8978c2ecf20Sopenharmony_ci		return;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	switch (fop_type) {
9008c2ecf20Sopenharmony_ci	case MEI_FOP_CONNECT:
9018c2ecf20Sopenharmony_ci		mei_hbm_cl_connect_res(dev, cl, rs);
9028c2ecf20Sopenharmony_ci		break;
9038c2ecf20Sopenharmony_ci	case MEI_FOP_DISCONNECT:
9048c2ecf20Sopenharmony_ci		mei_hbm_cl_disconnect_res(dev, cl, rs);
9058c2ecf20Sopenharmony_ci		break;
9068c2ecf20Sopenharmony_ci	case MEI_FOP_NOTIFY_START:
9078c2ecf20Sopenharmony_ci		mei_hbm_cl_notify_start_res(dev, cl, rs);
9088c2ecf20Sopenharmony_ci		break;
9098c2ecf20Sopenharmony_ci	case MEI_FOP_NOTIFY_STOP:
9108c2ecf20Sopenharmony_ci		mei_hbm_cl_notify_stop_res(dev, cl, rs);
9118c2ecf20Sopenharmony_ci		break;
9128c2ecf20Sopenharmony_ci	default:
9138c2ecf20Sopenharmony_ci		return;
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	cl->timer_count = 0;
9178c2ecf20Sopenharmony_ci	wake_up(&cl->wait);
9188c2ecf20Sopenharmony_ci}
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci/**
9228c2ecf20Sopenharmony_ci * mei_hbm_fw_disconnect_req - disconnect request initiated by ME firmware
9238c2ecf20Sopenharmony_ci *  host sends disconnect response
9248c2ecf20Sopenharmony_ci *
9258c2ecf20Sopenharmony_ci * @dev: the device structure.
9268c2ecf20Sopenharmony_ci * @disconnect_req: disconnect request bus message from the me
9278c2ecf20Sopenharmony_ci *
9288c2ecf20Sopenharmony_ci * Return: -ENOMEM on allocation failure
9298c2ecf20Sopenharmony_ci */
9308c2ecf20Sopenharmony_cistatic int mei_hbm_fw_disconnect_req(struct mei_device *dev,
9318c2ecf20Sopenharmony_ci		struct hbm_client_connect_request *disconnect_req)
9328c2ecf20Sopenharmony_ci{
9338c2ecf20Sopenharmony_ci	struct mei_cl *cl;
9348c2ecf20Sopenharmony_ci	struct mei_cl_cb *cb;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	cl = mei_hbm_cl_find_by_cmd(dev, disconnect_req);
9378c2ecf20Sopenharmony_ci	if (cl) {
9388c2ecf20Sopenharmony_ci		cl_warn(dev, cl, "fw disconnect request received\n");
9398c2ecf20Sopenharmony_ci		cl->state = MEI_FILE_DISCONNECTING;
9408c2ecf20Sopenharmony_ci		cl->timer_count = 0;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci		cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_DISCONNECT_RSP,
9438c2ecf20Sopenharmony_ci					       NULL);
9448c2ecf20Sopenharmony_ci		if (!cb)
9458c2ecf20Sopenharmony_ci			return -ENOMEM;
9468c2ecf20Sopenharmony_ci	}
9478c2ecf20Sopenharmony_ci	return 0;
9488c2ecf20Sopenharmony_ci}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci/**
9518c2ecf20Sopenharmony_ci * mei_hbm_pg_enter_res - PG enter response received
9528c2ecf20Sopenharmony_ci *
9538c2ecf20Sopenharmony_ci * @dev: the device structure.
9548c2ecf20Sopenharmony_ci *
9558c2ecf20Sopenharmony_ci * Return: 0 on success, -EPROTO on state mismatch
9568c2ecf20Sopenharmony_ci */
9578c2ecf20Sopenharmony_cistatic int mei_hbm_pg_enter_res(struct mei_device *dev)
9588c2ecf20Sopenharmony_ci{
9598c2ecf20Sopenharmony_ci	if (mei_pg_state(dev) != MEI_PG_OFF ||
9608c2ecf20Sopenharmony_ci	    dev->pg_event != MEI_PG_EVENT_WAIT) {
9618c2ecf20Sopenharmony_ci		dev_err(dev->dev, "hbm: pg entry response: state mismatch [%s, %d]\n",
9628c2ecf20Sopenharmony_ci			mei_pg_state_str(mei_pg_state(dev)), dev->pg_event);
9638c2ecf20Sopenharmony_ci		return -EPROTO;
9648c2ecf20Sopenharmony_ci	}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	dev->pg_event = MEI_PG_EVENT_RECEIVED;
9678c2ecf20Sopenharmony_ci	wake_up(&dev->wait_pg);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	return 0;
9708c2ecf20Sopenharmony_ci}
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci/**
9738c2ecf20Sopenharmony_ci * mei_hbm_pg_resume - process with PG resume
9748c2ecf20Sopenharmony_ci *
9758c2ecf20Sopenharmony_ci * @dev: the device structure.
9768c2ecf20Sopenharmony_ci */
9778c2ecf20Sopenharmony_civoid mei_hbm_pg_resume(struct mei_device *dev)
9788c2ecf20Sopenharmony_ci{
9798c2ecf20Sopenharmony_ci	pm_request_resume(dev->dev);
9808c2ecf20Sopenharmony_ci}
9818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mei_hbm_pg_resume);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci/**
9848c2ecf20Sopenharmony_ci * mei_hbm_pg_exit_res - PG exit response received
9858c2ecf20Sopenharmony_ci *
9868c2ecf20Sopenharmony_ci * @dev: the device structure.
9878c2ecf20Sopenharmony_ci *
9888c2ecf20Sopenharmony_ci * Return: 0 on success, -EPROTO on state mismatch
9898c2ecf20Sopenharmony_ci */
9908c2ecf20Sopenharmony_cistatic int mei_hbm_pg_exit_res(struct mei_device *dev)
9918c2ecf20Sopenharmony_ci{
9928c2ecf20Sopenharmony_ci	if (mei_pg_state(dev) != MEI_PG_ON ||
9938c2ecf20Sopenharmony_ci	    (dev->pg_event != MEI_PG_EVENT_WAIT &&
9948c2ecf20Sopenharmony_ci	     dev->pg_event != MEI_PG_EVENT_IDLE)) {
9958c2ecf20Sopenharmony_ci		dev_err(dev->dev, "hbm: pg exit response: state mismatch [%s, %d]\n",
9968c2ecf20Sopenharmony_ci			mei_pg_state_str(mei_pg_state(dev)), dev->pg_event);
9978c2ecf20Sopenharmony_ci		return -EPROTO;
9988c2ecf20Sopenharmony_ci	}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	switch (dev->pg_event) {
10018c2ecf20Sopenharmony_ci	case MEI_PG_EVENT_WAIT:
10028c2ecf20Sopenharmony_ci		dev->pg_event = MEI_PG_EVENT_RECEIVED;
10038c2ecf20Sopenharmony_ci		wake_up(&dev->wait_pg);
10048c2ecf20Sopenharmony_ci		break;
10058c2ecf20Sopenharmony_ci	case MEI_PG_EVENT_IDLE:
10068c2ecf20Sopenharmony_ci		/*
10078c2ecf20Sopenharmony_ci		* If the driver is not waiting on this then
10088c2ecf20Sopenharmony_ci		* this is HW initiated exit from PG.
10098c2ecf20Sopenharmony_ci		* Start runtime pm resume sequence to exit from PG.
10108c2ecf20Sopenharmony_ci		*/
10118c2ecf20Sopenharmony_ci		dev->pg_event = MEI_PG_EVENT_RECEIVED;
10128c2ecf20Sopenharmony_ci		mei_hbm_pg_resume(dev);
10138c2ecf20Sopenharmony_ci		break;
10148c2ecf20Sopenharmony_ci	default:
10158c2ecf20Sopenharmony_ci		WARN(1, "hbm: pg exit response: unexpected pg event = %d\n",
10168c2ecf20Sopenharmony_ci		     dev->pg_event);
10178c2ecf20Sopenharmony_ci		return -EPROTO;
10188c2ecf20Sopenharmony_ci	}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	return 0;
10218c2ecf20Sopenharmony_ci}
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci/**
10248c2ecf20Sopenharmony_ci * mei_hbm_config_features - check what hbm features and commands
10258c2ecf20Sopenharmony_ci *        are supported by the fw
10268c2ecf20Sopenharmony_ci *
10278c2ecf20Sopenharmony_ci * @dev: the device structure
10288c2ecf20Sopenharmony_ci */
10298c2ecf20Sopenharmony_cistatic void mei_hbm_config_features(struct mei_device *dev)
10308c2ecf20Sopenharmony_ci{
10318c2ecf20Sopenharmony_ci	/* Power Gating Isolation Support */
10328c2ecf20Sopenharmony_ci	dev->hbm_f_pg_supported = 0;
10338c2ecf20Sopenharmony_ci	if (dev->version.major_version > HBM_MAJOR_VERSION_PGI)
10348c2ecf20Sopenharmony_ci		dev->hbm_f_pg_supported = 1;
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	if (dev->version.major_version == HBM_MAJOR_VERSION_PGI &&
10378c2ecf20Sopenharmony_ci	    dev->version.minor_version >= HBM_MINOR_VERSION_PGI)
10388c2ecf20Sopenharmony_ci		dev->hbm_f_pg_supported = 1;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	dev->hbm_f_dc_supported = 0;
10418c2ecf20Sopenharmony_ci	if (dev->version.major_version >= HBM_MAJOR_VERSION_DC)
10428c2ecf20Sopenharmony_ci		dev->hbm_f_dc_supported = 1;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	dev->hbm_f_ie_supported = 0;
10458c2ecf20Sopenharmony_ci	if (dev->version.major_version >= HBM_MAJOR_VERSION_IE)
10468c2ecf20Sopenharmony_ci		dev->hbm_f_ie_supported = 1;
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	/* disconnect on connect timeout instead of link reset */
10498c2ecf20Sopenharmony_ci	dev->hbm_f_dot_supported = 0;
10508c2ecf20Sopenharmony_ci	if (dev->version.major_version >= HBM_MAJOR_VERSION_DOT)
10518c2ecf20Sopenharmony_ci		dev->hbm_f_dot_supported = 1;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	/* Notification Event Support */
10548c2ecf20Sopenharmony_ci	dev->hbm_f_ev_supported = 0;
10558c2ecf20Sopenharmony_ci	if (dev->version.major_version >= HBM_MAJOR_VERSION_EV)
10568c2ecf20Sopenharmony_ci		dev->hbm_f_ev_supported = 1;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	/* Fixed Address Client Support */
10598c2ecf20Sopenharmony_ci	dev->hbm_f_fa_supported = 0;
10608c2ecf20Sopenharmony_ci	if (dev->version.major_version >= HBM_MAJOR_VERSION_FA)
10618c2ecf20Sopenharmony_ci		dev->hbm_f_fa_supported = 1;
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	/* OS ver message Support */
10648c2ecf20Sopenharmony_ci	dev->hbm_f_os_supported = 0;
10658c2ecf20Sopenharmony_ci	if (dev->version.major_version >= HBM_MAJOR_VERSION_OS)
10668c2ecf20Sopenharmony_ci		dev->hbm_f_os_supported = 1;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	/* DMA Ring Support */
10698c2ecf20Sopenharmony_ci	dev->hbm_f_dr_supported = 0;
10708c2ecf20Sopenharmony_ci	if (dev->version.major_version > HBM_MAJOR_VERSION_DR ||
10718c2ecf20Sopenharmony_ci	    (dev->version.major_version == HBM_MAJOR_VERSION_DR &&
10728c2ecf20Sopenharmony_ci	     dev->version.minor_version >= HBM_MINOR_VERSION_DR))
10738c2ecf20Sopenharmony_ci		dev->hbm_f_dr_supported = 1;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	/* VTag Support */
10768c2ecf20Sopenharmony_ci	dev->hbm_f_vt_supported = 0;
10778c2ecf20Sopenharmony_ci	if (dev->version.major_version > HBM_MAJOR_VERSION_VT ||
10788c2ecf20Sopenharmony_ci	    (dev->version.major_version == HBM_MAJOR_VERSION_VT &&
10798c2ecf20Sopenharmony_ci	     dev->version.minor_version >= HBM_MINOR_VERSION_VT))
10808c2ecf20Sopenharmony_ci		dev->hbm_f_vt_supported = 1;
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	/* Capability message Support */
10838c2ecf20Sopenharmony_ci	dev->hbm_f_cap_supported = 0;
10848c2ecf20Sopenharmony_ci	if (dev->version.major_version > HBM_MAJOR_VERSION_CAP ||
10858c2ecf20Sopenharmony_ci	    (dev->version.major_version == HBM_MAJOR_VERSION_CAP &&
10868c2ecf20Sopenharmony_ci	     dev->version.minor_version >= HBM_MINOR_VERSION_CAP))
10878c2ecf20Sopenharmony_ci		dev->hbm_f_cap_supported = 1;
10888c2ecf20Sopenharmony_ci}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci/**
10918c2ecf20Sopenharmony_ci * mei_hbm_version_is_supported - checks whether the driver can
10928c2ecf20Sopenharmony_ci *     support the hbm version of the device
10938c2ecf20Sopenharmony_ci *
10948c2ecf20Sopenharmony_ci * @dev: the device structure
10958c2ecf20Sopenharmony_ci * Return: true if driver can support hbm version of the device
10968c2ecf20Sopenharmony_ci */
10978c2ecf20Sopenharmony_cibool mei_hbm_version_is_supported(struct mei_device *dev)
10988c2ecf20Sopenharmony_ci{
10998c2ecf20Sopenharmony_ci	return	(dev->version.major_version < HBM_MAJOR_VERSION) ||
11008c2ecf20Sopenharmony_ci		(dev->version.major_version == HBM_MAJOR_VERSION &&
11018c2ecf20Sopenharmony_ci		 dev->version.minor_version <= HBM_MINOR_VERSION);
11028c2ecf20Sopenharmony_ci}
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci/**
11058c2ecf20Sopenharmony_ci * mei_hbm_dispatch - bottom half read routine after ISR to
11068c2ecf20Sopenharmony_ci * handle the read bus message cmd processing.
11078c2ecf20Sopenharmony_ci *
11088c2ecf20Sopenharmony_ci * @dev: the device structure
11098c2ecf20Sopenharmony_ci * @hdr: header of bus message
11108c2ecf20Sopenharmony_ci *
11118c2ecf20Sopenharmony_ci * Return: 0 on success and < 0 on failure
11128c2ecf20Sopenharmony_ci */
11138c2ecf20Sopenharmony_ciint mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
11148c2ecf20Sopenharmony_ci{
11158c2ecf20Sopenharmony_ci	struct mei_bus_message *mei_msg;
11168c2ecf20Sopenharmony_ci	struct hbm_host_version_response *version_res;
11178c2ecf20Sopenharmony_ci	struct hbm_props_response *props_res;
11188c2ecf20Sopenharmony_ci	struct hbm_host_enum_response *enum_res;
11198c2ecf20Sopenharmony_ci	struct hbm_dma_setup_response *dma_setup_res;
11208c2ecf20Sopenharmony_ci	struct hbm_add_client_request *add_cl_req;
11218c2ecf20Sopenharmony_ci	struct hbm_capability_response *capability_res;
11228c2ecf20Sopenharmony_ci	int ret;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	struct mei_hbm_cl_cmd *cl_cmd;
11258c2ecf20Sopenharmony_ci	struct hbm_client_connect_request *disconnect_req;
11268c2ecf20Sopenharmony_ci	struct hbm_flow_control *fctrl;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	/* read the message to our buffer */
11298c2ecf20Sopenharmony_ci	BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
11308c2ecf20Sopenharmony_ci	mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
11318c2ecf20Sopenharmony_ci	mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
11328c2ecf20Sopenharmony_ci	cl_cmd  = (struct mei_hbm_cl_cmd *)mei_msg;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	/* ignore spurious message and prevent reset nesting
11358c2ecf20Sopenharmony_ci	 * hbm is put to idle during system reset
11368c2ecf20Sopenharmony_ci	 */
11378c2ecf20Sopenharmony_ci	if (dev->hbm_state == MEI_HBM_IDLE) {
11388c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: state is idle ignore spurious messages\n");
11398c2ecf20Sopenharmony_ci		return 0;
11408c2ecf20Sopenharmony_ci	}
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	switch (mei_msg->hbm_cmd) {
11438c2ecf20Sopenharmony_ci	case HOST_START_RES_CMD:
11448c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: start: response message received.\n");
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci		dev->init_clients_timer = 0;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci		version_res = (struct hbm_host_version_response *)mei_msg;
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n",
11518c2ecf20Sopenharmony_ci				HBM_MAJOR_VERSION, HBM_MINOR_VERSION,
11528c2ecf20Sopenharmony_ci				version_res->me_max_version.major_version,
11538c2ecf20Sopenharmony_ci				version_res->me_max_version.minor_version);
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci		if (version_res->host_version_supported) {
11568c2ecf20Sopenharmony_ci			dev->version.major_version = HBM_MAJOR_VERSION;
11578c2ecf20Sopenharmony_ci			dev->version.minor_version = HBM_MINOR_VERSION;
11588c2ecf20Sopenharmony_ci		} else {
11598c2ecf20Sopenharmony_ci			dev->version.major_version =
11608c2ecf20Sopenharmony_ci				version_res->me_max_version.major_version;
11618c2ecf20Sopenharmony_ci			dev->version.minor_version =
11628c2ecf20Sopenharmony_ci				version_res->me_max_version.minor_version;
11638c2ecf20Sopenharmony_ci		}
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci		if (!mei_hbm_version_is_supported(dev)) {
11668c2ecf20Sopenharmony_ci			dev_warn(dev->dev, "hbm: start: version mismatch - stopping the driver.\n");
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci			dev->hbm_state = MEI_HBM_STOPPED;
11698c2ecf20Sopenharmony_ci			if (mei_hbm_stop_req(dev)) {
11708c2ecf20Sopenharmony_ci				dev_err(dev->dev, "hbm: start: failed to send stop request\n");
11718c2ecf20Sopenharmony_ci				return -EIO;
11728c2ecf20Sopenharmony_ci			}
11738c2ecf20Sopenharmony_ci			break;
11748c2ecf20Sopenharmony_ci		}
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci		mei_hbm_config_features(dev);
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci		if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
11798c2ecf20Sopenharmony_ci		    dev->hbm_state != MEI_HBM_STARTING) {
11808c2ecf20Sopenharmony_ci			dev_err(dev->dev, "hbm: start: state mismatch, [%d, %d]\n",
11818c2ecf20Sopenharmony_ci				dev->dev_state, dev->hbm_state);
11828c2ecf20Sopenharmony_ci			return -EPROTO;
11838c2ecf20Sopenharmony_ci		}
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci		if (dev->hbm_f_cap_supported) {
11868c2ecf20Sopenharmony_ci			if (mei_hbm_capabilities_req(dev))
11878c2ecf20Sopenharmony_ci				return -EIO;
11888c2ecf20Sopenharmony_ci			wake_up(&dev->wait_hbm_start);
11898c2ecf20Sopenharmony_ci			break;
11908c2ecf20Sopenharmony_ci		}
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci		if (dev->hbm_f_dr_supported) {
11938c2ecf20Sopenharmony_ci			if (mei_dmam_ring_alloc(dev))
11948c2ecf20Sopenharmony_ci				dev_info(dev->dev, "running w/o dma ring\n");
11958c2ecf20Sopenharmony_ci			if (mei_dma_ring_is_allocated(dev)) {
11968c2ecf20Sopenharmony_ci				if (mei_hbm_dma_setup_req(dev))
11978c2ecf20Sopenharmony_ci					return -EIO;
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci				wake_up(&dev->wait_hbm_start);
12008c2ecf20Sopenharmony_ci				break;
12018c2ecf20Sopenharmony_ci			}
12028c2ecf20Sopenharmony_ci		}
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci		dev->hbm_f_dr_supported = 0;
12058c2ecf20Sopenharmony_ci		mei_dmam_ring_free(dev);
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci		if (mei_hbm_enum_clients_req(dev))
12088c2ecf20Sopenharmony_ci			return -EIO;
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci		wake_up(&dev->wait_hbm_start);
12118c2ecf20Sopenharmony_ci		break;
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	case MEI_HBM_CAPABILITIES_RES_CMD:
12148c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: capabilities response: message received.\n");
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci		dev->init_clients_timer = 0;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci		if (dev->hbm_state != MEI_HBM_CAP_SETUP) {
12198c2ecf20Sopenharmony_ci			dev_err(dev->dev, "hbm: capabilities response: state mismatch, [%d, %d]\n",
12208c2ecf20Sopenharmony_ci				dev->dev_state, dev->hbm_state);
12218c2ecf20Sopenharmony_ci			return -EPROTO;
12228c2ecf20Sopenharmony_ci		}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci		capability_res = (struct hbm_capability_response *)mei_msg;
12258c2ecf20Sopenharmony_ci		if (!(capability_res->capability_granted[0] & HBM_CAP_VT))
12268c2ecf20Sopenharmony_ci			dev->hbm_f_vt_supported = 0;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci		if (dev->hbm_f_dr_supported) {
12298c2ecf20Sopenharmony_ci			if (mei_dmam_ring_alloc(dev))
12308c2ecf20Sopenharmony_ci				dev_info(dev->dev, "running w/o dma ring\n");
12318c2ecf20Sopenharmony_ci			if (mei_dma_ring_is_allocated(dev)) {
12328c2ecf20Sopenharmony_ci				if (mei_hbm_dma_setup_req(dev))
12338c2ecf20Sopenharmony_ci					return -EIO;
12348c2ecf20Sopenharmony_ci				break;
12358c2ecf20Sopenharmony_ci			}
12368c2ecf20Sopenharmony_ci		}
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci		dev->hbm_f_dr_supported = 0;
12398c2ecf20Sopenharmony_ci		mei_dmam_ring_free(dev);
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci		if (mei_hbm_enum_clients_req(dev))
12428c2ecf20Sopenharmony_ci			return -EIO;
12438c2ecf20Sopenharmony_ci		break;
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	case MEI_HBM_DMA_SETUP_RES_CMD:
12468c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: dma setup response: message received.\n");
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci		dev->init_clients_timer = 0;
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci		if (dev->hbm_state != MEI_HBM_DR_SETUP) {
12518c2ecf20Sopenharmony_ci			dev_err(dev->dev, "hbm: dma setup response: state mismatch, [%d, %d]\n",
12528c2ecf20Sopenharmony_ci				dev->dev_state, dev->hbm_state);
12538c2ecf20Sopenharmony_ci			return -EPROTO;
12548c2ecf20Sopenharmony_ci		}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci		dma_setup_res = (struct hbm_dma_setup_response *)mei_msg;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci		if (dma_setup_res->status) {
12598c2ecf20Sopenharmony_ci			u8 status = dma_setup_res->status;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci			if (status == MEI_HBMS_NOT_ALLOWED) {
12628c2ecf20Sopenharmony_ci				dev_dbg(dev->dev, "hbm: dma setup not allowed\n");
12638c2ecf20Sopenharmony_ci			} else {
12648c2ecf20Sopenharmony_ci				dev_info(dev->dev, "hbm: dma setup response: failure = %d %s\n",
12658c2ecf20Sopenharmony_ci					 status,
12668c2ecf20Sopenharmony_ci					 mei_hbm_status_str(status));
12678c2ecf20Sopenharmony_ci			}
12688c2ecf20Sopenharmony_ci			dev->hbm_f_dr_supported = 0;
12698c2ecf20Sopenharmony_ci			mei_dmam_ring_free(dev);
12708c2ecf20Sopenharmony_ci		}
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci		if (mei_hbm_enum_clients_req(dev))
12738c2ecf20Sopenharmony_ci			return -EIO;
12748c2ecf20Sopenharmony_ci		break;
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	case CLIENT_CONNECT_RES_CMD:
12778c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: client connect response: message received.\n");
12788c2ecf20Sopenharmony_ci		mei_hbm_cl_res(dev, cl_cmd, MEI_FOP_CONNECT);
12798c2ecf20Sopenharmony_ci		break;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	case CLIENT_DISCONNECT_RES_CMD:
12828c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: client disconnect response: message received.\n");
12838c2ecf20Sopenharmony_ci		mei_hbm_cl_res(dev, cl_cmd, MEI_FOP_DISCONNECT);
12848c2ecf20Sopenharmony_ci		break;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	case MEI_FLOW_CONTROL_CMD:
12878c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: client flow control response: message received.\n");
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci		fctrl = (struct hbm_flow_control *)mei_msg;
12908c2ecf20Sopenharmony_ci		mei_hbm_cl_tx_flow_ctrl_creds_res(dev, fctrl);
12918c2ecf20Sopenharmony_ci		break;
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	case MEI_PG_ISOLATION_ENTRY_RES_CMD:
12948c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: power gate isolation entry response received\n");
12958c2ecf20Sopenharmony_ci		ret = mei_hbm_pg_enter_res(dev);
12968c2ecf20Sopenharmony_ci		if (ret)
12978c2ecf20Sopenharmony_ci			return ret;
12988c2ecf20Sopenharmony_ci		break;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	case MEI_PG_ISOLATION_EXIT_REQ_CMD:
13018c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: power gate isolation exit request received\n");
13028c2ecf20Sopenharmony_ci		ret = mei_hbm_pg_exit_res(dev);
13038c2ecf20Sopenharmony_ci		if (ret)
13048c2ecf20Sopenharmony_ci			return ret;
13058c2ecf20Sopenharmony_ci		break;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	case HOST_CLIENT_PROPERTIES_RES_CMD:
13088c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: properties response: message received.\n");
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci		dev->init_clients_timer = 0;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci		if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
13138c2ecf20Sopenharmony_ci		    dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
13148c2ecf20Sopenharmony_ci			dev_err(dev->dev, "hbm: properties response: state mismatch, [%d, %d]\n",
13158c2ecf20Sopenharmony_ci				dev->dev_state, dev->hbm_state);
13168c2ecf20Sopenharmony_ci			return -EPROTO;
13178c2ecf20Sopenharmony_ci		}
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci		props_res = (struct hbm_props_response *)mei_msg;
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci		if (props_res->status == MEI_HBMS_CLIENT_NOT_FOUND) {
13228c2ecf20Sopenharmony_ci			dev_dbg(dev->dev, "hbm: properties response: %d CLIENT_NOT_FOUND\n",
13238c2ecf20Sopenharmony_ci				props_res->me_addr);
13248c2ecf20Sopenharmony_ci		} else if (props_res->status) {
13258c2ecf20Sopenharmony_ci			dev_err(dev->dev, "hbm: properties response: wrong status = %d %s\n",
13268c2ecf20Sopenharmony_ci				props_res->status,
13278c2ecf20Sopenharmony_ci				mei_hbm_status_str(props_res->status));
13288c2ecf20Sopenharmony_ci			return -EPROTO;
13298c2ecf20Sopenharmony_ci		} else {
13308c2ecf20Sopenharmony_ci			mei_hbm_me_cl_add(dev, props_res);
13318c2ecf20Sopenharmony_ci		}
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci		/* request property for the next client */
13348c2ecf20Sopenharmony_ci		if (mei_hbm_prop_req(dev, props_res->me_addr + 1))
13358c2ecf20Sopenharmony_ci			return -EIO;
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci		break;
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	case HOST_ENUM_RES_CMD:
13408c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: enumeration response: message received\n");
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci		dev->init_clients_timer = 0;
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci		enum_res = (struct hbm_host_enum_response *) mei_msg;
13458c2ecf20Sopenharmony_ci		BUILD_BUG_ON(sizeof(dev->me_clients_map)
13468c2ecf20Sopenharmony_ci				< sizeof(enum_res->valid_addresses));
13478c2ecf20Sopenharmony_ci		memcpy(dev->me_clients_map, enum_res->valid_addresses,
13488c2ecf20Sopenharmony_ci				sizeof(enum_res->valid_addresses));
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci		if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
13518c2ecf20Sopenharmony_ci		    dev->hbm_state != MEI_HBM_ENUM_CLIENTS) {
13528c2ecf20Sopenharmony_ci			dev_err(dev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n",
13538c2ecf20Sopenharmony_ci				dev->dev_state, dev->hbm_state);
13548c2ecf20Sopenharmony_ci			return -EPROTO;
13558c2ecf20Sopenharmony_ci		}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci		dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci		/* first property request */
13608c2ecf20Sopenharmony_ci		if (mei_hbm_prop_req(dev, 0))
13618c2ecf20Sopenharmony_ci			return -EIO;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci		break;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	case HOST_STOP_RES_CMD:
13668c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: stop response: message received\n");
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci		dev->init_clients_timer = 0;
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci		if (dev->hbm_state != MEI_HBM_STOPPED) {
13718c2ecf20Sopenharmony_ci			dev_err(dev->dev, "hbm: stop response: state mismatch, [%d, %d]\n",
13728c2ecf20Sopenharmony_ci				dev->dev_state, dev->hbm_state);
13738c2ecf20Sopenharmony_ci			return -EPROTO;
13748c2ecf20Sopenharmony_ci		}
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci		mei_set_devstate(dev, MEI_DEV_POWER_DOWN);
13778c2ecf20Sopenharmony_ci		dev_info(dev->dev, "hbm: stop response: resetting.\n");
13788c2ecf20Sopenharmony_ci		/* force the reset */
13798c2ecf20Sopenharmony_ci		return -EPROTO;
13808c2ecf20Sopenharmony_ci		break;
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	case CLIENT_DISCONNECT_REQ_CMD:
13838c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: disconnect request: message received\n");
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci		disconnect_req = (struct hbm_client_connect_request *)mei_msg;
13868c2ecf20Sopenharmony_ci		mei_hbm_fw_disconnect_req(dev, disconnect_req);
13878c2ecf20Sopenharmony_ci		break;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	case ME_STOP_REQ_CMD:
13908c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: stop request: message received\n");
13918c2ecf20Sopenharmony_ci		dev->hbm_state = MEI_HBM_STOPPED;
13928c2ecf20Sopenharmony_ci		if (mei_hbm_stop_req(dev)) {
13938c2ecf20Sopenharmony_ci			dev_err(dev->dev, "hbm: stop request: failed to send stop request\n");
13948c2ecf20Sopenharmony_ci			return -EIO;
13958c2ecf20Sopenharmony_ci		}
13968c2ecf20Sopenharmony_ci		break;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	case MEI_HBM_ADD_CLIENT_REQ_CMD:
13998c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: add client request received\n");
14008c2ecf20Sopenharmony_ci		/*
14018c2ecf20Sopenharmony_ci		 * after the host receives the enum_resp
14028c2ecf20Sopenharmony_ci		 * message clients may be added or removed
14038c2ecf20Sopenharmony_ci		 */
14048c2ecf20Sopenharmony_ci		if (dev->hbm_state <= MEI_HBM_ENUM_CLIENTS ||
14058c2ecf20Sopenharmony_ci		    dev->hbm_state >= MEI_HBM_STOPPED) {
14068c2ecf20Sopenharmony_ci			dev_err(dev->dev, "hbm: add client: state mismatch, [%d, %d]\n",
14078c2ecf20Sopenharmony_ci				dev->dev_state, dev->hbm_state);
14088c2ecf20Sopenharmony_ci			return -EPROTO;
14098c2ecf20Sopenharmony_ci		}
14108c2ecf20Sopenharmony_ci		add_cl_req = (struct hbm_add_client_request *)mei_msg;
14118c2ecf20Sopenharmony_ci		ret = mei_hbm_fw_add_cl_req(dev, add_cl_req);
14128c2ecf20Sopenharmony_ci		if (ret) {
14138c2ecf20Sopenharmony_ci			dev_err(dev->dev, "hbm: add client: failed to send response %d\n",
14148c2ecf20Sopenharmony_ci				ret);
14158c2ecf20Sopenharmony_ci			return -EIO;
14168c2ecf20Sopenharmony_ci		}
14178c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: add client request processed\n");
14188c2ecf20Sopenharmony_ci		break;
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	case MEI_HBM_NOTIFY_RES_CMD:
14218c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: notify response received\n");
14228c2ecf20Sopenharmony_ci		mei_hbm_cl_res(dev, cl_cmd, notify_res_to_fop(cl_cmd));
14238c2ecf20Sopenharmony_ci		break;
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	case MEI_HBM_NOTIFICATION_CMD:
14268c2ecf20Sopenharmony_ci		dev_dbg(dev->dev, "hbm: notification\n");
14278c2ecf20Sopenharmony_ci		mei_hbm_cl_notify(dev, cl_cmd);
14288c2ecf20Sopenharmony_ci		break;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	default:
14318c2ecf20Sopenharmony_ci		WARN(1, "hbm: wrong command %d\n", mei_msg->hbm_cmd);
14328c2ecf20Sopenharmony_ci		return -EPROTO;
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	}
14358c2ecf20Sopenharmony_ci	return 0;
14368c2ecf20Sopenharmony_ci}
14378c2ecf20Sopenharmony_ci
1438