Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 54c49cee authored by Arun Kumar Neelakantam's avatar Arun Kumar Neelakantam
Browse files

soc: qcom: glink_pkt: Use spinlock to protect Rx data packet list



The current implementation is using mutex lock to protect the Rx data
packet list but Glink core can notify the Rx data in atomic context
and the mutex lock is not used in some places.

Replace the mutex lock with spinlock to protect the Rx data packet list.

CRs-Fixed: 852949
Change-Id: Ie7543a98e6589e8068b873a8bb4f49b9a195d881
Signed-off-by: default avatarArun Kumar Neelakantam <aneela@codeaurora.org>
parent 5bfe3af8
Loading
Loading
Loading
Loading
+31 −12
Original line number Diff line number Diff line
@@ -120,7 +120,7 @@ struct glink_pkt_dev {
	wait_queue_head_t ch_opened_wait_queue;
	wait_queue_head_t ch_closed_wait_queue;
	struct list_head pkt_list;
	struct mutex pkt_list_lock;
	spinlock_t pkt_list_lock;

	struct wakeup_source pa_ws;	/* Packet Arrival Wakeup Source */
	struct work_struct packet_arrival_work;
@@ -194,6 +194,7 @@ module_param_named(debug_mask, msm_glink_pkt_debug_mask,

static void glink_pkt_queue_rx_intent_worker(struct work_struct *work);
static void glink_pkt_notify_state_worker(struct work_struct *work);
static bool glink_pkt_read_avail(struct glink_pkt_dev *devp);

#define DEBUG

@@ -324,7 +325,7 @@ void glink_pkt_notify_rx(void *handle, const void *priv,
	GLINK_PKT_INFO("%s(): priv[%p] data[%p] size[%zu]\n",
		   __func__, pkt_priv, (char *)ptr, size);

	pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
	pkt = kzalloc(sizeof(*pkt), GFP_ATOMIC);
	if (!pkt) {
		GLINK_PKT_ERR("%s: memory allocation failed\n", __func__);
		return;
@@ -333,9 +334,9 @@ void glink_pkt_notify_rx(void *handle, const void *priv,
	pkt->data = ptr;
	pkt->pkt_priv = pkt_priv;
	pkt->size = size;
	mutex_lock(&devp->pkt_list_lock);
	spin_lock_irqsave(&devp->pkt_list_lock, flags);
	list_add_tail(&pkt->list, &devp->pkt_list);
	mutex_unlock(&devp->pkt_list_lock);
	spin_unlock_irqrestore(&devp->pkt_list_lock, flags);

	spin_lock_irqsave(&devp->pa_spinlock, flags);
	__pm_stay_awake(&devp->pa_ws);
@@ -526,6 +527,24 @@ static void glink_pkt_notify_state_worker(struct work_struct *work)
	kfree(work_item);
}

/**
 * glink_pkt_read_avail() - check any pending packets to read
 * devp:	pointer to G-Link packet device.
 *
 * This function is used to check any pending data packets are
 * available to read or not.
 */
static bool glink_pkt_read_avail(struct glink_pkt_dev *devp)
{
	bool list_is_empty;
	unsigned long flags;

	spin_lock_irqsave(&devp->pkt_list_lock, flags);
	list_is_empty = list_empty(&devp->pkt_list);
	spin_unlock_irqrestore(&devp->pkt_list_lock, flags);
	return !list_is_empty;
}

/**
 * glink_pkt_read() - read() syscall for the glink_pkt device
 * file:	Pointer to the file structure.
@@ -577,9 +596,8 @@ ssize_t glink_pkt_read(struct file *file,
		__func__, devp->i, count);

	ret = wait_event_interruptible(devp->ch_read_wait_queue,
				     !devp->handle ||
				     !list_empty(&devp->pkt_list) ||
				     devp->in_reset);
				     !devp->handle || devp->in_reset ||
				     glink_pkt_read_avail(devp));
	if (devp->in_reset) {
		GLINK_PKT_ERR("%s: notifying reset for glink_pkt_dev id:%d\n",
			__func__, devp->i);
@@ -600,15 +618,16 @@ ssize_t glink_pkt_read(struct file *file,
		return ret;
	}

	spin_lock_irqsave(&devp->pkt_list_lock, flags);
	pkt = list_first_entry(&devp->pkt_list, struct glink_rx_pkt, list);

	if (pkt->size > count) {
		GLINK_PKT_ERR("%s: Small Buff on dev Id:%d-[%zu > %zu]\n",
				__func__, devp->i, pkt->size, count);
		spin_unlock_irqrestore(&devp->pkt_list_lock, flags);
		return -ETOOSMALL;
	}

	list_del(&pkt->list);
	spin_unlock_irqrestore(&devp->pkt_list_lock, flags);

	ret = copy_to_user(buf, pkt->data, pkt->size);
	BUG_ON(ret != 0);
@@ -619,7 +638,7 @@ ssize_t glink_pkt_read(struct file *file,

	mutex_lock(&devp->ch_lock);
	spin_lock_irqsave(&devp->pa_spinlock, flags);
	if (devp->poll_mode && list_empty(&devp->pkt_list)) {
	if (devp->poll_mode && !glink_pkt_read_avail(devp)) {
		__pm_relax(&devp->pa_ws);
		devp->ws_locked = 0;
		devp->poll_mode = 0;
@@ -731,7 +750,7 @@ static unsigned int glink_pkt_poll(struct file *file, poll_table *wait)
		return POLLHUP;
	}

	if (!list_empty(&devp->pkt_list)) {
	if (glink_pkt_read_avail(devp)) {
		mask |= POLLIN | POLLRDNORM;
		GLINK_PKT_INFO("%s sets POLLIN for glink_pkt_dev id: %d\n",
			__func__, devp->i);
@@ -1042,7 +1061,7 @@ static int glink_pkt_init_add_device(struct glink_pkt_dev *devp, int i)
	init_waitqueue_head(&devp->ch_closed_wait_queue);
	spin_lock_init(&devp->pa_spinlock);
	INIT_LIST_HEAD(&devp->pkt_list);
	mutex_init(&devp->pkt_list_lock);
	spin_lock_init(&devp->pkt_list_lock);
	wakeup_source_init(&devp->pa_ws, devp->dev_name);
	INIT_WORK(&devp->packet_arrival_work, packet_arrival_worker);