mei: add mei_cl_notify_request command

Add per client notification request infrastructure
that allows client to enable or disable async
event notification.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Tomas Winkler 2015-07-26 09:54:18 +03:00 committed by Greg Kroah-Hartman
parent 4d99877d87
commit 51678ccb7b
4 changed files with 157 additions and 4 deletions

View File

@ -1208,6 +1208,147 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
return 0;
}
/**
* mei_cl_notify_fop2req - convert fop to proper request
*
* @fop: client notification start response command
*
* Return: MEI_HBM_NOTIFICATION_START/STOP
*/
u8 mei_cl_notify_fop2req(enum mei_cb_file_ops fop)
{
if (fop == MEI_FOP_NOTIFY_START)
return MEI_HBM_NOTIFICATION_START;
else
return MEI_HBM_NOTIFICATION_STOP;
}
/**
* mei_cl_notify_req2fop - convert notification request top file operation type
*
* @req: hbm notification request type
*
* Return: MEI_FOP_NOTIFY_START/STOP
*/
enum mei_cb_file_ops mei_cl_notify_req2fop(u8 req)
{
if (req == MEI_HBM_NOTIFICATION_START)
return MEI_FOP_NOTIFY_START;
else
return MEI_FOP_NOTIFY_STOP;
}
/**
* mei_cl_irq_notify - send notification request in irq_thread context
*
* @cl: client
* @cb: callback block.
* @cmpl_list: complete list.
*
* Return: 0 on such and error otherwise.
*/
int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list)
{
struct mei_device *dev = cl->dev;
u32 msg_slots;
int slots;
int ret;
bool request;
msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
slots = mei_hbuf_empty_slots(dev);
if (slots < msg_slots)
return -EMSGSIZE;
request = mei_cl_notify_fop2req(cb->fop_type);
ret = mei_hbm_cl_notify_req(dev, cl, request);
if (ret) {
cl->status = ret;
list_move_tail(&cb->list, &cmpl_list->list);
return ret;
}
list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
return 0;
}
/**
* mei_cl_notify_request - send notification stop/start request
*
* @cl: host client
* @file: associate request with file
* @request: 1 for start or 0 for stop
*
* Locking: called under "dev->device_lock" lock
*
* Return: 0 on such and error otherwise.
*/
int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request)
{
struct mei_device *dev;
struct mei_cl_cb *cb;
enum mei_cb_file_ops fop_type;
int rets;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
dev = cl->dev;
if (!dev->hbm_f_ev_supported) {
cl_dbg(dev, cl, "notifications not supported\n");
return -EOPNOTSUPP;
}
rets = pm_runtime_get(dev->dev);
if (rets < 0 && rets != -EINPROGRESS) {
pm_runtime_put_noidle(dev->dev);
cl_err(dev, cl, "rpm: get failed %d\n", rets);
return rets;
}
fop_type = mei_cl_notify_req2fop(request);
cb = mei_io_cb_init(cl, fop_type, file);
if (!cb) {
rets = -ENOMEM;
goto out;
}
if (mei_hbuf_acquire(dev)) {
if (mei_hbm_cl_notify_req(dev, cl, request)) {
rets = -ENODEV;
goto out;
}
list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
} else {
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
}
mutex_unlock(&dev->device_lock);
wait_event_timeout(cl->wait, cl->notify_en == request,
mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
mutex_lock(&dev->device_lock);
if (cl->notify_en != request) {
mei_io_list_flush(&dev->ctrl_rd_list, cl);
mei_io_list_flush(&dev->ctrl_wr_list, cl);
if (!cl->status)
cl->status = -EFAULT;
}
rets = cl->status;
out:
cl_dbg(dev, cl, "rpm: autosuspend\n");
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
mei_io_cb_free(cb);
return rets;
}
/**
* mei_cl_read_start - the start read client message function.
*
@ -1516,6 +1657,8 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
case MEI_FOP_CONNECT:
case MEI_FOP_DISCONNECT:
case MEI_FOP_NOTIFY_STOP:
case MEI_FOP_NOTIFY_START:
if (waitqueue_active(&cl->wait))
wake_up(&cl->wait);

View File

@ -219,6 +219,12 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
void mei_host_client_init(struct work_struct *work);
u8 mei_cl_notify_fop2req(enum mei_cb_file_ops fop);
enum mei_cb_file_ops mei_cl_notify_req2fop(u8 request);
int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request);
int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list);
void mei_cl_all_disconnect(struct mei_device *dev);
void mei_cl_all_wakeup(struct mei_device *dev);
void mei_cl_all_write_clear(struct mei_device *dev);

View File

@ -446,10 +446,7 @@ static inline enum mei_cb_file_ops notify_res_to_fop(struct mei_hbm_cl_cmd *cmd)
struct hbm_notification_response *rs =
(struct hbm_notification_response *)cmd;
if (rs->start == MEI_HBM_NOTIFICATION_START)
return MEI_FOP_NOTIFY_START;
else
return MEI_FOP_NOTIFY_STOP;
return mei_cl_notify_req2fop(rs->start);
}
/**

View File

@ -403,6 +403,13 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
if (ret)
return ret;
break;
case MEI_FOP_NOTIFY_START:
case MEI_FOP_NOTIFY_STOP:
ret = mei_cl_irq_notify(cl, cb, cmpl_list);
if (ret)
return ret;
break;
default:
BUG();
}