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

View File

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

View File

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