diff options
Diffstat (limited to 'chip/ish/ipc_heci.c')
-rw-r--r-- | chip/ish/ipc_heci.c | 743 |
1 files changed, 0 insertions, 743 deletions
diff --git a/chip/ish/ipc_heci.c b/chip/ish/ipc_heci.c deleted file mode 100644 index 5271aa3a91..0000000000 --- a/chip/ish/ipc_heci.c +++ /dev/null @@ -1,743 +0,0 @@ -/* Copyright 2018 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* IPC module for ISH */ - -/** - * IPC - Inter Processor Communication - * ----------------------------------- - * - * IPC is a bi-directional doorbell based message passing interface sans - * session and transport layers, between hardware blocks. ISH uses IPC to - * communicate with the Host, PMC (Power Management Controller), CSME - * (Converged Security and Manageability Engine), Audio, Graphics and ISP. - * - * Both the initiator and target ends each have a 32-bit doorbell register and - * 128-byte message regions. In addition, the following register pairs help in - * synchronizing IPC. - * - * - Peripheral Interrupt Status Register (PISR) - * - Peripheral Interrupt Mask Register (PIMR) - * - Doorbell Clear Status Register (DB CSR) - */ - -#include "registers.h" -#include "console.h" -#include "task.h" -#include "util.h" -#include "ipc_heci.h" -#include "ish_fwst.h" -#include "queue.h" -#include "hooks.h" -#include "hwtimer.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) - -/* - * comminucation protocol is defined in Linux Documentation - * <kernel_root>/Documentation/hid/intel-ish-hid.txt - */ - -/* MNG commands */ -/* The ipc_mng_task manages IPC link. It should be the highest priority */ -#define MNG_RX_CMPL_ENABLE 0 -#define MNG_RX_CMPL_DISABLE 1 -#define MNG_RX_CMPL_INDICATION 2 -#define MNG_RESET_NOTIFY 3 -#define MNG_RESET_NOTIFY_ACK 4 -#define MNG_SYNC_FW_CLOCK 5 -#define MNG_ILLEGAL_CMD 0xFF - -/* Doorbell */ -#define IPC_DB_MSG_LENGTH_FIELD 0x3FF -#define IPC_DB_MSG_LENGTH_SHIFT 0 -#define IPC_DB_MSG_LENGTH_MASK \ - (IPC_DB_MSG_LENGTH_FIELD << IPC_DB_MSG_LENGTH_SHIFT) - -#define IPC_DB_PROTOCOL_FIELD 0x0F -#define IPC_DB_PROTOCOL_SHIFT 10 -#define IPC_DB_PROTOCOL_MASK (IPC_DB_PROTOCOL_FIELD << IPC_DB_PROTOCOL_SHIFT) - -#define IPC_DB_CMD_FIELD 0x0F -#define IPC_DB_CMD_SHIFT 16 -#define IPC_DB_CMD_MASK (IPC_DB_CMD_FIELD << IPC_DB_CMD_SHIFT) - -#define IPC_DB_BUSY_SHIFT 31 -#define IPC_DB_BUSY_MASK BIT(IPC_DB_BUSY_SHIFT) - -#define IPC_DB_MSG_LENGTH(drbl) \ - (((drbl) & IPC_DB_MSG_LENGTH_MASK) >> IPC_DB_MSG_LENGTH_SHIFT) -#define IPC_DB_PROTOCOL(drbl) \ - (((drbl) & IPC_DB_PROTOCOL_MASK) >> IPC_DB_PROTOCOL_SHIFT) -#define IPC_DB_CMD(drbl) \ - (((drbl) & IPC_DB_CMD_MASK) >> IPC_DB_CMD_SHIFT) -#define IPC_DB_BUSY(drbl) (!!((drbl) & IPC_DB_BUSY_MASK)) - -#define IPC_BUILD_DB(length, proto, cmd, busy) \ - (((busy) << IPC_DB_BUSY_SHIFT) | ((cmd) << IPC_DB_CMD_SHIFT) | \ - ((proto) << IPC_DB_PROTOCOL_SHIFT) | \ - ((length) << IPC_DB_MSG_LENGTH_SHIFT)) - -#define IPC_BUILD_MNG_DB(cmd, length) \ - IPC_BUILD_DB(length, IPC_PROTOCOL_MNG, cmd, 1) - -#define IPC_BUILD_HECI_DB(length) \ - IPC_BUILD_DB(length, IPC_PROTOCOL_HECI, 0, 1) - -#define IPC_MSG_MAX_SIZE 0x80 -#define IPC_HOST_MSG_QUEUE_SIZE 8 -#define IPC_PMC_MSG_QUEUE_SIZE 2 - -#define IPC_HANDLE_PEER_ID_SHIFT 4 -#define IPC_HANDLE_PROTOCOL_SHIFT 0 -#define IPC_HANDLE_PROTOCOL_MASK 0x0F -#define IPC_BUILD_HANDLE(peer_id, protocol) \ - ((ipc_handle_t)(((peer_id) << IPC_HANDLE_PEER_ID_SHIFT) | (protocol))) -#define IPC_BUILD_MNG_HANDLE(peer_id) \ - IPC_BUILD_HANDLE((peer_id), IPC_PROTOCOL_MNG) -#define IPC_BUILD_HOST_MNG_HANDLE() IPC_BUILD_MNG_HANDLE(IPC_PEER_ID_HOST) -#define IPC_HANDLE_PEER_ID(handle) \ - ((uint32_t)(handle) >> IPC_HANDLE_PEER_ID_SHIFT) -#define IPC_HANDLE_PROTOCOL(handle) \ - ((uint32_t)(handle) & IPC_HANDLE_PROTOCOL_MASK) -#define IPC_IS_VALID_HANDLE(handle) \ - (IPC_HANDLE_PEER_ID(handle) < IPC_PEERS_COUNT && \ - IPC_HANDLE_PROTOCOL(handle) < IPC_PROTOCOL_COUNT) - -struct ipc_msg { - uint32_t drbl; - uint32_t *timestamp_of_outgoing_doorbell; - uint8_t payload[IPC_MSG_MAX_SIZE]; -} __packed; - -struct ipc_rst_payload { - uint16_t reset_id; - uint16_t reserved; -}; - -struct ipc_oob_msg { - uint32_t address; - uint32_t length; -}; - -struct ipc_msg_event { - task_id_t task_id; - uint32_t event; - uint8_t enabled; -}; - -/* - * IPC interface context - * This is per-IPC context. - */ -struct ipc_if_ctx { - volatile uint8_t *in_msg_reg; - volatile uint8_t *out_msg_reg; - volatile uint32_t *in_drbl_reg; - volatile uint32_t *out_drbl_reg; - uint32_t clr_busy_bit; - uint32_t pimr_2ish_bit; - uint32_t pimr_2host_clearing_bit; - uint8_t irq_in; - uint8_t irq_clr; - uint16_t reset_id; - struct ipc_msg_event msg_events[IPC_PROTOCOL_COUNT]; - struct mutex lock; - struct mutex write_lock; - - struct queue tx_queue; - uint8_t is_tx_ipc_busy; - uint8_t initialized; -}; - -/* list of peer contexts */ -static struct ipc_if_ctx ipc_peer_ctxs[IPC_PEERS_COUNT] = { - [IPC_PEER_ID_HOST] = { - .in_msg_reg = IPC_HOST2ISH_MSG_BASE, - .out_msg_reg = IPC_ISH2HOST_MSG_BASE, - .in_drbl_reg = IPC_HOST2ISH_DOORBELL_ADDR, - .out_drbl_reg = IPC_ISH2HOST_DOORBELL_ADDR, - .clr_busy_bit = IPC_DB_CLR_STS_ISH2HOST_BIT, - .pimr_2ish_bit = IPC_PIMR_HOST2ISH_BIT, - .pimr_2host_clearing_bit = IPC_PIMR_ISH2HOST_CLR_BIT, - .irq_in = ISH_IPC_HOST2ISH_IRQ, - .irq_clr = ISH_IPC_ISH2HOST_CLR_IRQ, - .tx_queue = QUEUE_NULL(IPC_HOST_MSG_QUEUE_SIZE, struct ipc_msg), - }, - /* Other peers (PMC, CSME, etc) to be added when required */ -}; - -static inline struct ipc_if_ctx *ipc_get_if_ctx(const uint32_t peer_id) -{ - return &ipc_peer_ctxs[peer_id]; -} - -static inline struct ipc_if_ctx *ipc_handle_to_if_ctx(const ipc_handle_t handle) -{ - return ipc_get_if_ctx(IPC_HANDLE_PEER_ID(handle)); -} - -static inline void ipc_enable_pimr_db_interrupt(const struct ipc_if_ctx *ctx) -{ - IPC_PIMR |= ctx->pimr_2ish_bit; -} - -static inline void ipc_disable_pimr_db_interrupt(const struct ipc_if_ctx *ctx) -{ - IPC_PIMR &= ~ctx->pimr_2ish_bit; -} - -static inline void ipc_enable_pimr_clearing_interrupt( - const struct ipc_if_ctx *ctx) -{ - IPC_PIMR |= ctx->pimr_2host_clearing_bit; -} - -static inline void ipc_disable_pimr_clearing_interrupt( - const struct ipc_if_ctx *ctx) -{ - IPC_PIMR &= ~ctx->pimr_2host_clearing_bit; -} - -static void write_payload_and_ring_drbl(const struct ipc_if_ctx *ctx, - uint32_t drbl, - const uint8_t *payload, - size_t payload_size) -{ - memcpy((void *)(ctx->out_msg_reg), payload, payload_size); - *(ctx->out_drbl_reg) = drbl; -} - -static int ipc_write_raw_timestamp(struct ipc_if_ctx *ctx, uint32_t drbl, - const uint8_t *payload, size_t payload_size, - uint32_t *timestamp) -{ - struct queue *q = &ctx->tx_queue; - struct ipc_msg *msg; - size_t tail, space; - int res = 0; - - mutex_lock(&ctx->write_lock); - - ipc_disable_pimr_clearing_interrupt(ctx); - if (ctx->is_tx_ipc_busy) { - space = queue_space(q); - if (space) { - tail = q->state->tail & (q->buffer_units - 1); - msg = (struct ipc_msg *)q->buffer + tail; - msg->drbl = drbl; - msg->timestamp_of_outgoing_doorbell = timestamp; - memcpy(msg->payload, payload, payload_size); - queue_advance_tail(q, 1); - } else { - CPRINTS("tx queue is full"); - res = -IPC_ERR_TX_QUEUE_FULL; - } - - ipc_enable_pimr_clearing_interrupt(ctx); - goto write_unlock; - } - ctx->is_tx_ipc_busy = 1; - ipc_enable_pimr_clearing_interrupt(ctx); - - write_payload_and_ring_drbl(ctx, drbl, payload, payload_size); - - /* We wrote inline, take timestamp now */ - if (timestamp) - *timestamp = __hw_clock_source_read(); - -write_unlock: - mutex_unlock(&ctx->write_lock); - return res; -} - -static int ipc_write_raw(struct ipc_if_ctx *ctx, uint32_t drbl, - const uint8_t *payload, size_t payload_size) -{ - return ipc_write_raw_timestamp(ctx, drbl, payload, payload_size, NULL); -} - -static int ipc_send_reset_notify(const ipc_handle_t handle) -{ - struct ipc_rst_payload *ipc_rst; - struct ipc_if_ctx *ctx; - struct ipc_msg msg; - - ctx = ipc_handle_to_if_ctx(handle); - ctx->reset_id = (uint16_t)ish_fwst_get_reset_id(); - ipc_rst = (struct ipc_rst_payload *)msg.payload; - ipc_rst->reset_id = ctx->reset_id; - - msg.drbl = IPC_BUILD_MNG_DB(MNG_RESET_NOTIFY, sizeof(*ipc_rst)); - ipc_write_raw(ctx, msg.drbl, msg.payload, IPC_DB_MSG_LENGTH(msg.drbl)); - - return 0; -} - -static int ipc_send_cmpl_indication(struct ipc_if_ctx *ctx) -{ - struct ipc_msg msg; - - msg.drbl = IPC_BUILD_MNG_DB(MNG_RX_CMPL_INDICATION, 0); - ipc_write_raw(ctx, msg.drbl, msg.payload, IPC_DB_MSG_LENGTH(msg.drbl)); - - return 0; -} - -static int ipc_get_protocol_data(const struct ipc_if_ctx *ctx, - const uint32_t protocol, - uint8_t *buf, const size_t buf_size) -{ - int len = 0, payload_size; - uint8_t *src = NULL, *dest = NULL; - struct ipc_msg *msg; - uint32_t drbl_val; - - drbl_val = *(ctx->in_drbl_reg); - payload_size = IPC_DB_MSG_LENGTH(drbl_val); - - if (payload_size > IPC_MAX_PAYLOAD_SIZE) { - CPRINTS("invalid msg : payload is too big"); - return -IPC_ERR_INVALID_MSG; - } - - switch (protocol) { - case IPC_PROTOCOL_HECI: - /* copy only payload which is a heci packet */ - len = payload_size; - break; - case IPC_PROTOCOL_MNG: - /* copy including doorbell which forms a ipc packet */ - len = payload_size + sizeof(drbl_val); - break; - default: - CPRINTS("protocol %d not supported yet", protocol); - break; - } - - if (len > buf_size) { - CPRINTS("buffer is smaller than payload"); - return -IPC_ERR_TOO_SMALL_BUFFER; - } - - if (IS_ENABLED(IPC_HECI_DEBUG)) - CPRINTF("ipc p=%d, db=0x%0x, payload_size=%d\n", - protocol, drbl_val, - IPC_DB_MSG_LENGTH(drbl_val)); - - switch (protocol) { - case IPC_PROTOCOL_HECI: - src = (uint8_t *)ctx->in_msg_reg; - dest = buf; - break; - case IPC_PROTOCOL_MNG: - src = (uint8_t *)ctx->in_msg_reg; - msg = (struct ipc_msg *)buf; - msg->drbl = drbl_val; - dest = msg->payload; - break; - default : - break; - } - - if (src && dest) - memcpy(dest, src, payload_size); - - return len; -} - -static void set_pimr_and_send_rx_complete(struct ipc_if_ctx *ctx) -{ - ipc_enable_pimr_db_interrupt(ctx); - ipc_send_cmpl_indication(ctx); -} - -static void handle_msg_recv_interrupt(const uint32_t peer_id) -{ - struct ipc_if_ctx *ctx; - uint32_t drbl_val, payload_size, protocol, invalid_msg = 0; - - ctx = ipc_get_if_ctx(peer_id); - ipc_disable_pimr_db_interrupt(ctx); - - drbl_val = *(ctx->in_drbl_reg); - protocol = IPC_DB_PROTOCOL(drbl_val); - payload_size = IPC_DB_MSG_LENGTH(drbl_val); - - if (payload_size > IPC_MSG_MAX_SIZE) - invalid_msg = 1; - - if (!ctx->msg_events[protocol].enabled) - invalid_msg = 2; - - if (!invalid_msg) { - /* send event to task */ - task_set_event(ctx->msg_events[protocol].task_id, - ctx->msg_events[protocol].event, 0); - } else { - CPRINTS("discard msg (%d) : %d", protocol, invalid_msg); - - *(ctx->in_drbl_reg) = 0; - set_pimr_and_send_rx_complete(ctx); - } -} - -static void handle_busy_clear_interrupt(const uint32_t peer_id) -{ - struct ipc_if_ctx *ctx; - struct ipc_msg *msg; - struct queue *q; - size_t head; - - ctx = ipc_get_if_ctx(peer_id); - - /* - * Resetting interrupt status bit should be done - * before sending an item in tx_queue. - */ - IPC_BUSY_CLEAR = ctx->clr_busy_bit; - - /* - * No need to use sync mechanism here since the accesing the queue - * happens only when either this IRQ is disabled or - * in ISR context(here) of this IRQ. - */ - if (!queue_is_empty(&ctx->tx_queue)) { - q = &ctx->tx_queue; - head = q->state->head & (q->buffer_units - 1); - msg = (struct ipc_msg *)(q->buffer + head * q->unit_bytes); - write_payload_and_ring_drbl(ctx, msg->drbl, msg->payload, - IPC_DB_MSG_LENGTH(msg->drbl)); - if (msg->timestamp_of_outgoing_doorbell) - *msg->timestamp_of_outgoing_doorbell = - __hw_clock_source_read(); - - queue_advance_head(q, 1); - } else { - ctx->is_tx_ipc_busy = 0; - } -} - -/** - * IPC interrupts are received by the FW when a) Host SW rings doorbell and - * b) when Host SW clears doorbell busy bit [31]. - * - * Doorbell Register (DB) bits - * ----+-------+--------+-----------+--------+------------+-------------------- - * 31 | 30 29 | 28-20 |19 18 17 16| 15 14 | 13 12 11 10| 9 8 7 6 5 4 3 2 1 0 - * ----+-------+--------+-----------+--------+------------+-------------------- - * Busy|Options|Reserved| Command |Reserved| Protocol | Message Length - * ----+-------+--------+-----------+--------+------------+-------------------- - * - * ISH Peripheral Interrupt Status Register: - * Bit 0 - If set, indicates interrupt was caused by setting Host2ISH DB - * - * ISH Peripheral Interrupt Mask Register - * Bit 0 - If set, mask interrupt caused by Host2ISH DB - * - * ISH Peripheral DB Clear Status Register - * Bit 0 - If set, indicates interrupt was caused by clearing Host2ISH DB - */ -static void ipc_host2ish_isr(void) -{ - uint32_t pisr = IPC_PISR; - uint32_t pimr = IPC_PIMR; - - /* - * Ensure that the host IPC write power is requested after getting an - * interrupt otherwise the resume message will never get delivered (via - * host ipc communication). Resume is where we would like to restore all - * power settings, but that is too late for this power request. - */ - if (IS_ENABLED(CHIP_FAMILY_ISH5)) - PMU_VNN_REQ = VNN_REQ_IPC_HOST_WRITE & ~PMU_VNN_REQ; - - if ((pisr & IPC_PISR_HOST2ISH_BIT) && (pimr & IPC_PIMR_HOST2ISH_BIT)) - handle_msg_recv_interrupt(IPC_PEER_ID_HOST); -} -#ifndef CONFIG_ISH_HOST2ISH_COMBINED_ISR -DECLARE_IRQ(ISH_IPC_HOST2ISH_IRQ, ipc_host2ish_isr); -#endif - -static void ipc_host2ish_busy_clear_isr(void) -{ - uint32_t busy_clear = IPC_BUSY_CLEAR; - uint32_t pimr = IPC_PIMR; - - if ((busy_clear & IPC_DB_CLR_STS_ISH2HOST_BIT) && - (pimr & IPC_PIMR_ISH2HOST_CLR_BIT)) - handle_busy_clear_interrupt(IPC_PEER_ID_HOST); -} -#ifndef CONFIG_ISH_HOST2ISH_COMBINED_ISR -DECLARE_IRQ(ISH_IPC_ISH2HOST_CLR_IRQ, ipc_host2ish_busy_clear_isr); -#endif - -static __maybe_unused void ipc_host2ish_combined_isr(void) -{ - ipc_host2ish_isr(); - ipc_host2ish_busy_clear_isr(); -} -#ifdef CONFIG_ISH_HOST2ISH_COMBINED_ISR -DECLARE_IRQ(ISH_IPC_HOST2ISH_IRQ, ipc_host2ish_combined_isr); -#endif - -int ipc_write_timestamp(const ipc_handle_t handle, const void *buf, - const size_t buf_size, uint32_t *timestamp) -{ - int ret; - struct ipc_if_ctx *ctx; - uint32_t drbl = 0; - const uint8_t *payload = NULL; - int payload_size; - uint32_t protocol; - - if (!IPC_IS_VALID_HANDLE(handle)) - return -EC_ERROR_INVAL; - - protocol = IPC_HANDLE_PROTOCOL(handle); - ctx = ipc_handle_to_if_ctx(handle); - - if (ctx->initialized == 0) { - CPRINTS("open_ipc() for the peer is never called"); - return -EC_ERROR_INVAL; - } - - if (!ctx->msg_events[protocol].enabled) { - CPRINTS("call open_ipc() for the protocol first"); - return -EC_ERROR_INVAL; - } - - switch (protocol) { - case IPC_PROTOCOL_BOOT: - break; - case IPC_PROTOCOL_HECI: - drbl = IPC_BUILD_HECI_DB(buf_size); - payload = buf; - break; - case IPC_PROTOCOL_MCTP: - break; - case IPC_PROTOCOL_MNG: - drbl = ((struct ipc_msg *)buf)->drbl; - payload = ((struct ipc_msg *)buf)->payload; - break; - case IPC_PROTOCOL_ECP: - /* TODO : EC protocol */ - break; - } - - payload_size = IPC_DB_MSG_LENGTH(drbl); - if (payload_size > IPC_MSG_MAX_SIZE) { - /* too much input */ - return -EC_ERROR_OVERFLOW; - } - - ret = ipc_write_raw_timestamp(ctx, drbl, payload, payload_size, - timestamp); - if (ret) - return ret; - - return buf_size; -} - -ipc_handle_t ipc_open(const enum ipc_peer_id peer_id, - const enum ipc_protocol protocol, - const uint32_t event) -{ - struct ipc_if_ctx *ctx; - - if (protocol >= IPC_PROTOCOL_COUNT || - peer_id >= IPC_PEERS_COUNT) - return IPC_INVALID_HANDLE; - - ctx = ipc_get_if_ctx(peer_id); - mutex_lock(&ctx->lock); - if (ctx->msg_events[protocol].enabled) { - mutex_unlock(&ctx->lock); - return IPC_INVALID_HANDLE; - } - - ctx->msg_events[protocol].task_id = task_get_current(); - ctx->msg_events[protocol].enabled = 1; - ctx->msg_events[protocol].event = event; - - /* For HECI protocol, set HECI UP status when IPC link is ready */ - if (peer_id == IPC_PEER_ID_HOST && - protocol == IPC_PROTOCOL_HECI && ish_fwst_is_ilup_set()) - ish_fwst_set_hup(); - - if (ctx->initialized == 0) { - task_enable_irq(ctx->irq_in); - if (!IS_ENABLED(CONFIG_ISH_HOST2ISH_COMBINED_ISR)) - task_enable_irq(ctx->irq_clr); - - ipc_enable_pimr_db_interrupt(ctx); - ipc_enable_pimr_clearing_interrupt(ctx); - - ctx->initialized = 1; - } - mutex_unlock(&ctx->lock); - - return IPC_BUILD_HANDLE(peer_id, protocol); -} - -static void handle_mng_commands(const ipc_handle_t handle, - const struct ipc_msg *msg) -{ - struct ipc_rst_payload *ipc_rst; - struct ipc_if_ctx *ctx; - uint32_t peer_id = IPC_HANDLE_PEER_ID(handle); - - ctx = ipc_handle_to_if_ctx(handle); - - switch (IPC_DB_CMD(msg->drbl)) { - case MNG_RX_CMPL_ENABLE: - case MNG_RX_CMPL_DISABLE: - case MNG_RX_CMPL_INDICATION: - case MNG_RESET_NOTIFY: - CPRINTS("msg not handled %d", IPC_DB_CMD(msg->drbl)); - break; - case MNG_RESET_NOTIFY_ACK: - ipc_rst = (struct ipc_rst_payload *)msg->payload; - if (peer_id == IPC_PEER_ID_HOST && - ipc_rst->reset_id == ctx->reset_id) { - ish_fwst_set_ilup(); - if (ctx->msg_events[IPC_PROTOCOL_HECI].enabled) - ish_fwst_set_hup(); - } - - break; - case MNG_SYNC_FW_CLOCK: - /* Not supported currently, but kernel sends this about ~20s */ - break; - } -} - -static int do_ipc_read(struct ipc_if_ctx *ctx, const uint32_t protocol, - uint8_t *buf, const size_t buf_size) -{ - int len; - - len = ipc_get_protocol_data(ctx, protocol, buf, buf_size); - - *(ctx->in_drbl_reg) = 0; - set_pimr_and_send_rx_complete(ctx); - - return len; -} - -static int ipc_check_read_validity(const struct ipc_if_ctx *ctx, - const uint32_t protocol) -{ - if (ctx->initialized == 0) - return -EC_ERROR_INVAL; - - if (!ctx->msg_events[protocol].enabled) - return -EC_ERROR_INVAL; - - /* ipc_read() should be called by the same task called ipc_open() */ - if (ctx->msg_events[protocol].task_id != task_get_current()) - return -IPC_ERR_INVALID_TASK; - - return 0; -} - -/* - * ipc_read should be called by the same task context which called ipc_open() - */ -int ipc_read(const ipc_handle_t handle, void *buf, const size_t buf_size, - int timeout_us) -{ - struct ipc_if_ctx *ctx; - uint32_t events, protocol, drbl_protocol, drbl_val; - int ret; - - if (!IPC_IS_VALID_HANDLE(handle)) - return -EC_ERROR_INVAL; - - protocol = IPC_HANDLE_PROTOCOL(handle); - ctx = ipc_handle_to_if_ctx(handle); - - ret = ipc_check_read_validity(ctx, protocol); - if (ret) - return ret; - - if (timeout_us) { - events = task_wait_event_mask(ctx->msg_events[protocol].event, - timeout_us); - - if (events & TASK_EVENT_TIMER) - return -EC_ERROR_TIMEOUT; - - if (!(events & ctx->msg_events[protocol].event)) - return -EC_ERROR_UNKNOWN; - } else { - /* check if msg for the protocol is available */ - drbl_val = *(ctx->in_drbl_reg); - drbl_protocol = IPC_DB_PROTOCOL(drbl_val); - if (!(protocol == drbl_protocol) || !IPC_DB_BUSY(drbl_val)) - return -IPC_ERR_MSG_NOT_AVAILABLE; - } - - return do_ipc_read(ctx, protocol, buf, buf_size); -} - -/* event flag for MNG msg */ -#define EVENT_FLAG_BIT_MNG_MSG TASK_EVENT_CUSTOM_BIT(0) - -/* - * This task handles MNG messages - */ -void ipc_mng_task(void) -{ - int payload_size; - struct ipc_msg msg; - ipc_handle_t handle; - - /* - * Ensure that power for host IPC writes is requested and ack'ed - */ - if (IS_ENABLED(CHIP_FAMILY_ISH5)) { - PMU_VNN_REQ = VNN_REQ_IPC_HOST_WRITE & ~PMU_VNN_REQ; - while (!(PMU_VNN_REQ_ACK & PMU_VNN_REQ_ACK_STATUS)) - continue; - } - - handle = ipc_open(IPC_PEER_ID_HOST, IPC_PROTOCOL_MNG, - EVENT_FLAG_BIT_MNG_MSG); - - ASSERT(handle != IPC_INVALID_HANDLE); - - ipc_send_reset_notify(handle); - - while (1) { - payload_size = ipc_read(handle, &msg, sizeof(msg), -1); - - /* allow doorbell with any payload */ - if (payload_size < 0) { - CPRINTS("ipc_read error. discard msg"); - continue; /* TODO: retry several and exit */ - } - - /* handle MNG commands */ - handle_mng_commands(handle, &msg); - } -} - -void ipc_init(void) -{ - int i; - struct ipc_if_ctx *ctx; - - for (i = 0; i < IPC_PEERS_COUNT; i++) { - ctx = ipc_get_if_ctx(i); - queue_init(&ctx->tx_queue); - } - - /* inform host firmware is running */ - ish_fwst_set_fw_status(FWSTS_FW_IS_RUNNING); -} -DECLARE_HOOK(HOOK_INIT, ipc_init, HOOK_PRIO_DEFAULT); |