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