platform: msm: qcom-geni-se: Fix the race condition during bus voting
When two bus votes are added, one of them is executed while the second one
performs nothing. But the thread that does the second vote continues and
accesses the yet-to-be-clocked registers while the thread that does the
first vote is working on the votes to be executed. This leads to unclocked
register access.
Replace the spin_lock that protects the bus voting logic with a mutex and
protect the entire bus voting logic with that lock.
CRs-Fixed: 2093107
Change-Id: I1852566891d507f5599c4227ff7655e2bfc84598
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c
index c1e77aa..2a733cb 100644
--- a/drivers/platform/msm/qcom-geni-se.c
+++ b/drivers/platform/msm/qcom-geni-se.c
@@ -66,7 +66,7 @@
struct msm_bus_client_handle *bus_bw;
u32 bus_mas_id;
u32 bus_slv_id;
- spinlock_t ab_ib_lock;
+ struct mutex ab_ib_lock;
struct list_head ab_list_head;
struct list_head ib_list_head;
unsigned long cur_ab;
@@ -597,7 +597,6 @@
static int geni_se_rmv_ab_ib(struct geni_se_device *geni_se_dev,
struct se_geni_rsc *rsc)
{
- unsigned long flags;
struct se_geni_rsc *tmp;
bool bus_bw_update = false;
int ret = 0;
@@ -605,7 +604,7 @@
if (unlikely(list_empty(&rsc->ab_list) || list_empty(&rsc->ib_list)))
return -EINVAL;
- spin_lock_irqsave(&geni_se_dev->ab_ib_lock, flags);
+ mutex_lock(&geni_se_dev->ab_ib_lock);
list_del_init(&rsc->ab_list);
geni_se_dev->cur_ab -= rsc->ab;
@@ -618,8 +617,6 @@
geni_se_dev->cur_ib = 0;
bus_bw_update = geni_se_check_bus_bw(geni_se_dev);
- spin_unlock_irqrestore(&geni_se_dev->ab_ib_lock, flags);
-
if (bus_bw_update)
ret = msm_bus_scale_update_bw(geni_se_dev->bus_bw,
geni_se_dev->cur_ab,
@@ -628,6 +625,7 @@
"%s: %lu:%lu (%lu:%lu) %d\n", __func__,
geni_se_dev->cur_ab, geni_se_dev->cur_ib,
rsc->ab, rsc->ib, bus_bw_update);
+ mutex_unlock(&geni_se_dev->ab_ib_lock);
return ret;
}
@@ -690,13 +688,12 @@
static int geni_se_add_ab_ib(struct geni_se_device *geni_se_dev,
struct se_geni_rsc *rsc)
{
- unsigned long flags;
struct se_geni_rsc *tmp = NULL;
struct list_head *ins_list_head;
bool bus_bw_update = false;
int ret = 0;
- spin_lock_irqsave(&geni_se_dev->ab_ib_lock, flags);
+ mutex_lock(&geni_se_dev->ab_ib_lock);
list_add(&rsc->ab_list, &geni_se_dev->ab_list_head);
geni_se_dev->cur_ab += rsc->ab;
@@ -712,8 +709,6 @@
geni_se_dev->cur_ib = rsc->ib;
bus_bw_update = geni_se_check_bus_bw(geni_se_dev);
- spin_unlock_irqrestore(&geni_se_dev->ab_ib_lock, flags);
-
if (bus_bw_update)
ret = msm_bus_scale_update_bw(geni_se_dev->bus_bw,
geni_se_dev->cur_ab,
@@ -722,6 +717,7 @@
"%s: %lu:%lu (%lu:%lu) %d\n", __func__,
geni_se_dev->cur_ab, geni_se_dev->cur_ib,
rsc->ab, rsc->ib, bus_bw_update);
+ mutex_unlock(&geni_se_dev->ab_ib_lock);
return ret;
}
@@ -1319,7 +1315,7 @@
mutex_init(&geni_se_dev->iommu_lock);
INIT_LIST_HEAD(&geni_se_dev->ab_list_head);
INIT_LIST_HEAD(&geni_se_dev->ib_list_head);
- spin_lock_init(&geni_se_dev->ab_ib_lock);
+ mutex_init(&geni_se_dev->ab_ib_lock);
geni_se_dev->log_ctx = ipc_log_context_create(NUM_LOG_PAGES,
dev_name(geni_se_dev->dev), 0);
if (!geni_se_dev->log_ctx)