diff options
Diffstat (limited to 'drivers/misc/mei/client.c')
-rw-r--r-- | drivers/misc/mei/client.c | 163 |
1 files changed, 88 insertions, 75 deletions
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 391936c1aa04..68fe37b5bc52 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -377,19 +377,19 @@ static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, } /** - * __mei_io_list_flush - removes and frees cbs belonging to cl. + * __mei_io_list_flush_cl - removes and frees cbs belonging to cl. * - * @list: an instance of our list structure + * @head: an instance of our list structure * @cl: host client, can be NULL for flushing the whole list * @free: whether to free the cbs */ -static void __mei_io_list_flush(struct mei_cl_cb *list, - struct mei_cl *cl, bool free) +static void __mei_io_list_flush_cl(struct list_head *head, + const struct mei_cl *cl, bool free) { struct mei_cl_cb *cb, *next; /* enable removing everything if no cl is specified */ - list_for_each_entry_safe(cb, next, &list->list, list) { + list_for_each_entry_safe(cb, next, head, list) { if (!cl || mei_cl_cmp_id(cl, cb->cl)) { list_del_init(&cb->list); if (free) @@ -399,25 +399,42 @@ static void __mei_io_list_flush(struct mei_cl_cb *list, } /** - * mei_io_list_flush - removes list entry belonging to cl. + * mei_io_list_flush_cl - removes list entry belonging to cl. * - * @list: An instance of our list structure + * @head: An instance of our list structure * @cl: host client */ -void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) +static inline void mei_io_list_flush_cl(struct list_head *head, + const struct mei_cl *cl) { - __mei_io_list_flush(list, cl, false); + __mei_io_list_flush_cl(head, cl, false); } /** - * mei_io_list_free - removes cb belonging to cl and free them + * mei_io_list_free_cl - removes cb belonging to cl and free them * - * @list: An instance of our list structure + * @head: An instance of our list structure * @cl: host client */ -static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl) +static inline void mei_io_list_free_cl(struct list_head *head, + const struct mei_cl *cl) { - __mei_io_list_flush(list, cl, true); + __mei_io_list_flush_cl(head, cl, true); +} + +/** + * mei_io_list_free_fp - free cb from a list that matches file pointer + * + * @head: io list + * @fp: file pointer (matching cb file object), may be NULL + */ +void mei_io_list_free_fp(struct list_head *head, const struct file *fp) +{ + struct mei_cl_cb *cb, *next; + + list_for_each_entry_safe(cb, next, head, list) + if (!fp || fp == cb->fp) + mei_io_cb_free(cb); } /** @@ -479,7 +496,7 @@ struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length, if (!cb) return NULL; - list_add_tail(&cb->list, &cl->dev->ctrl_wr_list.list); + list_add_tail(&cb->list, &cl->dev->ctrl_wr_list); return cb; } @@ -504,27 +521,6 @@ struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, const struct file *fp) } /** - * mei_cl_read_cb_flush - free client's read pending and completed cbs - * for a specific file - * - * @cl: host client - * @fp: file pointer (matching cb file object), may be NULL - */ -void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp) -{ - struct mei_cl_cb *cb, *next; - - list_for_each_entry_safe(cb, next, &cl->rd_completed, list) - if (!fp || fp == cb->fp) - mei_io_cb_free(cb); - - - list_for_each_entry_safe(cb, next, &cl->rd_pending, list) - if (!fp || fp == cb->fp) - mei_io_cb_free(cb); -} - -/** * mei_cl_flush_queues - flushes queue lists belonging to cl. * * @cl: host client @@ -542,18 +538,16 @@ int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp) dev = cl->dev; cl_dbg(dev, cl, "remove list entry belonging to cl\n"); - mei_io_list_free(&cl->dev->write_list, cl); - mei_io_list_free(&cl->dev->write_waiting_list, cl); - mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); - mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); - mei_io_list_flush(&cl->dev->amthif_cmd_list, cl); - - mei_cl_read_cb_flush(cl, fp); + mei_io_list_free_cl(&cl->dev->write_list, cl); + mei_io_list_free_cl(&cl->dev->write_waiting_list, cl); + mei_io_list_flush_cl(&cl->dev->ctrl_wr_list, cl); + mei_io_list_flush_cl(&cl->dev->ctrl_rd_list, cl); + mei_io_list_free_fp(&cl->rd_pending, fp); + mei_io_list_free_fp(&cl->rd_completed, fp); return 0; } - /** * mei_cl_init - initializes cl. * @@ -756,7 +750,7 @@ static void mei_cl_wake_all(struct mei_cl *cl) * * @cl: host client */ -void mei_cl_set_disconnected(struct mei_cl *cl) +static void mei_cl_set_disconnected(struct mei_cl *cl) { struct mei_device *dev = cl->dev; @@ -765,15 +759,18 @@ void mei_cl_set_disconnected(struct mei_cl *cl) return; cl->state = MEI_FILE_DISCONNECTED; - mei_io_list_free(&dev->write_list, cl); - mei_io_list_free(&dev->write_waiting_list, cl); - mei_io_list_flush(&dev->ctrl_rd_list, cl); - mei_io_list_flush(&dev->ctrl_wr_list, cl); + mei_io_list_free_cl(&dev->write_list, cl); + mei_io_list_free_cl(&dev->write_waiting_list, cl); + mei_io_list_flush_cl(&dev->ctrl_rd_list, cl); + mei_io_list_flush_cl(&dev->ctrl_wr_list, cl); + mei_io_list_free_cl(&dev->amthif_cmd_list, cl); mei_cl_wake_all(cl); cl->rx_flow_ctrl_creds = 0; cl->tx_flow_ctrl_creds = 0; cl->timer_count = 0; + mei_cl_bus_module_put(cl); + if (!cl->me_cl) return; @@ -829,7 +826,7 @@ static int mei_cl_send_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb) return ret; } - list_move_tail(&cb->list, &dev->ctrl_rd_list.list); + list_move_tail(&cb->list, &dev->ctrl_rd_list); cl->timer_count = MEI_CONNECT_TIMEOUT; mei_schedule_stall_timer(dev); @@ -847,7 +844,7 @@ static int mei_cl_send_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb) * Return: 0, OK; otherwise, error. */ int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb, - struct mei_cl_cb *cmpl_list) + struct list_head *cmpl_list) { struct mei_device *dev = cl->dev; u32 msg_slots; @@ -862,7 +859,7 @@ int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb, ret = mei_cl_send_disconnect(cl, cb); if (ret) - list_move_tail(&cb->list, &cmpl_list->list); + list_move_tail(&cb->list, cmpl_list); return ret; } @@ -984,7 +981,7 @@ static bool mei_cl_is_other_connecting(struct mei_cl *cl) dev = cl->dev; - list_for_each_entry(cb, &dev->ctrl_rd_list.list, list) { + list_for_each_entry(cb, &dev->ctrl_rd_list, list) { if (cb->fop_type == MEI_FOP_CONNECT && mei_cl_me_id(cl) == mei_cl_me_id(cb->cl)) return true; @@ -1015,7 +1012,7 @@ static int mei_cl_send_connect(struct mei_cl *cl, struct mei_cl_cb *cb) return ret; } - list_move_tail(&cb->list, &dev->ctrl_rd_list.list); + list_move_tail(&cb->list, &dev->ctrl_rd_list); cl->timer_count = MEI_CONNECT_TIMEOUT; mei_schedule_stall_timer(dev); return 0; @@ -1031,7 +1028,7 @@ static int mei_cl_send_connect(struct mei_cl *cl, struct mei_cl_cb *cb) * Return: 0, OK; otherwise, error. */ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, - struct mei_cl_cb *cmpl_list) + struct list_head *cmpl_list) { struct mei_device *dev = cl->dev; u32 msg_slots; @@ -1049,7 +1046,7 @@ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, rets = mei_cl_send_connect(cl, cb); if (rets) - list_move_tail(&cb->list, &cmpl_list->list); + list_move_tail(&cb->list, cmpl_list); return rets; } @@ -1077,13 +1074,17 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, dev = cl->dev; + if (!mei_cl_bus_module_get(cl)) + return -ENODEV; + rets = mei_cl_set_connecting(cl, me_cl); if (rets) - return rets; + goto nortpm; if (mei_cl_is_fixed_address(cl)) { cl->state = MEI_FILE_CONNECTED; - return 0; + rets = 0; + goto nortpm; } rets = pm_runtime_get(dev->dev); @@ -1117,8 +1118,8 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, if (!mei_cl_is_connected(cl)) { if (cl->state == MEI_FILE_DISCONNECT_REQUIRED) { - mei_io_list_flush(&dev->ctrl_rd_list, cl); - mei_io_list_flush(&dev->ctrl_wr_list, cl); + mei_io_list_flush_cl(&dev->ctrl_rd_list, cl); + mei_io_list_flush_cl(&dev->ctrl_wr_list, cl); /* ignore disconnect return valuue; * in case of failure reset will be invoked */ @@ -1270,7 +1271,7 @@ enum mei_cb_file_ops mei_cl_notify_req2fop(u8 req) * 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 list_head *cmpl_list) { struct mei_device *dev = cl->dev; u32 msg_slots; @@ -1288,11 +1289,11 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, ret = mei_hbm_cl_notify_req(dev, cl, request); if (ret) { cl->status = ret; - list_move_tail(&cb->list, &cmpl_list->list); + list_move_tail(&cb->list, cmpl_list); return ret; } - list_move_tail(&cb->list, &dev->ctrl_rd_list.list); + list_move_tail(&cb->list, &dev->ctrl_rd_list); return 0; } @@ -1325,6 +1326,9 @@ int mei_cl_notify_request(struct mei_cl *cl, return -EOPNOTSUPP; } + if (!mei_cl_is_connected(cl)) + return -ENODEV; + rets = pm_runtime_get(dev->dev); if (rets < 0 && rets != -EINPROGRESS) { pm_runtime_put_noidle(dev->dev); @@ -1344,7 +1348,7 @@ int mei_cl_notify_request(struct mei_cl *cl, rets = -ENODEV; goto out; } - list_move_tail(&cb->list, &dev->ctrl_rd_list.list); + list_move_tail(&cb->list, &dev->ctrl_rd_list); } mutex_unlock(&dev->device_lock); @@ -1419,6 +1423,11 @@ int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev) dev = cl->dev; + if (!dev->hbm_f_ev_supported) { + cl_dbg(dev, cl, "notifications not supported\n"); + return -EOPNOTSUPP; + } + if (!mei_cl_is_connected(cl)) return -ENODEV; @@ -1519,7 +1528,7 @@ nortpm: * Return: 0, OK; otherwise error. */ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, - struct mei_cl_cb *cmpl_list) + struct list_head *cmpl_list) { struct mei_device *dev; struct mei_msg_data *buf; @@ -1541,7 +1550,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, rets = first_chunk ? mei_cl_tx_flow_ctrl_creds(cl) : 1; if (rets < 0) - return rets; + goto err; if (rets == 0) { cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); @@ -1575,11 +1584,8 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, cb->buf.size, cb->buf_idx); rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx); - if (rets) { - cl->status = rets; - list_move_tail(&cb->list, &cmpl_list->list); - return rets; - } + if (rets) + goto err; cl->status = 0; cl->writing_state = MEI_WRITING; @@ -1587,14 +1593,21 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, cb->completed = mei_hdr.msg_complete == 1; if (first_chunk) { - if (mei_cl_tx_flow_ctrl_creds_reduce(cl)) - return -EIO; + if (mei_cl_tx_flow_ctrl_creds_reduce(cl)) { + rets = -EIO; + goto err; + } } if (mei_hdr.msg_complete) - list_move_tail(&cb->list, &dev->write_waiting_list.list); + list_move_tail(&cb->list, &dev->write_waiting_list); return 0; + +err: + cl->status = rets; + list_move_tail(&cb->list, cmpl_list); + return rets; } /** @@ -1683,9 +1696,9 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb) out: if (mei_hdr.msg_complete) - list_add_tail(&cb->list, &dev->write_waiting_list.list); + list_add_tail(&cb->list, &dev->write_waiting_list); else - list_add_tail(&cb->list, &dev->write_list.list); + list_add_tail(&cb->list, &dev->write_list); cb = NULL; if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) { |