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:
Liu Yuan 2018-05-23 09:44:21 +08:00 committed by lijinxia
parent 11208dd6d5
commit 0b7af5b6e1
3 changed files with 199 additions and 50 deletions

View File

@ -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.
*/

View File

@ -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);
}
}

View File

@ -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