From 48067b1cab750672a4b0ca757e8d5f96bb09727b Mon Sep 17 00:00:00 2001 From: Yuan Liu Date: Wed, 20 Jun 2018 16:44:59 +0800 Subject: [PATCH] IOC mediator: Implement VM monitor operations This patch implements VM monitor operations including stop/suspend/resume. For other VM monitor operations(pause/unpause/query), IOC mediator would not register callbacks for them since there is no requirements from VM Manager. Signed-off-by: Yuan Liu Reviewed-by: Yu Wang Reviewed-by: Kevin Tian --- devicemodel/hw/platform/ioc.c | 107 ++++++++++++++++++++++++++++++ devicemodel/hw/platform/ioc_cbc.c | 48 +++++++++++++- devicemodel/include/ioc.h | 19 +++++- 3 files changed, 169 insertions(+), 5 deletions(-) diff --git a/devicemodel/hw/platform/ioc.c b/devicemodel/hw/platform/ioc.c index 2897fc62c..c35481c43 100644 --- a/devicemodel/hw/platform/ioc.c +++ b/devicemodel/hw/platform/ioc.c @@ -67,6 +67,7 @@ #include "ioc.h" #include "vmmapi.h" +#include "monitor.h" /* For debugging log to a file */ static int ioc_debug; @@ -126,6 +127,38 @@ static int dummy1_sfd = -1; static int dummy2_sfd = -1; #endif +/* + * VM Manager interfaces description. + * + * +---------+ +---------+ +---------+ + * |IOC | VM stop |VM | |SOS | + * |Mediator |<----------------+Manager | |Lifecycle| + * | | | | | | + * | | VM suspend | | | | + * | |<----------------+ | | | + * | | | | | | + * | | VM resume | | | | + * | |<----------------+ | | | + * | |get_wakeup_reason| |get wakeup reason| | + * | |for resume flow | |via unix socket | | + * | +---------------->| +---------------->| | + * +---------+ +---------+ +---------+ + * + * Only support stop/resume/suspend in IOC mediator currently. + * For resume request, IOC mediator will get the wakeup reason from SOS + * lifecycle service, then pass to UOS once received HB INIT from UOS. + * For stop and suspend requests, they are implemented as wakeup reason of + * ignition button. + */ +static int vm_stop_handler(void *arg); +static int vm_resume_handler(void *arg); +static int vm_suspend_handler(void *arg); +static struct monitor_vm_ops vm_ops = { + .stop = vm_stop_handler, + .resume = vm_resume_handler, + .suspend = vm_suspend_handler, +}; + /* * IOC State Transfer * @@ -1301,6 +1334,72 @@ ioc_is_platform_supported(void) return stat(IOC_NP_ESIG, &st); } +/* + * The callback to handle with VM stop request. + * To emulate ignition off wakeup reason including set force S5 bit. + */ +static int +vm_stop_handler(void *arg) +{ + struct ioc_dev *ioc = arg; + + if (!ioc) { + DPRINTF("%s", "ioc vm stop gets NULL pointer\r\n"); + return -1; + } + ioc->vm_req = VM_REQ_STOP; + return 0; +} + +/* + * The callback to handle with VM suspend. + * To emulate ignition off wakeup reason. + */ +static int +vm_suspend_handler(void *arg) +{ + struct ioc_dev *ioc = arg; + + if (!ioc) { + DPRINTF("%s", "ioc vm suspend gets NULL pointer\r\n"); + return -1; + } + ioc->vm_req = VM_REQ_SUSPEND; + return 0; +} + +/* + * The callback to handle with VM resume. + * To get wakeup reason and trigger IOC_E_RESUME event. + */ +static int +vm_resume_handler(void *arg) +{ + struct ioc_dev *ioc = arg; + uint32_t reason; + + if (!ioc) { + DPRINTF("%s", "ioc vm resume gets NULL pointer\r\n"); + return -1; + } + + reason = get_wakeup_reason(); + if (!reason) { + DPRINTF("%s", "ioc vm resume gets invalid wakeup reason \r\n"); + return -1; + } + + /* + * Change VM request to resume for stopping the emulation of suspend + * and shutdown wakeup reasons. + */ + ioc->vm_req = VM_REQ_RESUME; + + ioc->boot_reason = reason; + ioc_update_event(ioc->evt_fd, IOC_E_RESUME); + return 0; +} + /* * To get IOC bootup reason and virtual UART path for communication * between IOC mediator and virtual UART. @@ -1367,6 +1466,14 @@ ioc_init(struct vmctx *ctx) if (ioc->epfd < 0) goto alloc_err; + /* + * Register IOC mediator VM ops for stop/suspend/resume. + */ + if (monitor_register_vm_ops(&vm_ops, ioc, "ioc_dm") < 0) { + DPRINTF("%s", "ioc register to VM monitor failed\r\n"); + goto alloc_err; + } + /* * Put all buffered CBC requests on the free queue, the free queue is * used to be a cbc_request buffer. diff --git a/devicemodel/hw/platform/ioc_cbc.c b/devicemodel/hw/platform/ioc_cbc.c index 27b89d87a..be6e49098 100644 --- a/devicemodel/hw/platform/ioc_cbc.c +++ b/devicemodel/hw/platform/ioc_cbc.c @@ -601,7 +601,7 @@ cbc_update_wakeup_reason(struct cbc_pkt *pkt, uint32_t reason) /* * Mask the bits of wakeup reason that are not allowed by IOC mediator. - * Only allow Ignition button, cardoor, RTC and SoC currently. + * Only allow Ignition button, cardoor, RTC, SOC and force S5 currently. */ reason &= CBC_WK_RSN_ALL; @@ -814,6 +814,45 @@ cbc_rx_handler(struct cbc_pkt *pkt) } } +/* + * Convert VM request to the wakeup reason. + */ +static bool +send_wakeup_reason_of_vm_request(struct cbc_pkt *pkt) +{ + uint32_t reason; + + switch (pkt->ioc->vm_req) { + case VM_REQ_STOP: + /* + * Force S5 and SoC bits are set for emulating + * shutdown wakeup reason that VM initiates stop + */ + reason = CBC_WK_RSN_FS5 | CBC_WK_RSN_SOC; + break; + case VM_REQ_SUSPEND: + /* + * Only SoC bit is set for emulating suspend + * wakeup reason that VM initiates suspend. + */ + reason = CBC_WK_RSN_SOC; + break; + default: + /* + * There is no need to emulate wakeup reasons for VM_REQ_RESUME + * and VM_REQ_NONE VM requests since VM manager just only asks + * IOC mediator to emulate ignition off wakeup reason for + * VM_REQ_STOP and VM_REQ_SUSPEND, otherwise call primary + * periodic wakeup reason. + */ + return false; + } + + cbc_update_wakeup_reason(pkt, reason); + cbc_send_pkt(pkt); + return true; +} + /* * Tx handler mainly processes tx direction data flow, * the tx direction is that native CBC cdevs -> virtual UART. @@ -824,7 +863,12 @@ cbc_tx_handler(struct cbc_pkt *pkt) if (pkt->req->rtype == CBC_REQ_T_PROT && pkt->ioc->cbc_enable) { switch (pkt->req->id) { case IOC_NATIVE_LFCC: - cbc_process_wakeup_reason(pkt); + /* Check VM request firstly */ + if (send_wakeup_reason_of_vm_request(pkt) == false) { + + /* Primary periodic wakeup reason */ + cbc_process_wakeup_reason(pkt); + } break; case IOC_NATIVE_SIGNAL: cbc_process_signal(pkt); diff --git a/devicemodel/include/ioc.h b/devicemodel/include/ioc.h index affb376eb..2a07fe0e1 100644 --- a/devicemodel/include/ioc.h +++ b/devicemodel/include/ioc.h @@ -77,17 +77,19 @@ #define CBC_WK_RSN_BTN (1 << 5) /* CBC wakeup reason field button */ #define CBC_WK_RSN_RTC (1 << 9) /* CBC wakeup reason field rtc */ #define CBC_WK_RSN_DOR (1 << 11) /* CBC wakeup reason field cardoor */ +#define CBC_WK_RSN_FS5 (1 << 22) /* CBC wakeup reason field force S5 */ #define CBC_WK_RSN_SOC (1 << 23) /* CBC wakeup reason field soc */ /* CBC wakeup reason filed suspend or shutdown */ #define CBC_WK_RSN_SHUTDOWN (0) /* - * IOC mediator permits button, rtc and cardoor wakeup reasons which comes from - * IOC firmware, others will be masked. + * IOC mediator permits ignition button, cardoor, RTC, SOC and force S5 wakeup + * reasons which comes from IOC firmware, others will be masked. */ #define CBC_WK_RSN_ALL \ - (CBC_WK_RSN_BTN | CBC_WK_RSN_RTC | CBC_WK_RSN_DOR | CBC_WK_RSN_SOC) + (CBC_WK_RSN_BTN | CBC_WK_RSN_RTC | CBC_WK_RSN_DOR | CBC_WK_RSN_SOC | \ + CBC_WK_RSN_FS5) /* * CBC ring buffer is used to buffer bytes before build one complete CBC frame. @@ -660,6 +662,16 @@ enum ioc_event_type { IOC_E_RESUME }; +/* + * VM request types. + */ +enum vm_request_type { + VM_REQ_NONE, + VM_REQ_STOP, + VM_REQ_SUSPEND, + VM_REQ_RESUME +}; + /* * CBC packet is mainly structure for CBC protocol process. */ @@ -691,6 +703,7 @@ struct ioc_dev { int epfd; /* Epoll fd */ int32_t evt_fd; /* Pipe write fd to trigger one event */ uint32_t boot_reason; /* Boot or resume wakeup reason */ + enum vm_request_type vm_req; /* Request from VM Manager (acrnctl) */ enum ioc_state_type state; /* IOC state type */ struct epoll_event *evts; /* Epoll events table */ struct cbc_request *pool; /* CBC requests pool */