mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-19 12:12:16 +00:00
IOC mediator: Implement state transfer framework
Implements state transfer framework to support IOC lifecycle virtualization. Four states will be involved in this framework includes INIT, ACTIVE,SUSPENDING and SUSPENDED. Signed-off-by: Liu Yuan <yuan1.liu@intel.com> Reviewed-by: Wang Yu <yu1.wang@intel.com> Reviewed-by: Liu Shuo <shuo.a.liu@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
parent
92da8f4954
commit
11208dd6d5
@ -139,6 +139,59 @@ static int dummy1_sfd = -1;
|
|||||||
static int dummy2_sfd = -1;
|
static int dummy2_sfd = -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IOC State Transfer
|
||||||
|
*
|
||||||
|
* +-----------+ RESUME EVENT +-----------+
|
||||||
|
* | INIT +<---------------------------+ SUSPENDED |
|
||||||
|
* +-----+-----+ +-----------+
|
||||||
|
* | ^
|
||||||
|
* | |
|
||||||
|
* |HB ACTIVE |SHUTDOWN
|
||||||
|
* |EVENT |EVENT
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* v RAM REFRESH EVENT/ |
|
||||||
|
* +-----+-----+ HB INACTIVE EVENT +-----+-----+
|
||||||
|
* | ACTIVE +--------------------------->+SUSPENDING |
|
||||||
|
* +-----------+ +-----------+
|
||||||
|
*
|
||||||
|
* INIT state: The state is IOC mediator initialized IOC state, all of CBC
|
||||||
|
* protocol packats are handler normally. In this state, UOS has
|
||||||
|
* not yet sent active heartbeat.
|
||||||
|
*
|
||||||
|
* ACTIVE state: Enter this state if HB ACTIVE event is triggered that indicates
|
||||||
|
* UOS state has been active and need to set the bit 23(SoC active
|
||||||
|
* bit) in the wakeup reason.
|
||||||
|
*
|
||||||
|
* SUSPENDING state: Enter this state if RAM REFRESH event or HB INACTIVE event
|
||||||
|
* is triggered, the related event handler needs to set the
|
||||||
|
* suspend or shutdown to PM DM and begin to drop the queued
|
||||||
|
* CBC protocol packets.
|
||||||
|
*
|
||||||
|
* SUSPENDED state: Enter this state if SHUTDOWN event is triggered to close all
|
||||||
|
* native CBC char devices. The IOC mediator will be enter to
|
||||||
|
* sleeping until RESUME event is triggered that re-opens
|
||||||
|
* closed native CBC char devices and transfer to INIT state.
|
||||||
|
*/
|
||||||
|
static int process_hb_active_event(struct ioc_dev *ioc);
|
||||||
|
static int process_ram_refresh_event(struct ioc_dev *ioc);
|
||||||
|
static int process_hb_inactive_event(struct ioc_dev *ioc);
|
||||||
|
static int process_shutdown_event(struct ioc_dev *ioc);
|
||||||
|
static int process_resume_event(struct ioc_dev *ioc);
|
||||||
|
static struct ioc_state_info ioc_state_tbl[] = {
|
||||||
|
{IOC_S_INIT, IOC_S_ACTIVE, IOC_E_HB_ACTIVE,
|
||||||
|
process_hb_active_event},
|
||||||
|
{IOC_S_ACTIVE, IOC_S_SUSPENDING, IOC_E_RAM_REFRESH,
|
||||||
|
process_ram_refresh_event},
|
||||||
|
{IOC_S_ACTIVE, IOC_S_SUSPENDING, IOC_E_HB_INACTIVE,
|
||||||
|
process_hb_inactive_event},
|
||||||
|
{IOC_S_SUSPENDING, IOC_S_SUSPENDED, IOC_E_SHUTDOWN,
|
||||||
|
process_shutdown_event},
|
||||||
|
{IOC_S_SUSPENDED, IOC_S_INIT, IOC_E_RESUME,
|
||||||
|
process_resume_event},
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IOC channels definition.
|
* IOC channels definition.
|
||||||
*/
|
*/
|
||||||
@ -163,6 +216,7 @@ static struct ioc_ch_info ioc_ch_tbl[] = {
|
|||||||
{IOC_INIT_FD, IOC_NP_RAW10, IOC_NATIVE_RAW10, IOC_CH_ON},
|
{IOC_INIT_FD, IOC_NP_RAW10, IOC_NATIVE_RAW10, IOC_CH_ON},
|
||||||
{IOC_INIT_FD, IOC_NP_RAW11, IOC_NATIVE_RAW11, IOC_CH_ON},
|
{IOC_INIT_FD, IOC_NP_RAW11, IOC_NATIVE_RAW11, IOC_CH_ON},
|
||||||
{IOC_INIT_FD, IOC_DP_NONE, IOC_VIRTUAL_UART, IOC_CH_ON},
|
{IOC_INIT_FD, IOC_DP_NONE, IOC_VIRTUAL_UART, IOC_CH_ON},
|
||||||
|
{IOC_INIT_FD, IOC_DP_NONE, IOC_LOCAL_EVENT, IOC_CH_ON}
|
||||||
#ifdef IOC_DUMMY
|
#ifdef IOC_DUMMY
|
||||||
{IOC_INIT_FD, IOC_NP_FLF, IOC_NATIVE_DUMMY0, IOC_CH_ON},
|
{IOC_INIT_FD, IOC_NP_FLF, IOC_NATIVE_DUMMY0, IOC_CH_ON},
|
||||||
{IOC_INIT_FD, IOC_NP_FSIG, IOC_NATIVE_DUMMY1, IOC_CH_ON},
|
{IOC_INIT_FD, IOC_NP_FSIG, IOC_NATIVE_DUMMY1, IOC_CH_ON},
|
||||||
@ -564,6 +618,7 @@ ioc_ch_init(struct ioc_dev *ioc)
|
|||||||
{
|
{
|
||||||
int i, fd;
|
int i, fd;
|
||||||
struct ioc_ch_info *chl;
|
struct ioc_ch_info *chl;
|
||||||
|
int pipe_fds[2];
|
||||||
|
|
||||||
for (i = 0, chl = ioc_ch_tbl; i < ARRAY_SIZE(ioc_ch_tbl); i++, chl++) {
|
for (i = 0, chl = ioc_ch_tbl; i < ARRAY_SIZE(ioc_ch_tbl); i++, chl++) {
|
||||||
if (chl->stat == IOC_CH_OFF)
|
if (chl->stat == IOC_CH_OFF)
|
||||||
@ -578,6 +633,15 @@ ioc_ch_init(struct ioc_dev *ioc)
|
|||||||
case IOC_VIRTUAL_UART:
|
case IOC_VIRTUAL_UART:
|
||||||
fd = ioc_open_virtual_uart(virtual_uart_path);
|
fd = ioc_open_virtual_uart(virtual_uart_path);
|
||||||
break;
|
break;
|
||||||
|
case IOC_LOCAL_EVENT:
|
||||||
|
if (!pipe(pipe_fds)) {
|
||||||
|
fd = pipe_fds[0];
|
||||||
|
ioc->evt_fd = pipe_fds[1];
|
||||||
|
} else {
|
||||||
|
fd = IOC_INIT_FD;
|
||||||
|
DPRINTF("%s", "ioc open event fd failed\r\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
#ifdef IOC_DUMMY
|
#ifdef IOC_DUMMY
|
||||||
/*
|
/*
|
||||||
* TODO: check open if success for dummy fd
|
* TODO: check open if success for dummy fd
|
||||||
@ -606,7 +670,8 @@ ioc_ch_init(struct ioc_dev *ioc)
|
|||||||
* if can not open lifecycle or virtual UART
|
* if can not open lifecycle or virtual UART
|
||||||
* ioc needs to exit initilization with failure
|
* ioc needs to exit initilization with failure
|
||||||
*/
|
*/
|
||||||
if (fd < 0 && (i == IOC_NATIVE_LFCC || i == IOC_VIRTUAL_UART))
|
if (fd < 0 && (i == IOC_NATIVE_LFCC || i == IOC_VIRTUAL_UART ||
|
||||||
|
i == IOC_LOCAL_EVENT))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
chl->fd = fd;
|
chl->fd = fd;
|
||||||
@ -702,6 +767,85 @@ cbc_request_dequeue(struct ioc_dev *ioc, enum cbc_queue_type qtype)
|
|||||||
return free;
|
return free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process hb active event before transfer to next state
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
process_hb_active_event(struct ioc_dev *ioc)
|
||||||
|
{
|
||||||
|
/* TODO: Need implementation */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process ram refresh event before transfer to next state
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
process_ram_refresh_event(struct ioc_dev *ioc)
|
||||||
|
{
|
||||||
|
/* TODO: Need implementation */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process hb inactive event before transfer to next state
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
process_hb_inactive_event(struct ioc_dev *ioc)
|
||||||
|
{
|
||||||
|
/* TODO: Need implementation */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process shutdown reason event before transfer to next state
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
process_shutdown_event(struct ioc_dev *ioc)
|
||||||
|
{
|
||||||
|
/* TODO: Need implementation */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process resume event before transfer to next state
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
process_resume_event(struct ioc_dev *ioc)
|
||||||
|
{
|
||||||
|
/* TODO: Need implementation */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process IOC local events
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ioc_process_events(struct ioc_dev *ioc, enum ioc_ch_id id)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t evt;
|
||||||
|
|
||||||
|
/* Get one event */
|
||||||
|
if (ioc_ch_recv(id, &evt, sizeof(evt)) < 0) {
|
||||||
|
DPRINTF("%s", "ioc state gets event failed\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(ioc_state_tbl); i++) {
|
||||||
|
if (evt == ioc_state_tbl[i].evt &&
|
||||||
|
ioc->state == ioc_state_tbl[i].cur_stat) {
|
||||||
|
if (ioc_state_tbl[i].handler &&
|
||||||
|
ioc_state_tbl[i].handler(ioc) == 0)
|
||||||
|
ioc->state = ioc_state_tbl[i].next_stat;
|
||||||
|
else
|
||||||
|
DPRINTF("ioc state switching failed,%d->%d\r\n",
|
||||||
|
ioc_state_tbl[i].cur_stat,
|
||||||
|
ioc_state_tbl[i].next_stat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build a cbc_request with CBC link frame and add the cbc_request to
|
* Build a cbc_request with CBC link frame and add the cbc_request to
|
||||||
* the rx queue tail.
|
* the rx queue tail.
|
||||||
@ -816,6 +960,9 @@ ioc_dispatch(struct ioc_dev *ioc, struct ioc_ch_info *chl)
|
|||||||
case IOC_VIRTUAL_UART:
|
case IOC_VIRTUAL_UART:
|
||||||
ioc_process_rx(ioc, chl->id);
|
ioc_process_rx(ioc, chl->id);
|
||||||
break;
|
break;
|
||||||
|
case IOC_LOCAL_EVENT:
|
||||||
|
ioc_process_events(ioc, chl->id);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
DPRINTF("ioc dispatch got wrong channel:%d\r\n", chl->id);
|
DPRINTF("ioc dispatch got wrong channel:%d\r\n", chl->id);
|
||||||
break;
|
break;
|
||||||
@ -881,6 +1028,7 @@ ioc_rx_thread(void *arg)
|
|||||||
memset(&packet, 0, sizeof(packet));
|
memset(&packet, 0, sizeof(packet));
|
||||||
packet.cfg = &ioc->rx_config;
|
packet.cfg = &ioc->rx_config;
|
||||||
packet.boot_reason = ioc_boot_reason;
|
packet.boot_reason = ioc_boot_reason;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
pthread_mutex_lock(&ioc->rx_mtx);
|
pthread_mutex_lock(&ioc->rx_mtx);
|
||||||
while (SIMPLEQ_EMPTY(&ioc->rx_qhead)) {
|
while (SIMPLEQ_EMPTY(&ioc->rx_qhead)) {
|
||||||
@ -933,6 +1081,7 @@ ioc_tx_thread(void *arg)
|
|||||||
memset(&packet, 0, sizeof(packet));
|
memset(&packet, 0, sizeof(packet));
|
||||||
packet.cfg = &ioc->tx_config;
|
packet.cfg = &ioc->tx_config;
|
||||||
packet.boot_reason = ioc_boot_reason;
|
packet.boot_reason = ioc_boot_reason;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
pthread_mutex_lock(&ioc->tx_mtx);
|
pthread_mutex_lock(&ioc->tx_mtx);
|
||||||
while (SIMPLEQ_EMPTY(&ioc->tx_qhead)) {
|
while (SIMPLEQ_EMPTY(&ioc->tx_qhead)) {
|
||||||
@ -1095,12 +1244,19 @@ ioc_init(struct vmctx *ctx)
|
|||||||
for (i = 0; i < IOC_MAX_REQUESTS; i++)
|
for (i = 0; i < IOC_MAX_REQUESTS; i++)
|
||||||
SIMPLEQ_INSERT_TAIL(&ioc->free_qhead, ioc->pool + i, me_queue);
|
SIMPLEQ_INSERT_TAIL(&ioc->free_qhead, ioc->pool + i, me_queue);
|
||||||
|
|
||||||
|
/* Initialize IOC state */
|
||||||
|
ioc->state = IOC_S_INIT;
|
||||||
|
|
||||||
|
/* Set event fd to default value */
|
||||||
|
ioc->evt_fd = IOC_INIT_FD;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize native CBC cdev and virtual UART.
|
* Initialize native CBC cdev and virtual UART.
|
||||||
*/
|
*/
|
||||||
if (ioc_ch_init(ioc) != 0)
|
if (ioc_ch_init(ioc) != 0)
|
||||||
goto chl_err;
|
goto chl_err;
|
||||||
|
|
||||||
|
|
||||||
/* Initlialize CBC rx/tx signal and group whitelists */
|
/* Initlialize CBC rx/tx signal and group whitelists */
|
||||||
wlist_init_signal(cbc_rx_signal_table, ARRAY_SIZE(cbc_rx_signal_table),
|
wlist_init_signal(cbc_rx_signal_table, ARRAY_SIZE(cbc_rx_signal_table),
|
||||||
wlist_rx_signal_table,
|
wlist_rx_signal_table,
|
||||||
@ -1175,6 +1331,8 @@ work_err:
|
|||||||
chl_err:
|
chl_err:
|
||||||
ioc_ch_deinit();
|
ioc_ch_deinit();
|
||||||
pthread_mutex_destroy(&ioc->free_mtx);
|
pthread_mutex_destroy(&ioc->free_mtx);
|
||||||
|
if (ioc->evt_fd >= 0)
|
||||||
|
close(ioc->evt_fd);
|
||||||
close(ioc->epfd);
|
close(ioc->epfd);
|
||||||
alloc_err:
|
alloc_err:
|
||||||
free(ioc->evts);
|
free(ioc->evts);
|
||||||
@ -1200,6 +1358,8 @@ ioc_deinit(struct vmctx *ctx)
|
|||||||
}
|
}
|
||||||
ioc_kill_workers(ioc);
|
ioc_kill_workers(ioc);
|
||||||
ioc_ch_deinit();
|
ioc_ch_deinit();
|
||||||
|
if (ioc->evt_fd >= 0)
|
||||||
|
close(ioc->evt_fd);
|
||||||
close(ioc->epfd);
|
close(ioc->epfd);
|
||||||
free(ioc->evts);
|
free(ioc->evts);
|
||||||
free(ioc->pool);
|
free(ioc->pool);
|
||||||
|
@ -526,6 +526,7 @@ enum ioc_ch_id {
|
|||||||
IOC_NATIVE_RAW10, /* Native /dev/cbc-raw10 */
|
IOC_NATIVE_RAW10, /* Native /dev/cbc-raw10 */
|
||||||
IOC_NATIVE_RAW11, /* Native /dev/cbc-raw11 */
|
IOC_NATIVE_RAW11, /* Native /dev/cbc-raw11 */
|
||||||
IOC_VIRTUAL_UART, /* Virtual UART */
|
IOC_VIRTUAL_UART, /* Virtual UART */
|
||||||
|
IOC_LOCAL_EVENT, /* Local channel for IOC event */
|
||||||
IOC_NATIVE_DUMMY0, /* Native fake lifecycle channel */
|
IOC_NATIVE_DUMMY0, /* Native fake lifecycle channel */
|
||||||
IOC_NATIVE_DUMMY1, /* Native fake signal channel */
|
IOC_NATIVE_DUMMY1, /* Native fake signal channel */
|
||||||
IOC_NATIVE_DUMMY2, /* Native Fake oem raw channel */
|
IOC_NATIVE_DUMMY2, /* Native Fake oem raw channel */
|
||||||
@ -575,8 +576,8 @@ enum cbc_queue_type {
|
|||||||
*/
|
*/
|
||||||
enum cbc_request_type {
|
enum cbc_request_type {
|
||||||
CBC_REQ_T_PROT, /* CBC protocol request */
|
CBC_REQ_T_PROT, /* CBC protocol request */
|
||||||
CBC_REQ_T_VMM_S3, /* VMM suspend request */
|
CBC_REQ_T_SUSPEND, /* CBC suspend request */
|
||||||
CBC_REQ_T_VMM_S5, /* VMM shutdown request */
|
CBC_REQ_T_SHUTDOWN, /* CBC shutdown request */
|
||||||
CBC_REQ_T_SOC /* SOC state update request */
|
CBC_REQ_T_SOC /* SOC state update request */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -656,6 +657,28 @@ struct cbc_request {
|
|||||||
SIMPLEQ_ENTRY(cbc_request) me_queue;
|
SIMPLEQ_ENTRY(cbc_request) me_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IOC state types.
|
||||||
|
*/
|
||||||
|
enum ioc_state_type {
|
||||||
|
IOC_S_INIT,
|
||||||
|
IOC_S_ACTIVE,
|
||||||
|
IOC_S_SUSPENDING,
|
||||||
|
IOC_S_SUSPENDED
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IOC event types.
|
||||||
|
*/
|
||||||
|
enum ioc_event_type {
|
||||||
|
IOC_E_INVALID,
|
||||||
|
IOC_E_HB_ACTIVE,
|
||||||
|
IOC_E_RAM_REFRESH,
|
||||||
|
IOC_E_HB_INACTIVE,
|
||||||
|
IOC_E_SHUTDOWN,
|
||||||
|
IOC_E_RESUME
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CBC packet is mainly structure for CBC protocol process.
|
* CBC packet is mainly structure for CBC protocol process.
|
||||||
*/
|
*/
|
||||||
@ -684,6 +707,8 @@ struct ioc_dev {
|
|||||||
char name[16]; /* Core thread name */
|
char name[16]; /* Core thread name */
|
||||||
int closing; /* Close IOC mediator device flag */
|
int closing; /* Close IOC mediator device flag */
|
||||||
int epfd; /* Epoll fd */
|
int epfd; /* Epoll fd */
|
||||||
|
int32_t evt_fd; /* Pipe write fd to trigger one event */
|
||||||
|
enum ioc_state_type state; /* IOC state type */
|
||||||
struct epoll_event *evts; /* Epoll events table */
|
struct epoll_event *evts; /* Epoll events table */
|
||||||
struct cbc_request *pool; /* CBC requests pool */
|
struct cbc_request *pool; /* CBC requests pool */
|
||||||
struct cbc_ring ring; /* Ring buffer */
|
struct cbc_ring ring; /* Ring buffer */
|
||||||
@ -708,6 +733,16 @@ struct ioc_dev {
|
|||||||
void (*ioc_dev_tx)(struct cbc_pkt *pkt);
|
void (*ioc_dev_tx)(struct cbc_pkt *pkt);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IOC state information.
|
||||||
|
*/
|
||||||
|
struct ioc_state_info {
|
||||||
|
enum ioc_state_type cur_stat;
|
||||||
|
enum ioc_state_type next_stat;
|
||||||
|
enum ioc_event_type evt;
|
||||||
|
int32_t (*handler)(struct ioc_dev *ioc);
|
||||||
|
};
|
||||||
|
|
||||||
/* Parse IOC parameters */
|
/* Parse IOC parameters */
|
||||||
int ioc_parse(const char *opts);
|
int ioc_parse(const char *opts);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user