mei: revamp hbm state machine

1. Rename init_clients_state to hbm_state and use
MEI_HBM_ prefix for HBM states

2. Remove recvd_msg and use hbm state for synchronizing
hbm protocol has successful start.
We can wake up the hbm event from start response handler
and remove the hack from the interrupt thread

3. mei_hbm_start_wait function encapsulate start completion
waiting

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Tomas Winkler 2013-04-18 23:03:48 +03:00 committed by Greg Kroah-Hartman
parent 3a189b3ba0
commit 9b0d5efc42
7 changed files with 72 additions and 59 deletions

View File

@ -123,12 +123,33 @@ static bool is_treat_specially_client(struct mei_cl *cl,
return false; return false;
} }
int mei_hbm_start_wait(struct mei_device *dev)
{
int ret;
if (dev->hbm_state > MEI_HBM_START)
return 0;
mutex_unlock(&dev->device_lock);
ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
dev->hbm_state == MEI_HBM_IDLE ||
dev->hbm_state > MEI_HBM_START,
mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
mutex_lock(&dev->device_lock);
if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
dev->hbm_state = MEI_HBM_IDLE;
dev_err(&dev->pdev->dev, "wating for mei start failed\n");
return -ETIMEDOUT;
}
return 0;
}
/** /**
* mei_hbm_start_req - sends start request message. * mei_hbm_start_req - sends start request message.
* *
* @dev: the device structure * @dev: the device structure
*/ */
void mei_hbm_start_req(struct mei_device *dev) int mei_hbm_start_req(struct mei_device *dev)
{ {
struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
struct hbm_host_version_request *start_req; struct hbm_host_version_request *start_req;
@ -143,18 +164,19 @@ void mei_hbm_start_req(struct mei_device *dev)
start_req->host_version.major_version = HBM_MAJOR_VERSION; start_req->host_version.major_version = HBM_MAJOR_VERSION;
start_req->host_version.minor_version = HBM_MINOR_VERSION; start_req->host_version.minor_version = HBM_MINOR_VERSION;
dev->recvd_msg = false; dev->hbm_state = MEI_HBM_IDLE;
if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) { if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
dev_err(&dev->pdev->dev, "version message writet failed\n"); dev_err(&dev->pdev->dev, "version message writet failed\n");
dev->dev_state = MEI_DEV_RESETING; dev->dev_state = MEI_DEV_RESETING;
mei_reset(dev, 1); mei_reset(dev, 1);
return -ENODEV;
} }
dev->init_clients_state = MEI_START_MESSAGE; dev->hbm_state = MEI_HBM_START;
dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
return ; return 0;
} }
/** /*
* mei_hbm_enum_clients_req - sends enumeration client request message. * mei_hbm_enum_clients_req - sends enumeration client request message.
* *
* @dev: the device structure * @dev: the device structure
@ -178,7 +200,7 @@ static void mei_hbm_enum_clients_req(struct mei_device *dev)
dev_err(&dev->pdev->dev, "enumeration request write failed.\n"); dev_err(&dev->pdev->dev, "enumeration request write failed.\n");
mei_reset(dev, 1); mei_reset(dev, 1);
} }
dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE; dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
return; return;
} }
@ -208,6 +230,7 @@ static int mei_hbm_prop_req(struct mei_device *dev)
/* We got all client properties */ /* We got all client properties */
if (next_client_index == MEI_CLIENTS_MAX) { if (next_client_index == MEI_CLIENTS_MAX) {
dev->hbm_state = MEI_HBM_STARTED;
schedule_work(&dev->init_work); schedule_work(&dev->init_work);
return 0; return 0;
@ -542,27 +565,28 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
dev->version = version_res->me_max_version; dev->version = version_res->me_max_version;
dev_dbg(&dev->pdev->dev, "version mismatch.\n"); dev_dbg(&dev->pdev->dev, "version mismatch.\n");
dev->hbm_state = MEI_HBM_STOP;
mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr, mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr,
dev->wr_msg.data); dev->wr_msg.data);
mei_write_message(dev, &dev->wr_msg.hdr, mei_write_message(dev, &dev->wr_msg.hdr,
dev->wr_msg.data); dev->wr_msg.data);
return; return;
} }
dev->version.major_version = HBM_MAJOR_VERSION; dev->version.major_version = HBM_MAJOR_VERSION;
dev->version.minor_version = HBM_MINOR_VERSION; dev->version.minor_version = HBM_MINOR_VERSION;
if (dev->dev_state == MEI_DEV_INIT_CLIENTS && if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
dev->init_clients_state == MEI_START_MESSAGE) { dev->hbm_state == MEI_HBM_START) {
dev->init_clients_timer = 0; dev->init_clients_timer = 0;
mei_hbm_enum_clients_req(dev); mei_hbm_enum_clients_req(dev);
} else { } else {
dev->recvd_msg = false;
dev_err(&dev->pdev->dev, "reset: wrong host start response\n"); dev_err(&dev->pdev->dev, "reset: wrong host start response\n");
mei_reset(dev, 1); mei_reset(dev, 1);
return; return;
} }
dev->recvd_msg = true; wake_up_interruptible(&dev->wait_recvd_msg);
dev_dbg(&dev->pdev->dev, "host start response message received.\n"); dev_dbg(&dev->pdev->dev, "host start response message received.\n");
break; break;
@ -603,7 +627,7 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
} }
if (dev->dev_state != MEI_DEV_INIT_CLIENTS || if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) { dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
dev_err(&dev->pdev->dev, "reset: unexpected properties response\n"); dev_err(&dev->pdev->dev, "reset: unexpected properties response\n");
mei_reset(dev, 1); mei_reset(dev, 1);
@ -623,13 +647,12 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
enum_res = (struct hbm_host_enum_response *) mei_msg; enum_res = (struct hbm_host_enum_response *) mei_msg;
memcpy(dev->me_clients_map, enum_res->valid_addresses, 32); memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
if (dev->dev_state == MEI_DEV_INIT_CLIENTS && if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) { dev->hbm_state == MEI_HBM_ENUM_CLIENTS) {
dev->init_clients_timer = 0; dev->init_clients_timer = 0;
dev->me_client_presentation_num = 0; dev->me_client_presentation_num = 0;
dev->me_client_index = 0; dev->me_client_index = 0;
mei_hbm_me_cl_allocate(dev); mei_hbm_me_cl_allocate(dev);
dev->init_clients_state = dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
MEI_CLIENT_PROPERTIES_MESSAGE;
/* first property reqeust */ /* first property reqeust */
mei_hbm_prop_req(dev); mei_hbm_prop_req(dev);
@ -641,6 +664,9 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
break; break;
case HOST_STOP_RES_CMD: case HOST_STOP_RES_CMD:
if (dev->hbm_state != MEI_HBM_STOP)
dev_err(&dev->pdev->dev, "unexpected stop response hbm.\n");
dev->dev_state = MEI_DEV_DISABLED; dev->dev_state = MEI_DEV_DISABLED;
dev_info(&dev->pdev->dev, "reset: FW stop response.\n"); dev_info(&dev->pdev->dev, "reset: FW stop response.\n");
mei_reset(dev, 1); mei_reset(dev, 1);
@ -654,6 +680,7 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
case ME_STOP_REQ_CMD: case ME_STOP_REQ_CMD:
dev->hbm_state = MEI_HBM_STOP;
mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr, mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr,
dev->wr_ext_msg.data); dev->wr_ext_msg.data);
break; break;

View File

@ -17,6 +17,27 @@
#ifndef _MEI_HBM_H_ #ifndef _MEI_HBM_H_
#define _MEI_HBM_H_ #define _MEI_HBM_H_
struct mei_device;
struct mei_msg_hdr;
struct mei_cl;
/**
* enum mei_hbm_state - host bus message protocol state
*
* @MEI_HBM_IDLE : protocol not started
* @MEI_HBM_START : start request message was sent
* @MEI_HBM_ENUM_CLIENTS : enumeration request was sent
* @MEI_HBM_CLIENT_PROPERTIES : acquiring clients properties
*/
enum mei_hbm_state {
MEI_HBM_IDLE = 0,
MEI_HBM_START,
MEI_HBM_ENUM_CLIENTS,
MEI_HBM_CLIENT_PROPERTIES,
MEI_HBM_STARTED,
MEI_HBM_STOP,
};
void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr); void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr);
static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length) static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length)
@ -28,8 +49,8 @@ static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length)
hdr->reserved = 0; hdr->reserved = 0;
} }
void mei_hbm_start_req(struct mei_device *dev); int mei_hbm_start_req(struct mei_device *dev);
int mei_hbm_start_wait(struct mei_device *dev);
int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl); int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl);
int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl); int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl);
int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl); int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl);

View File

@ -468,8 +468,6 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
struct mei_cl_cb complete_list; struct mei_cl_cb complete_list;
s32 slots; s32 slots;
int rets; int rets;
bool bus_message_received;
dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n"); dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
/* initialize our complete list */ /* initialize our complete list */
@ -525,17 +523,7 @@ end:
dev_dbg(&dev->pdev->dev, "end of bottom half function.\n"); dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
dev->hbuf_is_ready = mei_hbuf_is_ready(dev); dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
bus_message_received = false;
if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
bus_message_received = true;
}
mutex_unlock(&dev->device_lock); mutex_unlock(&dev->device_lock);
if (bus_message_received) {
dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
wake_up_interruptible(&dev->wait_recvd_msg);
bus_message_received = false;
}
mei_irq_compl_handler(dev, &complete_list); mei_irq_compl_handler(dev, &complete_list);

View File

@ -80,8 +80,6 @@ EXPORT_SYMBOL_GPL(mei_device_init);
*/ */
int mei_start(struct mei_device *dev) int mei_start(struct mei_device *dev)
{ {
int ret = 0;
mutex_lock(&dev->device_lock); mutex_lock(&dev->device_lock);
/* acknowledge interrupt and stop interupts */ /* acknowledge interrupt and stop interupts */
@ -89,29 +87,15 @@ int mei_start(struct mei_device *dev)
mei_hw_config(dev); mei_hw_config(dev);
dev->recvd_msg = false;
dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n"); dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
mei_reset(dev, 1); mei_reset(dev, 1);
/* wait for ME to turn on ME_RDY */ if (mei_hbm_start_wait(dev)) {
if (!dev->recvd_msg) { dev_err(&dev->pdev->dev, "HBM haven't started");
mutex_unlock(&dev->device_lock);
ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
dev->recvd_msg,
mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
mutex_lock(&dev->device_lock);
}
if (ret <= 0 && !dev->recvd_msg) {
dev->dev_state = MEI_DEV_DISABLED;
dev_dbg(&dev->pdev->dev,
"wait_event_interruptible_timeout failed"
"on wait for ME to turn on ME_RDY.\n");
goto err; goto err;
} }
if (!mei_host_is_ready(dev)) { if (!mei_host_is_ready(dev)) {
dev_err(&dev->pdev->dev, "host is not ready.\n"); dev_err(&dev->pdev->dev, "host is not ready.\n");
goto err; goto err;
@ -128,7 +112,6 @@ int mei_start(struct mei_device *dev)
goto err; goto err;
} }
dev->recvd_msg = false;
dev_dbg(&dev->pdev->dev, "link layer has been established.\n"); dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
mutex_unlock(&dev->device_lock); mutex_unlock(&dev->device_lock);
@ -158,6 +141,7 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
mei_hw_reset(dev, interrupts_enabled); mei_hw_reset(dev, interrupts_enabled);
dev->hbm_state = MEI_HBM_IDLE;
if (dev->dev_state != MEI_DEV_INITIALIZING) { if (dev->dev_state != MEI_DEV_INITIALIZING) {
if (dev->dev_state != MEI_DEV_DISABLED && if (dev->dev_state != MEI_DEV_DISABLED &&

View File

@ -623,8 +623,8 @@ void mei_timer(struct work_struct *work)
if (dev->dev_state == MEI_DEV_INIT_CLIENTS) { if (dev->dev_state == MEI_DEV_INIT_CLIENTS) {
if (dev->init_clients_timer) { if (dev->init_clients_timer) {
if (--dev->init_clients_timer == 0) { if (--dev->init_clients_timer == 0) {
dev_err(&dev->pdev->dev, "reset: init clients timeout ,init clients state = %d.\n", dev_err(&dev->pdev->dev, "reset: init clients timeout hbm_state = %d.\n",
dev->init_clients_state); dev->hbm_state);
mei_reset(dev, 1); mei_reset(dev, 1);
} }
} }

View File

@ -48,7 +48,7 @@
* *
* @inode: pointer to inode structure * @inode: pointer to inode structure
* @file: pointer to file structure * @file: pointer to file structure
* e
* returns 0 on success, <0 on error * returns 0 on success, <0 on error
*/ */
static int mei_open(struct inode *inode, struct file *file) static int mei_open(struct inode *inode, struct file *file)

View File

@ -25,6 +25,7 @@
#include "hw.h" #include "hw.h"
#include "hw-me-regs.h" #include "hw-me-regs.h"
#include "hbm.h"
/* /*
* watch dog definition * watch dog definition
@ -104,13 +105,6 @@ enum mei_dev_state {
const char *mei_dev_state_str(int state); const char *mei_dev_state_str(int state);
/* init clients states*/
enum mei_init_clients_states {
MEI_START_MESSAGE = 0,
MEI_ENUM_CLIENTS_MESSAGE,
MEI_CLIENT_PROPERTIES_MESSAGE
};
enum iamthif_states { enum iamthif_states {
MEI_IAMTHIF_IDLE, MEI_IAMTHIF_IDLE,
MEI_IAMTHIF_WRITING, MEI_IAMTHIF_WRITING,
@ -338,6 +332,7 @@ struct mei_cl_device {
/** /**
* struct mei_device - MEI private device struct * struct mei_device - MEI private device struct
* @hbm_state - state of host bus message protocol
* @mem_addr - mem mapped base register address * @mem_addr - mem mapped base register address
* @hbuf_depth - depth of hardware host/write buffer is slots * @hbuf_depth - depth of hardware host/write buffer is slots
@ -370,8 +365,6 @@ struct mei_device {
struct delayed_work timer_work; /* MEI timer delayed work (timeouts) */ struct delayed_work timer_work; /* MEI timer delayed work (timeouts) */
bool recvd_hw_ready; bool recvd_hw_ready;
bool recvd_msg;
/* /*
* waiting queue for receive message from FW * waiting queue for receive message from FW
*/ */
@ -383,7 +376,7 @@ struct mei_device {
* mei device states * mei device states
*/ */
enum mei_dev_state dev_state; enum mei_dev_state dev_state;
enum mei_init_clients_states init_clients_state; enum mei_hbm_state hbm_state;
u16 init_clients_timer; u16 init_clients_timer;
unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */ unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */