18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * ISHTP bus layer messages handling
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2003-2016, Intel Corporation.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/export.h>
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci#include <linux/sched.h>
118c2ecf20Sopenharmony_ci#include <linux/wait.h>
128c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
138c2ecf20Sopenharmony_ci#include "ishtp-dev.h"
148c2ecf20Sopenharmony_ci#include "hbm.h"
158c2ecf20Sopenharmony_ci#include "client.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/**
188c2ecf20Sopenharmony_ci * ishtp_hbm_fw_cl_allocate() - Allocate FW clients
198c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * Allocates storage for fw clients
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_cistatic void ishtp_hbm_fw_cl_allocate(struct ishtp_device *dev)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	struct ishtp_fw_client *clients;
268c2ecf20Sopenharmony_ci	int b;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	/* count how many ISH clients we have */
298c2ecf20Sopenharmony_ci	for_each_set_bit(b, dev->fw_clients_map, ISHTP_CLIENTS_MAX)
308c2ecf20Sopenharmony_ci		dev->fw_clients_num++;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	if (dev->fw_clients_num <= 0)
338c2ecf20Sopenharmony_ci		return;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	/* allocate storage for fw clients representation */
368c2ecf20Sopenharmony_ci	clients = kcalloc(dev->fw_clients_num, sizeof(struct ishtp_fw_client),
378c2ecf20Sopenharmony_ci			  GFP_KERNEL);
388c2ecf20Sopenharmony_ci	if (!clients) {
398c2ecf20Sopenharmony_ci		dev->dev_state = ISHTP_DEV_RESETTING;
408c2ecf20Sopenharmony_ci		ish_hw_reset(dev);
418c2ecf20Sopenharmony_ci		return;
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci	dev->fw_clients = clients;
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/**
478c2ecf20Sopenharmony_ci * ishtp_hbm_cl_hdr() - construct client hbm header
488c2ecf20Sopenharmony_ci * @cl: client
498c2ecf20Sopenharmony_ci * @hbm_cmd: host bus message command
508c2ecf20Sopenharmony_ci * @buf: buffer for cl header
518c2ecf20Sopenharmony_ci * @len: buffer length
528c2ecf20Sopenharmony_ci *
538c2ecf20Sopenharmony_ci * Initialize HBM buffer
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_cistatic inline void ishtp_hbm_cl_hdr(struct ishtp_cl *cl, uint8_t hbm_cmd,
568c2ecf20Sopenharmony_ci	void *buf, size_t len)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	struct ishtp_hbm_cl_cmd *cmd = buf;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	memset(cmd, 0, len);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	cmd->hbm_cmd = hbm_cmd;
638c2ecf20Sopenharmony_ci	cmd->host_addr = cl->host_client_id;
648c2ecf20Sopenharmony_ci	cmd->fw_addr = cl->fw_client_id;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci/**
688c2ecf20Sopenharmony_ci * ishtp_hbm_cl_addr_equal() - Compare client address
698c2ecf20Sopenharmony_ci * @cl: client
708c2ecf20Sopenharmony_ci * @buf: Client command buffer
718c2ecf20Sopenharmony_ci *
728c2ecf20Sopenharmony_ci * Compare client address with the address in command buffer
738c2ecf20Sopenharmony_ci *
748c2ecf20Sopenharmony_ci * Return: True if they have the same address
758c2ecf20Sopenharmony_ci */
768c2ecf20Sopenharmony_cistatic inline bool ishtp_hbm_cl_addr_equal(struct ishtp_cl *cl, void *buf)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct ishtp_hbm_cl_cmd *cmd = buf;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return cl->host_client_id == cmd->host_addr &&
818c2ecf20Sopenharmony_ci		cl->fw_client_id == cmd->fw_addr;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci/**
858c2ecf20Sopenharmony_ci * ishtp_hbm_start_wait() - Wait for HBM start message
868c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
878c2ecf20Sopenharmony_ci *
888c2ecf20Sopenharmony_ci * Wait for HBM start message from firmware
898c2ecf20Sopenharmony_ci *
908c2ecf20Sopenharmony_ci * Return: 0 if HBM start is/was received else timeout error
918c2ecf20Sopenharmony_ci */
928c2ecf20Sopenharmony_ciint ishtp_hbm_start_wait(struct ishtp_device *dev)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	int ret;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (dev->hbm_state > ISHTP_HBM_START)
978c2ecf20Sopenharmony_ci		return 0;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	dev_dbg(dev->devc, "Going to wait for ishtp start. hbm_state=%08X\n",
1008c2ecf20Sopenharmony_ci		dev->hbm_state);
1018c2ecf20Sopenharmony_ci	ret = wait_event_interruptible_timeout(dev->wait_hbm_recvd_msg,
1028c2ecf20Sopenharmony_ci					dev->hbm_state >= ISHTP_HBM_STARTED,
1038c2ecf20Sopenharmony_ci					(ISHTP_INTEROP_TIMEOUT * HZ));
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	dev_dbg(dev->devc,
1068c2ecf20Sopenharmony_ci		"Woke up from waiting for ishtp start. hbm_state=%08X\n",
1078c2ecf20Sopenharmony_ci		dev->hbm_state);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (ret <= 0 && (dev->hbm_state <= ISHTP_HBM_START)) {
1108c2ecf20Sopenharmony_ci		dev->hbm_state = ISHTP_HBM_IDLE;
1118c2ecf20Sopenharmony_ci		dev_err(dev->devc,
1128c2ecf20Sopenharmony_ci		"waiting for ishtp start failed. ret=%d hbm_state=%08X\n",
1138c2ecf20Sopenharmony_ci			ret, dev->hbm_state);
1148c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci	return 0;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci/**
1208c2ecf20Sopenharmony_ci * ishtp_hbm_start_req() - Send HBM start message
1218c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
1228c2ecf20Sopenharmony_ci *
1238c2ecf20Sopenharmony_ci * Send HBM start message to firmware
1248c2ecf20Sopenharmony_ci *
1258c2ecf20Sopenharmony_ci * Return: 0 if success else error code
1268c2ecf20Sopenharmony_ci */
1278c2ecf20Sopenharmony_ciint ishtp_hbm_start_req(struct ishtp_device *dev)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr hdr;
1308c2ecf20Sopenharmony_ci	struct hbm_host_version_request start_req = { 0 };
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	ishtp_hbm_hdr(&hdr, sizeof(start_req));
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	/* host start message */
1358c2ecf20Sopenharmony_ci	start_req.hbm_cmd = HOST_START_REQ_CMD;
1368c2ecf20Sopenharmony_ci	start_req.host_version.major_version = HBM_MAJOR_VERSION;
1378c2ecf20Sopenharmony_ci	start_req.host_version.minor_version = HBM_MINOR_VERSION;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	/*
1408c2ecf20Sopenharmony_ci	 * (!) Response to HBM start may be so quick that this thread would get
1418c2ecf20Sopenharmony_ci	 * preempted BEFORE managing to set hbm_state = ISHTP_HBM_START.
1428c2ecf20Sopenharmony_ci	 * So set it at first, change back to ISHTP_HBM_IDLE upon failure
1438c2ecf20Sopenharmony_ci	 */
1448c2ecf20Sopenharmony_ci	dev->hbm_state = ISHTP_HBM_START;
1458c2ecf20Sopenharmony_ci	if (ishtp_write_message(dev, &hdr, &start_req)) {
1468c2ecf20Sopenharmony_ci		dev_err(dev->devc, "version message send failed\n");
1478c2ecf20Sopenharmony_ci		dev->dev_state = ISHTP_DEV_RESETTING;
1488c2ecf20Sopenharmony_ci		dev->hbm_state = ISHTP_HBM_IDLE;
1498c2ecf20Sopenharmony_ci		ish_hw_reset(dev);
1508c2ecf20Sopenharmony_ci		return -ENODEV;
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	return 0;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci/**
1578c2ecf20Sopenharmony_ci * ishtp_hbm_enum_clients_req() - Send client enum req
1588c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
1598c2ecf20Sopenharmony_ci *
1608c2ecf20Sopenharmony_ci * Send enumeration client request message
1618c2ecf20Sopenharmony_ci *
1628c2ecf20Sopenharmony_ci * Return: 0 if success else error code
1638c2ecf20Sopenharmony_ci */
1648c2ecf20Sopenharmony_civoid ishtp_hbm_enum_clients_req(struct ishtp_device *dev)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr hdr;
1678c2ecf20Sopenharmony_ci	struct hbm_host_enum_request enum_req = { 0 };
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	/* enumerate clients */
1708c2ecf20Sopenharmony_ci	ishtp_hbm_hdr(&hdr, sizeof(enum_req));
1718c2ecf20Sopenharmony_ci	enum_req.hbm_cmd = HOST_ENUM_REQ_CMD;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	if (ishtp_write_message(dev, &hdr, &enum_req)) {
1748c2ecf20Sopenharmony_ci		dev->dev_state = ISHTP_DEV_RESETTING;
1758c2ecf20Sopenharmony_ci		dev_err(dev->devc, "enumeration request send failed\n");
1768c2ecf20Sopenharmony_ci		ish_hw_reset(dev);
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci	dev->hbm_state = ISHTP_HBM_ENUM_CLIENTS;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci/**
1828c2ecf20Sopenharmony_ci * ishtp_hbm_prop_req() - Request property
1838c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
1848c2ecf20Sopenharmony_ci *
1858c2ecf20Sopenharmony_ci * Request property for a single client
1868c2ecf20Sopenharmony_ci *
1878c2ecf20Sopenharmony_ci * Return: 0 if success else error code
1888c2ecf20Sopenharmony_ci */
1898c2ecf20Sopenharmony_cistatic int ishtp_hbm_prop_req(struct ishtp_device *dev)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr hdr;
1928c2ecf20Sopenharmony_ci	struct hbm_props_request prop_req = { 0 };
1938c2ecf20Sopenharmony_ci	unsigned long next_client_index;
1948c2ecf20Sopenharmony_ci	uint8_t client_num;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	client_num = dev->fw_client_presentation_num;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	next_client_index = find_next_bit(dev->fw_clients_map,
1998c2ecf20Sopenharmony_ci		ISHTP_CLIENTS_MAX, dev->fw_client_index);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	/* We got all client properties */
2028c2ecf20Sopenharmony_ci	if (next_client_index == ISHTP_CLIENTS_MAX) {
2038c2ecf20Sopenharmony_ci		dev->hbm_state = ISHTP_HBM_WORKING;
2048c2ecf20Sopenharmony_ci		dev->dev_state = ISHTP_DEV_ENABLED;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci		for (dev->fw_client_presentation_num = 1;
2078c2ecf20Sopenharmony_ci			dev->fw_client_presentation_num < client_num + 1;
2088c2ecf20Sopenharmony_ci				++dev->fw_client_presentation_num)
2098c2ecf20Sopenharmony_ci			/* Add new client device */
2108c2ecf20Sopenharmony_ci			ishtp_bus_new_client(dev);
2118c2ecf20Sopenharmony_ci		return 0;
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	dev->fw_clients[client_num].client_id = next_client_index;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	ishtp_hbm_hdr(&hdr, sizeof(prop_req));
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	prop_req.hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
2198c2ecf20Sopenharmony_ci	prop_req.address = next_client_index;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (ishtp_write_message(dev, &hdr, &prop_req)) {
2228c2ecf20Sopenharmony_ci		dev->dev_state = ISHTP_DEV_RESETTING;
2238c2ecf20Sopenharmony_ci		dev_err(dev->devc, "properties request send failed\n");
2248c2ecf20Sopenharmony_ci		ish_hw_reset(dev);
2258c2ecf20Sopenharmony_ci		return -EIO;
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	dev->fw_client_index = next_client_index;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	return 0;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/**
2348c2ecf20Sopenharmony_ci * ishtp_hbm_stop_req() - Send HBM stop
2358c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
2368c2ecf20Sopenharmony_ci *
2378c2ecf20Sopenharmony_ci * Send stop request message
2388c2ecf20Sopenharmony_ci */
2398c2ecf20Sopenharmony_cistatic void ishtp_hbm_stop_req(struct ishtp_device *dev)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr hdr;
2428c2ecf20Sopenharmony_ci	struct hbm_host_stop_request stop_req = { 0 } ;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	ishtp_hbm_hdr(&hdr, sizeof(stop_req));
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	stop_req.hbm_cmd = HOST_STOP_REQ_CMD;
2478c2ecf20Sopenharmony_ci	stop_req.reason = DRIVER_STOP_REQUEST;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	ishtp_write_message(dev, &hdr, &stop_req);
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci/**
2538c2ecf20Sopenharmony_ci * ishtp_hbm_cl_flow_control_req() - Send flow control request
2548c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
2558c2ecf20Sopenharmony_ci * @cl: ISHTP client instance
2568c2ecf20Sopenharmony_ci *
2578c2ecf20Sopenharmony_ci * Send flow control request
2588c2ecf20Sopenharmony_ci *
2598c2ecf20Sopenharmony_ci * Return: 0 if success else error code
2608c2ecf20Sopenharmony_ci */
2618c2ecf20Sopenharmony_ciint ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev,
2628c2ecf20Sopenharmony_ci				  struct ishtp_cl *cl)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr hdr;
2658c2ecf20Sopenharmony_ci	struct hbm_flow_control flow_ctrl;
2668c2ecf20Sopenharmony_ci	const size_t len = sizeof(flow_ctrl);
2678c2ecf20Sopenharmony_ci	int	rv;
2688c2ecf20Sopenharmony_ci	unsigned long	flags;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	spin_lock_irqsave(&cl->fc_spinlock, flags);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	ishtp_hbm_hdr(&hdr, len);
2738c2ecf20Sopenharmony_ci	ishtp_hbm_cl_hdr(cl, ISHTP_FLOW_CONTROL_CMD, &flow_ctrl, len);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/*
2768c2ecf20Sopenharmony_ci	 * Sync possible race when RB recycle and packet receive paths
2778c2ecf20Sopenharmony_ci	 * both try to send an out FC
2788c2ecf20Sopenharmony_ci	 */
2798c2ecf20Sopenharmony_ci	if (cl->out_flow_ctrl_creds) {
2808c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&cl->fc_spinlock, flags);
2818c2ecf20Sopenharmony_ci		return	0;
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	cl->recv_msg_num_frags = 0;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	rv = ishtp_write_message(dev, &hdr, &flow_ctrl);
2878c2ecf20Sopenharmony_ci	if (!rv) {
2888c2ecf20Sopenharmony_ci		++cl->out_flow_ctrl_creds;
2898c2ecf20Sopenharmony_ci		++cl->out_flow_ctrl_cnt;
2908c2ecf20Sopenharmony_ci		cl->ts_out_fc = ktime_get();
2918c2ecf20Sopenharmony_ci		if (cl->ts_rx) {
2928c2ecf20Sopenharmony_ci			ktime_t ts_diff = ktime_sub(cl->ts_out_fc, cl->ts_rx);
2938c2ecf20Sopenharmony_ci			if (ktime_after(ts_diff, cl->ts_max_fc_delay))
2948c2ecf20Sopenharmony_ci				cl->ts_max_fc_delay = ts_diff;
2958c2ecf20Sopenharmony_ci		}
2968c2ecf20Sopenharmony_ci	} else {
2978c2ecf20Sopenharmony_ci		++cl->err_send_fc;
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&cl->fc_spinlock, flags);
3018c2ecf20Sopenharmony_ci	return	rv;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci/**
3058c2ecf20Sopenharmony_ci * ishtp_hbm_cl_disconnect_req() - Send disconnect request
3068c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
3078c2ecf20Sopenharmony_ci * @cl: ISHTP client instance
3088c2ecf20Sopenharmony_ci *
3098c2ecf20Sopenharmony_ci * Send disconnect message to fw
3108c2ecf20Sopenharmony_ci *
3118c2ecf20Sopenharmony_ci * Return: 0 if success else error code
3128c2ecf20Sopenharmony_ci */
3138c2ecf20Sopenharmony_ciint ishtp_hbm_cl_disconnect_req(struct ishtp_device *dev, struct ishtp_cl *cl)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr hdr;
3168c2ecf20Sopenharmony_ci	struct hbm_client_connect_request disconn_req;
3178c2ecf20Sopenharmony_ci	const size_t len = sizeof(disconn_req);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	ishtp_hbm_hdr(&hdr, len);
3208c2ecf20Sopenharmony_ci	ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, &disconn_req, len);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	return ishtp_write_message(dev, &hdr, &disconn_req);
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci/**
3268c2ecf20Sopenharmony_ci * ishtp_hbm_cl_disconnect_res() - Get disconnect response
3278c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
3288c2ecf20Sopenharmony_ci * @rs: Response message
3298c2ecf20Sopenharmony_ci *
3308c2ecf20Sopenharmony_ci * Received disconnect response from fw
3318c2ecf20Sopenharmony_ci */
3328c2ecf20Sopenharmony_cistatic void ishtp_hbm_cl_disconnect_res(struct ishtp_device *dev,
3338c2ecf20Sopenharmony_ci	struct hbm_client_connect_response *rs)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	struct ishtp_cl *cl = NULL;
3368c2ecf20Sopenharmony_ci	unsigned long	flags;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->cl_list_lock, flags);
3398c2ecf20Sopenharmony_ci	list_for_each_entry(cl, &dev->cl_list, link) {
3408c2ecf20Sopenharmony_ci		if (!rs->status && ishtp_hbm_cl_addr_equal(cl, rs)) {
3418c2ecf20Sopenharmony_ci			cl->state = ISHTP_CL_DISCONNECTED;
3428c2ecf20Sopenharmony_ci			wake_up_interruptible(&cl->wait_ctrl_res);
3438c2ecf20Sopenharmony_ci			break;
3448c2ecf20Sopenharmony_ci		}
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->cl_list_lock, flags);
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci/**
3508c2ecf20Sopenharmony_ci * ishtp_hbm_cl_connect_req() - Send connect request
3518c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
3528c2ecf20Sopenharmony_ci * @cl: client device instance
3538c2ecf20Sopenharmony_ci *
3548c2ecf20Sopenharmony_ci * Send connection request to specific fw client
3558c2ecf20Sopenharmony_ci *
3568c2ecf20Sopenharmony_ci * Return: 0 if success else error code
3578c2ecf20Sopenharmony_ci */
3588c2ecf20Sopenharmony_ciint ishtp_hbm_cl_connect_req(struct ishtp_device *dev, struct ishtp_cl *cl)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr hdr;
3618c2ecf20Sopenharmony_ci	struct hbm_client_connect_request conn_req;
3628c2ecf20Sopenharmony_ci	const size_t len = sizeof(conn_req);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	ishtp_hbm_hdr(&hdr, len);
3658c2ecf20Sopenharmony_ci	ishtp_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, &conn_req, len);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	return ishtp_write_message(dev, &hdr, &conn_req);
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci/**
3718c2ecf20Sopenharmony_ci * ishtp_hbm_cl_connect_res() - Get connect response
3728c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
3738c2ecf20Sopenharmony_ci * @rs: Response message
3748c2ecf20Sopenharmony_ci *
3758c2ecf20Sopenharmony_ci * Received connect response from fw
3768c2ecf20Sopenharmony_ci */
3778c2ecf20Sopenharmony_cistatic void ishtp_hbm_cl_connect_res(struct ishtp_device *dev,
3788c2ecf20Sopenharmony_ci	struct hbm_client_connect_response *rs)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct ishtp_cl *cl = NULL;
3818c2ecf20Sopenharmony_ci	unsigned long	flags;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->cl_list_lock, flags);
3848c2ecf20Sopenharmony_ci	list_for_each_entry(cl, &dev->cl_list, link) {
3858c2ecf20Sopenharmony_ci		if (ishtp_hbm_cl_addr_equal(cl, rs)) {
3868c2ecf20Sopenharmony_ci			if (!rs->status) {
3878c2ecf20Sopenharmony_ci				cl->state = ISHTP_CL_CONNECTED;
3888c2ecf20Sopenharmony_ci				cl->status = 0;
3898c2ecf20Sopenharmony_ci			} else {
3908c2ecf20Sopenharmony_ci				cl->state = ISHTP_CL_DISCONNECTED;
3918c2ecf20Sopenharmony_ci				cl->status = -ENODEV;
3928c2ecf20Sopenharmony_ci			}
3938c2ecf20Sopenharmony_ci			wake_up_interruptible(&cl->wait_ctrl_res);
3948c2ecf20Sopenharmony_ci			break;
3958c2ecf20Sopenharmony_ci		}
3968c2ecf20Sopenharmony_ci	}
3978c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->cl_list_lock, flags);
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci/**
4018c2ecf20Sopenharmony_ci * ishtp_client_disconnect_request() - Receive disconnect request
4028c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
4038c2ecf20Sopenharmony_ci * @disconnect_req: disconnect request structure
4048c2ecf20Sopenharmony_ci *
4058c2ecf20Sopenharmony_ci * Disconnect request bus message from the fw. Send disconnect response.
4068c2ecf20Sopenharmony_ci */
4078c2ecf20Sopenharmony_cistatic void ishtp_hbm_fw_disconnect_req(struct ishtp_device *dev,
4088c2ecf20Sopenharmony_ci	struct hbm_client_connect_request *disconnect_req)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct ishtp_cl *cl;
4118c2ecf20Sopenharmony_ci	const size_t len = sizeof(struct hbm_client_connect_response);
4128c2ecf20Sopenharmony_ci	unsigned long	flags;
4138c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr hdr;
4148c2ecf20Sopenharmony_ci	unsigned char data[4];	/* All HBM messages are 4 bytes */
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->cl_list_lock, flags);
4178c2ecf20Sopenharmony_ci	list_for_each_entry(cl, &dev->cl_list, link) {
4188c2ecf20Sopenharmony_ci		if (ishtp_hbm_cl_addr_equal(cl, disconnect_req)) {
4198c2ecf20Sopenharmony_ci			cl->state = ISHTP_CL_DISCONNECTED;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci			/* send disconnect response */
4228c2ecf20Sopenharmony_ci			ishtp_hbm_hdr(&hdr, len);
4238c2ecf20Sopenharmony_ci			ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD, data,
4248c2ecf20Sopenharmony_ci				len);
4258c2ecf20Sopenharmony_ci			ishtp_write_message(dev, &hdr, data);
4268c2ecf20Sopenharmony_ci			break;
4278c2ecf20Sopenharmony_ci		}
4288c2ecf20Sopenharmony_ci	}
4298c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->cl_list_lock, flags);
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci/**
4338c2ecf20Sopenharmony_ci * ishtp_hbm_dma_xfer_ack(() - Receive transfer ACK
4348c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
4358c2ecf20Sopenharmony_ci * @dma_xfer: HBM transfer message
4368c2ecf20Sopenharmony_ci *
4378c2ecf20Sopenharmony_ci * Receive ack for ISHTP-over-DMA client message
4388c2ecf20Sopenharmony_ci */
4398c2ecf20Sopenharmony_cistatic void ishtp_hbm_dma_xfer_ack(struct ishtp_device *dev,
4408c2ecf20Sopenharmony_ci				   struct dma_xfer_hbm *dma_xfer)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	void	*msg;
4438c2ecf20Sopenharmony_ci	uint64_t	offs;
4448c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr	*ishtp_hdr =
4458c2ecf20Sopenharmony_ci		(struct ishtp_msg_hdr *)&dev->ishtp_msg_hdr;
4468c2ecf20Sopenharmony_ci	unsigned int	msg_offs;
4478c2ecf20Sopenharmony_ci	struct ishtp_cl *cl;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	for (msg_offs = 0; msg_offs < ishtp_hdr->length;
4508c2ecf20Sopenharmony_ci		msg_offs += sizeof(struct dma_xfer_hbm)) {
4518c2ecf20Sopenharmony_ci		offs = dma_xfer->msg_addr - dev->ishtp_host_dma_tx_buf_phys;
4528c2ecf20Sopenharmony_ci		if (offs > dev->ishtp_host_dma_tx_buf_size) {
4538c2ecf20Sopenharmony_ci			dev_err(dev->devc, "Bad DMA Tx ack message address\n");
4548c2ecf20Sopenharmony_ci			return;
4558c2ecf20Sopenharmony_ci		}
4568c2ecf20Sopenharmony_ci		if (dma_xfer->msg_length >
4578c2ecf20Sopenharmony_ci				dev->ishtp_host_dma_tx_buf_size - offs) {
4588c2ecf20Sopenharmony_ci			dev_err(dev->devc, "Bad DMA Tx ack message size\n");
4598c2ecf20Sopenharmony_ci			return;
4608c2ecf20Sopenharmony_ci		}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci		/* logical address of the acked mem */
4638c2ecf20Sopenharmony_ci		msg = (unsigned char *)dev->ishtp_host_dma_tx_buf + offs;
4648c2ecf20Sopenharmony_ci		ishtp_cl_release_dma_acked_mem(dev, msg, dma_xfer->msg_length);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci		list_for_each_entry(cl, &dev->cl_list, link) {
4678c2ecf20Sopenharmony_ci			if (cl->fw_client_id == dma_xfer->fw_client_id &&
4688c2ecf20Sopenharmony_ci			    cl->host_client_id == dma_xfer->host_client_id)
4698c2ecf20Sopenharmony_ci				/*
4708c2ecf20Sopenharmony_ci				 * in case that a single ack may be sent
4718c2ecf20Sopenharmony_ci				 * over several dma transfers, and the last msg
4728c2ecf20Sopenharmony_ci				 * addr was inside the acked memory, but not in
4738c2ecf20Sopenharmony_ci				 * its start
4748c2ecf20Sopenharmony_ci				 */
4758c2ecf20Sopenharmony_ci				if (cl->last_dma_addr >=
4768c2ecf20Sopenharmony_ci							(unsigned char *)msg &&
4778c2ecf20Sopenharmony_ci						cl->last_dma_addr <
4788c2ecf20Sopenharmony_ci						(unsigned char *)msg +
4798c2ecf20Sopenharmony_ci						dma_xfer->msg_length) {
4808c2ecf20Sopenharmony_ci					cl->last_dma_acked = 1;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci					if (!list_empty(&cl->tx_list.list) &&
4838c2ecf20Sopenharmony_ci						cl->ishtp_flow_ctrl_creds) {
4848c2ecf20Sopenharmony_ci						/*
4858c2ecf20Sopenharmony_ci						 * start sending the first msg
4868c2ecf20Sopenharmony_ci						 */
4878c2ecf20Sopenharmony_ci						ishtp_cl_send_msg(dev, cl);
4888c2ecf20Sopenharmony_ci					}
4898c2ecf20Sopenharmony_ci				}
4908c2ecf20Sopenharmony_ci		}
4918c2ecf20Sopenharmony_ci		++dma_xfer;
4928c2ecf20Sopenharmony_ci	}
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci/**
4968c2ecf20Sopenharmony_ci * ishtp_hbm_dma_xfer() - Receive DMA transfer message
4978c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
4988c2ecf20Sopenharmony_ci * @dma_xfer: HBM transfer message
4998c2ecf20Sopenharmony_ci *
5008c2ecf20Sopenharmony_ci * Receive ISHTP-over-DMA client message
5018c2ecf20Sopenharmony_ci */
5028c2ecf20Sopenharmony_cistatic void ishtp_hbm_dma_xfer(struct ishtp_device *dev,
5038c2ecf20Sopenharmony_ci			       struct dma_xfer_hbm *dma_xfer)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	void	*msg;
5068c2ecf20Sopenharmony_ci	uint64_t	offs;
5078c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr	hdr;
5088c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr	*ishtp_hdr =
5098c2ecf20Sopenharmony_ci		(struct ishtp_msg_hdr *) &dev->ishtp_msg_hdr;
5108c2ecf20Sopenharmony_ci	struct dma_xfer_hbm	*prm = dma_xfer;
5118c2ecf20Sopenharmony_ci	unsigned int	msg_offs;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	for (msg_offs = 0; msg_offs < ishtp_hdr->length;
5148c2ecf20Sopenharmony_ci		msg_offs += sizeof(struct dma_xfer_hbm)) {
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci		offs = dma_xfer->msg_addr - dev->ishtp_host_dma_rx_buf_phys;
5178c2ecf20Sopenharmony_ci		if (offs > dev->ishtp_host_dma_rx_buf_size) {
5188c2ecf20Sopenharmony_ci			dev_err(dev->devc, "Bad DMA Rx message address\n");
5198c2ecf20Sopenharmony_ci			return;
5208c2ecf20Sopenharmony_ci		}
5218c2ecf20Sopenharmony_ci		if (dma_xfer->msg_length >
5228c2ecf20Sopenharmony_ci				dev->ishtp_host_dma_rx_buf_size - offs) {
5238c2ecf20Sopenharmony_ci			dev_err(dev->devc, "Bad DMA Rx message size\n");
5248c2ecf20Sopenharmony_ci			return;
5258c2ecf20Sopenharmony_ci		}
5268c2ecf20Sopenharmony_ci		msg = dev->ishtp_host_dma_rx_buf + offs;
5278c2ecf20Sopenharmony_ci		recv_ishtp_cl_msg_dma(dev, msg, dma_xfer);
5288c2ecf20Sopenharmony_ci		dma_xfer->hbm = DMA_XFER_ACK;	/* Prepare for response */
5298c2ecf20Sopenharmony_ci		++dma_xfer;
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	/* Send DMA_XFER_ACK [...] */
5338c2ecf20Sopenharmony_ci	ishtp_hbm_hdr(&hdr, ishtp_hdr->length);
5348c2ecf20Sopenharmony_ci	ishtp_write_message(dev, &hdr, (unsigned char *)prm);
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci/**
5388c2ecf20Sopenharmony_ci * ishtp_hbm_dispatch() - HBM dispatch function
5398c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
5408c2ecf20Sopenharmony_ci * @hdr: bus message
5418c2ecf20Sopenharmony_ci *
5428c2ecf20Sopenharmony_ci * Bottom half read routine after ISR to handle the read bus message cmd
5438c2ecf20Sopenharmony_ci * processing
5448c2ecf20Sopenharmony_ci */
5458c2ecf20Sopenharmony_civoid ishtp_hbm_dispatch(struct ishtp_device *dev,
5468c2ecf20Sopenharmony_ci			struct ishtp_bus_message *hdr)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	struct ishtp_bus_message *ishtp_msg;
5498c2ecf20Sopenharmony_ci	struct ishtp_fw_client *fw_client;
5508c2ecf20Sopenharmony_ci	struct hbm_host_version_response *version_res;
5518c2ecf20Sopenharmony_ci	struct hbm_client_connect_response *connect_res;
5528c2ecf20Sopenharmony_ci	struct hbm_client_connect_response *disconnect_res;
5538c2ecf20Sopenharmony_ci	struct hbm_client_connect_request *disconnect_req;
5548c2ecf20Sopenharmony_ci	struct hbm_props_response *props_res;
5558c2ecf20Sopenharmony_ci	struct hbm_host_enum_response *enum_res;
5568c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr ishtp_hdr;
5578c2ecf20Sopenharmony_ci	struct dma_alloc_notify	dma_alloc_notify;
5588c2ecf20Sopenharmony_ci	struct dma_xfer_hbm	*dma_xfer;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	ishtp_msg = hdr;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	switch (ishtp_msg->hbm_cmd) {
5638c2ecf20Sopenharmony_ci	case HOST_START_RES_CMD:
5648c2ecf20Sopenharmony_ci		version_res = (struct hbm_host_version_response *)ishtp_msg;
5658c2ecf20Sopenharmony_ci		if (!version_res->host_version_supported) {
5668c2ecf20Sopenharmony_ci			dev->version = version_res->fw_max_version;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci			dev->hbm_state = ISHTP_HBM_STOPPED;
5698c2ecf20Sopenharmony_ci			ishtp_hbm_stop_req(dev);
5708c2ecf20Sopenharmony_ci			return;
5718c2ecf20Sopenharmony_ci		}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci		dev->version.major_version = HBM_MAJOR_VERSION;
5748c2ecf20Sopenharmony_ci		dev->version.minor_version = HBM_MINOR_VERSION;
5758c2ecf20Sopenharmony_ci		if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS &&
5768c2ecf20Sopenharmony_ci				dev->hbm_state == ISHTP_HBM_START) {
5778c2ecf20Sopenharmony_ci			dev->hbm_state = ISHTP_HBM_STARTED;
5788c2ecf20Sopenharmony_ci			ishtp_hbm_enum_clients_req(dev);
5798c2ecf20Sopenharmony_ci		} else {
5808c2ecf20Sopenharmony_ci			dev_err(dev->devc,
5818c2ecf20Sopenharmony_ci				"reset: wrong host start response\n");
5828c2ecf20Sopenharmony_ci			/* BUG: why do we arrive here? */
5838c2ecf20Sopenharmony_ci			ish_hw_reset(dev);
5848c2ecf20Sopenharmony_ci			return;
5858c2ecf20Sopenharmony_ci		}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci		wake_up_interruptible(&dev->wait_hbm_recvd_msg);
5888c2ecf20Sopenharmony_ci		break;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	case CLIENT_CONNECT_RES_CMD:
5918c2ecf20Sopenharmony_ci		connect_res = (struct hbm_client_connect_response *)ishtp_msg;
5928c2ecf20Sopenharmony_ci		ishtp_hbm_cl_connect_res(dev, connect_res);
5938c2ecf20Sopenharmony_ci		break;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	case CLIENT_DISCONNECT_RES_CMD:
5968c2ecf20Sopenharmony_ci		disconnect_res =
5978c2ecf20Sopenharmony_ci			(struct hbm_client_connect_response *)ishtp_msg;
5988c2ecf20Sopenharmony_ci		ishtp_hbm_cl_disconnect_res(dev, disconnect_res);
5998c2ecf20Sopenharmony_ci		break;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	case HOST_CLIENT_PROPERTIES_RES_CMD:
6028c2ecf20Sopenharmony_ci		props_res = (struct hbm_props_response *)ishtp_msg;
6038c2ecf20Sopenharmony_ci		fw_client = &dev->fw_clients[dev->fw_client_presentation_num];
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci		if (props_res->status || !dev->fw_clients) {
6068c2ecf20Sopenharmony_ci			dev_err(dev->devc,
6078c2ecf20Sopenharmony_ci			"reset: properties response hbm wrong status\n");
6088c2ecf20Sopenharmony_ci			ish_hw_reset(dev);
6098c2ecf20Sopenharmony_ci			return;
6108c2ecf20Sopenharmony_ci		}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci		if (fw_client->client_id != props_res->address) {
6138c2ecf20Sopenharmony_ci			dev_err(dev->devc,
6148c2ecf20Sopenharmony_ci				"reset: host properties response address mismatch [%02X %02X]\n",
6158c2ecf20Sopenharmony_ci				fw_client->client_id, props_res->address);
6168c2ecf20Sopenharmony_ci			ish_hw_reset(dev);
6178c2ecf20Sopenharmony_ci			return;
6188c2ecf20Sopenharmony_ci		}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci		if (dev->dev_state != ISHTP_DEV_INIT_CLIENTS ||
6218c2ecf20Sopenharmony_ci			dev->hbm_state != ISHTP_HBM_CLIENT_PROPERTIES) {
6228c2ecf20Sopenharmony_ci			dev_err(dev->devc,
6238c2ecf20Sopenharmony_ci				"reset: unexpected properties response\n");
6248c2ecf20Sopenharmony_ci			ish_hw_reset(dev);
6258c2ecf20Sopenharmony_ci			return;
6268c2ecf20Sopenharmony_ci		}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci		fw_client->props = props_res->client_properties;
6298c2ecf20Sopenharmony_ci		dev->fw_client_index++;
6308c2ecf20Sopenharmony_ci		dev->fw_client_presentation_num++;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci		/* request property for the next client */
6338c2ecf20Sopenharmony_ci		ishtp_hbm_prop_req(dev);
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci		if (dev->dev_state != ISHTP_DEV_ENABLED)
6368c2ecf20Sopenharmony_ci			break;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci		if (!ishtp_use_dma_transfer())
6398c2ecf20Sopenharmony_ci			break;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci		dev_dbg(dev->devc, "Requesting to use DMA\n");
6428c2ecf20Sopenharmony_ci		ishtp_cl_alloc_dma_buf(dev);
6438c2ecf20Sopenharmony_ci		if (dev->ishtp_host_dma_rx_buf) {
6448c2ecf20Sopenharmony_ci			const size_t len = sizeof(dma_alloc_notify);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci			memset(&dma_alloc_notify, 0, sizeof(dma_alloc_notify));
6478c2ecf20Sopenharmony_ci			dma_alloc_notify.hbm = DMA_BUFFER_ALLOC_NOTIFY;
6488c2ecf20Sopenharmony_ci			dma_alloc_notify.buf_size =
6498c2ecf20Sopenharmony_ci					dev->ishtp_host_dma_rx_buf_size;
6508c2ecf20Sopenharmony_ci			dma_alloc_notify.buf_address =
6518c2ecf20Sopenharmony_ci					dev->ishtp_host_dma_rx_buf_phys;
6528c2ecf20Sopenharmony_ci			ishtp_hbm_hdr(&ishtp_hdr, len);
6538c2ecf20Sopenharmony_ci			ishtp_write_message(dev, &ishtp_hdr,
6548c2ecf20Sopenharmony_ci				(unsigned char *)&dma_alloc_notify);
6558c2ecf20Sopenharmony_ci		}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci		break;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	case HOST_ENUM_RES_CMD:
6608c2ecf20Sopenharmony_ci		enum_res = (struct hbm_host_enum_response *) ishtp_msg;
6618c2ecf20Sopenharmony_ci		memcpy(dev->fw_clients_map, enum_res->valid_addresses, 32);
6628c2ecf20Sopenharmony_ci		if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS &&
6638c2ecf20Sopenharmony_ci			dev->hbm_state == ISHTP_HBM_ENUM_CLIENTS) {
6648c2ecf20Sopenharmony_ci			dev->fw_client_presentation_num = 0;
6658c2ecf20Sopenharmony_ci			dev->fw_client_index = 0;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci			ishtp_hbm_fw_cl_allocate(dev);
6688c2ecf20Sopenharmony_ci			dev->hbm_state = ISHTP_HBM_CLIENT_PROPERTIES;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci			/* first property request */
6718c2ecf20Sopenharmony_ci			ishtp_hbm_prop_req(dev);
6728c2ecf20Sopenharmony_ci		} else {
6738c2ecf20Sopenharmony_ci			dev_err(dev->devc,
6748c2ecf20Sopenharmony_ci			      "reset: unexpected enumeration response hbm\n");
6758c2ecf20Sopenharmony_ci			ish_hw_reset(dev);
6768c2ecf20Sopenharmony_ci			return;
6778c2ecf20Sopenharmony_ci		}
6788c2ecf20Sopenharmony_ci		break;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	case HOST_STOP_RES_CMD:
6818c2ecf20Sopenharmony_ci		if (dev->hbm_state != ISHTP_HBM_STOPPED)
6828c2ecf20Sopenharmony_ci			dev_err(dev->devc, "unexpected stop response\n");
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci		dev->dev_state = ISHTP_DEV_DISABLED;
6858c2ecf20Sopenharmony_ci		dev_info(dev->devc, "reset: FW stop response\n");
6868c2ecf20Sopenharmony_ci		ish_hw_reset(dev);
6878c2ecf20Sopenharmony_ci		break;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	case CLIENT_DISCONNECT_REQ_CMD:
6908c2ecf20Sopenharmony_ci		/* search for client */
6918c2ecf20Sopenharmony_ci		disconnect_req =
6928c2ecf20Sopenharmony_ci			(struct hbm_client_connect_request *)ishtp_msg;
6938c2ecf20Sopenharmony_ci		ishtp_hbm_fw_disconnect_req(dev, disconnect_req);
6948c2ecf20Sopenharmony_ci		break;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	case FW_STOP_REQ_CMD:
6978c2ecf20Sopenharmony_ci		dev->hbm_state = ISHTP_HBM_STOPPED;
6988c2ecf20Sopenharmony_ci		break;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	case DMA_BUFFER_ALLOC_RESPONSE:
7018c2ecf20Sopenharmony_ci		dev->ishtp_host_dma_enabled = 1;
7028c2ecf20Sopenharmony_ci		break;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	case DMA_XFER:
7058c2ecf20Sopenharmony_ci		dma_xfer = (struct dma_xfer_hbm *)ishtp_msg;
7068c2ecf20Sopenharmony_ci		if (!dev->ishtp_host_dma_enabled) {
7078c2ecf20Sopenharmony_ci			dev_err(dev->devc,
7088c2ecf20Sopenharmony_ci				"DMA XFER requested but DMA is not enabled\n");
7098c2ecf20Sopenharmony_ci			break;
7108c2ecf20Sopenharmony_ci		}
7118c2ecf20Sopenharmony_ci		ishtp_hbm_dma_xfer(dev, dma_xfer);
7128c2ecf20Sopenharmony_ci		break;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	case DMA_XFER_ACK:
7158c2ecf20Sopenharmony_ci		dma_xfer = (struct dma_xfer_hbm *)ishtp_msg;
7168c2ecf20Sopenharmony_ci		if (!dev->ishtp_host_dma_enabled ||
7178c2ecf20Sopenharmony_ci		    !dev->ishtp_host_dma_tx_buf) {
7188c2ecf20Sopenharmony_ci			dev_err(dev->devc,
7198c2ecf20Sopenharmony_ci				"DMA XFER acked but DMA Tx is not enabled\n");
7208c2ecf20Sopenharmony_ci			break;
7218c2ecf20Sopenharmony_ci		}
7228c2ecf20Sopenharmony_ci		ishtp_hbm_dma_xfer_ack(dev, dma_xfer);
7238c2ecf20Sopenharmony_ci		break;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	default:
7268c2ecf20Sopenharmony_ci		dev_err(dev->devc, "unknown HBM: %u\n",
7278c2ecf20Sopenharmony_ci			(unsigned int)ishtp_msg->hbm_cmd);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci		break;
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci/**
7348c2ecf20Sopenharmony_ci * bh_hbm_work_fn() - HBM work function
7358c2ecf20Sopenharmony_ci * @work: work struct
7368c2ecf20Sopenharmony_ci *
7378c2ecf20Sopenharmony_ci * Bottom half processing work function (instead of thread handler)
7388c2ecf20Sopenharmony_ci * for processing hbm messages
7398c2ecf20Sopenharmony_ci */
7408c2ecf20Sopenharmony_civoid	bh_hbm_work_fn(struct work_struct *work)
7418c2ecf20Sopenharmony_ci{
7428c2ecf20Sopenharmony_ci	unsigned long	flags;
7438c2ecf20Sopenharmony_ci	struct ishtp_device	*dev;
7448c2ecf20Sopenharmony_ci	unsigned char	hbm[IPC_PAYLOAD_SIZE];
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	dev = container_of(work, struct ishtp_device, bh_hbm_work);
7478c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
7488c2ecf20Sopenharmony_ci	if (dev->rd_msg_fifo_head != dev->rd_msg_fifo_tail) {
7498c2ecf20Sopenharmony_ci		memcpy(hbm, dev->rd_msg_fifo + dev->rd_msg_fifo_head,
7508c2ecf20Sopenharmony_ci			IPC_PAYLOAD_SIZE);
7518c2ecf20Sopenharmony_ci		dev->rd_msg_fifo_head =
7528c2ecf20Sopenharmony_ci			(dev->rd_msg_fifo_head + IPC_PAYLOAD_SIZE) %
7538c2ecf20Sopenharmony_ci			(RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE);
7548c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
7558c2ecf20Sopenharmony_ci		ishtp_hbm_dispatch(dev, (struct ishtp_bus_message *)hbm);
7568c2ecf20Sopenharmony_ci	} else {
7578c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci/**
7628c2ecf20Sopenharmony_ci * recv_hbm() - Receive HBM message
7638c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
7648c2ecf20Sopenharmony_ci * @ishtp_hdr: received bus message
7658c2ecf20Sopenharmony_ci *
7668c2ecf20Sopenharmony_ci * Receive and process ISHTP bus messages in ISR context. This will schedule
7678c2ecf20Sopenharmony_ci * work function to process message
7688c2ecf20Sopenharmony_ci */
7698c2ecf20Sopenharmony_civoid	recv_hbm(struct ishtp_device *dev, struct ishtp_msg_hdr *ishtp_hdr)
7708c2ecf20Sopenharmony_ci{
7718c2ecf20Sopenharmony_ci	uint8_t	rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE];
7728c2ecf20Sopenharmony_ci	struct ishtp_bus_message	*ishtp_msg =
7738c2ecf20Sopenharmony_ci		(struct ishtp_bus_message *)rd_msg_buf;
7748c2ecf20Sopenharmony_ci	unsigned long	flags;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	/* Flow control - handle in place */
7798c2ecf20Sopenharmony_ci	if (ishtp_msg->hbm_cmd == ISHTP_FLOW_CONTROL_CMD) {
7808c2ecf20Sopenharmony_ci		struct hbm_flow_control *flow_control =
7818c2ecf20Sopenharmony_ci			(struct hbm_flow_control *)ishtp_msg;
7828c2ecf20Sopenharmony_ci		struct ishtp_cl *cl = NULL;
7838c2ecf20Sopenharmony_ci		unsigned long	flags, tx_flags;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci		spin_lock_irqsave(&dev->cl_list_lock, flags);
7868c2ecf20Sopenharmony_ci		list_for_each_entry(cl, &dev->cl_list, link) {
7878c2ecf20Sopenharmony_ci			if (cl->host_client_id == flow_control->host_addr &&
7888c2ecf20Sopenharmony_ci					cl->fw_client_id ==
7898c2ecf20Sopenharmony_ci					flow_control->fw_addr) {
7908c2ecf20Sopenharmony_ci				/*
7918c2ecf20Sopenharmony_ci				 * NOTE: It's valid only for counting
7928c2ecf20Sopenharmony_ci				 * flow-control implementation to receive a
7938c2ecf20Sopenharmony_ci				 * FC in the middle of sending. Meanwhile not
7948c2ecf20Sopenharmony_ci				 * supported
7958c2ecf20Sopenharmony_ci				 */
7968c2ecf20Sopenharmony_ci				if (cl->ishtp_flow_ctrl_creds)
7978c2ecf20Sopenharmony_ci					dev_err(dev->devc,
7988c2ecf20Sopenharmony_ci					 "recv extra FC from FW client %u (host client %u) (FC count was %d)\n",
7998c2ecf20Sopenharmony_ci					 (unsigned int)cl->fw_client_id,
8008c2ecf20Sopenharmony_ci					 (unsigned int)cl->host_client_id,
8018c2ecf20Sopenharmony_ci					 cl->ishtp_flow_ctrl_creds);
8028c2ecf20Sopenharmony_ci				else {
8038c2ecf20Sopenharmony_ci					++cl->ishtp_flow_ctrl_creds;
8048c2ecf20Sopenharmony_ci					++cl->ishtp_flow_ctrl_cnt;
8058c2ecf20Sopenharmony_ci					cl->last_ipc_acked = 1;
8068c2ecf20Sopenharmony_ci					spin_lock_irqsave(
8078c2ecf20Sopenharmony_ci							&cl->tx_list_spinlock,
8088c2ecf20Sopenharmony_ci							tx_flags);
8098c2ecf20Sopenharmony_ci					if (!list_empty(&cl->tx_list.list)) {
8108c2ecf20Sopenharmony_ci						/*
8118c2ecf20Sopenharmony_ci						 * start sending the first msg
8128c2ecf20Sopenharmony_ci						 *	= the callback function
8138c2ecf20Sopenharmony_ci						 */
8148c2ecf20Sopenharmony_ci						spin_unlock_irqrestore(
8158c2ecf20Sopenharmony_ci							&cl->tx_list_spinlock,
8168c2ecf20Sopenharmony_ci							tx_flags);
8178c2ecf20Sopenharmony_ci						ishtp_cl_send_msg(dev, cl);
8188c2ecf20Sopenharmony_ci					} else {
8198c2ecf20Sopenharmony_ci						spin_unlock_irqrestore(
8208c2ecf20Sopenharmony_ci							&cl->tx_list_spinlock,
8218c2ecf20Sopenharmony_ci							tx_flags);
8228c2ecf20Sopenharmony_ci					}
8238c2ecf20Sopenharmony_ci				}
8248c2ecf20Sopenharmony_ci				break;
8258c2ecf20Sopenharmony_ci			}
8268c2ecf20Sopenharmony_ci		}
8278c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&dev->cl_list_lock, flags);
8288c2ecf20Sopenharmony_ci		goto	eoi;
8298c2ecf20Sopenharmony_ci	}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	/*
8328c2ecf20Sopenharmony_ci	 * Some messages that are safe for ISR processing and important
8338c2ecf20Sopenharmony_ci	 * to be done "quickly" and in-order, go here
8348c2ecf20Sopenharmony_ci	 */
8358c2ecf20Sopenharmony_ci	if (ishtp_msg->hbm_cmd == CLIENT_CONNECT_RES_CMD ||
8368c2ecf20Sopenharmony_ci			ishtp_msg->hbm_cmd == CLIENT_DISCONNECT_RES_CMD ||
8378c2ecf20Sopenharmony_ci			ishtp_msg->hbm_cmd == CLIENT_DISCONNECT_REQ_CMD ||
8388c2ecf20Sopenharmony_ci			ishtp_msg->hbm_cmd == DMA_XFER) {
8398c2ecf20Sopenharmony_ci		ishtp_hbm_dispatch(dev, ishtp_msg);
8408c2ecf20Sopenharmony_ci		goto	eoi;
8418c2ecf20Sopenharmony_ci	}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	/*
8448c2ecf20Sopenharmony_ci	 * All other HBMs go here.
8458c2ecf20Sopenharmony_ci	 * We schedule HBMs for processing serially by using system wq,
8468c2ecf20Sopenharmony_ci	 * possibly there will be multiple HBMs scheduled at the same time.
8478c2ecf20Sopenharmony_ci	 */
8488c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
8498c2ecf20Sopenharmony_ci	if ((dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) %
8508c2ecf20Sopenharmony_ci			(RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE) ==
8518c2ecf20Sopenharmony_ci			dev->rd_msg_fifo_head) {
8528c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
8538c2ecf20Sopenharmony_ci		dev_err(dev->devc, "BH buffer overflow, dropping HBM %u\n",
8548c2ecf20Sopenharmony_ci			(unsigned int)ishtp_msg->hbm_cmd);
8558c2ecf20Sopenharmony_ci		goto	eoi;
8568c2ecf20Sopenharmony_ci	}
8578c2ecf20Sopenharmony_ci	memcpy(dev->rd_msg_fifo + dev->rd_msg_fifo_tail, ishtp_msg,
8588c2ecf20Sopenharmony_ci		ishtp_hdr->length);
8598c2ecf20Sopenharmony_ci	dev->rd_msg_fifo_tail = (dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) %
8608c2ecf20Sopenharmony_ci		(RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE);
8618c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
8628c2ecf20Sopenharmony_ci	schedule_work(&dev->bh_hbm_work);
8638c2ecf20Sopenharmony_cieoi:
8648c2ecf20Sopenharmony_ci	return;
8658c2ecf20Sopenharmony_ci}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci/**
8688c2ecf20Sopenharmony_ci * recv_fixed_cl_msg() - Receive fixed client message
8698c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
8708c2ecf20Sopenharmony_ci * @ishtp_hdr: received bus message
8718c2ecf20Sopenharmony_ci *
8728c2ecf20Sopenharmony_ci * Receive and process ISHTP fixed client messages (address == 0)
8738c2ecf20Sopenharmony_ci * in ISR context
8748c2ecf20Sopenharmony_ci */
8758c2ecf20Sopenharmony_civoid recv_fixed_cl_msg(struct ishtp_device *dev,
8768c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr *ishtp_hdr)
8778c2ecf20Sopenharmony_ci{
8788c2ecf20Sopenharmony_ci	uint8_t rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE];
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	dev->print_log(dev,
8818c2ecf20Sopenharmony_ci		"%s() got fixed client msg from client #%d\n",
8828c2ecf20Sopenharmony_ci		__func__, ishtp_hdr->fw_addr);
8838c2ecf20Sopenharmony_ci	dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length);
8848c2ecf20Sopenharmony_ci	if (ishtp_hdr->fw_addr == ISHTP_SYSTEM_STATE_CLIENT_ADDR) {
8858c2ecf20Sopenharmony_ci		struct ish_system_states_header *msg_hdr =
8868c2ecf20Sopenharmony_ci			(struct ish_system_states_header *)rd_msg_buf;
8878c2ecf20Sopenharmony_ci		if (msg_hdr->cmd == SYSTEM_STATE_SUBSCRIBE)
8888c2ecf20Sopenharmony_ci			ishtp_send_resume(dev);
8898c2ecf20Sopenharmony_ci		/* if FW request arrived here, the system is not suspended */
8908c2ecf20Sopenharmony_ci		else
8918c2ecf20Sopenharmony_ci			dev_err(dev->devc, "unknown fixed client msg [%02X]\n",
8928c2ecf20Sopenharmony_ci				msg_hdr->cmd);
8938c2ecf20Sopenharmony_ci	}
8948c2ecf20Sopenharmony_ci}
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci/**
8978c2ecf20Sopenharmony_ci * fix_cl_hdr() - Initialize fixed client header
8988c2ecf20Sopenharmony_ci * @hdr: message header
8998c2ecf20Sopenharmony_ci * @length: length of message
9008c2ecf20Sopenharmony_ci * @cl_addr: Client address
9018c2ecf20Sopenharmony_ci *
9028c2ecf20Sopenharmony_ci * Initialize message header for fixed client
9038c2ecf20Sopenharmony_ci */
9048c2ecf20Sopenharmony_cistatic inline void fix_cl_hdr(struct ishtp_msg_hdr *hdr, size_t length,
9058c2ecf20Sopenharmony_ci	uint8_t cl_addr)
9068c2ecf20Sopenharmony_ci{
9078c2ecf20Sopenharmony_ci	hdr->host_addr = 0;
9088c2ecf20Sopenharmony_ci	hdr->fw_addr = cl_addr;
9098c2ecf20Sopenharmony_ci	hdr->length = length;
9108c2ecf20Sopenharmony_ci	hdr->msg_complete = 1;
9118c2ecf20Sopenharmony_ci	hdr->reserved = 0;
9128c2ecf20Sopenharmony_ci}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci/*** Suspend and resume notification ***/
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_cistatic uint32_t current_state;
9178c2ecf20Sopenharmony_cistatic uint32_t supported_states = 0 | SUSPEND_STATE_BIT;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci/**
9208c2ecf20Sopenharmony_ci * ishtp_send_suspend() - Send suspend message to FW
9218c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
9228c2ecf20Sopenharmony_ci *
9238c2ecf20Sopenharmony_ci * Send suspend message to FW. This is useful for system freeze (non S3) case
9248c2ecf20Sopenharmony_ci */
9258c2ecf20Sopenharmony_civoid ishtp_send_suspend(struct ishtp_device *dev)
9268c2ecf20Sopenharmony_ci{
9278c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr	ishtp_hdr;
9288c2ecf20Sopenharmony_ci	struct ish_system_states_status state_status_msg;
9298c2ecf20Sopenharmony_ci	const size_t len = sizeof(struct ish_system_states_status);
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	memset(&state_status_msg, 0, len);
9348c2ecf20Sopenharmony_ci	state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
9358c2ecf20Sopenharmony_ci	state_status_msg.supported_states = supported_states;
9368c2ecf20Sopenharmony_ci	current_state |= SUSPEND_STATE_BIT;
9378c2ecf20Sopenharmony_ci	dev->print_log(dev, "%s() sends SUSPEND notification\n", __func__);
9388c2ecf20Sopenharmony_ci	state_status_msg.states_status = current_state;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	ishtp_write_message(dev, &ishtp_hdr,
9418c2ecf20Sopenharmony_ci		(unsigned char *)&state_status_msg);
9428c2ecf20Sopenharmony_ci}
9438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ishtp_send_suspend);
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci/**
9468c2ecf20Sopenharmony_ci * ishtp_send_resume() - Send resume message to FW
9478c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
9488c2ecf20Sopenharmony_ci *
9498c2ecf20Sopenharmony_ci * Send resume message to FW. This is useful for system freeze (non S3) case
9508c2ecf20Sopenharmony_ci */
9518c2ecf20Sopenharmony_civoid ishtp_send_resume(struct ishtp_device *dev)
9528c2ecf20Sopenharmony_ci{
9538c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr	ishtp_hdr;
9548c2ecf20Sopenharmony_ci	struct ish_system_states_status state_status_msg;
9558c2ecf20Sopenharmony_ci	const size_t len = sizeof(struct ish_system_states_status);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	memset(&state_status_msg, 0, len);
9608c2ecf20Sopenharmony_ci	state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
9618c2ecf20Sopenharmony_ci	state_status_msg.supported_states = supported_states;
9628c2ecf20Sopenharmony_ci	current_state &= ~SUSPEND_STATE_BIT;
9638c2ecf20Sopenharmony_ci	dev->print_log(dev, "%s() sends RESUME notification\n", __func__);
9648c2ecf20Sopenharmony_ci	state_status_msg.states_status = current_state;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	ishtp_write_message(dev, &ishtp_hdr,
9678c2ecf20Sopenharmony_ci		(unsigned char *)&state_status_msg);
9688c2ecf20Sopenharmony_ci}
9698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ishtp_send_resume);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci/**
9728c2ecf20Sopenharmony_ci * ishtp_query_subscribers() - Send query subscribers message
9738c2ecf20Sopenharmony_ci * @dev: ISHTP device instance
9748c2ecf20Sopenharmony_ci *
9758c2ecf20Sopenharmony_ci * Send message to query subscribers
9768c2ecf20Sopenharmony_ci */
9778c2ecf20Sopenharmony_civoid ishtp_query_subscribers(struct ishtp_device *dev)
9788c2ecf20Sopenharmony_ci{
9798c2ecf20Sopenharmony_ci	struct ishtp_msg_hdr	ishtp_hdr;
9808c2ecf20Sopenharmony_ci	struct ish_system_states_query_subscribers query_subscribers_msg;
9818c2ecf20Sopenharmony_ci	const size_t len = sizeof(struct ish_system_states_query_subscribers);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	memset(&query_subscribers_msg, 0, len);
9868c2ecf20Sopenharmony_ci	query_subscribers_msg.hdr.cmd = SYSTEM_STATE_QUERY_SUBSCRIBERS;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	ishtp_write_message(dev, &ishtp_hdr,
9898c2ecf20Sopenharmony_ci		(unsigned char *)&query_subscribers_msg);
9908c2ecf20Sopenharmony_ci}
991