cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hbm.c (26868B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ISHTP bus layer messages handling
      4 *
      5 * Copyright (c) 2003-2016, Intel Corporation.
      6 */
      7
      8#include <linux/export.h>
      9#include <linux/slab.h>
     10#include <linux/sched.h>
     11#include <linux/wait.h>
     12#include <linux/spinlock.h>
     13#include "ishtp-dev.h"
     14#include "hbm.h"
     15#include "client.h"
     16
     17/**
     18 * ishtp_hbm_fw_cl_allocate() - Allocate FW clients
     19 * @dev: ISHTP device instance
     20 *
     21 * Allocates storage for fw clients
     22 */
     23static void ishtp_hbm_fw_cl_allocate(struct ishtp_device *dev)
     24{
     25	struct ishtp_fw_client *clients;
     26	int b;
     27
     28	/* count how many ISH clients we have */
     29	for_each_set_bit(b, dev->fw_clients_map, ISHTP_CLIENTS_MAX)
     30		dev->fw_clients_num++;
     31
     32	if (dev->fw_clients_num <= 0)
     33		return;
     34
     35	/* allocate storage for fw clients representation */
     36	clients = kcalloc(dev->fw_clients_num, sizeof(struct ishtp_fw_client),
     37			  GFP_KERNEL);
     38	if (!clients) {
     39		dev->dev_state = ISHTP_DEV_RESETTING;
     40		ish_hw_reset(dev);
     41		return;
     42	}
     43	dev->fw_clients = clients;
     44}
     45
     46/**
     47 * ishtp_hbm_cl_hdr() - construct client hbm header
     48 * @cl: client
     49 * @hbm_cmd: host bus message command
     50 * @buf: buffer for cl header
     51 * @len: buffer length
     52 *
     53 * Initialize HBM buffer
     54 */
     55static inline void ishtp_hbm_cl_hdr(struct ishtp_cl *cl, uint8_t hbm_cmd,
     56	void *buf, size_t len)
     57{
     58	struct ishtp_hbm_cl_cmd *cmd = buf;
     59
     60	memset(cmd, 0, len);
     61
     62	cmd->hbm_cmd = hbm_cmd;
     63	cmd->host_addr = cl->host_client_id;
     64	cmd->fw_addr = cl->fw_client_id;
     65}
     66
     67/**
     68 * ishtp_hbm_cl_addr_equal() - Compare client address
     69 * @cl: client
     70 * @buf: Client command buffer
     71 *
     72 * Compare client address with the address in command buffer
     73 *
     74 * Return: True if they have the same address
     75 */
     76static inline bool ishtp_hbm_cl_addr_equal(struct ishtp_cl *cl, void *buf)
     77{
     78	struct ishtp_hbm_cl_cmd *cmd = buf;
     79
     80	return cl->host_client_id == cmd->host_addr &&
     81		cl->fw_client_id == cmd->fw_addr;
     82}
     83
     84/**
     85 * ishtp_hbm_start_wait() - Wait for HBM start message
     86 * @dev: ISHTP device instance
     87 *
     88 * Wait for HBM start message from firmware
     89 *
     90 * Return: 0 if HBM start is/was received else timeout error
     91 */
     92int ishtp_hbm_start_wait(struct ishtp_device *dev)
     93{
     94	int ret;
     95
     96	if (dev->hbm_state > ISHTP_HBM_START)
     97		return 0;
     98
     99	dev_dbg(dev->devc, "Going to wait for ishtp start. hbm_state=%08X\n",
    100		dev->hbm_state);
    101	ret = wait_event_interruptible_timeout(dev->wait_hbm_recvd_msg,
    102					dev->hbm_state >= ISHTP_HBM_STARTED,
    103					(ISHTP_INTEROP_TIMEOUT * HZ));
    104
    105	dev_dbg(dev->devc,
    106		"Woke up from waiting for ishtp start. hbm_state=%08X\n",
    107		dev->hbm_state);
    108
    109	if (ret <= 0 && (dev->hbm_state <= ISHTP_HBM_START)) {
    110		dev->hbm_state = ISHTP_HBM_IDLE;
    111		dev_err(dev->devc,
    112		"waiting for ishtp start failed. ret=%d hbm_state=%08X\n",
    113			ret, dev->hbm_state);
    114		return -ETIMEDOUT;
    115	}
    116	return 0;
    117}
    118
    119/**
    120 * ishtp_hbm_start_req() - Send HBM start message
    121 * @dev: ISHTP device instance
    122 *
    123 * Send HBM start message to firmware
    124 *
    125 * Return: 0 if success else error code
    126 */
    127int ishtp_hbm_start_req(struct ishtp_device *dev)
    128{
    129	struct ishtp_msg_hdr hdr;
    130	struct hbm_host_version_request start_req = { 0 };
    131
    132	ishtp_hbm_hdr(&hdr, sizeof(start_req));
    133
    134	/* host start message */
    135	start_req.hbm_cmd = HOST_START_REQ_CMD;
    136	start_req.host_version.major_version = HBM_MAJOR_VERSION;
    137	start_req.host_version.minor_version = HBM_MINOR_VERSION;
    138
    139	/*
    140	 * (!) Response to HBM start may be so quick that this thread would get
    141	 * preempted BEFORE managing to set hbm_state = ISHTP_HBM_START.
    142	 * So set it at first, change back to ISHTP_HBM_IDLE upon failure
    143	 */
    144	dev->hbm_state = ISHTP_HBM_START;
    145	if (ishtp_write_message(dev, &hdr, &start_req)) {
    146		dev_err(dev->devc, "version message send failed\n");
    147		dev->dev_state = ISHTP_DEV_RESETTING;
    148		dev->hbm_state = ISHTP_HBM_IDLE;
    149		ish_hw_reset(dev);
    150		return -ENODEV;
    151	}
    152
    153	return 0;
    154}
    155
    156/**
    157 * ishtp_hbm_enum_clients_req() - Send client enum req
    158 * @dev: ISHTP device instance
    159 *
    160 * Send enumeration client request message
    161 *
    162 * Return: 0 if success else error code
    163 */
    164void ishtp_hbm_enum_clients_req(struct ishtp_device *dev)
    165{
    166	struct ishtp_msg_hdr hdr;
    167	struct hbm_host_enum_request enum_req = { 0 };
    168
    169	/* enumerate clients */
    170	ishtp_hbm_hdr(&hdr, sizeof(enum_req));
    171	enum_req.hbm_cmd = HOST_ENUM_REQ_CMD;
    172
    173	if (ishtp_write_message(dev, &hdr, &enum_req)) {
    174		dev->dev_state = ISHTP_DEV_RESETTING;
    175		dev_err(dev->devc, "enumeration request send failed\n");
    176		ish_hw_reset(dev);
    177	}
    178	dev->hbm_state = ISHTP_HBM_ENUM_CLIENTS;
    179}
    180
    181/**
    182 * ishtp_hbm_prop_req() - Request property
    183 * @dev: ISHTP device instance
    184 *
    185 * Request property for a single client
    186 *
    187 * Return: 0 if success else error code
    188 */
    189static int ishtp_hbm_prop_req(struct ishtp_device *dev)
    190{
    191	struct ishtp_msg_hdr hdr;
    192	struct hbm_props_request prop_req = { 0 };
    193	unsigned long next_client_index;
    194	uint8_t client_num;
    195
    196	client_num = dev->fw_client_presentation_num;
    197
    198	next_client_index = find_next_bit(dev->fw_clients_map,
    199		ISHTP_CLIENTS_MAX, dev->fw_client_index);
    200
    201	/* We got all client properties */
    202	if (next_client_index == ISHTP_CLIENTS_MAX) {
    203		dev->hbm_state = ISHTP_HBM_WORKING;
    204		dev->dev_state = ISHTP_DEV_ENABLED;
    205
    206		for (dev->fw_client_presentation_num = 1;
    207			dev->fw_client_presentation_num < client_num + 1;
    208				++dev->fw_client_presentation_num)
    209			/* Add new client device */
    210			ishtp_bus_new_client(dev);
    211		return 0;
    212	}
    213
    214	dev->fw_clients[client_num].client_id = next_client_index;
    215
    216	ishtp_hbm_hdr(&hdr, sizeof(prop_req));
    217
    218	prop_req.hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
    219	prop_req.address = next_client_index;
    220
    221	if (ishtp_write_message(dev, &hdr, &prop_req)) {
    222		dev->dev_state = ISHTP_DEV_RESETTING;
    223		dev_err(dev->devc, "properties request send failed\n");
    224		ish_hw_reset(dev);
    225		return -EIO;
    226	}
    227
    228	dev->fw_client_index = next_client_index;
    229
    230	return 0;
    231}
    232
    233/**
    234 * ishtp_hbm_stop_req() - Send HBM stop
    235 * @dev: ISHTP device instance
    236 *
    237 * Send stop request message
    238 */
    239static void ishtp_hbm_stop_req(struct ishtp_device *dev)
    240{
    241	struct ishtp_msg_hdr hdr;
    242	struct hbm_host_stop_request stop_req = { 0 } ;
    243
    244	ishtp_hbm_hdr(&hdr, sizeof(stop_req));
    245
    246	stop_req.hbm_cmd = HOST_STOP_REQ_CMD;
    247	stop_req.reason = DRIVER_STOP_REQUEST;
    248
    249	ishtp_write_message(dev, &hdr, &stop_req);
    250}
    251
    252/**
    253 * ishtp_hbm_cl_flow_control_req() - Send flow control request
    254 * @dev: ISHTP device instance
    255 * @cl: ISHTP client instance
    256 *
    257 * Send flow control request
    258 *
    259 * Return: 0 if success else error code
    260 */
    261int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev,
    262				  struct ishtp_cl *cl)
    263{
    264	struct ishtp_msg_hdr hdr;
    265	struct hbm_flow_control flow_ctrl;
    266	const size_t len = sizeof(flow_ctrl);
    267	int	rv;
    268	unsigned long	flags;
    269
    270	spin_lock_irqsave(&cl->fc_spinlock, flags);
    271
    272	ishtp_hbm_hdr(&hdr, len);
    273	ishtp_hbm_cl_hdr(cl, ISHTP_FLOW_CONTROL_CMD, &flow_ctrl, len);
    274
    275	/*
    276	 * Sync possible race when RB recycle and packet receive paths
    277	 * both try to send an out FC
    278	 */
    279	if (cl->out_flow_ctrl_creds) {
    280		spin_unlock_irqrestore(&cl->fc_spinlock, flags);
    281		return	0;
    282	}
    283
    284	cl->recv_msg_num_frags = 0;
    285
    286	rv = ishtp_write_message(dev, &hdr, &flow_ctrl);
    287	if (!rv) {
    288		++cl->out_flow_ctrl_creds;
    289		++cl->out_flow_ctrl_cnt;
    290		cl->ts_out_fc = ktime_get();
    291		if (cl->ts_rx) {
    292			ktime_t ts_diff = ktime_sub(cl->ts_out_fc, cl->ts_rx);
    293			if (ktime_after(ts_diff, cl->ts_max_fc_delay))
    294				cl->ts_max_fc_delay = ts_diff;
    295		}
    296	} else {
    297		++cl->err_send_fc;
    298	}
    299
    300	spin_unlock_irqrestore(&cl->fc_spinlock, flags);
    301	return	rv;
    302}
    303
    304/**
    305 * ishtp_hbm_cl_disconnect_req() - Send disconnect request
    306 * @dev: ISHTP device instance
    307 * @cl: ISHTP client instance
    308 *
    309 * Send disconnect message to fw
    310 *
    311 * Return: 0 if success else error code
    312 */
    313int ishtp_hbm_cl_disconnect_req(struct ishtp_device *dev, struct ishtp_cl *cl)
    314{
    315	struct ishtp_msg_hdr hdr;
    316	struct hbm_client_connect_request disconn_req;
    317	const size_t len = sizeof(disconn_req);
    318
    319	ishtp_hbm_hdr(&hdr, len);
    320	ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, &disconn_req, len);
    321
    322	return ishtp_write_message(dev, &hdr, &disconn_req);
    323}
    324
    325/**
    326 * ishtp_hbm_cl_disconnect_res() - Get disconnect response
    327 * @dev: ISHTP device instance
    328 * @rs: Response message
    329 *
    330 * Received disconnect response from fw
    331 */
    332static void ishtp_hbm_cl_disconnect_res(struct ishtp_device *dev,
    333	struct hbm_client_connect_response *rs)
    334{
    335	struct ishtp_cl *cl = NULL;
    336	unsigned long	flags;
    337
    338	spin_lock_irqsave(&dev->cl_list_lock, flags);
    339	list_for_each_entry(cl, &dev->cl_list, link) {
    340		if (!rs->status && ishtp_hbm_cl_addr_equal(cl, rs)) {
    341			cl->state = ISHTP_CL_DISCONNECTED;
    342			wake_up_interruptible(&cl->wait_ctrl_res);
    343			break;
    344		}
    345	}
    346	spin_unlock_irqrestore(&dev->cl_list_lock, flags);
    347}
    348
    349/**
    350 * ishtp_hbm_cl_connect_req() - Send connect request
    351 * @dev: ISHTP device instance
    352 * @cl: client device instance
    353 *
    354 * Send connection request to specific fw client
    355 *
    356 * Return: 0 if success else error code
    357 */
    358int ishtp_hbm_cl_connect_req(struct ishtp_device *dev, struct ishtp_cl *cl)
    359{
    360	struct ishtp_msg_hdr hdr;
    361	struct hbm_client_connect_request conn_req;
    362	const size_t len = sizeof(conn_req);
    363
    364	ishtp_hbm_hdr(&hdr, len);
    365	ishtp_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, &conn_req, len);
    366
    367	return ishtp_write_message(dev, &hdr, &conn_req);
    368}
    369
    370/**
    371 * ishtp_hbm_cl_connect_res() - Get connect response
    372 * @dev: ISHTP device instance
    373 * @rs: Response message
    374 *
    375 * Received connect response from fw
    376 */
    377static void ishtp_hbm_cl_connect_res(struct ishtp_device *dev,
    378	struct hbm_client_connect_response *rs)
    379{
    380	struct ishtp_cl *cl = NULL;
    381	unsigned long	flags;
    382
    383	spin_lock_irqsave(&dev->cl_list_lock, flags);
    384	list_for_each_entry(cl, &dev->cl_list, link) {
    385		if (ishtp_hbm_cl_addr_equal(cl, rs)) {
    386			if (!rs->status) {
    387				cl->state = ISHTP_CL_CONNECTED;
    388				cl->status = 0;
    389			} else {
    390				cl->state = ISHTP_CL_DISCONNECTED;
    391				cl->status = -ENODEV;
    392			}
    393			wake_up_interruptible(&cl->wait_ctrl_res);
    394			break;
    395		}
    396	}
    397	spin_unlock_irqrestore(&dev->cl_list_lock, flags);
    398}
    399
    400/**
    401 * ishtp_hbm_fw_disconnect_req() - Receive disconnect request
    402 * @dev: ISHTP device instance
    403 * @disconnect_req: disconnect request structure
    404 *
    405 * Disconnect request bus message from the fw. Send disconnect response.
    406 */
    407static void ishtp_hbm_fw_disconnect_req(struct ishtp_device *dev,
    408	struct hbm_client_connect_request *disconnect_req)
    409{
    410	struct ishtp_cl *cl;
    411	const size_t len = sizeof(struct hbm_client_connect_response);
    412	unsigned long	flags;
    413	struct ishtp_msg_hdr hdr;
    414	unsigned char data[4];	/* All HBM messages are 4 bytes */
    415
    416	spin_lock_irqsave(&dev->cl_list_lock, flags);
    417	list_for_each_entry(cl, &dev->cl_list, link) {
    418		if (ishtp_hbm_cl_addr_equal(cl, disconnect_req)) {
    419			cl->state = ISHTP_CL_DISCONNECTED;
    420
    421			/* send disconnect response */
    422			ishtp_hbm_hdr(&hdr, len);
    423			ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD, data,
    424				len);
    425			ishtp_write_message(dev, &hdr, data);
    426			break;
    427		}
    428	}
    429	spin_unlock_irqrestore(&dev->cl_list_lock, flags);
    430}
    431
    432/**
    433 * ishtp_hbm_dma_xfer_ack() - Receive transfer ACK
    434 * @dev: ISHTP device instance
    435 * @dma_xfer: HBM transfer message
    436 *
    437 * Receive ack for ISHTP-over-DMA client message
    438 */
    439static void ishtp_hbm_dma_xfer_ack(struct ishtp_device *dev,
    440				   struct dma_xfer_hbm *dma_xfer)
    441{
    442	void	*msg;
    443	uint64_t	offs;
    444	struct ishtp_msg_hdr	*ishtp_hdr =
    445		(struct ishtp_msg_hdr *)&dev->ishtp_msg_hdr;
    446	unsigned int	msg_offs;
    447	struct ishtp_cl *cl;
    448
    449	for (msg_offs = 0; msg_offs < ishtp_hdr->length;
    450		msg_offs += sizeof(struct dma_xfer_hbm)) {
    451		offs = dma_xfer->msg_addr - dev->ishtp_host_dma_tx_buf_phys;
    452		if (offs > dev->ishtp_host_dma_tx_buf_size) {
    453			dev_err(dev->devc, "Bad DMA Tx ack message address\n");
    454			return;
    455		}
    456		if (dma_xfer->msg_length >
    457				dev->ishtp_host_dma_tx_buf_size - offs) {
    458			dev_err(dev->devc, "Bad DMA Tx ack message size\n");
    459			return;
    460		}
    461
    462		/* logical address of the acked mem */
    463		msg = (unsigned char *)dev->ishtp_host_dma_tx_buf + offs;
    464		ishtp_cl_release_dma_acked_mem(dev, msg, dma_xfer->msg_length);
    465
    466		list_for_each_entry(cl, &dev->cl_list, link) {
    467			if (cl->fw_client_id == dma_xfer->fw_client_id &&
    468			    cl->host_client_id == dma_xfer->host_client_id)
    469				/*
    470				 * in case that a single ack may be sent
    471				 * over several dma transfers, and the last msg
    472				 * addr was inside the acked memory, but not in
    473				 * its start
    474				 */
    475				if (cl->last_dma_addr >=
    476							(unsigned char *)msg &&
    477						cl->last_dma_addr <
    478						(unsigned char *)msg +
    479						dma_xfer->msg_length) {
    480					cl->last_dma_acked = 1;
    481
    482					if (!list_empty(&cl->tx_list.list) &&
    483						cl->ishtp_flow_ctrl_creds) {
    484						/*
    485						 * start sending the first msg
    486						 */
    487						ishtp_cl_send_msg(dev, cl);
    488					}
    489				}
    490		}
    491		++dma_xfer;
    492	}
    493}
    494
    495/**
    496 * ishtp_hbm_dma_xfer() - Receive DMA transfer message
    497 * @dev: ISHTP device instance
    498 * @dma_xfer: HBM transfer message
    499 *
    500 * Receive ISHTP-over-DMA client message
    501 */
    502static void ishtp_hbm_dma_xfer(struct ishtp_device *dev,
    503			       struct dma_xfer_hbm *dma_xfer)
    504{
    505	void	*msg;
    506	uint64_t	offs;
    507	struct ishtp_msg_hdr	hdr;
    508	struct ishtp_msg_hdr	*ishtp_hdr =
    509		(struct ishtp_msg_hdr *) &dev->ishtp_msg_hdr;
    510	struct dma_xfer_hbm	*prm = dma_xfer;
    511	unsigned int	msg_offs;
    512
    513	for (msg_offs = 0; msg_offs < ishtp_hdr->length;
    514		msg_offs += sizeof(struct dma_xfer_hbm)) {
    515
    516		offs = dma_xfer->msg_addr - dev->ishtp_host_dma_rx_buf_phys;
    517		if (offs > dev->ishtp_host_dma_rx_buf_size) {
    518			dev_err(dev->devc, "Bad DMA Rx message address\n");
    519			return;
    520		}
    521		if (dma_xfer->msg_length >
    522				dev->ishtp_host_dma_rx_buf_size - offs) {
    523			dev_err(dev->devc, "Bad DMA Rx message size\n");
    524			return;
    525		}
    526		msg = dev->ishtp_host_dma_rx_buf + offs;
    527		recv_ishtp_cl_msg_dma(dev, msg, dma_xfer);
    528		dma_xfer->hbm = DMA_XFER_ACK;	/* Prepare for response */
    529		++dma_xfer;
    530	}
    531
    532	/* Send DMA_XFER_ACK [...] */
    533	ishtp_hbm_hdr(&hdr, ishtp_hdr->length);
    534	ishtp_write_message(dev, &hdr, (unsigned char *)prm);
    535}
    536
    537/**
    538 * ishtp_hbm_dispatch() - HBM dispatch function
    539 * @dev: ISHTP device instance
    540 * @hdr: bus message
    541 *
    542 * Bottom half read routine after ISR to handle the read bus message cmd
    543 * processing
    544 */
    545void ishtp_hbm_dispatch(struct ishtp_device *dev,
    546			struct ishtp_bus_message *hdr)
    547{
    548	struct ishtp_bus_message *ishtp_msg;
    549	struct ishtp_fw_client *fw_client;
    550	struct hbm_host_version_response *version_res;
    551	struct hbm_client_connect_response *connect_res;
    552	struct hbm_client_connect_response *disconnect_res;
    553	struct hbm_client_connect_request *disconnect_req;
    554	struct hbm_props_response *props_res;
    555	struct hbm_host_enum_response *enum_res;
    556	struct ishtp_msg_hdr ishtp_hdr;
    557	struct dma_alloc_notify	dma_alloc_notify;
    558	struct dma_xfer_hbm	*dma_xfer;
    559
    560	ishtp_msg = hdr;
    561
    562	switch (ishtp_msg->hbm_cmd) {
    563	case HOST_START_RES_CMD:
    564		version_res = (struct hbm_host_version_response *)ishtp_msg;
    565		if (!version_res->host_version_supported) {
    566			dev->version = version_res->fw_max_version;
    567
    568			dev->hbm_state = ISHTP_HBM_STOPPED;
    569			ishtp_hbm_stop_req(dev);
    570			return;
    571		}
    572
    573		dev->version.major_version = HBM_MAJOR_VERSION;
    574		dev->version.minor_version = HBM_MINOR_VERSION;
    575		if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS &&
    576				dev->hbm_state == ISHTP_HBM_START) {
    577			dev->hbm_state = ISHTP_HBM_STARTED;
    578			ishtp_hbm_enum_clients_req(dev);
    579		} else {
    580			dev_err(dev->devc,
    581				"reset: wrong host start response\n");
    582			/* BUG: why do we arrive here? */
    583			ish_hw_reset(dev);
    584			return;
    585		}
    586
    587		wake_up_interruptible(&dev->wait_hbm_recvd_msg);
    588		break;
    589
    590	case CLIENT_CONNECT_RES_CMD:
    591		connect_res = (struct hbm_client_connect_response *)ishtp_msg;
    592		ishtp_hbm_cl_connect_res(dev, connect_res);
    593		break;
    594
    595	case CLIENT_DISCONNECT_RES_CMD:
    596		disconnect_res =
    597			(struct hbm_client_connect_response *)ishtp_msg;
    598		ishtp_hbm_cl_disconnect_res(dev, disconnect_res);
    599		break;
    600
    601	case HOST_CLIENT_PROPERTIES_RES_CMD:
    602		props_res = (struct hbm_props_response *)ishtp_msg;
    603		fw_client = &dev->fw_clients[dev->fw_client_presentation_num];
    604
    605		if (props_res->status || !dev->fw_clients) {
    606			dev_err(dev->devc,
    607			"reset: properties response hbm wrong status\n");
    608			ish_hw_reset(dev);
    609			return;
    610		}
    611
    612		if (fw_client->client_id != props_res->address) {
    613			dev_err(dev->devc,
    614				"reset: host properties response address mismatch [%02X %02X]\n",
    615				fw_client->client_id, props_res->address);
    616			ish_hw_reset(dev);
    617			return;
    618		}
    619
    620		if (dev->dev_state != ISHTP_DEV_INIT_CLIENTS ||
    621			dev->hbm_state != ISHTP_HBM_CLIENT_PROPERTIES) {
    622			dev_err(dev->devc,
    623				"reset: unexpected properties response\n");
    624			ish_hw_reset(dev);
    625			return;
    626		}
    627
    628		fw_client->props = props_res->client_properties;
    629		dev->fw_client_index++;
    630		dev->fw_client_presentation_num++;
    631
    632		/* request property for the next client */
    633		ishtp_hbm_prop_req(dev);
    634
    635		if (dev->dev_state != ISHTP_DEV_ENABLED)
    636			break;
    637
    638		if (!ishtp_use_dma_transfer())
    639			break;
    640
    641		dev_dbg(dev->devc, "Requesting to use DMA\n");
    642		ishtp_cl_alloc_dma_buf(dev);
    643		if (dev->ishtp_host_dma_rx_buf) {
    644			const size_t len = sizeof(dma_alloc_notify);
    645
    646			memset(&dma_alloc_notify, 0, sizeof(dma_alloc_notify));
    647			dma_alloc_notify.hbm = DMA_BUFFER_ALLOC_NOTIFY;
    648			dma_alloc_notify.buf_size =
    649					dev->ishtp_host_dma_rx_buf_size;
    650			dma_alloc_notify.buf_address =
    651					dev->ishtp_host_dma_rx_buf_phys;
    652			ishtp_hbm_hdr(&ishtp_hdr, len);
    653			ishtp_write_message(dev, &ishtp_hdr,
    654				(unsigned char *)&dma_alloc_notify);
    655		}
    656
    657		break;
    658
    659	case HOST_ENUM_RES_CMD:
    660		enum_res = (struct hbm_host_enum_response *) ishtp_msg;
    661		memcpy(dev->fw_clients_map, enum_res->valid_addresses, 32);
    662		if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS &&
    663			dev->hbm_state == ISHTP_HBM_ENUM_CLIENTS) {
    664			dev->fw_client_presentation_num = 0;
    665			dev->fw_client_index = 0;
    666
    667			ishtp_hbm_fw_cl_allocate(dev);
    668			dev->hbm_state = ISHTP_HBM_CLIENT_PROPERTIES;
    669
    670			/* first property request */
    671			ishtp_hbm_prop_req(dev);
    672		} else {
    673			dev_err(dev->devc,
    674			      "reset: unexpected enumeration response hbm\n");
    675			ish_hw_reset(dev);
    676			return;
    677		}
    678		break;
    679
    680	case HOST_STOP_RES_CMD:
    681		if (dev->hbm_state != ISHTP_HBM_STOPPED)
    682			dev_err(dev->devc, "unexpected stop response\n");
    683
    684		dev->dev_state = ISHTP_DEV_DISABLED;
    685		dev_info(dev->devc, "reset: FW stop response\n");
    686		ish_hw_reset(dev);
    687		break;
    688
    689	case CLIENT_DISCONNECT_REQ_CMD:
    690		/* search for client */
    691		disconnect_req =
    692			(struct hbm_client_connect_request *)ishtp_msg;
    693		ishtp_hbm_fw_disconnect_req(dev, disconnect_req);
    694		break;
    695
    696	case FW_STOP_REQ_CMD:
    697		dev->hbm_state = ISHTP_HBM_STOPPED;
    698		break;
    699
    700	case DMA_BUFFER_ALLOC_RESPONSE:
    701		dev->ishtp_host_dma_enabled = 1;
    702		break;
    703
    704	case DMA_XFER:
    705		dma_xfer = (struct dma_xfer_hbm *)ishtp_msg;
    706		if (!dev->ishtp_host_dma_enabled) {
    707			dev_err(dev->devc,
    708				"DMA XFER requested but DMA is not enabled\n");
    709			break;
    710		}
    711		ishtp_hbm_dma_xfer(dev, dma_xfer);
    712		break;
    713
    714	case DMA_XFER_ACK:
    715		dma_xfer = (struct dma_xfer_hbm *)ishtp_msg;
    716		if (!dev->ishtp_host_dma_enabled ||
    717		    !dev->ishtp_host_dma_tx_buf) {
    718			dev_err(dev->devc,
    719				"DMA XFER acked but DMA Tx is not enabled\n");
    720			break;
    721		}
    722		ishtp_hbm_dma_xfer_ack(dev, dma_xfer);
    723		break;
    724
    725	default:
    726		dev_err(dev->devc, "unknown HBM: %u\n",
    727			(unsigned int)ishtp_msg->hbm_cmd);
    728
    729		break;
    730	}
    731}
    732
    733/**
    734 * bh_hbm_work_fn() - HBM work function
    735 * @work: work struct
    736 *
    737 * Bottom half processing work function (instead of thread handler)
    738 * for processing hbm messages
    739 */
    740void	bh_hbm_work_fn(struct work_struct *work)
    741{
    742	unsigned long	flags;
    743	struct ishtp_device	*dev;
    744	unsigned char	hbm[IPC_PAYLOAD_SIZE];
    745
    746	dev = container_of(work, struct ishtp_device, bh_hbm_work);
    747	spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
    748	if (dev->rd_msg_fifo_head != dev->rd_msg_fifo_tail) {
    749		memcpy(hbm, dev->rd_msg_fifo + dev->rd_msg_fifo_head,
    750			IPC_PAYLOAD_SIZE);
    751		dev->rd_msg_fifo_head =
    752			(dev->rd_msg_fifo_head + IPC_PAYLOAD_SIZE) %
    753			(RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE);
    754		spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
    755		ishtp_hbm_dispatch(dev, (struct ishtp_bus_message *)hbm);
    756	} else {
    757		spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
    758	}
    759}
    760
    761/**
    762 * recv_hbm() - Receive HBM message
    763 * @dev: ISHTP device instance
    764 * @ishtp_hdr: received bus message
    765 *
    766 * Receive and process ISHTP bus messages in ISR context. This will schedule
    767 * work function to process message
    768 */
    769void	recv_hbm(struct ishtp_device *dev, struct ishtp_msg_hdr *ishtp_hdr)
    770{
    771	uint8_t	rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE];
    772	struct ishtp_bus_message	*ishtp_msg =
    773		(struct ishtp_bus_message *)rd_msg_buf;
    774	unsigned long	flags;
    775
    776	dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length);
    777
    778	/* Flow control - handle in place */
    779	if (ishtp_msg->hbm_cmd == ISHTP_FLOW_CONTROL_CMD) {
    780		struct hbm_flow_control *flow_control =
    781			(struct hbm_flow_control *)ishtp_msg;
    782		struct ishtp_cl *cl = NULL;
    783		unsigned long	flags, tx_flags;
    784
    785		spin_lock_irqsave(&dev->cl_list_lock, flags);
    786		list_for_each_entry(cl, &dev->cl_list, link) {
    787			if (cl->host_client_id == flow_control->host_addr &&
    788					cl->fw_client_id ==
    789					flow_control->fw_addr) {
    790				/*
    791				 * NOTE: It's valid only for counting
    792				 * flow-control implementation to receive a
    793				 * FC in the middle of sending. Meanwhile not
    794				 * supported
    795				 */
    796				if (cl->ishtp_flow_ctrl_creds)
    797					dev_err(dev->devc,
    798					 "recv extra FC from FW client %u (host client %u) (FC count was %d)\n",
    799					 (unsigned int)cl->fw_client_id,
    800					 (unsigned int)cl->host_client_id,
    801					 cl->ishtp_flow_ctrl_creds);
    802				else {
    803					++cl->ishtp_flow_ctrl_creds;
    804					++cl->ishtp_flow_ctrl_cnt;
    805					cl->last_ipc_acked = 1;
    806					spin_lock_irqsave(
    807							&cl->tx_list_spinlock,
    808							tx_flags);
    809					if (!list_empty(&cl->tx_list.list)) {
    810						/*
    811						 * start sending the first msg
    812						 *	= the callback function
    813						 */
    814						spin_unlock_irqrestore(
    815							&cl->tx_list_spinlock,
    816							tx_flags);
    817						ishtp_cl_send_msg(dev, cl);
    818					} else {
    819						spin_unlock_irqrestore(
    820							&cl->tx_list_spinlock,
    821							tx_flags);
    822					}
    823				}
    824				break;
    825			}
    826		}
    827		spin_unlock_irqrestore(&dev->cl_list_lock, flags);
    828		goto	eoi;
    829	}
    830
    831	/*
    832	 * Some messages that are safe for ISR processing and important
    833	 * to be done "quickly" and in-order, go here
    834	 */
    835	if (ishtp_msg->hbm_cmd == CLIENT_CONNECT_RES_CMD ||
    836			ishtp_msg->hbm_cmd == CLIENT_DISCONNECT_RES_CMD ||
    837			ishtp_msg->hbm_cmd == CLIENT_DISCONNECT_REQ_CMD ||
    838			ishtp_msg->hbm_cmd == DMA_XFER) {
    839		ishtp_hbm_dispatch(dev, ishtp_msg);
    840		goto	eoi;
    841	}
    842
    843	/*
    844	 * All other HBMs go here.
    845	 * We schedule HBMs for processing serially by using system wq,
    846	 * possibly there will be multiple HBMs scheduled at the same time.
    847	 */
    848	spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
    849	if ((dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) %
    850			(RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE) ==
    851			dev->rd_msg_fifo_head) {
    852		spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
    853		dev_err(dev->devc, "BH buffer overflow, dropping HBM %u\n",
    854			(unsigned int)ishtp_msg->hbm_cmd);
    855		goto	eoi;
    856	}
    857	memcpy(dev->rd_msg_fifo + dev->rd_msg_fifo_tail, ishtp_msg,
    858		ishtp_hdr->length);
    859	dev->rd_msg_fifo_tail = (dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) %
    860		(RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE);
    861	spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
    862	schedule_work(&dev->bh_hbm_work);
    863eoi:
    864	return;
    865}
    866
    867/**
    868 * recv_fixed_cl_msg() - Receive fixed client message
    869 * @dev: ISHTP device instance
    870 * @ishtp_hdr: received bus message
    871 *
    872 * Receive and process ISHTP fixed client messages (address == 0)
    873 * in ISR context
    874 */
    875void recv_fixed_cl_msg(struct ishtp_device *dev,
    876	struct ishtp_msg_hdr *ishtp_hdr)
    877{
    878	uint8_t rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE];
    879
    880	dev->print_log(dev,
    881		"%s() got fixed client msg from client #%d\n",
    882		__func__, ishtp_hdr->fw_addr);
    883	dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length);
    884	if (ishtp_hdr->fw_addr == ISHTP_SYSTEM_STATE_CLIENT_ADDR) {
    885		struct ish_system_states_header *msg_hdr =
    886			(struct ish_system_states_header *)rd_msg_buf;
    887		if (msg_hdr->cmd == SYSTEM_STATE_SUBSCRIBE)
    888			ishtp_send_resume(dev);
    889		/* if FW request arrived here, the system is not suspended */
    890		else
    891			dev_err(dev->devc, "unknown fixed client msg [%02X]\n",
    892				msg_hdr->cmd);
    893	}
    894}
    895
    896/**
    897 * fix_cl_hdr() - Initialize fixed client header
    898 * @hdr: message header
    899 * @length: length of message
    900 * @cl_addr: Client address
    901 *
    902 * Initialize message header for fixed client
    903 */
    904static inline void fix_cl_hdr(struct ishtp_msg_hdr *hdr, size_t length,
    905	uint8_t cl_addr)
    906{
    907	hdr->host_addr = 0;
    908	hdr->fw_addr = cl_addr;
    909	hdr->length = length;
    910	hdr->msg_complete = 1;
    911	hdr->reserved = 0;
    912}
    913
    914/*** Suspend and resume notification ***/
    915
    916static uint32_t current_state;
    917static uint32_t supported_states = SUSPEND_STATE_BIT | CONNECTED_STANDBY_STATE_BIT;
    918
    919/**
    920 * ishtp_send_suspend() - Send suspend message to FW
    921 * @dev: ISHTP device instance
    922 *
    923 * Send suspend message to FW. This is useful for system freeze (non S3) case
    924 */
    925void ishtp_send_suspend(struct ishtp_device *dev)
    926{
    927	struct ishtp_msg_hdr	ishtp_hdr;
    928	struct ish_system_states_status state_status_msg;
    929	const size_t len = sizeof(struct ish_system_states_status);
    930
    931	fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
    932
    933	memset(&state_status_msg, 0, len);
    934	state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
    935	state_status_msg.supported_states = supported_states;
    936	current_state |= (SUSPEND_STATE_BIT | CONNECTED_STANDBY_STATE_BIT);
    937	dev->print_log(dev, "%s() sends SUSPEND notification\n", __func__);
    938	state_status_msg.states_status = current_state;
    939
    940	ishtp_write_message(dev, &ishtp_hdr,
    941		(unsigned char *)&state_status_msg);
    942}
    943EXPORT_SYMBOL(ishtp_send_suspend);
    944
    945/**
    946 * ishtp_send_resume() - Send resume message to FW
    947 * @dev: ISHTP device instance
    948 *
    949 * Send resume message to FW. This is useful for system freeze (non S3) case
    950 */
    951void ishtp_send_resume(struct ishtp_device *dev)
    952{
    953	struct ishtp_msg_hdr	ishtp_hdr;
    954	struct ish_system_states_status state_status_msg;
    955	const size_t len = sizeof(struct ish_system_states_status);
    956
    957	fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
    958
    959	memset(&state_status_msg, 0, len);
    960	state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
    961	state_status_msg.supported_states = supported_states;
    962	current_state &= ~(CONNECTED_STANDBY_STATE_BIT | SUSPEND_STATE_BIT);
    963	dev->print_log(dev, "%s() sends RESUME notification\n", __func__);
    964	state_status_msg.states_status = current_state;
    965
    966	ishtp_write_message(dev, &ishtp_hdr,
    967		(unsigned char *)&state_status_msg);
    968}
    969EXPORT_SYMBOL(ishtp_send_resume);
    970
    971/**
    972 * ishtp_query_subscribers() - Send query subscribers message
    973 * @dev: ISHTP device instance
    974 *
    975 * Send message to query subscribers
    976 */
    977void ishtp_query_subscribers(struct ishtp_device *dev)
    978{
    979	struct ishtp_msg_hdr	ishtp_hdr;
    980	struct ish_system_states_query_subscribers query_subscribers_msg;
    981	const size_t len = sizeof(struct ish_system_states_query_subscribers);
    982
    983	fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
    984
    985	memset(&query_subscribers_msg, 0, len);
    986	query_subscribers_msg.hdr.cmd = SYSTEM_STATE_QUERY_SUBSCRIBERS;
    987
    988	ishtp_write_message(dev, &ishtp_hdr,
    989		(unsigned char *)&query_subscribers_msg);
    990}