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:
Liu Yuan 2018-05-17 16:06:59 +08:00 committed by lijinxia
parent 92da8f4954
commit 11208dd6d5
2 changed files with 198 additions and 3 deletions

View File

@ -139,6 +139,59 @@ static int dummy1_sfd = -1;
static int dummy2_sfd = -1;
#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.
*/
@ -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_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_LOCAL_EVENT, IOC_CH_ON}
#ifdef IOC_DUMMY
{IOC_INIT_FD, IOC_NP_FLF, IOC_NATIVE_DUMMY0, 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;
struct ioc_ch_info *chl;
int pipe_fds[2];
for (i = 0, chl = ioc_ch_tbl; i < ARRAY_SIZE(ioc_ch_tbl); i++, chl++) {
if (chl->stat == IOC_CH_OFF)
@ -578,6 +633,15 @@ ioc_ch_init(struct ioc_dev *ioc)
case IOC_VIRTUAL_UART:
fd = ioc_open_virtual_uart(virtual_uart_path);
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
/*
* 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
* 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;
chl->fd = fd;
@ -702,6 +767,85 @@ cbc_request_dequeue(struct ioc_dev *ioc, enum cbc_queue_type qtype)
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
* the rx queue tail.
@ -816,6 +960,9 @@ ioc_dispatch(struct ioc_dev *ioc, struct ioc_ch_info *chl)
case IOC_VIRTUAL_UART:
ioc_process_rx(ioc, chl->id);
break;
case IOC_LOCAL_EVENT:
ioc_process_events(ioc, chl->id);
break;
default:
DPRINTF("ioc dispatch got wrong channel:%d\r\n", chl->id);
break;
@ -881,6 +1028,7 @@ ioc_rx_thread(void *arg)
memset(&packet, 0, sizeof(packet));
packet.cfg = &ioc->rx_config;
packet.boot_reason = ioc_boot_reason;
for (;;) {
pthread_mutex_lock(&ioc->rx_mtx);
while (SIMPLEQ_EMPTY(&ioc->rx_qhead)) {
@ -933,6 +1081,7 @@ ioc_tx_thread(void *arg)
memset(&packet, 0, sizeof(packet));
packet.cfg = &ioc->tx_config;
packet.boot_reason = ioc_boot_reason;
for (;;) {
pthread_mutex_lock(&ioc->tx_mtx);
while (SIMPLEQ_EMPTY(&ioc->tx_qhead)) {
@ -1095,12 +1244,19 @@ ioc_init(struct vmctx *ctx)
for (i = 0; i < IOC_MAX_REQUESTS; i++)
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.
*/
if (ioc_ch_init(ioc) != 0)
goto chl_err;
/* Initlialize CBC rx/tx signal and group whitelists */
wlist_init_signal(cbc_rx_signal_table, ARRAY_SIZE(cbc_rx_signal_table),
wlist_rx_signal_table,
@ -1175,6 +1331,8 @@ work_err:
chl_err:
ioc_ch_deinit();
pthread_mutex_destroy(&ioc->free_mtx);
if (ioc->evt_fd >= 0)
close(ioc->evt_fd);
close(ioc->epfd);
alloc_err:
free(ioc->evts);
@ -1200,6 +1358,8 @@ ioc_deinit(struct vmctx *ctx)
}
ioc_kill_workers(ioc);
ioc_ch_deinit();
if (ioc->evt_fd >= 0)
close(ioc->evt_fd);
close(ioc->epfd);
free(ioc->evts);
free(ioc->pool);

View File

@ -526,6 +526,7 @@ enum ioc_ch_id {
IOC_NATIVE_RAW10, /* Native /dev/cbc-raw10 */
IOC_NATIVE_RAW11, /* Native /dev/cbc-raw11 */
IOC_VIRTUAL_UART, /* Virtual UART */
IOC_LOCAL_EVENT, /* Local channel for IOC event */
IOC_NATIVE_DUMMY0, /* Native fake lifecycle channel */
IOC_NATIVE_DUMMY1, /* Native fake signal channel */
IOC_NATIVE_DUMMY2, /* Native Fake oem raw channel */
@ -575,8 +576,8 @@ enum cbc_queue_type {
*/
enum cbc_request_type {
CBC_REQ_T_PROT, /* CBC protocol request */
CBC_REQ_T_VMM_S3, /* VMM suspend request */
CBC_REQ_T_VMM_S5, /* VMM shutdown request */
CBC_REQ_T_SUSPEND, /* CBC suspend request */
CBC_REQ_T_SHUTDOWN, /* CBC shutdown request */
CBC_REQ_T_SOC /* SOC state update request */
};
@ -656,6 +657,28 @@ struct cbc_request {
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.
*/
@ -684,6 +707,8 @@ struct ioc_dev {
char name[16]; /* Core thread name */
int closing; /* Close IOC mediator device flag */
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 cbc_request *pool; /* CBC requests pool */
struct cbc_ring ring; /* Ring buffer */
@ -708,6 +733,16 @@ struct ioc_dev {
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 */
int ioc_parse(const char *opts);