xref: /linux/drivers/hid/intel-ish-hid/ishtp/hbm.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23703f53bSSrinivas Pandruvada /*
33703f53bSSrinivas Pandruvada  * ISHTP bus layer messages handling
43703f53bSSrinivas Pandruvada  *
53703f53bSSrinivas Pandruvada  * Copyright (c) 2003-2016, Intel Corporation.
63703f53bSSrinivas Pandruvada  */
73703f53bSSrinivas Pandruvada 
83703f53bSSrinivas Pandruvada #include <linux/export.h>
93703f53bSSrinivas Pandruvada #include <linux/slab.h>
103703f53bSSrinivas Pandruvada #include <linux/sched.h>
113703f53bSSrinivas Pandruvada #include <linux/wait.h>
123703f53bSSrinivas Pandruvada #include <linux/spinlock.h>
133703f53bSSrinivas Pandruvada #include "ishtp-dev.h"
143703f53bSSrinivas Pandruvada #include "hbm.h"
153703f53bSSrinivas Pandruvada #include "client.h"
163703f53bSSrinivas Pandruvada 
173703f53bSSrinivas Pandruvada /**
183703f53bSSrinivas Pandruvada  * ishtp_hbm_fw_cl_allocate() - Allocate FW clients
193703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
203703f53bSSrinivas Pandruvada  *
213703f53bSSrinivas Pandruvada  * Allocates storage for fw clients
223703f53bSSrinivas Pandruvada  */
233703f53bSSrinivas Pandruvada static void ishtp_hbm_fw_cl_allocate(struct ishtp_device *dev)
243703f53bSSrinivas Pandruvada {
253703f53bSSrinivas Pandruvada 	struct ishtp_fw_client *clients;
263703f53bSSrinivas Pandruvada 	int b;
273703f53bSSrinivas Pandruvada 
283703f53bSSrinivas Pandruvada 	/* count how many ISH clients we have */
293703f53bSSrinivas Pandruvada 	for_each_set_bit(b, dev->fw_clients_map, ISHTP_CLIENTS_MAX)
303703f53bSSrinivas Pandruvada 		dev->fw_clients_num++;
313703f53bSSrinivas Pandruvada 
323703f53bSSrinivas Pandruvada 	if (dev->fw_clients_num <= 0)
333703f53bSSrinivas Pandruvada 		return;
343703f53bSSrinivas Pandruvada 
353703f53bSSrinivas Pandruvada 	/* allocate storage for fw clients representation */
363703f53bSSrinivas Pandruvada 	clients = kcalloc(dev->fw_clients_num, sizeof(struct ishtp_fw_client),
373703f53bSSrinivas Pandruvada 			  GFP_KERNEL);
383703f53bSSrinivas Pandruvada 	if (!clients) {
393703f53bSSrinivas Pandruvada 		dev->dev_state = ISHTP_DEV_RESETTING;
403703f53bSSrinivas Pandruvada 		ish_hw_reset(dev);
413703f53bSSrinivas Pandruvada 		return;
423703f53bSSrinivas Pandruvada 	}
433703f53bSSrinivas Pandruvada 	dev->fw_clients = clients;
443703f53bSSrinivas Pandruvada }
453703f53bSSrinivas Pandruvada 
463703f53bSSrinivas Pandruvada /**
473703f53bSSrinivas Pandruvada  * ishtp_hbm_cl_hdr() - construct client hbm header
483703f53bSSrinivas Pandruvada  * @cl: client
493703f53bSSrinivas Pandruvada  * @hbm_cmd: host bus message command
503703f53bSSrinivas Pandruvada  * @buf: buffer for cl header
513703f53bSSrinivas Pandruvada  * @len: buffer length
523703f53bSSrinivas Pandruvada  *
533703f53bSSrinivas Pandruvada  * Initialize HBM buffer
543703f53bSSrinivas Pandruvada  */
553703f53bSSrinivas Pandruvada static inline void ishtp_hbm_cl_hdr(struct ishtp_cl *cl, uint8_t hbm_cmd,
563703f53bSSrinivas Pandruvada 	void *buf, size_t len)
573703f53bSSrinivas Pandruvada {
583703f53bSSrinivas Pandruvada 	struct ishtp_hbm_cl_cmd *cmd = buf;
593703f53bSSrinivas Pandruvada 
603703f53bSSrinivas Pandruvada 	memset(cmd, 0, len);
613703f53bSSrinivas Pandruvada 
623703f53bSSrinivas Pandruvada 	cmd->hbm_cmd = hbm_cmd;
633703f53bSSrinivas Pandruvada 	cmd->host_addr = cl->host_client_id;
643703f53bSSrinivas Pandruvada 	cmd->fw_addr = cl->fw_client_id;
653703f53bSSrinivas Pandruvada }
663703f53bSSrinivas Pandruvada 
673703f53bSSrinivas Pandruvada /**
683703f53bSSrinivas Pandruvada  * ishtp_hbm_cl_addr_equal() - Compare client address
693703f53bSSrinivas Pandruvada  * @cl: client
703703f53bSSrinivas Pandruvada  * @buf: Client command buffer
713703f53bSSrinivas Pandruvada  *
723703f53bSSrinivas Pandruvada  * Compare client address with the address in command buffer
733703f53bSSrinivas Pandruvada  *
743703f53bSSrinivas Pandruvada  * Return: True if they have the same address
753703f53bSSrinivas Pandruvada  */
763703f53bSSrinivas Pandruvada static inline bool ishtp_hbm_cl_addr_equal(struct ishtp_cl *cl, void *buf)
773703f53bSSrinivas Pandruvada {
783703f53bSSrinivas Pandruvada 	struct ishtp_hbm_cl_cmd *cmd = buf;
793703f53bSSrinivas Pandruvada 
803703f53bSSrinivas Pandruvada 	return cl->host_client_id == cmd->host_addr &&
813703f53bSSrinivas Pandruvada 		cl->fw_client_id == cmd->fw_addr;
823703f53bSSrinivas Pandruvada }
833703f53bSSrinivas Pandruvada 
843703f53bSSrinivas Pandruvada /**
853703f53bSSrinivas Pandruvada  * ishtp_hbm_start_wait() - Wait for HBM start message
863703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
873703f53bSSrinivas Pandruvada  *
883703f53bSSrinivas Pandruvada  * Wait for HBM start message from firmware
893703f53bSSrinivas Pandruvada  *
903703f53bSSrinivas Pandruvada  * Return: 0 if HBM start is/was received else timeout error
913703f53bSSrinivas Pandruvada  */
923703f53bSSrinivas Pandruvada int ishtp_hbm_start_wait(struct ishtp_device *dev)
933703f53bSSrinivas Pandruvada {
943703f53bSSrinivas Pandruvada 	int ret;
953703f53bSSrinivas Pandruvada 
963703f53bSSrinivas Pandruvada 	if (dev->hbm_state > ISHTP_HBM_START)
973703f53bSSrinivas Pandruvada 		return 0;
983703f53bSSrinivas Pandruvada 
993703f53bSSrinivas Pandruvada 	dev_dbg(dev->devc, "Going to wait for ishtp start. hbm_state=%08X\n",
1003703f53bSSrinivas Pandruvada 		dev->hbm_state);
1013703f53bSSrinivas Pandruvada 	ret = wait_event_interruptible_timeout(dev->wait_hbm_recvd_msg,
1023703f53bSSrinivas Pandruvada 					dev->hbm_state >= ISHTP_HBM_STARTED,
1033703f53bSSrinivas Pandruvada 					(ISHTP_INTEROP_TIMEOUT * HZ));
1043703f53bSSrinivas Pandruvada 
1053703f53bSSrinivas Pandruvada 	dev_dbg(dev->devc,
1063703f53bSSrinivas Pandruvada 		"Woke up from waiting for ishtp start. hbm_state=%08X\n",
1073703f53bSSrinivas Pandruvada 		dev->hbm_state);
1083703f53bSSrinivas Pandruvada 
1093703f53bSSrinivas Pandruvada 	if (ret <= 0 && (dev->hbm_state <= ISHTP_HBM_START)) {
1103703f53bSSrinivas Pandruvada 		dev->hbm_state = ISHTP_HBM_IDLE;
1113703f53bSSrinivas Pandruvada 		dev_err(dev->devc,
1123703f53bSSrinivas Pandruvada 		"waiting for ishtp start failed. ret=%d hbm_state=%08X\n",
1133703f53bSSrinivas Pandruvada 			ret, dev->hbm_state);
1143703f53bSSrinivas Pandruvada 		return -ETIMEDOUT;
1153703f53bSSrinivas Pandruvada 	}
1163703f53bSSrinivas Pandruvada 	return 0;
1173703f53bSSrinivas Pandruvada }
1183703f53bSSrinivas Pandruvada 
1193703f53bSSrinivas Pandruvada /**
1203703f53bSSrinivas Pandruvada  * ishtp_hbm_start_req() - Send HBM start message
1213703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
1223703f53bSSrinivas Pandruvada  *
1233703f53bSSrinivas Pandruvada  * Send HBM start message to firmware
1243703f53bSSrinivas Pandruvada  *
1253703f53bSSrinivas Pandruvada  * Return: 0 if success else error code
1263703f53bSSrinivas Pandruvada  */
1273703f53bSSrinivas Pandruvada int ishtp_hbm_start_req(struct ishtp_device *dev)
1283703f53bSSrinivas Pandruvada {
1293703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr hdr;
13009cc8b36SHong Liu 	struct hbm_host_version_request start_req = { 0 };
1313703f53bSSrinivas Pandruvada 
13209cc8b36SHong Liu 	ishtp_hbm_hdr(&hdr, sizeof(start_req));
1333703f53bSSrinivas Pandruvada 
1343703f53bSSrinivas Pandruvada 	/* host start message */
13509cc8b36SHong Liu 	start_req.hbm_cmd = HOST_START_REQ_CMD;
13609cc8b36SHong Liu 	start_req.host_version.major_version = HBM_MAJOR_VERSION;
13709cc8b36SHong Liu 	start_req.host_version.minor_version = HBM_MINOR_VERSION;
1383703f53bSSrinivas Pandruvada 
1393703f53bSSrinivas Pandruvada 	/*
1403703f53bSSrinivas Pandruvada 	 * (!) Response to HBM start may be so quick that this thread would get
1413703f53bSSrinivas Pandruvada 	 * preempted BEFORE managing to set hbm_state = ISHTP_HBM_START.
1423703f53bSSrinivas Pandruvada 	 * So set it at first, change back to ISHTP_HBM_IDLE upon failure
1433703f53bSSrinivas Pandruvada 	 */
1443703f53bSSrinivas Pandruvada 	dev->hbm_state = ISHTP_HBM_START;
14509cc8b36SHong Liu 	if (ishtp_write_message(dev, &hdr, &start_req)) {
1463703f53bSSrinivas Pandruvada 		dev_err(dev->devc, "version message send failed\n");
1473703f53bSSrinivas Pandruvada 		dev->dev_state = ISHTP_DEV_RESETTING;
1483703f53bSSrinivas Pandruvada 		dev->hbm_state = ISHTP_HBM_IDLE;
1493703f53bSSrinivas Pandruvada 		ish_hw_reset(dev);
1503703f53bSSrinivas Pandruvada 		return -ENODEV;
1513703f53bSSrinivas Pandruvada 	}
1523703f53bSSrinivas Pandruvada 
1533703f53bSSrinivas Pandruvada 	return 0;
1543703f53bSSrinivas Pandruvada }
1553703f53bSSrinivas Pandruvada 
1563703f53bSSrinivas Pandruvada /**
1573703f53bSSrinivas Pandruvada  * ishtp_hbm_enum_clients_req() - Send client enum req
1583703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
1593703f53bSSrinivas Pandruvada  *
1603703f53bSSrinivas Pandruvada  * Send enumeration client request message
1613703f53bSSrinivas Pandruvada  *
1623703f53bSSrinivas Pandruvada  * Return: 0 if success else error code
1633703f53bSSrinivas Pandruvada  */
1643703f53bSSrinivas Pandruvada void ishtp_hbm_enum_clients_req(struct ishtp_device *dev)
1653703f53bSSrinivas Pandruvada {
1663703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr hdr;
16709cc8b36SHong Liu 	struct hbm_host_enum_request enum_req = { 0 };
1683703f53bSSrinivas Pandruvada 
1693703f53bSSrinivas Pandruvada 	/* enumerate clients */
17009cc8b36SHong Liu 	ishtp_hbm_hdr(&hdr, sizeof(enum_req));
17109cc8b36SHong Liu 	enum_req.hbm_cmd = HOST_ENUM_REQ_CMD;
1723703f53bSSrinivas Pandruvada 
17309cc8b36SHong Liu 	if (ishtp_write_message(dev, &hdr, &enum_req)) {
1743703f53bSSrinivas Pandruvada 		dev->dev_state = ISHTP_DEV_RESETTING;
1753703f53bSSrinivas Pandruvada 		dev_err(dev->devc, "enumeration request send failed\n");
1763703f53bSSrinivas Pandruvada 		ish_hw_reset(dev);
1773703f53bSSrinivas Pandruvada 	}
1783703f53bSSrinivas Pandruvada 	dev->hbm_state = ISHTP_HBM_ENUM_CLIENTS;
1793703f53bSSrinivas Pandruvada }
1803703f53bSSrinivas Pandruvada 
1813703f53bSSrinivas Pandruvada /**
1823703f53bSSrinivas Pandruvada  * ishtp_hbm_prop_req() - Request property
1833703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
1843703f53bSSrinivas Pandruvada  *
1853703f53bSSrinivas Pandruvada  * Request property for a single client
1863703f53bSSrinivas Pandruvada  *
1873703f53bSSrinivas Pandruvada  * Return: 0 if success else error code
1883703f53bSSrinivas Pandruvada  */
1893703f53bSSrinivas Pandruvada static int ishtp_hbm_prop_req(struct ishtp_device *dev)
1903703f53bSSrinivas Pandruvada {
1913703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr hdr;
19209cc8b36SHong Liu 	struct hbm_props_request prop_req = { 0 };
1933703f53bSSrinivas Pandruvada 	unsigned long next_client_index;
1943703f53bSSrinivas Pandruvada 	uint8_t client_num;
1953703f53bSSrinivas Pandruvada 
1963703f53bSSrinivas Pandruvada 	client_num = dev->fw_client_presentation_num;
1973703f53bSSrinivas Pandruvada 
1983703f53bSSrinivas Pandruvada 	next_client_index = find_next_bit(dev->fw_clients_map,
1993703f53bSSrinivas Pandruvada 		ISHTP_CLIENTS_MAX, dev->fw_client_index);
2003703f53bSSrinivas Pandruvada 
2013703f53bSSrinivas Pandruvada 	/* We got all client properties */
2023703f53bSSrinivas Pandruvada 	if (next_client_index == ISHTP_CLIENTS_MAX) {
2033703f53bSSrinivas Pandruvada 		dev->hbm_state = ISHTP_HBM_WORKING;
2043703f53bSSrinivas Pandruvada 		dev->dev_state = ISHTP_DEV_ENABLED;
2053703f53bSSrinivas Pandruvada 
2063703f53bSSrinivas Pandruvada 		for (dev->fw_client_presentation_num = 1;
2073703f53bSSrinivas Pandruvada 			dev->fw_client_presentation_num < client_num + 1;
2083703f53bSSrinivas Pandruvada 				++dev->fw_client_presentation_num)
2093703f53bSSrinivas Pandruvada 			/* Add new client device */
2103703f53bSSrinivas Pandruvada 			ishtp_bus_new_client(dev);
2113703f53bSSrinivas Pandruvada 		return 0;
2123703f53bSSrinivas Pandruvada 	}
2133703f53bSSrinivas Pandruvada 
2143703f53bSSrinivas Pandruvada 	dev->fw_clients[client_num].client_id = next_client_index;
2153703f53bSSrinivas Pandruvada 
21609cc8b36SHong Liu 	ishtp_hbm_hdr(&hdr, sizeof(prop_req));
2173703f53bSSrinivas Pandruvada 
21809cc8b36SHong Liu 	prop_req.hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
21909cc8b36SHong Liu 	prop_req.address = next_client_index;
2203703f53bSSrinivas Pandruvada 
22109cc8b36SHong Liu 	if (ishtp_write_message(dev, &hdr, &prop_req)) {
2223703f53bSSrinivas Pandruvada 		dev->dev_state = ISHTP_DEV_RESETTING;
2233703f53bSSrinivas Pandruvada 		dev_err(dev->devc, "properties request send failed\n");
2243703f53bSSrinivas Pandruvada 		ish_hw_reset(dev);
2253703f53bSSrinivas Pandruvada 		return -EIO;
2263703f53bSSrinivas Pandruvada 	}
2273703f53bSSrinivas Pandruvada 
2283703f53bSSrinivas Pandruvada 	dev->fw_client_index = next_client_index;
2293703f53bSSrinivas Pandruvada 
2303703f53bSSrinivas Pandruvada 	return 0;
2313703f53bSSrinivas Pandruvada }
2323703f53bSSrinivas Pandruvada 
2333703f53bSSrinivas Pandruvada /**
2343703f53bSSrinivas Pandruvada  * ishtp_hbm_stop_req() - Send HBM stop
2353703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
2363703f53bSSrinivas Pandruvada  *
2373703f53bSSrinivas Pandruvada  * Send stop request message
2383703f53bSSrinivas Pandruvada  */
2393703f53bSSrinivas Pandruvada static void ishtp_hbm_stop_req(struct ishtp_device *dev)
2403703f53bSSrinivas Pandruvada {
2413703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr hdr;
24209cc8b36SHong Liu 	struct hbm_host_stop_request stop_req = { 0 } ;
2433703f53bSSrinivas Pandruvada 
24409cc8b36SHong Liu 	ishtp_hbm_hdr(&hdr, sizeof(stop_req));
2453703f53bSSrinivas Pandruvada 
24609cc8b36SHong Liu 	stop_req.hbm_cmd = HOST_STOP_REQ_CMD;
24709cc8b36SHong Liu 	stop_req.reason = DRIVER_STOP_REQUEST;
2483703f53bSSrinivas Pandruvada 
24909cc8b36SHong Liu 	ishtp_write_message(dev, &hdr, &stop_req);
2503703f53bSSrinivas Pandruvada }
2513703f53bSSrinivas Pandruvada 
2523703f53bSSrinivas Pandruvada /**
2533703f53bSSrinivas Pandruvada  * ishtp_hbm_cl_flow_control_req() - Send flow control request
2543703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
2553703f53bSSrinivas Pandruvada  * @cl: ISHTP client instance
2563703f53bSSrinivas Pandruvada  *
2573703f53bSSrinivas Pandruvada  * Send flow control request
2583703f53bSSrinivas Pandruvada  *
2593703f53bSSrinivas Pandruvada  * Return: 0 if success else error code
2603703f53bSSrinivas Pandruvada  */
2613703f53bSSrinivas Pandruvada int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev,
2623703f53bSSrinivas Pandruvada 				  struct ishtp_cl *cl)
2633703f53bSSrinivas Pandruvada {
2643703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr hdr;
26509cc8b36SHong Liu 	struct hbm_flow_control flow_ctrl;
26609cc8b36SHong Liu 	const size_t len = sizeof(flow_ctrl);
2673703f53bSSrinivas Pandruvada 	int	rv;
2683703f53bSSrinivas Pandruvada 	unsigned long	flags;
2693703f53bSSrinivas Pandruvada 
2703703f53bSSrinivas Pandruvada 	spin_lock_irqsave(&cl->fc_spinlock, flags);
27109cc8b36SHong Liu 
27209cc8b36SHong Liu 	ishtp_hbm_hdr(&hdr, len);
27309cc8b36SHong Liu 	ishtp_hbm_cl_hdr(cl, ISHTP_FLOW_CONTROL_CMD, &flow_ctrl, len);
2743703f53bSSrinivas Pandruvada 
2753703f53bSSrinivas Pandruvada 	/*
2763703f53bSSrinivas Pandruvada 	 * Sync possible race when RB recycle and packet receive paths
2773703f53bSSrinivas Pandruvada 	 * both try to send an out FC
2783703f53bSSrinivas Pandruvada 	 */
2793703f53bSSrinivas Pandruvada 	if (cl->out_flow_ctrl_creds) {
2803703f53bSSrinivas Pandruvada 		spin_unlock_irqrestore(&cl->fc_spinlock, flags);
2813703f53bSSrinivas Pandruvada 		return	0;
2823703f53bSSrinivas Pandruvada 	}
2833703f53bSSrinivas Pandruvada 
2843703f53bSSrinivas Pandruvada 	cl->recv_msg_num_frags = 0;
2853703f53bSSrinivas Pandruvada 
28609cc8b36SHong Liu 	rv = ishtp_write_message(dev, &hdr, &flow_ctrl);
2873703f53bSSrinivas Pandruvada 	if (!rv) {
2883703f53bSSrinivas Pandruvada 		++cl->out_flow_ctrl_creds;
2893703f53bSSrinivas Pandruvada 		++cl->out_flow_ctrl_cnt;
2902503f7baSArnd Bergmann 		cl->ts_out_fc = ktime_get();
2912503f7baSArnd Bergmann 		if (cl->ts_rx) {
2922503f7baSArnd Bergmann 			ktime_t ts_diff = ktime_sub(cl->ts_out_fc, cl->ts_rx);
2932503f7baSArnd Bergmann 			if (ktime_after(ts_diff, cl->ts_max_fc_delay))
2943703f53bSSrinivas Pandruvada 				cl->ts_max_fc_delay = ts_diff;
2953703f53bSSrinivas Pandruvada 		}
2963703f53bSSrinivas Pandruvada 	} else {
2973703f53bSSrinivas Pandruvada 		++cl->err_send_fc;
2983703f53bSSrinivas Pandruvada 	}
2993703f53bSSrinivas Pandruvada 
3003703f53bSSrinivas Pandruvada 	spin_unlock_irqrestore(&cl->fc_spinlock, flags);
3013703f53bSSrinivas Pandruvada 	return	rv;
3023703f53bSSrinivas Pandruvada }
3033703f53bSSrinivas Pandruvada 
3043703f53bSSrinivas Pandruvada /**
3053703f53bSSrinivas Pandruvada  * ishtp_hbm_cl_disconnect_req() - Send disconnect request
3063703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
3073703f53bSSrinivas Pandruvada  * @cl: ISHTP client instance
3083703f53bSSrinivas Pandruvada  *
3093703f53bSSrinivas Pandruvada  * Send disconnect message to fw
3103703f53bSSrinivas Pandruvada  *
3113703f53bSSrinivas Pandruvada  * Return: 0 if success else error code
3123703f53bSSrinivas Pandruvada  */
3133703f53bSSrinivas Pandruvada int ishtp_hbm_cl_disconnect_req(struct ishtp_device *dev, struct ishtp_cl *cl)
3143703f53bSSrinivas Pandruvada {
3153703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr hdr;
31609cc8b36SHong Liu 	struct hbm_client_connect_request disconn_req;
31709cc8b36SHong Liu 	const size_t len = sizeof(disconn_req);
3183703f53bSSrinivas Pandruvada 
31909cc8b36SHong Liu 	ishtp_hbm_hdr(&hdr, len);
32009cc8b36SHong Liu 	ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, &disconn_req, len);
3213703f53bSSrinivas Pandruvada 
32209cc8b36SHong Liu 	return ishtp_write_message(dev, &hdr, &disconn_req);
3233703f53bSSrinivas Pandruvada }
3243703f53bSSrinivas Pandruvada 
3253703f53bSSrinivas Pandruvada /**
3263703f53bSSrinivas Pandruvada  * ishtp_hbm_cl_disconnect_res() - Get disconnect response
3273703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
3283703f53bSSrinivas Pandruvada  * @rs: Response message
3293703f53bSSrinivas Pandruvada  *
3303703f53bSSrinivas Pandruvada  * Received disconnect response from fw
3313703f53bSSrinivas Pandruvada  */
3323703f53bSSrinivas Pandruvada static void ishtp_hbm_cl_disconnect_res(struct ishtp_device *dev,
3333703f53bSSrinivas Pandruvada 	struct hbm_client_connect_response *rs)
3343703f53bSSrinivas Pandruvada {
3353703f53bSSrinivas Pandruvada 	struct ishtp_cl *cl = NULL;
3363703f53bSSrinivas Pandruvada 	unsigned long	flags;
3373703f53bSSrinivas Pandruvada 
3383703f53bSSrinivas Pandruvada 	spin_lock_irqsave(&dev->cl_list_lock, flags);
3393703f53bSSrinivas Pandruvada 	list_for_each_entry(cl, &dev->cl_list, link) {
3403703f53bSSrinivas Pandruvada 		if (!rs->status && ishtp_hbm_cl_addr_equal(cl, rs)) {
3413703f53bSSrinivas Pandruvada 			cl->state = ISHTP_CL_DISCONNECTED;
3426d290391SSrinivas Pandruvada 			wake_up_interruptible(&cl->wait_ctrl_res);
3433703f53bSSrinivas Pandruvada 			break;
3443703f53bSSrinivas Pandruvada 		}
3453703f53bSSrinivas Pandruvada 	}
3463703f53bSSrinivas Pandruvada 	spin_unlock_irqrestore(&dev->cl_list_lock, flags);
3473703f53bSSrinivas Pandruvada }
3483703f53bSSrinivas Pandruvada 
3493703f53bSSrinivas Pandruvada /**
3503703f53bSSrinivas Pandruvada  * ishtp_hbm_cl_connect_req() - Send connect request
3513703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
3523703f53bSSrinivas Pandruvada  * @cl: client device instance
3533703f53bSSrinivas Pandruvada  *
3543703f53bSSrinivas Pandruvada  * Send connection request to specific fw client
3553703f53bSSrinivas Pandruvada  *
3563703f53bSSrinivas Pandruvada  * Return: 0 if success else error code
3573703f53bSSrinivas Pandruvada  */
3583703f53bSSrinivas Pandruvada int ishtp_hbm_cl_connect_req(struct ishtp_device *dev, struct ishtp_cl *cl)
3593703f53bSSrinivas Pandruvada {
3603703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr hdr;
36109cc8b36SHong Liu 	struct hbm_client_connect_request conn_req;
36209cc8b36SHong Liu 	const size_t len = sizeof(conn_req);
3633703f53bSSrinivas Pandruvada 
36409cc8b36SHong Liu 	ishtp_hbm_hdr(&hdr, len);
36509cc8b36SHong Liu 	ishtp_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, &conn_req, len);
3663703f53bSSrinivas Pandruvada 
36709cc8b36SHong Liu 	return ishtp_write_message(dev, &hdr, &conn_req);
3683703f53bSSrinivas Pandruvada }
3693703f53bSSrinivas Pandruvada 
3703703f53bSSrinivas Pandruvada /**
3713703f53bSSrinivas Pandruvada  * ishtp_hbm_cl_connect_res() - Get connect response
3723703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
3733703f53bSSrinivas Pandruvada  * @rs: Response message
3743703f53bSSrinivas Pandruvada  *
3753703f53bSSrinivas Pandruvada  * Received connect response from fw
3763703f53bSSrinivas Pandruvada  */
3773703f53bSSrinivas Pandruvada static void ishtp_hbm_cl_connect_res(struct ishtp_device *dev,
3783703f53bSSrinivas Pandruvada 	struct hbm_client_connect_response *rs)
3793703f53bSSrinivas Pandruvada {
3803703f53bSSrinivas Pandruvada 	struct ishtp_cl *cl = NULL;
3813703f53bSSrinivas Pandruvada 	unsigned long	flags;
3823703f53bSSrinivas Pandruvada 
3833703f53bSSrinivas Pandruvada 	spin_lock_irqsave(&dev->cl_list_lock, flags);
3843703f53bSSrinivas Pandruvada 	list_for_each_entry(cl, &dev->cl_list, link) {
3853703f53bSSrinivas Pandruvada 		if (ishtp_hbm_cl_addr_equal(cl, rs)) {
3863703f53bSSrinivas Pandruvada 			if (!rs->status) {
3873703f53bSSrinivas Pandruvada 				cl->state = ISHTP_CL_CONNECTED;
3883703f53bSSrinivas Pandruvada 				cl->status = 0;
3893703f53bSSrinivas Pandruvada 			} else {
3903703f53bSSrinivas Pandruvada 				cl->state = ISHTP_CL_DISCONNECTED;
3913703f53bSSrinivas Pandruvada 				cl->status = -ENODEV;
3923703f53bSSrinivas Pandruvada 			}
3936d290391SSrinivas Pandruvada 			wake_up_interruptible(&cl->wait_ctrl_res);
3943703f53bSSrinivas Pandruvada 			break;
3953703f53bSSrinivas Pandruvada 		}
3963703f53bSSrinivas Pandruvada 	}
3973703f53bSSrinivas Pandruvada 	spin_unlock_irqrestore(&dev->cl_list_lock, flags);
3983703f53bSSrinivas Pandruvada }
3993703f53bSSrinivas Pandruvada 
4003703f53bSSrinivas Pandruvada /**
401*15484948SLee Jones  * ishtp_hbm_fw_disconnect_req() - Receive disconnect request
4023703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
4033703f53bSSrinivas Pandruvada  * @disconnect_req: disconnect request structure
4043703f53bSSrinivas Pandruvada  *
40576f8cf6eSGeert Uytterhoeven  * Disconnect request bus message from the fw. Send disconnect response.
4063703f53bSSrinivas Pandruvada  */
4073703f53bSSrinivas Pandruvada static void ishtp_hbm_fw_disconnect_req(struct ishtp_device *dev,
4083703f53bSSrinivas Pandruvada 	struct hbm_client_connect_request *disconnect_req)
4093703f53bSSrinivas Pandruvada {
4103703f53bSSrinivas Pandruvada 	struct ishtp_cl *cl;
4113703f53bSSrinivas Pandruvada 	const size_t len = sizeof(struct hbm_client_connect_response);
4123703f53bSSrinivas Pandruvada 	unsigned long	flags;
4133703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr hdr;
4143703f53bSSrinivas Pandruvada 	unsigned char data[4];	/* All HBM messages are 4 bytes */
4153703f53bSSrinivas Pandruvada 
4163703f53bSSrinivas Pandruvada 	spin_lock_irqsave(&dev->cl_list_lock, flags);
4173703f53bSSrinivas Pandruvada 	list_for_each_entry(cl, &dev->cl_list, link) {
4183703f53bSSrinivas Pandruvada 		if (ishtp_hbm_cl_addr_equal(cl, disconnect_req)) {
4193703f53bSSrinivas Pandruvada 			cl->state = ISHTP_CL_DISCONNECTED;
4203703f53bSSrinivas Pandruvada 
4213703f53bSSrinivas Pandruvada 			/* send disconnect response */
4223703f53bSSrinivas Pandruvada 			ishtp_hbm_hdr(&hdr, len);
4233703f53bSSrinivas Pandruvada 			ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD, data,
4243703f53bSSrinivas Pandruvada 				len);
4253703f53bSSrinivas Pandruvada 			ishtp_write_message(dev, &hdr, data);
4263703f53bSSrinivas Pandruvada 			break;
4273703f53bSSrinivas Pandruvada 		}
4283703f53bSSrinivas Pandruvada 	}
4293703f53bSSrinivas Pandruvada 	spin_unlock_irqrestore(&dev->cl_list_lock, flags);
4303703f53bSSrinivas Pandruvada }
4313703f53bSSrinivas Pandruvada 
4323703f53bSSrinivas Pandruvada /**
433*15484948SLee Jones  * ishtp_hbm_dma_xfer_ack() - Receive transfer ACK
4343703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
4353703f53bSSrinivas Pandruvada  * @dma_xfer: HBM transfer message
4363703f53bSSrinivas Pandruvada  *
4373703f53bSSrinivas Pandruvada  * Receive ack for ISHTP-over-DMA client message
4383703f53bSSrinivas Pandruvada  */
4393703f53bSSrinivas Pandruvada static void ishtp_hbm_dma_xfer_ack(struct ishtp_device *dev,
4403703f53bSSrinivas Pandruvada 				   struct dma_xfer_hbm *dma_xfer)
4413703f53bSSrinivas Pandruvada {
4423703f53bSSrinivas Pandruvada 	void	*msg;
4433703f53bSSrinivas Pandruvada 	uint64_t	offs;
4443703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr	*ishtp_hdr =
4453703f53bSSrinivas Pandruvada 		(struct ishtp_msg_hdr *)&dev->ishtp_msg_hdr;
4463703f53bSSrinivas Pandruvada 	unsigned int	msg_offs;
4473703f53bSSrinivas Pandruvada 	struct ishtp_cl *cl;
4483703f53bSSrinivas Pandruvada 
4493703f53bSSrinivas Pandruvada 	for (msg_offs = 0; msg_offs < ishtp_hdr->length;
4503703f53bSSrinivas Pandruvada 		msg_offs += sizeof(struct dma_xfer_hbm)) {
4513703f53bSSrinivas Pandruvada 		offs = dma_xfer->msg_addr - dev->ishtp_host_dma_tx_buf_phys;
4523703f53bSSrinivas Pandruvada 		if (offs > dev->ishtp_host_dma_tx_buf_size) {
4533703f53bSSrinivas Pandruvada 			dev_err(dev->devc, "Bad DMA Tx ack message address\n");
4543703f53bSSrinivas Pandruvada 			return;
4553703f53bSSrinivas Pandruvada 		}
4563703f53bSSrinivas Pandruvada 		if (dma_xfer->msg_length >
4573703f53bSSrinivas Pandruvada 				dev->ishtp_host_dma_tx_buf_size - offs) {
4583703f53bSSrinivas Pandruvada 			dev_err(dev->devc, "Bad DMA Tx ack message size\n");
4593703f53bSSrinivas Pandruvada 			return;
4603703f53bSSrinivas Pandruvada 		}
4613703f53bSSrinivas Pandruvada 
4623703f53bSSrinivas Pandruvada 		/* logical address of the acked mem */
4633703f53bSSrinivas Pandruvada 		msg = (unsigned char *)dev->ishtp_host_dma_tx_buf + offs;
4643703f53bSSrinivas Pandruvada 		ishtp_cl_release_dma_acked_mem(dev, msg, dma_xfer->msg_length);
4653703f53bSSrinivas Pandruvada 
4663703f53bSSrinivas Pandruvada 		list_for_each_entry(cl, &dev->cl_list, link) {
4673703f53bSSrinivas Pandruvada 			if (cl->fw_client_id == dma_xfer->fw_client_id &&
4683703f53bSSrinivas Pandruvada 			    cl->host_client_id == dma_xfer->host_client_id)
4693703f53bSSrinivas Pandruvada 				/*
4703703f53bSSrinivas Pandruvada 				 * in case that a single ack may be sent
4713703f53bSSrinivas Pandruvada 				 * over several dma transfers, and the last msg
4723703f53bSSrinivas Pandruvada 				 * addr was inside the acked memory, but not in
4733703f53bSSrinivas Pandruvada 				 * its start
4743703f53bSSrinivas Pandruvada 				 */
4753703f53bSSrinivas Pandruvada 				if (cl->last_dma_addr >=
4763703f53bSSrinivas Pandruvada 							(unsigned char *)msg &&
4773703f53bSSrinivas Pandruvada 						cl->last_dma_addr <
4783703f53bSSrinivas Pandruvada 						(unsigned char *)msg +
4793703f53bSSrinivas Pandruvada 						dma_xfer->msg_length) {
4803703f53bSSrinivas Pandruvada 					cl->last_dma_acked = 1;
4813703f53bSSrinivas Pandruvada 
4823703f53bSSrinivas Pandruvada 					if (!list_empty(&cl->tx_list.list) &&
4833703f53bSSrinivas Pandruvada 						cl->ishtp_flow_ctrl_creds) {
4843703f53bSSrinivas Pandruvada 						/*
4853703f53bSSrinivas Pandruvada 						 * start sending the first msg
4863703f53bSSrinivas Pandruvada 						 */
4873703f53bSSrinivas Pandruvada 						ishtp_cl_send_msg(dev, cl);
4883703f53bSSrinivas Pandruvada 					}
4893703f53bSSrinivas Pandruvada 				}
4903703f53bSSrinivas Pandruvada 		}
4913703f53bSSrinivas Pandruvada 		++dma_xfer;
4923703f53bSSrinivas Pandruvada 	}
4933703f53bSSrinivas Pandruvada }
4943703f53bSSrinivas Pandruvada 
4953703f53bSSrinivas Pandruvada /**
4963703f53bSSrinivas Pandruvada  * ishtp_hbm_dma_xfer() - Receive DMA transfer message
4973703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
4983703f53bSSrinivas Pandruvada  * @dma_xfer: HBM transfer message
4993703f53bSSrinivas Pandruvada  *
5003703f53bSSrinivas Pandruvada  * Receive ISHTP-over-DMA client message
5013703f53bSSrinivas Pandruvada  */
5023703f53bSSrinivas Pandruvada static void ishtp_hbm_dma_xfer(struct ishtp_device *dev,
5033703f53bSSrinivas Pandruvada 			       struct dma_xfer_hbm *dma_xfer)
5043703f53bSSrinivas Pandruvada {
5053703f53bSSrinivas Pandruvada 	void	*msg;
5063703f53bSSrinivas Pandruvada 	uint64_t	offs;
5073703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr	hdr;
5083703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr	*ishtp_hdr =
5093703f53bSSrinivas Pandruvada 		(struct ishtp_msg_hdr *) &dev->ishtp_msg_hdr;
5103703f53bSSrinivas Pandruvada 	struct dma_xfer_hbm	*prm = dma_xfer;
5113703f53bSSrinivas Pandruvada 	unsigned int	msg_offs;
5123703f53bSSrinivas Pandruvada 
5133703f53bSSrinivas Pandruvada 	for (msg_offs = 0; msg_offs < ishtp_hdr->length;
5143703f53bSSrinivas Pandruvada 		msg_offs += sizeof(struct dma_xfer_hbm)) {
5153703f53bSSrinivas Pandruvada 
5163703f53bSSrinivas Pandruvada 		offs = dma_xfer->msg_addr - dev->ishtp_host_dma_rx_buf_phys;
5173703f53bSSrinivas Pandruvada 		if (offs > dev->ishtp_host_dma_rx_buf_size) {
5183703f53bSSrinivas Pandruvada 			dev_err(dev->devc, "Bad DMA Rx message address\n");
5193703f53bSSrinivas Pandruvada 			return;
5203703f53bSSrinivas Pandruvada 		}
5213703f53bSSrinivas Pandruvada 		if (dma_xfer->msg_length >
5223703f53bSSrinivas Pandruvada 				dev->ishtp_host_dma_rx_buf_size - offs) {
5233703f53bSSrinivas Pandruvada 			dev_err(dev->devc, "Bad DMA Rx message size\n");
5243703f53bSSrinivas Pandruvada 			return;
5253703f53bSSrinivas Pandruvada 		}
5263703f53bSSrinivas Pandruvada 		msg = dev->ishtp_host_dma_rx_buf + offs;
5273703f53bSSrinivas Pandruvada 		recv_ishtp_cl_msg_dma(dev, msg, dma_xfer);
5283703f53bSSrinivas Pandruvada 		dma_xfer->hbm = DMA_XFER_ACK;	/* Prepare for response */
5293703f53bSSrinivas Pandruvada 		++dma_xfer;
5303703f53bSSrinivas Pandruvada 	}
5313703f53bSSrinivas Pandruvada 
5323703f53bSSrinivas Pandruvada 	/* Send DMA_XFER_ACK [...] */
5333703f53bSSrinivas Pandruvada 	ishtp_hbm_hdr(&hdr, ishtp_hdr->length);
5343703f53bSSrinivas Pandruvada 	ishtp_write_message(dev, &hdr, (unsigned char *)prm);
5353703f53bSSrinivas Pandruvada }
5363703f53bSSrinivas Pandruvada 
5373703f53bSSrinivas Pandruvada /**
5383703f53bSSrinivas Pandruvada  * ishtp_hbm_dispatch() - HBM dispatch function
5393703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
5403703f53bSSrinivas Pandruvada  * @hdr: bus message
5413703f53bSSrinivas Pandruvada  *
5423703f53bSSrinivas Pandruvada  * Bottom half read routine after ISR to handle the read bus message cmd
5433703f53bSSrinivas Pandruvada  * processing
5443703f53bSSrinivas Pandruvada  */
5453703f53bSSrinivas Pandruvada void ishtp_hbm_dispatch(struct ishtp_device *dev,
5463703f53bSSrinivas Pandruvada 			struct ishtp_bus_message *hdr)
5473703f53bSSrinivas Pandruvada {
5483703f53bSSrinivas Pandruvada 	struct ishtp_bus_message *ishtp_msg;
5493703f53bSSrinivas Pandruvada 	struct ishtp_fw_client *fw_client;
5503703f53bSSrinivas Pandruvada 	struct hbm_host_version_response *version_res;
5513703f53bSSrinivas Pandruvada 	struct hbm_client_connect_response *connect_res;
5523703f53bSSrinivas Pandruvada 	struct hbm_client_connect_response *disconnect_res;
5533703f53bSSrinivas Pandruvada 	struct hbm_client_connect_request *disconnect_req;
5543703f53bSSrinivas Pandruvada 	struct hbm_props_response *props_res;
5553703f53bSSrinivas Pandruvada 	struct hbm_host_enum_response *enum_res;
5563703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr ishtp_hdr;
5573703f53bSSrinivas Pandruvada 	struct dma_alloc_notify	dma_alloc_notify;
5583703f53bSSrinivas Pandruvada 	struct dma_xfer_hbm	*dma_xfer;
5593703f53bSSrinivas Pandruvada 
5603703f53bSSrinivas Pandruvada 	ishtp_msg = hdr;
5613703f53bSSrinivas Pandruvada 
5623703f53bSSrinivas Pandruvada 	switch (ishtp_msg->hbm_cmd) {
5633703f53bSSrinivas Pandruvada 	case HOST_START_RES_CMD:
5643703f53bSSrinivas Pandruvada 		version_res = (struct hbm_host_version_response *)ishtp_msg;
5653703f53bSSrinivas Pandruvada 		if (!version_res->host_version_supported) {
5663703f53bSSrinivas Pandruvada 			dev->version = version_res->fw_max_version;
5673703f53bSSrinivas Pandruvada 
5683703f53bSSrinivas Pandruvada 			dev->hbm_state = ISHTP_HBM_STOPPED;
5693703f53bSSrinivas Pandruvada 			ishtp_hbm_stop_req(dev);
5703703f53bSSrinivas Pandruvada 			return;
5713703f53bSSrinivas Pandruvada 		}
5723703f53bSSrinivas Pandruvada 
5733703f53bSSrinivas Pandruvada 		dev->version.major_version = HBM_MAJOR_VERSION;
5743703f53bSSrinivas Pandruvada 		dev->version.minor_version = HBM_MINOR_VERSION;
5753703f53bSSrinivas Pandruvada 		if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS &&
5763703f53bSSrinivas Pandruvada 				dev->hbm_state == ISHTP_HBM_START) {
5773703f53bSSrinivas Pandruvada 			dev->hbm_state = ISHTP_HBM_STARTED;
5783703f53bSSrinivas Pandruvada 			ishtp_hbm_enum_clients_req(dev);
5793703f53bSSrinivas Pandruvada 		} else {
5803703f53bSSrinivas Pandruvada 			dev_err(dev->devc,
5813703f53bSSrinivas Pandruvada 				"reset: wrong host start response\n");
5823703f53bSSrinivas Pandruvada 			/* BUG: why do we arrive here? */
5833703f53bSSrinivas Pandruvada 			ish_hw_reset(dev);
5843703f53bSSrinivas Pandruvada 			return;
5853703f53bSSrinivas Pandruvada 		}
5863703f53bSSrinivas Pandruvada 
5873703f53bSSrinivas Pandruvada 		wake_up_interruptible(&dev->wait_hbm_recvd_msg);
5883703f53bSSrinivas Pandruvada 		break;
5893703f53bSSrinivas Pandruvada 
5903703f53bSSrinivas Pandruvada 	case CLIENT_CONNECT_RES_CMD:
5913703f53bSSrinivas Pandruvada 		connect_res = (struct hbm_client_connect_response *)ishtp_msg;
5923703f53bSSrinivas Pandruvada 		ishtp_hbm_cl_connect_res(dev, connect_res);
5933703f53bSSrinivas Pandruvada 		break;
5943703f53bSSrinivas Pandruvada 
5953703f53bSSrinivas Pandruvada 	case CLIENT_DISCONNECT_RES_CMD:
5963703f53bSSrinivas Pandruvada 		disconnect_res =
5973703f53bSSrinivas Pandruvada 			(struct hbm_client_connect_response *)ishtp_msg;
5983703f53bSSrinivas Pandruvada 		ishtp_hbm_cl_disconnect_res(dev, disconnect_res);
5993703f53bSSrinivas Pandruvada 		break;
6003703f53bSSrinivas Pandruvada 
6013703f53bSSrinivas Pandruvada 	case HOST_CLIENT_PROPERTIES_RES_CMD:
6023703f53bSSrinivas Pandruvada 		props_res = (struct hbm_props_response *)ishtp_msg;
6033703f53bSSrinivas Pandruvada 		fw_client = &dev->fw_clients[dev->fw_client_presentation_num];
6043703f53bSSrinivas Pandruvada 
6053703f53bSSrinivas Pandruvada 		if (props_res->status || !dev->fw_clients) {
6063703f53bSSrinivas Pandruvada 			dev_err(dev->devc,
6073703f53bSSrinivas Pandruvada 			"reset: properties response hbm wrong status\n");
6083703f53bSSrinivas Pandruvada 			ish_hw_reset(dev);
6093703f53bSSrinivas Pandruvada 			return;
6103703f53bSSrinivas Pandruvada 		}
6113703f53bSSrinivas Pandruvada 
6123703f53bSSrinivas Pandruvada 		if (fw_client->client_id != props_res->address) {
6133703f53bSSrinivas Pandruvada 			dev_err(dev->devc,
6143703f53bSSrinivas Pandruvada 				"reset: host properties response address mismatch [%02X %02X]\n",
6153703f53bSSrinivas Pandruvada 				fw_client->client_id, props_res->address);
6163703f53bSSrinivas Pandruvada 			ish_hw_reset(dev);
6173703f53bSSrinivas Pandruvada 			return;
6183703f53bSSrinivas Pandruvada 		}
6193703f53bSSrinivas Pandruvada 
6203703f53bSSrinivas Pandruvada 		if (dev->dev_state != ISHTP_DEV_INIT_CLIENTS ||
6213703f53bSSrinivas Pandruvada 			dev->hbm_state != ISHTP_HBM_CLIENT_PROPERTIES) {
6223703f53bSSrinivas Pandruvada 			dev_err(dev->devc,
6233703f53bSSrinivas Pandruvada 				"reset: unexpected properties response\n");
6243703f53bSSrinivas Pandruvada 			ish_hw_reset(dev);
6253703f53bSSrinivas Pandruvada 			return;
6263703f53bSSrinivas Pandruvada 		}
6273703f53bSSrinivas Pandruvada 
6283703f53bSSrinivas Pandruvada 		fw_client->props = props_res->client_properties;
6293703f53bSSrinivas Pandruvada 		dev->fw_client_index++;
6303703f53bSSrinivas Pandruvada 		dev->fw_client_presentation_num++;
6313703f53bSSrinivas Pandruvada 
6323703f53bSSrinivas Pandruvada 		/* request property for the next client */
6333703f53bSSrinivas Pandruvada 		ishtp_hbm_prop_req(dev);
6343703f53bSSrinivas Pandruvada 
6353703f53bSSrinivas Pandruvada 		if (dev->dev_state != ISHTP_DEV_ENABLED)
6363703f53bSSrinivas Pandruvada 			break;
6373703f53bSSrinivas Pandruvada 
6383703f53bSSrinivas Pandruvada 		if (!ishtp_use_dma_transfer())
6393703f53bSSrinivas Pandruvada 			break;
6403703f53bSSrinivas Pandruvada 
6413703f53bSSrinivas Pandruvada 		dev_dbg(dev->devc, "Requesting to use DMA\n");
6423703f53bSSrinivas Pandruvada 		ishtp_cl_alloc_dma_buf(dev);
6433703f53bSSrinivas Pandruvada 		if (dev->ishtp_host_dma_rx_buf) {
6443703f53bSSrinivas Pandruvada 			const size_t len = sizeof(dma_alloc_notify);
6453703f53bSSrinivas Pandruvada 
6463703f53bSSrinivas Pandruvada 			memset(&dma_alloc_notify, 0, sizeof(dma_alloc_notify));
6473703f53bSSrinivas Pandruvada 			dma_alloc_notify.hbm = DMA_BUFFER_ALLOC_NOTIFY;
6483703f53bSSrinivas Pandruvada 			dma_alloc_notify.buf_size =
6493703f53bSSrinivas Pandruvada 					dev->ishtp_host_dma_rx_buf_size;
6503703f53bSSrinivas Pandruvada 			dma_alloc_notify.buf_address =
6513703f53bSSrinivas Pandruvada 					dev->ishtp_host_dma_rx_buf_phys;
6523703f53bSSrinivas Pandruvada 			ishtp_hbm_hdr(&ishtp_hdr, len);
6533703f53bSSrinivas Pandruvada 			ishtp_write_message(dev, &ishtp_hdr,
6543703f53bSSrinivas Pandruvada 				(unsigned char *)&dma_alloc_notify);
6553703f53bSSrinivas Pandruvada 		}
6563703f53bSSrinivas Pandruvada 
6573703f53bSSrinivas Pandruvada 		break;
6583703f53bSSrinivas Pandruvada 
6593703f53bSSrinivas Pandruvada 	case HOST_ENUM_RES_CMD:
6603703f53bSSrinivas Pandruvada 		enum_res = (struct hbm_host_enum_response *) ishtp_msg;
6613703f53bSSrinivas Pandruvada 		memcpy(dev->fw_clients_map, enum_res->valid_addresses, 32);
6623703f53bSSrinivas Pandruvada 		if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS &&
6633703f53bSSrinivas Pandruvada 			dev->hbm_state == ISHTP_HBM_ENUM_CLIENTS) {
6643703f53bSSrinivas Pandruvada 			dev->fw_client_presentation_num = 0;
6653703f53bSSrinivas Pandruvada 			dev->fw_client_index = 0;
6663703f53bSSrinivas Pandruvada 
6673703f53bSSrinivas Pandruvada 			ishtp_hbm_fw_cl_allocate(dev);
6683703f53bSSrinivas Pandruvada 			dev->hbm_state = ISHTP_HBM_CLIENT_PROPERTIES;
6693703f53bSSrinivas Pandruvada 
6703703f53bSSrinivas Pandruvada 			/* first property request */
6713703f53bSSrinivas Pandruvada 			ishtp_hbm_prop_req(dev);
6723703f53bSSrinivas Pandruvada 		} else {
6733703f53bSSrinivas Pandruvada 			dev_err(dev->devc,
6743703f53bSSrinivas Pandruvada 			      "reset: unexpected enumeration response hbm\n");
6753703f53bSSrinivas Pandruvada 			ish_hw_reset(dev);
6763703f53bSSrinivas Pandruvada 			return;
6773703f53bSSrinivas Pandruvada 		}
6783703f53bSSrinivas Pandruvada 		break;
6793703f53bSSrinivas Pandruvada 
6803703f53bSSrinivas Pandruvada 	case HOST_STOP_RES_CMD:
6813703f53bSSrinivas Pandruvada 		if (dev->hbm_state != ISHTP_HBM_STOPPED)
6823703f53bSSrinivas Pandruvada 			dev_err(dev->devc, "unexpected stop response\n");
6833703f53bSSrinivas Pandruvada 
6843703f53bSSrinivas Pandruvada 		dev->dev_state = ISHTP_DEV_DISABLED;
6853703f53bSSrinivas Pandruvada 		dev_info(dev->devc, "reset: FW stop response\n");
6863703f53bSSrinivas Pandruvada 		ish_hw_reset(dev);
6873703f53bSSrinivas Pandruvada 		break;
6883703f53bSSrinivas Pandruvada 
6893703f53bSSrinivas Pandruvada 	case CLIENT_DISCONNECT_REQ_CMD:
6903703f53bSSrinivas Pandruvada 		/* search for client */
6913703f53bSSrinivas Pandruvada 		disconnect_req =
6923703f53bSSrinivas Pandruvada 			(struct hbm_client_connect_request *)ishtp_msg;
6933703f53bSSrinivas Pandruvada 		ishtp_hbm_fw_disconnect_req(dev, disconnect_req);
6943703f53bSSrinivas Pandruvada 		break;
6953703f53bSSrinivas Pandruvada 
6963703f53bSSrinivas Pandruvada 	case FW_STOP_REQ_CMD:
6973703f53bSSrinivas Pandruvada 		dev->hbm_state = ISHTP_HBM_STOPPED;
6983703f53bSSrinivas Pandruvada 		break;
6993703f53bSSrinivas Pandruvada 
7003703f53bSSrinivas Pandruvada 	case DMA_BUFFER_ALLOC_RESPONSE:
7013703f53bSSrinivas Pandruvada 		dev->ishtp_host_dma_enabled = 1;
7023703f53bSSrinivas Pandruvada 		break;
7033703f53bSSrinivas Pandruvada 
7043703f53bSSrinivas Pandruvada 	case DMA_XFER:
7053703f53bSSrinivas Pandruvada 		dma_xfer = (struct dma_xfer_hbm *)ishtp_msg;
7063703f53bSSrinivas Pandruvada 		if (!dev->ishtp_host_dma_enabled) {
7073703f53bSSrinivas Pandruvada 			dev_err(dev->devc,
7083703f53bSSrinivas Pandruvada 				"DMA XFER requested but DMA is not enabled\n");
7093703f53bSSrinivas Pandruvada 			break;
7103703f53bSSrinivas Pandruvada 		}
7113703f53bSSrinivas Pandruvada 		ishtp_hbm_dma_xfer(dev, dma_xfer);
7123703f53bSSrinivas Pandruvada 		break;
7133703f53bSSrinivas Pandruvada 
7143703f53bSSrinivas Pandruvada 	case DMA_XFER_ACK:
7153703f53bSSrinivas Pandruvada 		dma_xfer = (struct dma_xfer_hbm *)ishtp_msg;
7163703f53bSSrinivas Pandruvada 		if (!dev->ishtp_host_dma_enabled ||
7173703f53bSSrinivas Pandruvada 		    !dev->ishtp_host_dma_tx_buf) {
7183703f53bSSrinivas Pandruvada 			dev_err(dev->devc,
7193703f53bSSrinivas Pandruvada 				"DMA XFER acked but DMA Tx is not enabled\n");
7203703f53bSSrinivas Pandruvada 			break;
7213703f53bSSrinivas Pandruvada 		}
7223703f53bSSrinivas Pandruvada 		ishtp_hbm_dma_xfer_ack(dev, dma_xfer);
7233703f53bSSrinivas Pandruvada 		break;
7243703f53bSSrinivas Pandruvada 
7253703f53bSSrinivas Pandruvada 	default:
7263703f53bSSrinivas Pandruvada 		dev_err(dev->devc, "unknown HBM: %u\n",
7273703f53bSSrinivas Pandruvada 			(unsigned int)ishtp_msg->hbm_cmd);
7283703f53bSSrinivas Pandruvada 
7293703f53bSSrinivas Pandruvada 		break;
7303703f53bSSrinivas Pandruvada 	}
7313703f53bSSrinivas Pandruvada }
7323703f53bSSrinivas Pandruvada 
7333703f53bSSrinivas Pandruvada /**
7343703f53bSSrinivas Pandruvada  * bh_hbm_work_fn() - HBM work function
7353703f53bSSrinivas Pandruvada  * @work: work struct
7363703f53bSSrinivas Pandruvada  *
7373703f53bSSrinivas Pandruvada  * Bottom half processing work function (instead of thread handler)
7383703f53bSSrinivas Pandruvada  * for processing hbm messages
7393703f53bSSrinivas Pandruvada  */
7403703f53bSSrinivas Pandruvada void	bh_hbm_work_fn(struct work_struct *work)
7413703f53bSSrinivas Pandruvada {
7423703f53bSSrinivas Pandruvada 	unsigned long	flags;
7433703f53bSSrinivas Pandruvada 	struct ishtp_device	*dev;
7443703f53bSSrinivas Pandruvada 	unsigned char	hbm[IPC_PAYLOAD_SIZE];
7453703f53bSSrinivas Pandruvada 
7463703f53bSSrinivas Pandruvada 	dev = container_of(work, struct ishtp_device, bh_hbm_work);
7473703f53bSSrinivas Pandruvada 	spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
7483703f53bSSrinivas Pandruvada 	if (dev->rd_msg_fifo_head != dev->rd_msg_fifo_tail) {
7493703f53bSSrinivas Pandruvada 		memcpy(hbm, dev->rd_msg_fifo + dev->rd_msg_fifo_head,
7503703f53bSSrinivas Pandruvada 			IPC_PAYLOAD_SIZE);
7513703f53bSSrinivas Pandruvada 		dev->rd_msg_fifo_head =
7523703f53bSSrinivas Pandruvada 			(dev->rd_msg_fifo_head + IPC_PAYLOAD_SIZE) %
7533703f53bSSrinivas Pandruvada 			(RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE);
7543703f53bSSrinivas Pandruvada 		spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
7553703f53bSSrinivas Pandruvada 		ishtp_hbm_dispatch(dev, (struct ishtp_bus_message *)hbm);
7563703f53bSSrinivas Pandruvada 	} else {
7573703f53bSSrinivas Pandruvada 		spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
7583703f53bSSrinivas Pandruvada 	}
7593703f53bSSrinivas Pandruvada }
7603703f53bSSrinivas Pandruvada 
7613703f53bSSrinivas Pandruvada /**
7623703f53bSSrinivas Pandruvada  * recv_hbm() - Receive HBM message
7633703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
7643703f53bSSrinivas Pandruvada  * @ishtp_hdr: received bus message
7653703f53bSSrinivas Pandruvada  *
7663703f53bSSrinivas Pandruvada  * Receive and process ISHTP bus messages in ISR context. This will schedule
7673703f53bSSrinivas Pandruvada  * work function to process message
7683703f53bSSrinivas Pandruvada  */
7693703f53bSSrinivas Pandruvada void	recv_hbm(struct ishtp_device *dev, struct ishtp_msg_hdr *ishtp_hdr)
7703703f53bSSrinivas Pandruvada {
7713703f53bSSrinivas Pandruvada 	uint8_t	rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE];
7723703f53bSSrinivas Pandruvada 	struct ishtp_bus_message	*ishtp_msg =
7733703f53bSSrinivas Pandruvada 		(struct ishtp_bus_message *)rd_msg_buf;
7743703f53bSSrinivas Pandruvada 	unsigned long	flags;
7753703f53bSSrinivas Pandruvada 
7763703f53bSSrinivas Pandruvada 	dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length);
7773703f53bSSrinivas Pandruvada 
7783703f53bSSrinivas Pandruvada 	/* Flow control - handle in place */
7793703f53bSSrinivas Pandruvada 	if (ishtp_msg->hbm_cmd == ISHTP_FLOW_CONTROL_CMD) {
7803703f53bSSrinivas Pandruvada 		struct hbm_flow_control *flow_control =
7813703f53bSSrinivas Pandruvada 			(struct hbm_flow_control *)ishtp_msg;
7823703f53bSSrinivas Pandruvada 		struct ishtp_cl *cl = NULL;
7833703f53bSSrinivas Pandruvada 		unsigned long	flags, tx_flags;
7843703f53bSSrinivas Pandruvada 
7853703f53bSSrinivas Pandruvada 		spin_lock_irqsave(&dev->cl_list_lock, flags);
7863703f53bSSrinivas Pandruvada 		list_for_each_entry(cl, &dev->cl_list, link) {
7873703f53bSSrinivas Pandruvada 			if (cl->host_client_id == flow_control->host_addr &&
7883703f53bSSrinivas Pandruvada 					cl->fw_client_id ==
7893703f53bSSrinivas Pandruvada 					flow_control->fw_addr) {
7903703f53bSSrinivas Pandruvada 				/*
7913703f53bSSrinivas Pandruvada 				 * NOTE: It's valid only for counting
7923703f53bSSrinivas Pandruvada 				 * flow-control implementation to receive a
7933703f53bSSrinivas Pandruvada 				 * FC in the middle of sending. Meanwhile not
7943703f53bSSrinivas Pandruvada 				 * supported
7953703f53bSSrinivas Pandruvada 				 */
7963703f53bSSrinivas Pandruvada 				if (cl->ishtp_flow_ctrl_creds)
7973703f53bSSrinivas Pandruvada 					dev_err(dev->devc,
7983703f53bSSrinivas Pandruvada 					 "recv extra FC from FW client %u (host client %u) (FC count was %d)\n",
7993703f53bSSrinivas Pandruvada 					 (unsigned int)cl->fw_client_id,
8003703f53bSSrinivas Pandruvada 					 (unsigned int)cl->host_client_id,
8013703f53bSSrinivas Pandruvada 					 cl->ishtp_flow_ctrl_creds);
8023703f53bSSrinivas Pandruvada 				else {
8033703f53bSSrinivas Pandruvada 					++cl->ishtp_flow_ctrl_creds;
8043703f53bSSrinivas Pandruvada 					++cl->ishtp_flow_ctrl_cnt;
8053703f53bSSrinivas Pandruvada 					cl->last_ipc_acked = 1;
8063703f53bSSrinivas Pandruvada 					spin_lock_irqsave(
8073703f53bSSrinivas Pandruvada 							&cl->tx_list_spinlock,
8083703f53bSSrinivas Pandruvada 							tx_flags);
8093703f53bSSrinivas Pandruvada 					if (!list_empty(&cl->tx_list.list)) {
8103703f53bSSrinivas Pandruvada 						/*
8113703f53bSSrinivas Pandruvada 						 * start sending the first msg
8123703f53bSSrinivas Pandruvada 						 *	= the callback function
8133703f53bSSrinivas Pandruvada 						 */
8143703f53bSSrinivas Pandruvada 						spin_unlock_irqrestore(
8153703f53bSSrinivas Pandruvada 							&cl->tx_list_spinlock,
8163703f53bSSrinivas Pandruvada 							tx_flags);
8173703f53bSSrinivas Pandruvada 						ishtp_cl_send_msg(dev, cl);
8183703f53bSSrinivas Pandruvada 					} else {
8193703f53bSSrinivas Pandruvada 						spin_unlock_irqrestore(
8203703f53bSSrinivas Pandruvada 							&cl->tx_list_spinlock,
8213703f53bSSrinivas Pandruvada 							tx_flags);
8223703f53bSSrinivas Pandruvada 					}
8233703f53bSSrinivas Pandruvada 				}
8243703f53bSSrinivas Pandruvada 				break;
8253703f53bSSrinivas Pandruvada 			}
8263703f53bSSrinivas Pandruvada 		}
8273703f53bSSrinivas Pandruvada 		spin_unlock_irqrestore(&dev->cl_list_lock, flags);
8283703f53bSSrinivas Pandruvada 		goto	eoi;
8293703f53bSSrinivas Pandruvada 	}
8303703f53bSSrinivas Pandruvada 
8313703f53bSSrinivas Pandruvada 	/*
8323703f53bSSrinivas Pandruvada 	 * Some messages that are safe for ISR processing and important
8333703f53bSSrinivas Pandruvada 	 * to be done "quickly" and in-order, go here
8343703f53bSSrinivas Pandruvada 	 */
8353703f53bSSrinivas Pandruvada 	if (ishtp_msg->hbm_cmd == CLIENT_CONNECT_RES_CMD ||
8363703f53bSSrinivas Pandruvada 			ishtp_msg->hbm_cmd == CLIENT_DISCONNECT_RES_CMD ||
8373703f53bSSrinivas Pandruvada 			ishtp_msg->hbm_cmd == CLIENT_DISCONNECT_REQ_CMD ||
8383703f53bSSrinivas Pandruvada 			ishtp_msg->hbm_cmd == DMA_XFER) {
8393703f53bSSrinivas Pandruvada 		ishtp_hbm_dispatch(dev, ishtp_msg);
8403703f53bSSrinivas Pandruvada 		goto	eoi;
8413703f53bSSrinivas Pandruvada 	}
8423703f53bSSrinivas Pandruvada 
8433703f53bSSrinivas Pandruvada 	/*
8443703f53bSSrinivas Pandruvada 	 * All other HBMs go here.
8453703f53bSSrinivas Pandruvada 	 * We schedule HBMs for processing serially by using system wq,
8463703f53bSSrinivas Pandruvada 	 * possibly there will be multiple HBMs scheduled at the same time.
8473703f53bSSrinivas Pandruvada 	 */
8483703f53bSSrinivas Pandruvada 	spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
8493703f53bSSrinivas Pandruvada 	if ((dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) %
8503703f53bSSrinivas Pandruvada 			(RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE) ==
8513703f53bSSrinivas Pandruvada 			dev->rd_msg_fifo_head) {
8523703f53bSSrinivas Pandruvada 		spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
8533703f53bSSrinivas Pandruvada 		dev_err(dev->devc, "BH buffer overflow, dropping HBM %u\n",
8543703f53bSSrinivas Pandruvada 			(unsigned int)ishtp_msg->hbm_cmd);
8553703f53bSSrinivas Pandruvada 		goto	eoi;
8563703f53bSSrinivas Pandruvada 	}
8573703f53bSSrinivas Pandruvada 	memcpy(dev->rd_msg_fifo + dev->rd_msg_fifo_tail, ishtp_msg,
8583703f53bSSrinivas Pandruvada 		ishtp_hdr->length);
8593703f53bSSrinivas Pandruvada 	dev->rd_msg_fifo_tail = (dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) %
8603703f53bSSrinivas Pandruvada 		(RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE);
8613703f53bSSrinivas Pandruvada 	spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
8623703f53bSSrinivas Pandruvada 	schedule_work(&dev->bh_hbm_work);
8633703f53bSSrinivas Pandruvada eoi:
8643703f53bSSrinivas Pandruvada 	return;
8653703f53bSSrinivas Pandruvada }
8663703f53bSSrinivas Pandruvada 
8673703f53bSSrinivas Pandruvada /**
8683703f53bSSrinivas Pandruvada  * recv_fixed_cl_msg() - Receive fixed client message
8693703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
8703703f53bSSrinivas Pandruvada  * @ishtp_hdr: received bus message
8713703f53bSSrinivas Pandruvada  *
8723703f53bSSrinivas Pandruvada  * Receive and process ISHTP fixed client messages (address == 0)
8733703f53bSSrinivas Pandruvada  * in ISR context
8743703f53bSSrinivas Pandruvada  */
8753703f53bSSrinivas Pandruvada void recv_fixed_cl_msg(struct ishtp_device *dev,
8763703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr *ishtp_hdr)
8773703f53bSSrinivas Pandruvada {
8783703f53bSSrinivas Pandruvada 	uint8_t rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE];
8793703f53bSSrinivas Pandruvada 
8803703f53bSSrinivas Pandruvada 	dev->print_log(dev,
8813703f53bSSrinivas Pandruvada 		"%s() got fixed client msg from client #%d\n",
8823703f53bSSrinivas Pandruvada 		__func__, ishtp_hdr->fw_addr);
8833703f53bSSrinivas Pandruvada 	dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length);
8843703f53bSSrinivas Pandruvada 	if (ishtp_hdr->fw_addr == ISHTP_SYSTEM_STATE_CLIENT_ADDR) {
8853703f53bSSrinivas Pandruvada 		struct ish_system_states_header *msg_hdr =
8863703f53bSSrinivas Pandruvada 			(struct ish_system_states_header *)rd_msg_buf;
8873703f53bSSrinivas Pandruvada 		if (msg_hdr->cmd == SYSTEM_STATE_SUBSCRIBE)
8883703f53bSSrinivas Pandruvada 			ishtp_send_resume(dev);
8893703f53bSSrinivas Pandruvada 		/* if FW request arrived here, the system is not suspended */
8903703f53bSSrinivas Pandruvada 		else
8913703f53bSSrinivas Pandruvada 			dev_err(dev->devc, "unknown fixed client msg [%02X]\n",
8923703f53bSSrinivas Pandruvada 				msg_hdr->cmd);
8933703f53bSSrinivas Pandruvada 	}
8943703f53bSSrinivas Pandruvada }
8953703f53bSSrinivas Pandruvada 
8963703f53bSSrinivas Pandruvada /**
8973703f53bSSrinivas Pandruvada  * fix_cl_hdr() - Initialize fixed client header
8983703f53bSSrinivas Pandruvada  * @hdr: message header
8993703f53bSSrinivas Pandruvada  * @length: length of message
9003703f53bSSrinivas Pandruvada  * @cl_addr: Client address
9013703f53bSSrinivas Pandruvada  *
9023703f53bSSrinivas Pandruvada  * Initialize message header for fixed client
9033703f53bSSrinivas Pandruvada  */
9043703f53bSSrinivas Pandruvada static inline void fix_cl_hdr(struct ishtp_msg_hdr *hdr, size_t length,
9053703f53bSSrinivas Pandruvada 	uint8_t cl_addr)
9063703f53bSSrinivas Pandruvada {
9073703f53bSSrinivas Pandruvada 	hdr->host_addr = 0;
9083703f53bSSrinivas Pandruvada 	hdr->fw_addr = cl_addr;
9093703f53bSSrinivas Pandruvada 	hdr->length = length;
9103703f53bSSrinivas Pandruvada 	hdr->msg_complete = 1;
9113703f53bSSrinivas Pandruvada 	hdr->reserved = 0;
9123703f53bSSrinivas Pandruvada }
9133703f53bSSrinivas Pandruvada 
9143703f53bSSrinivas Pandruvada /*** Suspend and resume notification ***/
9153703f53bSSrinivas Pandruvada 
9163703f53bSSrinivas Pandruvada static uint32_t current_state;
91794cad2ddSYe Xiang static uint32_t supported_states = SUSPEND_STATE_BIT | CONNECTED_STANDBY_STATE_BIT;
9183703f53bSSrinivas Pandruvada 
9193703f53bSSrinivas Pandruvada /**
9203703f53bSSrinivas Pandruvada  * ishtp_send_suspend() - Send suspend message to FW
9213703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
9223703f53bSSrinivas Pandruvada  *
9233703f53bSSrinivas Pandruvada  * Send suspend message to FW. This is useful for system freeze (non S3) case
9243703f53bSSrinivas Pandruvada  */
9253703f53bSSrinivas Pandruvada void ishtp_send_suspend(struct ishtp_device *dev)
9263703f53bSSrinivas Pandruvada {
9273703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr	ishtp_hdr;
9283703f53bSSrinivas Pandruvada 	struct ish_system_states_status state_status_msg;
9293703f53bSSrinivas Pandruvada 	const size_t len = sizeof(struct ish_system_states_status);
9303703f53bSSrinivas Pandruvada 
9313703f53bSSrinivas Pandruvada 	fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
9323703f53bSSrinivas Pandruvada 
9333703f53bSSrinivas Pandruvada 	memset(&state_status_msg, 0, len);
9343703f53bSSrinivas Pandruvada 	state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
9353703f53bSSrinivas Pandruvada 	state_status_msg.supported_states = supported_states;
93694cad2ddSYe Xiang 	current_state |= (SUSPEND_STATE_BIT | CONNECTED_STANDBY_STATE_BIT);
9373703f53bSSrinivas Pandruvada 	dev->print_log(dev, "%s() sends SUSPEND notification\n", __func__);
9383703f53bSSrinivas Pandruvada 	state_status_msg.states_status = current_state;
9393703f53bSSrinivas Pandruvada 
9403703f53bSSrinivas Pandruvada 	ishtp_write_message(dev, &ishtp_hdr,
9413703f53bSSrinivas Pandruvada 		(unsigned char *)&state_status_msg);
9423703f53bSSrinivas Pandruvada }
9433703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_send_suspend);
9443703f53bSSrinivas Pandruvada 
9453703f53bSSrinivas Pandruvada /**
9463703f53bSSrinivas Pandruvada  * ishtp_send_resume() - Send resume message to FW
9473703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
9483703f53bSSrinivas Pandruvada  *
9493703f53bSSrinivas Pandruvada  * Send resume message to FW. This is useful for system freeze (non S3) case
9503703f53bSSrinivas Pandruvada  */
9513703f53bSSrinivas Pandruvada void ishtp_send_resume(struct ishtp_device *dev)
9523703f53bSSrinivas Pandruvada {
9533703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr	ishtp_hdr;
9543703f53bSSrinivas Pandruvada 	struct ish_system_states_status state_status_msg;
9553703f53bSSrinivas Pandruvada 	const size_t len = sizeof(struct ish_system_states_status);
9563703f53bSSrinivas Pandruvada 
9573703f53bSSrinivas Pandruvada 	fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
9583703f53bSSrinivas Pandruvada 
9593703f53bSSrinivas Pandruvada 	memset(&state_status_msg, 0, len);
9603703f53bSSrinivas Pandruvada 	state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
9613703f53bSSrinivas Pandruvada 	state_status_msg.supported_states = supported_states;
96294cad2ddSYe Xiang 	current_state &= ~(CONNECTED_STANDBY_STATE_BIT | SUSPEND_STATE_BIT);
9633703f53bSSrinivas Pandruvada 	dev->print_log(dev, "%s() sends RESUME notification\n", __func__);
9643703f53bSSrinivas Pandruvada 	state_status_msg.states_status = current_state;
9653703f53bSSrinivas Pandruvada 
9663703f53bSSrinivas Pandruvada 	ishtp_write_message(dev, &ishtp_hdr,
9673703f53bSSrinivas Pandruvada 		(unsigned char *)&state_status_msg);
9683703f53bSSrinivas Pandruvada }
9693703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_send_resume);
9703703f53bSSrinivas Pandruvada 
9713703f53bSSrinivas Pandruvada /**
9723703f53bSSrinivas Pandruvada  * ishtp_query_subscribers() - Send query subscribers message
9733703f53bSSrinivas Pandruvada  * @dev: ISHTP device instance
9743703f53bSSrinivas Pandruvada  *
9753703f53bSSrinivas Pandruvada  * Send message to query subscribers
9763703f53bSSrinivas Pandruvada  */
9773703f53bSSrinivas Pandruvada void ishtp_query_subscribers(struct ishtp_device *dev)
9783703f53bSSrinivas Pandruvada {
9793703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr	ishtp_hdr;
9803703f53bSSrinivas Pandruvada 	struct ish_system_states_query_subscribers query_subscribers_msg;
9813703f53bSSrinivas Pandruvada 	const size_t len = sizeof(struct ish_system_states_query_subscribers);
9823703f53bSSrinivas Pandruvada 
9833703f53bSSrinivas Pandruvada 	fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
9843703f53bSSrinivas Pandruvada 
9853703f53bSSrinivas Pandruvada 	memset(&query_subscribers_msg, 0, len);
9863703f53bSSrinivas Pandruvada 	query_subscribers_msg.hdr.cmd = SYSTEM_STATE_QUERY_SUBSCRIBERS;
9873703f53bSSrinivas Pandruvada 
9883703f53bSSrinivas Pandruvada 	ishtp_write_message(dev, &ishtp_hdr,
9893703f53bSSrinivas Pandruvada 		(unsigned char *)&query_subscribers_msg);
9903703f53bSSrinivas Pandruvada }
991