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)
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
*
*/
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_ */
{
struct mei_cl *cl = file->private_data;
struct mei_cl_cb *write_cb = NULL;
- struct mei_msg_hdr mei_hdr;
struct mei_device *dev;
unsigned long timeout = 0;
int rets;
- int i;
+ int id;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
if (dev->dev_state != MEI_DEV_ENABLED) {
rets = -ENODEV;
- goto err;
+ goto out;
}
- i = mei_me_cl_by_id(dev, cl->me_client_id);
- if (i < 0) {
+ id = mei_me_cl_by_id(dev, cl->me_client_id);
+ if (id < 0) {
rets = -ENODEV;
- goto err;
+ goto out;
}
- if (length > dev->me_clients[i].props.max_msg_length || length <= 0) {
+ if (length > dev->me_clients[id].props.max_msg_length || length <= 0) {
rets = -EMSGSIZE;
- goto err;
+ goto out;
}
if (cl->state != MEI_FILE_CONNECTED) {
- rets = -ENODEV;
dev_err(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d",
cl->host_client_id, cl->me_client_id);
- goto err;
+ rets = -ENODEV;
+ goto out;
}
if (cl == &dev->iamthif_cl) {
write_cb = mei_amthif_find_read_list_entry(dev, file);
if (!write_cb) {
dev_err(&dev->pdev->dev, "write cb allocation failed\n");
rets = -ENOMEM;
- goto err;
+ goto out;
}
rets = mei_io_cb_alloc_req_buf(write_cb, length);
if (rets)
- goto err;
-
- dev_dbg(&dev->pdev->dev, "cb request size = %zd\n", length);
+ goto out;
rets = copy_from_user(write_cb->request_buffer.data, ubuf, length);
if (rets)
- goto err;
+ goto out;
cl->sm_state = 0;
if (length == 4 &&
if (rets) {
dev_err(&dev->pdev->dev,
"amthif write failed with status = %d\n", rets);
- goto err;
+ goto out;
}
mutex_unlock(&dev->device_lock);
return length;
}
- write_cb->fop_type = MEI_FOP_WRITE;
-
- dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n",
- cl->host_client_id, cl->me_client_id);
- rets = mei_cl_flow_ctrl_creds(cl);
- if (rets < 0)
- goto err;
-
- if (rets == 0 || !dev->hbuf_is_ready) {
- write_cb->buf_idx = 0;
- mei_hdr.msg_complete = 0;
- cl->writing_state = MEI_WRITING;
- goto out;
- }
-
- dev->hbuf_is_ready = false;
- 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;
-
- dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n",
- MEI_HDR_PRM(&mei_hdr));
- if (mei_write_message(dev, &mei_hdr, write_cb->request_buffer.data)) {
- rets = -ENODEV;
- goto err;
- }
- cl->writing_state = MEI_WRITING;
- write_cb->buf_idx = mei_hdr.length;
-
+ rets = mei_cl_write(cl, write_cb, false);
out:
- if (mei_hdr.msg_complete) {
- if (mei_cl_flow_ctrl_reduce(cl)) {
- rets = -ENODEV;
- goto err;
- }
- list_add_tail(&write_cb->list, &dev->write_waiting_list.list);
- } else {
- list_add_tail(&write_cb->list, &dev->write_list.list);
- }
-
- mutex_unlock(&dev->device_lock);
- return length;
-
-err:
mutex_unlock(&dev->device_lock);
- mei_io_cb_free(write_cb);
+ if (rets < 0)
+ mei_io_cb_free(write_cb);
return rets;
}
/*
* Intel MEI message data struct
*/
-struct mei_message_data {
+struct mei_msg_data {
u32 size;
unsigned char *data;
};
struct list_head list;
struct mei_cl *cl;
enum mei_cb_file_ops fop_type;
- struct mei_message_data request_buffer;
- struct mei_message_data response_buffer;
+ struct mei_msg_data request_buffer;
+ struct mei_msg_data response_buffer;
unsigned long buf_idx;
unsigned long read_time;
struct file *file_object;