Skip to content

Commit

Permalink
mei: add a spin lock to protect rd_completed queue
Browse files Browse the repository at this point in the history
In order to support vtags we need to access read completed
queue out of driver big lock.
Add a spin lock to protect rd_completed queue.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Link: https://lore.kernel.org/r/20200818115147.2567012-7-tomas.winkler@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Alexander Usyskin authored and Greg Kroah-Hartman committed Aug 18, 2020
1 parent 74a9c96 commit d1376f3
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 14 deletions.
6 changes: 3 additions & 3 deletions drivers/misc/mei/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length,
if (timeout) {
rets = wait_event_interruptible_timeout
(cl->rx_wait,
(!list_empty(&cl->rd_completed)) ||
mei_cl_read_cb(cl, NULL) ||
(!mei_cl_is_connected(cl)),
msecs_to_jiffies(timeout));
if (rets == 0)
Expand All @@ -165,7 +165,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length,
} else {
if (wait_event_interruptible
(cl->rx_wait,
(!list_empty(&cl->rd_completed)) ||
mei_cl_read_cb(cl, NULL) ||
(!mei_cl_is_connected(cl)))) {
if (signal_pending(current))
return -EINTR;
Expand Down Expand Up @@ -198,7 +198,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length,
rets = r_length;

free:
mei_io_cb_free(cb);
mei_cl_del_rd_completed(cl, cb);
out:
mutex_unlock(&bus->device_lock);

Expand Down
47 changes: 41 additions & 6 deletions drivers/misc/mei/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -507,15 +507,19 @@ struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length,
*
* Return: cb on success, NULL if cb is not found
*/
struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, const struct file *fp)
struct mei_cl_cb *mei_cl_read_cb(struct mei_cl *cl, const struct file *fp)
{
struct mei_cl_cb *cb;
struct mei_cl_cb *ret_cb = NULL;

spin_lock(&cl->rd_completed_lock);
list_for_each_entry(cb, &cl->rd_completed, list)
if (!fp || fp == cb->fp)
return cb;

return NULL;
if (!fp || fp == cb->fp) {
ret_cb = cb;
break;
}
spin_unlock(&cl->rd_completed_lock);
return ret_cb;
}

/**
Expand All @@ -541,7 +545,9 @@ int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp)
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);
spin_lock(&cl->rd_completed_lock);
mei_io_list_free_fp(&cl->rd_completed, fp);
spin_unlock(&cl->rd_completed_lock);

return 0;
}
Expand All @@ -559,6 +565,7 @@ static void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
init_waitqueue_head(&cl->rx_wait);
init_waitqueue_head(&cl->tx_wait);
init_waitqueue_head(&cl->ev_wait);
spin_lock_init(&cl->rd_completed_lock);
INIT_LIST_HEAD(&cl->rd_completed);
INIT_LIST_HEAD(&cl->rd_pending);
INIT_LIST_HEAD(&cl->link);
Expand Down Expand Up @@ -1230,6 +1237,34 @@ static int mei_cl_tx_flow_ctrl_creds_reduce(struct mei_cl *cl)
return 0;
}

/**
* mei_cl_add_rd_completed - add read completed callback to list with lock
*
* @cl: host client
* @cb: callback block
*
*/
void mei_cl_add_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb)
{
spin_lock(&cl->rd_completed_lock);
list_add_tail(&cb->list, &cl->rd_completed);
spin_unlock(&cl->rd_completed_lock);
}

/**
* mei_cl_del_rd_completed - free read completed callback with lock
*
* @cl: host client
* @cb: callback block
*
*/
void mei_cl_del_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb)
{
spin_lock(&cl->rd_completed_lock);
mei_io_cb_free(cb);
spin_unlock(&cl->rd_completed_lock);
}

/**
* mei_cl_notify_fop2req - convert fop to proper request
*
Expand Down Expand Up @@ -1897,7 +1932,7 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
break;

case MEI_FOP_READ:
list_add_tail(&cb->list, &cl->rd_completed);
mei_cl_add_rd_completed(cl, cb);
if (!mei_cl_is_fixed_address(cl) &&
!WARN_ON(!cl->rx_flow_ctrl_creds))
cl->rx_flow_ctrl_creds--;
Expand Down
7 changes: 5 additions & 2 deletions drivers/misc/mei/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,11 @@ int mei_cl_unlink(struct mei_cl *cl);

struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev);

struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl,
const struct file *fp);
struct mei_cl_cb *mei_cl_read_cb(struct mei_cl *cl, const struct file *fp);

void mei_cl_add_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb);
void mei_cl_del_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb);

struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
enum mei_cb_file_ops type,
const struct file *fp);
Expand Down
6 changes: 3 additions & 3 deletions drivers/misc/mei/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,

mutex_unlock(&dev->device_lock);
if (wait_event_interruptible(cl->rx_wait,
!list_empty(&cl->rd_completed) ||
mei_cl_read_cb(cl, file) ||
!mei_cl_is_connected(cl))) {
if (signal_pending(current))
return -EINTR;
Expand Down Expand Up @@ -229,7 +229,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
goto out;

free:
mei_io_cb_free(cb);
mei_cl_del_rd_completed(cl, cb);
*offset = 0;

out:
Expand Down Expand Up @@ -572,7 +572,7 @@ static __poll_t mei_poll(struct file *file, poll_table *wait)
if (req_events & (EPOLLIN | EPOLLRDNORM)) {
poll_wait(file, &cl->rx_wait, wait);

if (!list_empty(&cl->rd_completed))
if (mei_cl_read_cb(cl, file))
mask |= EPOLLIN | EPOLLRDNORM;
else
mei_cl_read_start(cl, mei_cl_mtu(cl), file);
Expand Down
2 changes: 2 additions & 0 deletions drivers/misc/mei/mei_dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ struct mei_cl_cb {
* @tx_cb_queued: number of tx callbacks in queue
* @writing_state: state of the tx
* @rd_pending: pending read credits
* @rd_completed_lock: protects rd_completed queue
* @rd_completed: completed read
*
* @cldev: device on the mei client bus
Expand All @@ -242,6 +243,7 @@ struct mei_cl {
u8 tx_cb_queued;
enum mei_file_transaction_states writing_state;
struct list_head rd_pending;
spinlock_t rd_completed_lock; /* protects rd_completed queue */
struct list_head rd_completed;

struct mei_cl_device *cldev;
Expand Down

0 comments on commit d1376f3

Please sign in to comment.