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: Arun Kumar Neelakantam <aneela@codeaurora.org> Signed-off-by: Dhoat Harpal <hdhoat@codeaurora.org>
This commit is contained in:
parent
cb5b5db1cf
commit
00515286cf
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2014-2015, 2017 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -117,7 +117,7 @@ struct glink_pkt_dev {
|
|||
wait_queue_head_t ch_read_wait_queue;
|
||||
wait_queue_head_t ch_opened_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;
|
||||
|
@ -177,7 +177,7 @@ module_param_named(debug_mask, msm_glink_pkt_debug_mask,
|
|||
int, S_IRUGO | S_IWUSR | S_IWGRP);
|
||||
|
||||
static void glink_pkt_queue_rx_intent_worker(struct work_struct *work);
|
||||
|
||||
static bool glink_pkt_read_avail(struct glink_pkt_dev *devp);
|
||||
|
||||
#define DEBUG
|
||||
|
||||
|
@ -308,7 +308,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(struct glink_rx_pkt), GFP_KERNEL);
|
||||
pkt = kzalloc(sizeof(*pkt), GFP_ATOMIC);
|
||||
if (!pkt) {
|
||||
GLINK_PKT_ERR("%s: memory allocation failed\n", __func__);
|
||||
return;
|
||||
|
@ -317,9 +317,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);
|
||||
|
@ -456,6 +456,24 @@ static void glink_pkt_queue_rx_intent_worker(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -507,9 +525,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);
|
||||
|
@ -530,15 +547,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);
|
||||
|
@ -549,7 +567,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;
|
||||
|
@ -661,7 +679,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);
|
||||
|
@ -933,7 +951,7 @@ static int glink_pkt_init_add_device(struct glink_pkt_dev *devp, int i)
|
|||
init_waitqueue_head(&devp->ch_opened_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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue