/* * Copyright (c) 2020 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include "espi_oob_handler.h" LOG_MODULE_DECLARE(espi, CONFIG_ESPI_LOG_LEVEL); struct oob_header { uint8_t dest_slave_addr; uint8_t oob_cmd_code; uint8_t byte_cnt; uint8_t src_slave_addr; }; #ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC #define OOB_THREAD_STACK_SIZE 512ul #define OOB_THREAD_PRIORITY K_PRIO_COOP(5) #define OOB_THREAD_WAIT -1 /* Thread to process asynchronous callbacks */ void espihub_thread(void *p1, void *p2, void *p3); void temperature_timer(struct k_timer *timer_id); K_TIMER_DEFINE(temp_timer, temperature_timer, NULL); K_THREAD_DEFINE(espihub_thrd_id, OOB_THREAD_STACK_SIZE, espihub_thread, NULL, NULL, NULL, OOB_THREAD_PRIORITY, K_INHERIT_PERMS, OOB_THREAD_WAIT); K_MSGQ_DEFINE(from_host, sizeof(uint8_t), 8, 4); struct thread_context { const struct device *espi_dev; int cycles; }; static struct thread_context context; static bool need_temp; #endif static struct espi_oob_packet resp_pckt; static uint8_t buf[MAX_ESPI_BUF_LEN]; static int request_temp(const struct device *dev) { int ret; struct oob_header oob_hdr; struct espi_oob_packet req_pckt; LOG_WRN("%s", __func__); oob_hdr.dest_slave_addr = PCH_DEST_SLV_ADDR; oob_hdr.oob_cmd_code = OOB_CMDCODE; oob_hdr.byte_cnt = 1; oob_hdr.src_slave_addr = SRC_SLV_ADDR; /* Packetize OOB request */ req_pckt.buf = (uint8_t *)&oob_hdr; req_pckt.len = sizeof(struct oob_header); ret = espi_send_oob(dev, &req_pckt); if (ret) { LOG_ERR("OOB Tx failed %d", ret); return ret; } return 0; } static int retrieve_packet(const struct device *dev, uint8_t *sender) { int ret; #ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC /* Note that no data is in the item */ uint8_t response_len; if (k_msgq_num_used_get(&from_host) == 0U) { return -EINVAL; } k_msgq_get(&from_host, &response_len, K_FOREVER); #endif resp_pckt.buf = (uint8_t *)&buf; resp_pckt.len = MAX_ESPI_BUF_LEN; ret = espi_receive_oob(dev, &resp_pckt); if (ret) { LOG_ERR("OOB Rx failed %d", ret); return ret; } LOG_INF("OOB transaction completed rcvd: %d bytes", resp_pckt.len); for (int i = 0; i < resp_pckt.len; i++) { LOG_INF("%x ", buf[i]); } if (sender) { *sender = buf[OOB_RESPONSE_SENDER_INDEX]; } return 0; } int get_pch_temp_sync(const struct device *dev) { int ret; for (int i = 0; i < MIN_GET_TEMP_CYCLES; i++) { ret = request_temp(dev); if (ret) { LOG_ERR("OOB req failed %d", ret); return ret; } ret = retrieve_packet(dev, NULL); if (ret) { LOG_ERR("OOB retrieve failed %d", ret); return ret; } } return 0; } int get_pch_temp_async(const struct device *dev) { #if !defined(CONFIG_ESPI_OOB_CHANNEL) || \ !defined(CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC) return -ENOTSUP; #else context.espi_dev = dev; context.cycles = MIN_GET_TEMP_CYCLES; k_thread_start(espihub_thrd_id); k_thread_join(espihub_thrd_id, K_FOREVER); return 0; #endif } #ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC void oob_rx_handler(const struct device *dev, struct espi_callback *cb, struct espi_event event) { uint8_t last_resp_len = event.evt_details; LOG_WRN("%s", __func__); /* Post for post-processing in a thread * Should not attempt to retrieve in callback context */ k_msgq_put(&from_host, &last_resp_len, K_NO_WAIT); } void temperature_timer(struct k_timer *timer_id) { LOG_WRN("%s", __func__); need_temp = true; } void espihub_thread(void *p1, void *p2, void *p3) { int ret; uint8_t temp; uint8_t sender; LOG_DBG("%s", __func__); k_timer_start(&temp_timer, K_MSEC(100), K_MSEC(100)); while (context.cycles > 0) { k_msleep(50); ret = retrieve_packet(context.espi_dev, &sender); if (!ret) { switch (sender) { case PCH_DEST_SLV_ADDR: LOG_INF("PCH response"); /* Any other checks */ if (resp_pckt.len == OOB_RESPONSE_LEN) { temp = buf[OOB_RESPONSE_DATA_INDEX]; LOG_INF("Temp %d", temp); } else { LOG_ERR("Incorrect size response"); } break; default: LOG_INF("Other host sender %x", sender); } } else { LOG_ERR("Failure to retrieve temp %d", ret); } /* Decrease cycles in both cases failure/success */ context.cycles--; if (need_temp) { request_temp(context.espi_dev); need_temp = false; } } k_timer_stop(&temp_timer); } #endif /* CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC */