17bd4b999SAlexander Usyskin // SPDX-License-Identifier: GPL-2.0 27bd4b999SAlexander Usyskin /* Copyright (C) 2023-2026 Intel Corporation */ 37bd4b999SAlexander Usyskin #include <linux/dev_printk.h> 47bd4b999SAlexander Usyskin #include <linux/errno.h> 57bd4b999SAlexander Usyskin #include <linux/slab.h> 67bd4b999SAlexander Usyskin #include <linux/string.h> 77bd4b999SAlexander Usyskin 87bd4b999SAlexander Usyskin #include "dma.h" 97bd4b999SAlexander Usyskin #include "fw_client.h" 107bd4b999SAlexander Usyskin #include "ham.h" 117bd4b999SAlexander Usyskin #include "hw_msg.h" 127bd4b999SAlexander Usyskin #include "issei_dev.h" 137bd4b999SAlexander Usyskin 147bd4b999SAlexander Usyskin static int __issei_ham_send_msg(struct issei_device *idev, u32 length, void *buf) 157bd4b999SAlexander Usyskin { 167bd4b999SAlexander Usyskin struct issei_dma_data data = { }; 177bd4b999SAlexander Usyskin int ret; 187bd4b999SAlexander Usyskin 197bd4b999SAlexander Usyskin data.length = length; 207bd4b999SAlexander Usyskin data.buf = buf; 217bd4b999SAlexander Usyskin ret = issei_dma_write(idev, &data); 227bd4b999SAlexander Usyskin if (ret) 237bd4b999SAlexander Usyskin return ret; 247bd4b999SAlexander Usyskin return idev->ops->irq_write_generate(idev); 257bd4b999SAlexander Usyskin } 267bd4b999SAlexander Usyskin 277bd4b999SAlexander Usyskin /** 287bd4b999SAlexander Usyskin * issei_ham_send_start_req - send start request to firmware 297bd4b999SAlexander Usyskin * @idev: issei device object 307bd4b999SAlexander Usyskin * 317bd4b999SAlexander Usyskin * Return: 0 on success, <0 on failures 327bd4b999SAlexander Usyskin */ 337bd4b999SAlexander Usyskin int issei_ham_send_start_req(struct issei_device *idev) 347bd4b999SAlexander Usyskin { 357bd4b999SAlexander Usyskin struct ham_start_message_req req; 367bd4b999SAlexander Usyskin 377bd4b999SAlexander Usyskin req.header.cmd = HAM_BUS_CMD_START_REQ; 387bd4b999SAlexander Usyskin req.supported_version = ISSEI_SUPPORTED_PROTOCOL_VER; 397bd4b999SAlexander Usyskin req.heci_capabilities_length = 0; 407bd4b999SAlexander Usyskin 417bd4b999SAlexander Usyskin return __issei_ham_send_msg(idev, sizeof(req), &req); 427bd4b999SAlexander Usyskin } 437bd4b999SAlexander Usyskin 447bd4b999SAlexander Usyskin /** 457bd4b999SAlexander Usyskin * issei_ham_send_clients_req - send clients request to firmware 467bd4b999SAlexander Usyskin * @idev: issei device object 477bd4b999SAlexander Usyskin * 487bd4b999SAlexander Usyskin * Return: 0 on success, <0 on failures 497bd4b999SAlexander Usyskin */ 507bd4b999SAlexander Usyskin int issei_ham_send_clients_req(struct issei_device *idev) 517bd4b999SAlexander Usyskin { 527bd4b999SAlexander Usyskin struct ham_get_clients_req req; 537bd4b999SAlexander Usyskin 547bd4b999SAlexander Usyskin req.header.cmd = HAM_BUS_CMD_CLIENT_REQ; 557bd4b999SAlexander Usyskin 567bd4b999SAlexander Usyskin return __issei_ham_send_msg(idev, sizeof(req), &req); 577bd4b999SAlexander Usyskin } 587bd4b999SAlexander Usyskin 597bd4b999SAlexander Usyskin static int issei_ham_start_rsp(struct issei_device *idev, const u8 *buf, size_t length) 607bd4b999SAlexander Usyskin { 617bd4b999SAlexander Usyskin struct ham_start_message_res *res = (struct ham_start_message_res *)buf; 627bd4b999SAlexander Usyskin int ret; 637bd4b999SAlexander Usyskin 647bd4b999SAlexander Usyskin if (idev->rst_state != ISSEI_RST_STATE_START) { 657bd4b999SAlexander Usyskin dev_err(&idev->dev, "Wrong state %d != %d\n", 667bd4b999SAlexander Usyskin idev->rst_state, ISSEI_RST_STATE_START); 677bd4b999SAlexander Usyskin return -EPROTO; 687bd4b999SAlexander Usyskin } 697bd4b999SAlexander Usyskin 707bd4b999SAlexander Usyskin if (length < sizeof(*res)) { 717bd4b999SAlexander Usyskin dev_err(&idev->dev, "Small start response size %zu < %zu\n", 727bd4b999SAlexander Usyskin length, sizeof(*res)); 737bd4b999SAlexander Usyskin return -EPROTO; 747bd4b999SAlexander Usyskin } 757bd4b999SAlexander Usyskin 767bd4b999SAlexander Usyskin if (length - sizeof(*res) != res->heci_capabilities_length) { 777bd4b999SAlexander Usyskin dev_err(&idev->dev, "Wrong start response size %zu != %u\n", 787bd4b999SAlexander Usyskin length - sizeof(*res), res->heci_capabilities_length); 797bd4b999SAlexander Usyskin return -EPROTO; 807bd4b999SAlexander Usyskin } 817bd4b999SAlexander Usyskin 827bd4b999SAlexander Usyskin memcpy(idev->fw_version, res->fw_version, sizeof(idev->fw_version)); 837bd4b999SAlexander Usyskin idev->fw_protocol_ver = res->supported_version; 847bd4b999SAlexander Usyskin dev_dbg(&idev->dev, "FW protocol: %u FW version %u.%u.%u.%u", idev->fw_protocol_ver, 857bd4b999SAlexander Usyskin idev->fw_version[0], idev->fw_version[1], 867bd4b999SAlexander Usyskin idev->fw_version[2], idev->fw_version[3]); 877bd4b999SAlexander Usyskin 887bd4b999SAlexander Usyskin ret = issei_ham_send_clients_req(idev); 897bd4b999SAlexander Usyskin if (ret == -EBUSY) 907bd4b999SAlexander Usyskin ret = 0; 917bd4b999SAlexander Usyskin 927bd4b999SAlexander Usyskin return ret; 937bd4b999SAlexander Usyskin } 947bd4b999SAlexander Usyskin 957bd4b999SAlexander Usyskin static int issei_ham_client_rsp(struct issei_device *idev, const u8 *buf, size_t length) 967bd4b999SAlexander Usyskin { 977bd4b999SAlexander Usyskin struct ham_get_clients_res *res = (struct ham_get_clients_res *)buf; 987bd4b999SAlexander Usyskin struct ham_client_properties *client; 997bd4b999SAlexander Usyskin 1007bd4b999SAlexander Usyskin if (idev->rst_state != ISSEI_RST_STATE_CLIENT_ENUM) { 1017bd4b999SAlexander Usyskin dev_err(&idev->dev, "Wrong state %d != %d\n", 1027bd4b999SAlexander Usyskin idev->rst_state, ISSEI_RST_STATE_CLIENT_ENUM); 1037bd4b999SAlexander Usyskin return -EPROTO; 1047bd4b999SAlexander Usyskin } 1057bd4b999SAlexander Usyskin 1067bd4b999SAlexander Usyskin if (length < sizeof(*res)) { 1077bd4b999SAlexander Usyskin dev_err(&idev->dev, "Small response size %zu < %zu\n", length, sizeof(*res)); 1087bd4b999SAlexander Usyskin return -EPROTO; 1097bd4b999SAlexander Usyskin } 1107bd4b999SAlexander Usyskin 1117bd4b999SAlexander Usyskin if (length - sizeof(*res) != res->client_count * sizeof(struct ham_client_properties)) { 1127bd4b999SAlexander Usyskin dev_err(&idev->dev, "Wrong response size %zu < %zu\n", 1137bd4b999SAlexander Usyskin length - sizeof(*res), 1147bd4b999SAlexander Usyskin res->client_count * sizeof(struct ham_client_properties)); 1157bd4b999SAlexander Usyskin return -EPROTO; 1167bd4b999SAlexander Usyskin } 1177bd4b999SAlexander Usyskin 1187bd4b999SAlexander Usyskin guard(mutex)(&idev->client_lock); 1197bd4b999SAlexander Usyskin 1207bd4b999SAlexander Usyskin for (size_t i = 0; i < res->client_count; i++) { 1217bd4b999SAlexander Usyskin client = &res->clients_props[i]; 1227bd4b999SAlexander Usyskin dev_dbg(&idev->dev, "client: id = %u ver = %u uuid = %pUb mtu = %u flags = %u", 1237bd4b999SAlexander Usyskin client->client_number, client->protocol_ver, &client->client_uuid, 1247bd4b999SAlexander Usyskin client->client_mtu, client->flags); 1257bd4b999SAlexander Usyskin issei_fw_cl_create(idev, client->client_number, client->protocol_ver, 1267bd4b999SAlexander Usyskin &client->client_uuid, client->client_mtu, client->flags); 1277bd4b999SAlexander Usyskin } 1287bd4b999SAlexander Usyskin return 0; 1297bd4b999SAlexander Usyskin } 1307bd4b999SAlexander Usyskin 1317bd4b999SAlexander Usyskin static int __issei_ham_process_ham_rsp(struct issei_device *idev, const u8 *buf, size_t length) 1327bd4b999SAlexander Usyskin { 1337bd4b999SAlexander Usyskin struct ham_bus_message *hdr = (struct ham_bus_message *)buf; 1347bd4b999SAlexander Usyskin 135*220190f9SLinmao Li if (length < sizeof(*hdr)) { 136*220190f9SLinmao Li dev_err(&idev->dev, "Small bus message size %zu < %zu\n", 137*220190f9SLinmao Li length, sizeof(*hdr)); 138*220190f9SLinmao Li return -EPROTO; 139*220190f9SLinmao Li } 140*220190f9SLinmao Li 1417bd4b999SAlexander Usyskin switch (hdr->cmd) { 1427bd4b999SAlexander Usyskin case HAM_BUS_CMD_START_RSP: 1437bd4b999SAlexander Usyskin return issei_ham_start_rsp(idev, buf, length); 1447bd4b999SAlexander Usyskin 1457bd4b999SAlexander Usyskin case HAM_BUS_CMD_CLIENT_RSP: 1467bd4b999SAlexander Usyskin return issei_ham_client_rsp(idev, buf, length); 1477bd4b999SAlexander Usyskin 1487bd4b999SAlexander Usyskin default: 1497bd4b999SAlexander Usyskin dev_err(&idev->dev, "Unexpected command 0x%x", hdr->cmd); 1507bd4b999SAlexander Usyskin return -EPROTO; 1517bd4b999SAlexander Usyskin } 1527bd4b999SAlexander Usyskin } 1537bd4b999SAlexander Usyskin 1547bd4b999SAlexander Usyskin /** 1557bd4b999SAlexander Usyskin * issei_ham_process_ham_rsp - process response from firmware and release buffer 1567bd4b999SAlexander Usyskin * @idev: issei device object 1577bd4b999SAlexander Usyskin * @buf: response buffer 1587bd4b999SAlexander Usyskin * @length: response buffer length 1597bd4b999SAlexander Usyskin * 1607bd4b999SAlexander Usyskin * Return: 0 on success, <0 on failures 1617bd4b999SAlexander Usyskin */ 1627bd4b999SAlexander Usyskin int issei_ham_process_ham_rsp(struct issei_device *idev, const u8 *buf, size_t length) 1637bd4b999SAlexander Usyskin { 1647bd4b999SAlexander Usyskin int ret; 1657bd4b999SAlexander Usyskin 1667bd4b999SAlexander Usyskin ret = __issei_ham_process_ham_rsp(idev, buf, length); 1677bd4b999SAlexander Usyskin kfree(buf); 1687bd4b999SAlexander Usyskin return ret; 1697bd4b999SAlexander Usyskin } 170