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