mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-08-16 15:21:48 +00:00
IOC mediator: Implement state transfer operations
This patch implements INIT, ACTIVE, SUSPENDING and SUSPENDED operations of IOC mediator lifecycle virtualization. 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
11208dd6d5
commit
0b7af5b6e1
@ -767,14 +767,33 @@ cbc_request_dequeue(struct ioc_dev *ioc, enum cbc_queue_type qtype)
|
|||||||
return free;
|
return free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send a cbc_request to TX handler
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
send_tx_request(struct ioc_dev *ioc, enum cbc_request_type type)
|
||||||
|
{
|
||||||
|
struct cbc_request *req;
|
||||||
|
|
||||||
|
req = cbc_request_dequeue(ioc, CBC_QUEUE_T_FREE);
|
||||||
|
if (!req) {
|
||||||
|
DPRINTF("%s", "ioc sends a tx request failed\r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
req->rtype = type;
|
||||||
|
cbc_request_enqueue(ioc, req, CBC_QUEUE_T_TX, true);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process hb active event before transfer to next state
|
* Process hb active event before transfer to next state
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
process_hb_active_event(struct ioc_dev *ioc)
|
process_hb_active_event(struct ioc_dev *ioc)
|
||||||
{
|
{
|
||||||
/* TODO: Need implementation */
|
/* Enable wakeup reason bit 23 that indicating UOS is active */
|
||||||
return 0;
|
return send_tx_request(ioc, CBC_REQ_T_UOS_ACTIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -783,8 +802,22 @@ process_hb_active_event(struct ioc_dev *ioc)
|
|||||||
static int
|
static int
|
||||||
process_ram_refresh_event(struct ioc_dev *ioc)
|
process_ram_refresh_event(struct ioc_dev *ioc)
|
||||||
{
|
{
|
||||||
/* TODO: Need implementation */
|
int rc;
|
||||||
return 0;
|
|
||||||
|
/* Rx and Tx threads discard all CBC protocol packets */
|
||||||
|
ioc->cbc_enable = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tx handler sents shutdown wakeup reason,
|
||||||
|
* Then enter suspended state.
|
||||||
|
*/
|
||||||
|
rc = send_tx_request(ioc, CBC_REQ_T_UOS_INACTIVE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: set suspend to PM DM
|
||||||
|
*/
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -793,8 +826,22 @@ process_ram_refresh_event(struct ioc_dev *ioc)
|
|||||||
static int
|
static int
|
||||||
process_hb_inactive_event(struct ioc_dev *ioc)
|
process_hb_inactive_event(struct ioc_dev *ioc)
|
||||||
{
|
{
|
||||||
/* TODO: Need implementation */
|
int rc;
|
||||||
return 0;
|
|
||||||
|
/* Rx and Tx threads discard all CBC protocol packets */
|
||||||
|
ioc->cbc_enable = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tx sents shutdown wakeup reason,
|
||||||
|
* Then enter shutdown state.
|
||||||
|
*/
|
||||||
|
rc = send_tx_request(ioc, CBC_REQ_T_UOS_INACTIVE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: set shutdown to PM DM
|
||||||
|
*/
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -803,7 +850,26 @@ process_hb_inactive_event(struct ioc_dev *ioc)
|
|||||||
static int
|
static int
|
||||||
process_shutdown_event(struct ioc_dev *ioc)
|
process_shutdown_event(struct ioc_dev *ioc)
|
||||||
{
|
{
|
||||||
/* TODO: Need implementation */
|
int i;
|
||||||
|
struct ioc_ch_info *chl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Due to native CBC driver buffer will be full if the native CBC char
|
||||||
|
* devices are opened, but not keep reading. So close the native devices
|
||||||
|
* when removing them from epoll.
|
||||||
|
*/
|
||||||
|
for (i = 0, chl = ioc_ch_tbl; i < ARRAY_SIZE(ioc_ch_tbl); i++, chl++) {
|
||||||
|
switch (i) {
|
||||||
|
case IOC_NATIVE_PMT ... IOC_NATIVE_RAW11:
|
||||||
|
if (chl->stat == IOC_CH_OFF || chl->fd < 0)
|
||||||
|
continue;
|
||||||
|
epoll_ctl(ioc->epfd, EPOLL_CTL_DEL, chl->fd, NULL);
|
||||||
|
close(chl->fd);
|
||||||
|
chl->fd = IOC_INIT_FD;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -813,7 +879,29 @@ process_shutdown_event(struct ioc_dev *ioc)
|
|||||||
static int
|
static int
|
||||||
process_resume_event(struct ioc_dev *ioc)
|
process_resume_event(struct ioc_dev *ioc)
|
||||||
{
|
{
|
||||||
/* TODO: Need implementation */
|
int i;
|
||||||
|
struct ioc_ch_info *chl;
|
||||||
|
|
||||||
|
/* Rx and Tx threads begin to process CBC protocol packets */
|
||||||
|
ioc->cbc_enable = true;
|
||||||
|
|
||||||
|
/* re-open native CBC char devices and add them into epoll */
|
||||||
|
for (i = 0, chl = ioc_ch_tbl; i < ARRAY_SIZE(ioc_ch_tbl); i++, chl++) {
|
||||||
|
switch (i) {
|
||||||
|
case IOC_NATIVE_PMT ... IOC_NATIVE_RAW11:
|
||||||
|
if (chl->stat == IOC_CH_OFF || chl->fd != IOC_INIT_FD)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
chl->fd = ioc_open_native_ch(chl->name);
|
||||||
|
if (chl->fd > 0)
|
||||||
|
epoll_ctl(ioc->epfd, EPOLL_CTL_ADD, chl->fd,
|
||||||
|
&ioc->evts[i]);
|
||||||
|
else
|
||||||
|
DPRINTF("ioc open failed, channel:%s\r\n",
|
||||||
|
chl->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -846,6 +934,21 @@ ioc_process_events(struct ioc_dev *ioc, enum ioc_ch_id id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For a new event update.
|
||||||
|
* The interface is for mult-threads, currently write one byte to core thread,
|
||||||
|
* So if write more types, needs to add protection for thread safety.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ioc_update_event(int fd, enum ioc_event_type evt)
|
||||||
|
{
|
||||||
|
uint8_t val = evt;
|
||||||
|
|
||||||
|
if (write(fd, &val, sizeof(val)) < 0)
|
||||||
|
DPRINTF("ioc update event failed, error:%s\r\n",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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.
|
||||||
@ -1027,7 +1130,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.ioc = ioc;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
pthread_mutex_lock(&ioc->rx_mtx);
|
pthread_mutex_lock(&ioc->rx_mtx);
|
||||||
@ -1080,7 +1183,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.ioc = ioc;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
pthread_mutex_lock(&ioc->tx_mtx);
|
pthread_mutex_lock(&ioc->tx_mtx);
|
||||||
@ -1250,6 +1353,12 @@ ioc_init(struct vmctx *ctx)
|
|||||||
/* Set event fd to default value */
|
/* Set event fd to default value */
|
||||||
ioc->evt_fd = IOC_INIT_FD;
|
ioc->evt_fd = IOC_INIT_FD;
|
||||||
|
|
||||||
|
/* Enable CBC packet processing by default */
|
||||||
|
ioc->cbc_enable = true;
|
||||||
|
|
||||||
|
/* Set boot reason from IOC mediator boot command line */
|
||||||
|
ioc->boot_reason = ioc_boot_reason;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize native CBC cdev and virtual UART.
|
* Initialize native CBC cdev and virtual UART.
|
||||||
*/
|
*/
|
||||||
|
@ -586,31 +586,30 @@ cbc_send_pkt(struct cbc_pkt *pkt)
|
|||||||
static void
|
static void
|
||||||
cbc_update_heartbeat(struct cbc_pkt *pkt, uint8_t cmd, uint8_t sus_action)
|
cbc_update_heartbeat(struct cbc_pkt *pkt, uint8_t cmd, uint8_t sus_action)
|
||||||
{
|
{
|
||||||
uint8_t stat;
|
enum ioc_event_type evt;
|
||||||
|
|
||||||
(void) sus_action;
|
if (cmd == CBC_HB_INITIAL || cmd == CBC_HB_ACTIVE ||
|
||||||
|
cmd == CBC_HB_STANDBY ||
|
||||||
/*
|
cmd == CBC_HB_SD_DLY)
|
||||||
* If heartbeat state switches(active/inactive), update the new state
|
evt = IOC_E_HB_ACTIVE;
|
||||||
* value based on heartbeat commands.
|
else if (cmd == CBC_HB_SD_PREP)
|
||||||
* The default state is inactive.
|
evt = (sus_action == CBC_SS_REFRESH) ? IOC_E_RAM_REFRESH :
|
||||||
*/
|
IOC_E_HB_INACTIVE;
|
||||||
if (cmd == CBC_HB_ACTIVE || cmd == CBC_HB_STANDBY ||
|
|
||||||
cmd == CBC_HB_INITIAL)
|
|
||||||
stat = 1;
|
|
||||||
else
|
else
|
||||||
stat = 0;
|
return;
|
||||||
|
|
||||||
/* Default heartbeat state is zero, that means not active */
|
/* Update IOC state with a new event */
|
||||||
if (stat != pkt->hb_state) {
|
if (evt != pkt->evt) {
|
||||||
/*
|
ioc_update_event(pkt->ioc->evt_fd, evt);
|
||||||
* Route the cbc request to the tx thread
|
pkt->evt = evt;
|
||||||
* and request type is SOC state update
|
}
|
||||||
*/
|
|
||||||
|
/* Tigger a wakeup reason immediately */
|
||||||
|
if (cmd == CBC_HB_INITIAL) {
|
||||||
|
|
||||||
|
/* Route the cbc request to the tx thread */
|
||||||
pkt->qtype = CBC_QUEUE_T_TX;
|
pkt->qtype = CBC_QUEUE_T_TX;
|
||||||
pkt->req->rtype = CBC_REQ_T_SOC;
|
pkt->req->rtype = CBC_REQ_T_HB_INIT;
|
||||||
pkt->req->buf[0] = stat;
|
|
||||||
pkt->hb_state = stat;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -670,6 +669,11 @@ cbc_process_wakeup_reason(struct cbc_pkt *pkt)
|
|||||||
*/
|
*/
|
||||||
pkt->reason = reason;
|
pkt->reason = reason;
|
||||||
|
|
||||||
|
if (pkt->uos_active)
|
||||||
|
reason |= CBC_WK_RSN_SOC;
|
||||||
|
else
|
||||||
|
reason &= ~CBC_WK_RSN_SOC;
|
||||||
|
|
||||||
/* Update periodic wakeup reason */
|
/* Update periodic wakeup reason */
|
||||||
cbc_update_wakeup_reason(pkt, reason);
|
cbc_update_wakeup_reason(pkt, reason);
|
||||||
|
|
||||||
@ -795,11 +799,18 @@ cbc_rx_handler(struct cbc_pkt *pkt)
|
|||||||
uint8_t mux, prio;
|
uint8_t mux, prio;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: need to check CBC request type in the rx handler
|
* Rx only handle CBC protocol packet currently.
|
||||||
* currently simply check is enough, expand the check in the further
|
* Drop the packet when the CBC protocl status is not enable.
|
||||||
*/
|
*/
|
||||||
if (pkt->req->rtype != CBC_REQ_T_PROT)
|
if (pkt->req->rtype != CBC_REQ_T_PROT ||
|
||||||
|
pkt->ioc->cbc_enable == false) {
|
||||||
|
|
||||||
|
/* Discard the packet */
|
||||||
|
DPRINTF("ioc rx discard the packet, type:%d\r\n",
|
||||||
|
pkt->req->rtype);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: use this prio to enable dynamic cbc priority configuration
|
* TODO: use this prio to enable dynamic cbc priority configuration
|
||||||
* feature in the future, currently ignore it.
|
* feature in the future, currently ignore it.
|
||||||
@ -834,7 +845,7 @@ cbc_rx_handler(struct cbc_pkt *pkt)
|
|||||||
void
|
void
|
||||||
cbc_tx_handler(struct cbc_pkt *pkt)
|
cbc_tx_handler(struct cbc_pkt *pkt)
|
||||||
{
|
{
|
||||||
if (pkt->req->rtype == CBC_REQ_T_PROT) {
|
if (pkt->req->rtype == CBC_REQ_T_PROT && pkt->ioc->cbc_enable) {
|
||||||
switch (pkt->req->id) {
|
switch (pkt->req->id) {
|
||||||
case IOC_NATIVE_LFCC:
|
case IOC_NATIVE_LFCC:
|
||||||
cbc_process_wakeup_reason(pkt);
|
cbc_process_wakeup_reason(pkt);
|
||||||
@ -850,20 +861,39 @@ cbc_tx_handler(struct cbc_pkt *pkt)
|
|||||||
pkt->req->id);
|
pkt->req->id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (pkt->req->rtype == CBC_REQ_T_SOC) {
|
} else if (pkt->req->rtype == CBC_REQ_T_HB_INIT) {
|
||||||
/*
|
|
||||||
* Update wakeup reasons with SoC new state
|
|
||||||
* the new state update by heartbeat state change
|
|
||||||
* (active/inactive) in rx thread
|
|
||||||
*/
|
|
||||||
pkt->soc_active = pkt->req->buf[0];
|
|
||||||
cbc_update_wakeup_reason(pkt, pkt->reason);
|
|
||||||
|
|
||||||
/* Send wakeup reason */
|
/*
|
||||||
|
* Boot reason represents the wakeup reason from IOC mediator
|
||||||
|
* boot command line or resume callback.
|
||||||
|
*/
|
||||||
|
cbc_update_wakeup_reason(pkt, pkt->ioc->boot_reason |
|
||||||
|
CBC_WK_RSN_SOC);
|
||||||
cbc_send_pkt(pkt);
|
cbc_send_pkt(pkt);
|
||||||
|
|
||||||
|
/* Heartbeat init also indicates UOS enter active state */
|
||||||
|
pkt->uos_active = true;
|
||||||
|
} else if (pkt->req->rtype == CBC_REQ_T_UOS_ACTIVE) {
|
||||||
|
cbc_update_wakeup_reason(pkt, pkt->reason | CBC_WK_RSN_SOC);
|
||||||
|
cbc_send_pkt(pkt);
|
||||||
|
|
||||||
|
/* Enable UOS active flag */
|
||||||
|
pkt->uos_active = true;
|
||||||
|
} else if (pkt->req->rtype == CBC_REQ_T_UOS_INACTIVE) {
|
||||||
|
cbc_update_wakeup_reason(pkt, CBC_WK_RSN_SHUTDOWN);
|
||||||
|
cbc_send_pkt(pkt);
|
||||||
|
|
||||||
|
/* Disable UOS active flag */
|
||||||
|
pkt->uos_active = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After sending shutdown wakeup reason, then trigger shutdown
|
||||||
|
* IOC event that IOC mediator can enter suspended.
|
||||||
|
*/
|
||||||
|
ioc_update_event(pkt->ioc->evt_fd, IOC_E_SHUTDOWN);
|
||||||
} else {
|
} else {
|
||||||
/* TODO: others request types process */
|
/* Discard the packet */
|
||||||
DPRINTF("ioc invalid cbc_request type in tx:%d\r\n",
|
DPRINTF("ioc tx discard the packet, type:%d\r\n",
|
||||||
pkt->req->rtype);
|
pkt->req->rtype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,9 @@
|
|||||||
#define CBC_WK_RSN_DOR (1 << 11) /* CBC wakeup reason field cardoor */
|
#define CBC_WK_RSN_DOR (1 << 11) /* CBC wakeup reason field cardoor */
|
||||||
#define CBC_WK_RSN_SOC (1 << 23) /* CBC wakeup reason field soc */
|
#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 mediator permits button, rtc and cardoor wakeup reasons which comes from
|
||||||
* IOC firmware, others will be masked.
|
* IOC firmware, others will be masked.
|
||||||
@ -578,7 +581,9 @@ enum cbc_request_type {
|
|||||||
CBC_REQ_T_PROT, /* CBC protocol request */
|
CBC_REQ_T_PROT, /* CBC protocol request */
|
||||||
CBC_REQ_T_SUSPEND, /* CBC suspend request */
|
CBC_REQ_T_SUSPEND, /* CBC suspend request */
|
||||||
CBC_REQ_T_SHUTDOWN, /* CBC shutdown request */
|
CBC_REQ_T_SHUTDOWN, /* CBC shutdown request */
|
||||||
CBC_REQ_T_SOC /* SOC state update request */
|
CBC_REQ_T_HB_INIT, /* CBC Heartbeat init request */
|
||||||
|
CBC_REQ_T_UOS_ACTIVE, /* CBC UOS active request */
|
||||||
|
CBC_REQ_T_UOS_INACTIVE /* CBC UOS inactive request */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -683,13 +688,13 @@ enum ioc_event_type {
|
|||||||
* CBC packet is mainly structure for CBC protocol process.
|
* CBC packet is mainly structure for CBC protocol process.
|
||||||
*/
|
*/
|
||||||
struct cbc_pkt {
|
struct cbc_pkt {
|
||||||
uint8_t soc_active; /* Record soc state */
|
bool uos_active; /* Mark UOS active status */
|
||||||
uint8_t hb_state; /* Record Heartbeat state */
|
|
||||||
uint32_t reason; /* Record current wakeup reason */
|
uint32_t reason; /* Record current wakeup reason */
|
||||||
uint32_t boot_reason; /* Record boot up wakeup reason */
|
|
||||||
struct cbc_request *req; /* CBC packet data */
|
struct cbc_request *req; /* CBC packet data */
|
||||||
struct cbc_config *cfg; /* CBC and whitelist configurations */
|
struct cbc_config *cfg; /* CBC and whitelist configurations */
|
||||||
enum cbc_queue_type qtype; /* Routes cbc_request to queue */
|
enum cbc_queue_type qtype; /* Routes cbc_request to queue */
|
||||||
|
enum ioc_event_type evt; /* Record last event */
|
||||||
|
struct ioc_dev *ioc; /* IOC device */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -705,9 +710,11 @@ SIMPLEQ_HEAD(cbc_qhead, cbc_request);
|
|||||||
*/
|
*/
|
||||||
struct ioc_dev {
|
struct ioc_dev {
|
||||||
char name[16]; /* Core thread name */
|
char name[16]; /* Core thread name */
|
||||||
|
bool cbc_enable; /* Tx and Rx protocol enable flag */
|
||||||
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 */
|
int32_t evt_fd; /* Pipe write fd to trigger one event */
|
||||||
|
uint32_t boot_reason; /* Boot or resume wakeup reason */
|
||||||
enum ioc_state_type state; /* IOC state type */
|
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 */
|
||||||
@ -776,4 +783,7 @@ void wlist_init_group(struct cbc_group *cbc_tbl, size_t cbc_size,
|
|||||||
|
|
||||||
/* Set CBC log file */
|
/* Set CBC log file */
|
||||||
void cbc_set_log_file(FILE *f);
|
void cbc_set_log_file(FILE *f);
|
||||||
|
|
||||||
|
/* Update IOC state by the event */
|
||||||
|
void ioc_update_event(int fd, enum ioc_event_type evt);
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user