Skip to content

Commit

Permalink
mei: add mei_cl_write function
Browse files Browse the repository at this point in the history
consolidate write code to a specific me client in mei_cl_write function
the function is called from mei device write handler and from
mei_cl bus send function

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Tomas Winkler authored and Greg Kroah-Hartman committed Apr 8, 2013
1 parent 606f34a commit 4234a6d
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 158 deletions.
103 changes: 19 additions & 84 deletions drivers/misc/mei/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,112 +226,47 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
bool blocking)
{
struct mei_device *dev;
struct mei_msg_hdr mei_hdr;
struct mei_cl_cb *cb;
int me_cl_id, err;
int id;
int rets;

if (WARN_ON(!cl || !cl->dev))
return -ENODEV;

dev = cl->dev;

if (cl->state != MEI_FILE_CONNECTED)
return -ENODEV;

/* Check if we have an ME client device */
id = mei_me_cl_by_id(dev, cl->me_client_id);
if (id < 0)
return -ENODEV;

if (length > dev->me_clients[id].props.max_msg_length)
return -EINVAL;

cb = mei_io_cb_init(cl, NULL);
if (!cb)
return -ENOMEM;

err = mei_io_cb_alloc_req_buf(cb, length);
if (err < 0) {
rets = mei_io_cb_alloc_req_buf(cb, length);
if (rets < 0) {
mei_io_cb_free(cb);
return err;
return rets;
}

memcpy(cb->request_buffer.data, buf, length);
cb->fop_type = MEI_FOP_WRITE;

dev = cl->dev;

mutex_lock(&dev->device_lock);

/* Check if we have an ME client device */
me_cl_id = mei_me_cl_by_id(dev, cl->me_client_id);
if (me_cl_id == dev->me_clients_num) {
err = -ENODEV;
goto out_err;
}

if (length > dev->me_clients[me_cl_id].props.max_msg_length) {
err = -EINVAL;
goto out_err;
}

err = mei_cl_flow_ctrl_creds(cl);
if (err < 0)
goto out_err;

/* Host buffer is not ready, we queue the request */
if (err == 0 || !dev->hbuf_is_ready) {
cb->buf_idx = 0;
mei_hdr.msg_complete = 0;
cl->writing_state = MEI_WRITING;

goto out;
}

dev->hbuf_is_ready = false;

/* Check for a maximum length */
if (length > mei_hbuf_max_len(dev)) {
mei_hdr.length = mei_hbuf_max_len(dev);
mei_hdr.msg_complete = 0;
} else {
mei_hdr.length = length;
mei_hdr.msg_complete = 1;
}

mei_hdr.host_addr = cl->host_client_id;
mei_hdr.me_addr = cl->me_client_id;
mei_hdr.reserved = 0;

if (mei_write_message(dev, &mei_hdr, buf)) {
err = -EIO;
goto out_err;
}

cl->writing_state = MEI_WRITING;
cb->buf_idx = mei_hdr.length;

out:
if (mei_hdr.msg_complete) {
if (mei_cl_flow_ctrl_reduce(cl)) {
err = -ENODEV;
goto out_err;
}
list_add_tail(&cb->list, &dev->write_waiting_list.list);
} else {
list_add_tail(&cb->list, &dev->write_list.list);
}
rets = mei_cl_write(cl, cb, blocking);

mutex_unlock(&dev->device_lock);
if (rets < 0)
mei_io_cb_free(cb);

if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
if (wait_event_interruptible(cl->tx_wait,
cl->writing_state == MEI_WRITE_COMPLETE)) {
if (signal_pending(current))
err = -EINTR;
err = -ERESTARTSYS;
mutex_lock(&dev->device_lock);
goto out_err;
}
}

return mei_hdr.length;

out_err:
mutex_unlock(&dev->device_lock);
mei_io_cb_free(cb);

return err;
return rets;
}

int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
Expand Down
105 changes: 105 additions & 0 deletions drivers/misc/mei/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,111 @@ int mei_cl_read_start(struct mei_cl *cl)
return rets;
}

/**
* mei_cl_write - submit a write cb to mei device
assumes device_lock is locked
*
* @cl: host client
* @cl: write callback with filled data
*
* returns numbe of bytes sent on success, <0 on failure.
*/
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
{
struct mei_device *dev;
struct mei_msg_data *buf;
struct mei_msg_hdr mei_hdr;
int rets;


if (WARN_ON(!cl || !cl->dev))
return -ENODEV;

if (WARN_ON(!cb))
return -EINVAL;

dev = cl->dev;


buf = &cb->request_buffer;

dev_dbg(&dev->pdev->dev, "mei_cl_write %d\n", buf->size);


cb->fop_type = MEI_FOP_WRITE;

rets = mei_cl_flow_ctrl_creds(cl);
if (rets < 0)
goto err;

/* Host buffer is not ready, we queue the request */
if (rets == 0 || !dev->hbuf_is_ready) {
cb->buf_idx = 0;
/* unseting complete will enqueue the cb for write */
mei_hdr.msg_complete = 0;
cl->writing_state = MEI_WRITING;
rets = buf->size;
goto out;
}

dev->hbuf_is_ready = false;

/* Check for a maximum length */
if (buf->size > mei_hbuf_max_len(dev)) {
mei_hdr.length = mei_hbuf_max_len(dev);
mei_hdr.msg_complete = 0;
} else {
mei_hdr.length = buf->size;
mei_hdr.msg_complete = 1;
}

mei_hdr.host_addr = cl->host_client_id;
mei_hdr.me_addr = cl->me_client_id;
mei_hdr.reserved = 0;

dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n",
MEI_HDR_PRM(&mei_hdr));


if (mei_write_message(dev, &mei_hdr, buf->data)) {
rets = -EIO;
goto err;
}

cl->writing_state = MEI_WRITING;
cb->buf_idx = mei_hdr.length;

rets = buf->size;
out:
if (mei_hdr.msg_complete) {
if (mei_cl_flow_ctrl_reduce(cl)) {
rets = -ENODEV;
goto err;
}
list_add_tail(&cb->list, &dev->write_waiting_list.list);
} else {
list_add_tail(&cb->list, &dev->write_list.list);
}


if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {

mutex_unlock(&dev->device_lock);
if (wait_event_interruptible(cl->tx_wait,
cl->writing_state == MEI_WRITE_COMPLETE)) {
if (signal_pending(current))
rets = -EINTR;
else
rets = -ERESTARTSYS;
}
mutex_lock(&dev->device_lock);
}
err:
return rets;
}



/**
* mei_cl_all_disconnect - disconnect forcefully all connected clients
*
Expand Down
7 changes: 3 additions & 4 deletions drivers/misc/mei/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,16 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl);
*/
bool mei_cl_is_other_connecting(struct mei_cl *cl);
int mei_cl_disconnect(struct mei_cl *cl);

int mei_cl_read_start(struct mei_cl *cl);

int mei_cl_connect(struct mei_cl *cl, struct file *file);
int mei_cl_read_start(struct mei_cl *cl);
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking);

void mei_host_client_init(struct work_struct *work);



void mei_cl_all_disconnect(struct mei_device *dev);
void mei_cl_all_read_wakeup(struct mei_device *dev);
void mei_cl_all_write_clear(struct mei_device *dev);


#endif /* _MEI_CLIENT_H_ */
Loading

0 comments on commit 4234a6d

Please sign in to comment.