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

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.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 74a9c967
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -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)
@@ -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;
@@ -198,7 +198,7 @@ copy:
	rets = r_length;

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

+41 −6
Original line number Diff line number Diff line
@@ -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;
}

/**
@@ -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;
}
@@ -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);
@@ -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
 *
@@ -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--;
+5 −2
Original line number Diff line number Diff line
@@ -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);
+3 −3
Original line number Diff line number Diff line
@@ -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;
@@ -229,7 +229,7 @@ copy_buffer:
		goto out;

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

out:
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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
@@ -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;