mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-08-15 23:05:15 +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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
static int
|
||||
process_hb_active_event(struct ioc_dev *ioc)
|
||||
{
|
||||
/* TODO: Need implementation */
|
||||
return 0;
|
||||
/* Enable wakeup reason bit 23 that indicating UOS is active */
|
||||
return send_tx_request(ioc, CBC_REQ_T_UOS_ACTIVE);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -783,8 +802,22 @@ process_hb_active_event(struct ioc_dev *ioc)
|
||||
static int
|
||||
process_ram_refresh_event(struct ioc_dev *ioc)
|
||||
{
|
||||
/* TODO: Need implementation */
|
||||
return 0;
|
||||
int rc;
|
||||
|
||||
/* 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
|
||||
process_hb_inactive_event(struct ioc_dev *ioc)
|
||||
{
|
||||
/* TODO: Need implementation */
|
||||
return 0;
|
||||
int rc;
|
||||
|
||||
/* 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
|
||||
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;
|
||||
}
|
||||
|
||||
@ -813,7 +879,29 @@ process_shutdown_event(struct ioc_dev *ioc)
|
||||
static int
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
* the rx queue tail.
|
||||
@ -1027,7 +1130,7 @@ ioc_rx_thread(void *arg)
|
||||
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
packet.cfg = &ioc->rx_config;
|
||||
packet.boot_reason = ioc_boot_reason;
|
||||
packet.ioc = ioc;
|
||||
|
||||
for (;;) {
|
||||
pthread_mutex_lock(&ioc->rx_mtx);
|
||||
@ -1080,7 +1183,7 @@ ioc_tx_thread(void *arg)
|
||||
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
packet.cfg = &ioc->tx_config;
|
||||
packet.boot_reason = ioc_boot_reason;
|
||||
packet.ioc = ioc;
|
||||
|
||||
for (;;) {
|
||||
pthread_mutex_lock(&ioc->tx_mtx);
|
||||
@ -1250,6 +1353,12 @@ ioc_init(struct vmctx *ctx)
|
||||
/* Set event fd to default value */
|
||||
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.
|
||||
*/
|
||||
|
@ -586,31 +586,30 @@ cbc_send_pkt(struct cbc_pkt *pkt)
|
||||
static void
|
||||
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 heartbeat state switches(active/inactive), update the new state
|
||||
* value based on heartbeat commands.
|
||||
* The default state is inactive.
|
||||
*/
|
||||
if (cmd == CBC_HB_ACTIVE || cmd == CBC_HB_STANDBY ||
|
||||
cmd == CBC_HB_INITIAL)
|
||||
stat = 1;
|
||||
if (cmd == CBC_HB_INITIAL || cmd == CBC_HB_ACTIVE ||
|
||||
cmd == CBC_HB_STANDBY ||
|
||||
cmd == CBC_HB_SD_DLY)
|
||||
evt = IOC_E_HB_ACTIVE;
|
||||
else if (cmd == CBC_HB_SD_PREP)
|
||||
evt = (sus_action == CBC_SS_REFRESH) ? IOC_E_RAM_REFRESH :
|
||||
IOC_E_HB_INACTIVE;
|
||||
else
|
||||
stat = 0;
|
||||
return;
|
||||
|
||||
/* Default heartbeat state is zero, that means not active */
|
||||
if (stat != pkt->hb_state) {
|
||||
/*
|
||||
* Route the cbc request to the tx thread
|
||||
* and request type is SOC state update
|
||||
*/
|
||||
/* Update IOC state with a new event */
|
||||
if (evt != pkt->evt) {
|
||||
ioc_update_event(pkt->ioc->evt_fd, evt);
|
||||
pkt->evt = evt;
|
||||
}
|
||||
|
||||
/* 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->req->rtype = CBC_REQ_T_SOC;
|
||||
pkt->req->buf[0] = stat;
|
||||
pkt->hb_state = stat;
|
||||
pkt->req->rtype = CBC_REQ_T_HB_INIT;
|
||||
}
|
||||
}
|
||||
|
||||
@ -670,6 +669,11 @@ cbc_process_wakeup_reason(struct cbc_pkt *pkt)
|
||||
*/
|
||||
pkt->reason = reason;
|
||||
|
||||
if (pkt->uos_active)
|
||||
reason |= CBC_WK_RSN_SOC;
|
||||
else
|
||||
reason &= ~CBC_WK_RSN_SOC;
|
||||
|
||||
/* Update periodic wakeup reason */
|
||||
cbc_update_wakeup_reason(pkt, reason);
|
||||
|
||||
@ -795,11 +799,18 @@ cbc_rx_handler(struct cbc_pkt *pkt)
|
||||
uint8_t mux, prio;
|
||||
|
||||
/*
|
||||
* FIXME: need to check CBC request type in the rx handler
|
||||
* currently simply check is enough, expand the check in the further
|
||||
* Rx only handle CBC protocol packet currently.
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: use this prio to enable dynamic cbc priority configuration
|
||||
* feature in the future, currently ignore it.
|
||||
@ -834,7 +845,7 @@ cbc_rx_handler(struct cbc_pkt *pkt)
|
||||
void
|
||||
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) {
|
||||
case IOC_NATIVE_LFCC:
|
||||
cbc_process_wakeup_reason(pkt);
|
||||
@ -850,20 +861,39 @@ cbc_tx_handler(struct cbc_pkt *pkt)
|
||||
pkt->req->id);
|
||||
break;
|
||||
}
|
||||
} else if (pkt->req->rtype == CBC_REQ_T_SOC) {
|
||||
/*
|
||||
* 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);
|
||||
} else if (pkt->req->rtype == CBC_REQ_T_HB_INIT) {
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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 {
|
||||
/* TODO: others request types process */
|
||||
DPRINTF("ioc invalid cbc_request type in tx:%d\r\n",
|
||||
/* Discard the packet */
|
||||
DPRINTF("ioc tx discard the packet, type:%d\r\n",
|
||||
pkt->req->rtype);
|
||||
}
|
||||
}
|
||||
|
@ -103,6 +103,9 @@
|
||||
#define CBC_WK_RSN_DOR (1 << 11) /* CBC wakeup reason field cardoor */
|
||||
#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.
|
||||
@ -578,7 +581,9 @@ enum cbc_request_type {
|
||||
CBC_REQ_T_PROT, /* CBC protocol request */
|
||||
CBC_REQ_T_SUSPEND, /* CBC suspend 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.
|
||||
*/
|
||||
struct cbc_pkt {
|
||||
uint8_t soc_active; /* Record soc state */
|
||||
uint8_t hb_state; /* Record Heartbeat state */
|
||||
bool uos_active; /* Mark UOS active status */
|
||||
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_config *cfg; /* CBC and whitelist configurations */
|
||||
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 {
|
||||
char name[16]; /* Core thread name */
|
||||
bool cbc_enable; /* Tx and Rx protocol enable flag */
|
||||
int closing; /* Close IOC mediator device flag */
|
||||
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 ioc_state_type state; /* IOC state type */
|
||||
struct epoll_event *evts; /* Epoll events table */
|
||||
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 */
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user