Commit d1376f3d authored by Alexander Usyskin's avatar Alexander Usyskin Committed by Greg Kroah-Hartman

mei: add a spin lock to protect rd_completed queue

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: default avatarAlexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Link: https://lore.kernel.org/r/20200818115147.2567012-7-tomas.winkler@intel.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 74a9c967
...@@ -152,7 +152,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length, ...@@ -152,7 +152,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length,
if (timeout) { if (timeout) {
rets = wait_event_interruptible_timeout rets = wait_event_interruptible_timeout
(cl->rx_wait, (cl->rx_wait,
(!list_empty(&cl->rd_completed)) || mei_cl_read_cb(cl, NULL) ||
(!mei_cl_is_connected(cl)), (!mei_cl_is_connected(cl)),
msecs_to_jiffies(timeout)); msecs_to_jiffies(timeout));
if (rets == 0) if (rets == 0)
...@@ -165,7 +165,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length, ...@@ -165,7 +165,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length,
} else { } else {
if (wait_event_interruptible if (wait_event_interruptible
(cl->rx_wait, (cl->rx_wait,
(!list_empty(&cl->rd_completed)) || mei_cl_read_cb(cl, NULL) ||
(!mei_cl_is_connected(cl)))) { (!mei_cl_is_connected(cl)))) {
if (signal_pending(current)) if (signal_pending(current))
return -EINTR; return -EINTR;
...@@ -198,7 +198,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length, ...@@ -198,7 +198,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length,
rets = r_length; rets = r_length;
free: free:
mei_io_cb_free(cb); mei_cl_del_rd_completed(cl, cb);
out: out:
mutex_unlock(&bus->device_lock); mutex_unlock(&bus->device_lock);
......
...@@ -507,15 +507,19 @@ struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length, ...@@ -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 * 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 *cb;
struct mei_cl_cb *ret_cb = NULL;
spin_lock(&cl->rd_completed_lock);
list_for_each_entry(cb, &cl->rd_completed, list) list_for_each_entry(cb, &cl->rd_completed, list)
if (!fp || fp == cb->fp) if (!fp || fp == cb->fp) {
return cb; ret_cb = cb;
break;
return NULL; }
spin_unlock(&cl->rd_completed_lock);
return ret_cb;
} }
/** /**
...@@ -541,7 +545,9 @@ int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp) ...@@ -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_wr_list, cl);
mei_io_list_flush_cl(&cl->dev->ctrl_rd_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_pending, fp);
spin_lock(&cl->rd_completed_lock);
mei_io_list_free_fp(&cl->rd_completed, fp); mei_io_list_free_fp(&cl->rd_completed, fp);
spin_unlock(&cl->rd_completed_lock);
return 0; return 0;
} }
...@@ -559,6 +565,7 @@ static void mei_cl_init(struct mei_cl *cl, struct mei_device *dev) ...@@ -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->rx_wait);
init_waitqueue_head(&cl->tx_wait); init_waitqueue_head(&cl->tx_wait);
init_waitqueue_head(&cl->ev_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_completed);
INIT_LIST_HEAD(&cl->rd_pending); INIT_LIST_HEAD(&cl->rd_pending);
INIT_LIST_HEAD(&cl->link); INIT_LIST_HEAD(&cl->link);
...@@ -1230,6 +1237,34 @@ static int mei_cl_tx_flow_ctrl_creds_reduce(struct mei_cl *cl) ...@@ -1230,6 +1237,34 @@ static int mei_cl_tx_flow_ctrl_creds_reduce(struct mei_cl *cl)
return 0; 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 * mei_cl_notify_fop2req - convert fop to proper request
* *
...@@ -1897,7 +1932,7 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb) ...@@ -1897,7 +1932,7 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
break; break;
case MEI_FOP_READ: 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) && if (!mei_cl_is_fixed_address(cl) &&
!WARN_ON(!cl->rx_flow_ctrl_creds)) !WARN_ON(!cl->rx_flow_ctrl_creds))
cl->rx_flow_ctrl_creds--; cl->rx_flow_ctrl_creds--;
......
...@@ -133,8 +133,11 @@ int mei_cl_unlink(struct mei_cl *cl); ...@@ -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 *mei_cl_alloc_linked(struct mei_device *dev);
struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, struct mei_cl_cb *mei_cl_read_cb(struct mei_cl *cl, const struct file *fp);
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, struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
enum mei_cb_file_ops type, enum mei_cb_file_ops type,
const struct file *fp); const struct file *fp);
......
...@@ -178,7 +178,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, ...@@ -178,7 +178,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
mutex_unlock(&dev->device_lock); mutex_unlock(&dev->device_lock);
if (wait_event_interruptible(cl->rx_wait, if (wait_event_interruptible(cl->rx_wait,
!list_empty(&cl->rd_completed) || mei_cl_read_cb(cl, file) ||
!mei_cl_is_connected(cl))) { !mei_cl_is_connected(cl))) {
if (signal_pending(current)) if (signal_pending(current))
return -EINTR; return -EINTR;
...@@ -229,7 +229,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, ...@@ -229,7 +229,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
goto out; goto out;
free: free:
mei_io_cb_free(cb); mei_cl_del_rd_completed(cl, cb);
*offset = 0; *offset = 0;
out: out:
...@@ -572,7 +572,7 @@ static __poll_t mei_poll(struct file *file, poll_table *wait) ...@@ -572,7 +572,7 @@ static __poll_t mei_poll(struct file *file, poll_table *wait)
if (req_events & (EPOLLIN | EPOLLRDNORM)) { if (req_events & (EPOLLIN | EPOLLRDNORM)) {
poll_wait(file, &cl->rx_wait, wait); poll_wait(file, &cl->rx_wait, wait);
if (!list_empty(&cl->rd_completed)) if (mei_cl_read_cb(cl, file))
mask |= EPOLLIN | EPOLLRDNORM; mask |= EPOLLIN | EPOLLRDNORM;
else else
mei_cl_read_start(cl, mei_cl_mtu(cl), file); mei_cl_read_start(cl, mei_cl_mtu(cl), file);
......
...@@ -217,6 +217,7 @@ struct mei_cl_cb { ...@@ -217,6 +217,7 @@ struct mei_cl_cb {
* @tx_cb_queued: number of tx callbacks in queue * @tx_cb_queued: number of tx callbacks in queue
* @writing_state: state of the tx * @writing_state: state of the tx
* @rd_pending: pending read credits * @rd_pending: pending read credits
* @rd_completed_lock: protects rd_completed queue
* @rd_completed: completed read * @rd_completed: completed read
* *
* @cldev: device on the mei client bus * @cldev: device on the mei client bus
...@@ -242,6 +243,7 @@ struct mei_cl { ...@@ -242,6 +243,7 @@ struct mei_cl {
u8 tx_cb_queued; u8 tx_cb_queued;
enum mei_file_transaction_states writing_state; enum mei_file_transaction_states writing_state;
struct list_head rd_pending; struct list_head rd_pending;
spinlock_t rd_completed_lock; /* protects rd_completed queue */
struct list_head rd_completed; struct list_head rd_completed;
struct mei_cl_device *cldev; struct mei_cl_device *cldev;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment