/* Copyright 2019 The ChromiumOS Authors * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "common.h" #include "console.h" #include "heci_client.h" #include "host_command.h" #include "host_command_heci.h" #include "ipc_heci.h" #include "ish_fwst.h" #include "util.h" #define CPUTS(outstr) cputs(CC_LPC, outstr) #define CPRINTS(format, args...) cprints(CC_LPC, format, ## args) #define CPRINTF(format, args...) cprintf(CC_LPC, format, ## args) #define HECI_CLIENT_CROS_EC_ISH_GUID { 0x7b7154d0, 0x56f4, 0x4bdc,\ { 0xb0, 0xd8, 0x9e, 0x7c, 0xda, 0xe0, 0xd6, 0xa0 } } /* Handle for all heci cros_ec interactions */ static heci_handle_t heci_cros_ec_handle = HECI_INVALID_HANDLE; /* * If we hit response buffer size issues, we can increase this. This is the * current size of a single HECI packet. * * Aligning with other assumptions in host command stack, only a single host * command can be processed at a given time. */ struct cros_ec_ishtp_msg_hdr { uint8_t channel; uint8_t status; uint8_t id; /* Pairs up request and responses */ uint8_t reserved; } __ec_align4; #define CROS_EC_ISHTP_MSG_HDR_SIZE sizeof(struct cros_ec_ishtp_msg_hdr) #define HECI_CROS_EC_RESPONSE_MAX \ (HECI_IPC_PAYLOAD_SIZE - CROS_EC_ISHTP_MSG_HDR_SIZE) struct cros_ec_ishtp_msg { struct cros_ec_ishtp_msg_hdr hdr; uint8_t data[0]; } __ec_align4; enum heci_cros_ec_channel { CROS_EC_COMMAND = 1, /* initiated from AP */ CROS_MKBP_EVENT = 2, /* initiated from EC */ }; static uint8_t response_buffer[IPC_MAX_PAYLOAD_SIZE] __aligned(4); static struct host_packet heci_packet; int heci_send_mkbp_event(uint32_t *timestamp) { struct cros_ec_ishtp_msg evt; int rv; evt.hdr.channel = CROS_MKBP_EVENT; evt.hdr.status = 0; rv = heci_send_msg_timestamp(heci_cros_ec_handle, (uint8_t *)&evt, sizeof(evt), timestamp); /* * heci_send_msg_timestamp sends back negative error codes. Change to * EC style codes */ return rv < 0 ? -rv : EC_SUCCESS; } static void heci_send_hostcmd_response(struct host_packet *pkt) { int rv; struct cros_ec_ishtp_msg *out = (struct cros_ec_ishtp_msg *)response_buffer; out->hdr.channel = CROS_EC_COMMAND; out->hdr.status = 0; /* id is already set in the receiving method */ rv = heci_send_msg(heci_cros_ec_handle, (uint8_t *)out, pkt->response_size + CROS_EC_ISHTP_MSG_HDR_SIZE); if (rv < 0) CPRINTS("HC response failed %d", -rv); } static void cros_ec_ishtp_subsys_new_msg_received(const heci_handle_t handle, uint8_t *msg, const size_t msg_size) { struct cros_ec_ishtp_msg *in = (void *) msg; struct cros_ec_ishtp_msg *out = (void *) response_buffer; if (in->hdr.channel != CROS_EC_COMMAND) { CPRINTS("Unknown HECI packet 0x%02x", in->hdr.channel); return; } memset(&heci_packet, 0, sizeof(heci_packet)); /* Copy over id from sender so they can pair up messages */ out->hdr.id = in->hdr.id; heci_packet.send_response = heci_send_hostcmd_response; heci_packet.request = in->data; heci_packet.request_max = HECI_MAX_MSG_SIZE; heci_packet.request_size = msg_size - CROS_EC_ISHTP_MSG_HDR_SIZE; heci_packet.response = out->data; heci_packet.response_max = HECI_CROS_EC_RESPONSE_MAX; heci_packet.response_size = 0; heci_packet.driver_result = EC_RES_SUCCESS; host_packet_receive(&heci_packet); } /* * IPC transfer max is actual 4K, but we don't need kernel buffers that big * * Basing size off of existing cros_ec implementations ranging from 128 to 512 */ #define HECI_CROS_EC_LIMIT_PACKET_SIZE 256 /** * Get protocol information */ static enum ec_status heci_get_protocol_info(struct host_cmd_handler_args *args) { struct ec_response_get_protocol_info *r = args->response; memset(r, 0, sizeof(*r)); r->protocol_versions = BIT(3); r->max_request_packet_size = HECI_CROS_EC_LIMIT_PACKET_SIZE; r->max_response_packet_size = HECI_CROS_EC_RESPONSE_MAX; args->response_size = sizeof(*r); return EC_RES_SUCCESS; } DECLARE_HOST_COMMAND(EC_CMD_GET_PROTOCOL_INFO, heci_get_protocol_info, EC_VER_MASK(0)); static int cros_ec_ishtp_subsys_initialize(const heci_handle_t heci_handle) { heci_cros_ec_handle = heci_handle; ish_fwst_set_fw_status(FWSTS_SENSOR_APP_RUNNING); return EC_SUCCESS; } static int cros_ec_ishtp_no_op(const heci_handle_t heci_handle) { return EC_SUCCESS; } static void cros_ec_ishtp_disconneted(const heci_handle_t heci_handle) { } static const struct heci_client_callbacks cros_ec_ishtp_subsys_heci_cbs = { .initialize = cros_ec_ishtp_subsys_initialize, .new_msg_received = cros_ec_ishtp_subsys_new_msg_received, .suspend = cros_ec_ishtp_no_op, .resume = cros_ec_ishtp_no_op, .disconnected = cros_ec_ishtp_disconneted, }; static const struct heci_client cros_ec_ishtp_heci_client = { .protocol_id = HECI_CLIENT_CROS_EC_ISH_GUID, .max_msg_size = HECI_MAX_MSG_SIZE, .protocol_ver = 1, .max_n_of_connections = 1, .cbs = &cros_ec_ishtp_subsys_heci_cbs, }; HECI_CLIENT_ENTRY(cros_ec_ishtp_heci_client);