whiterose

linux unikernel
Log | Files | Refs | README | LICENSE | git clone https://git.ne02ptzero.me/git/whiterose

hbm.c (27194B)


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