summaryrefslogtreecommitdiff
path: root/chip/ish/ipc_heci.c
diff options
context:
space:
mode:
Diffstat (limited to 'chip/ish/ipc_heci.c')
-rw-r--r--chip/ish/ipc_heci.c743
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);