video: tegra: host: gk20a: fix pmu sequencing
Eric Eells [Tue, 18 Feb 2014 23:32:30 +0000 (15:32 -0800)]
Currently the access to pmu->pmu_seq_tbl is not
synchronized resulting in possble multiple uses
of the same sequence.

Bug 1458524

Change-Id: I50acf3a7c0988a11131e903e7b93cea478dc69a8
Reviewed-on: http://git-master/r/367488
(cherry picked from commit cb2c2c2e1c8da73dd062b195104077246347302d)
Signed-off-by: Eric Eells <eeells@nvidia.com>
Reviewed-on: http://git-master/r/370078
Reviewed-by: Naveen Kumar S <nkumars@nvidia.com>
Reviewed-by: Bryan Wu <pengw@nvidia.com>
Tested-by: Bryan Wu <pengw@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Winnie Hsu <whsu@nvidia.com>

drivers/video/tegra/host/gk20a/pmu_gk20a.c
drivers/video/tegra/host/gk20a/pmu_gk20a.h

index 9ad1abd..96b1989 100644 (file)
@@ -417,14 +417,17 @@ static int pmu_seq_acquire(struct pmu_gk20a *pmu,
        struct pmu_sequence *seq;
        u32 index;
 
+       mutex_lock(&pmu->pmu_seq_lock);
        index = find_first_zero_bit(pmu->pmu_seq_tbl,
                                sizeof(pmu->pmu_seq_tbl));
        if (index >= sizeof(pmu->pmu_seq_tbl)) {
                nvhost_err(dev_from_gk20a(g),
                        "no free sequence available");
+               mutex_unlock(&pmu->pmu_seq_lock);
                return -EAGAIN;
        }
        set_bit(index, pmu->pmu_seq_tbl);
+       mutex_unlock(&pmu->pmu_seq_lock);
 
        seq = &pmu->seq[index];
        seq->state = PMU_SEQ_STATE_PENDING;
@@ -1123,6 +1126,7 @@ skip_init:
        mutex_init(&pmu->elpg_mutex);
        mutex_init(&pmu->isr_mutex);
        mutex_init(&pmu->pmu_copy_lock);
+       mutex_init(&pmu->pmu_seq_lock);
        mutex_init(&pmu->pg_init_mutex);
 
        pmu->perfmon_counter.index = 3; /* GR & CE2 */
@@ -2539,7 +2543,7 @@ static int gk20a_pmu_enable_elpg_locked(struct gk20a *g)
 {
        struct pmu_gk20a *pmu = &g->pmu;
        struct pmu_cmd cmd;
-       u32 seq;
+       u32 seq, status;
 
        nvhost_dbg_fn("");
 
@@ -2554,9 +2558,11 @@ static int gk20a_pmu_enable_elpg_locked(struct gk20a *g)
           with follow up ELPG disable */
        pmu->elpg_stat = PMU_ELPG_STAT_ON_PENDING;
 
-       gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
+       status = gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
                        pmu_handle_pg_elpg_msg, pmu, &seq, ~0);
 
+       BUG_ON(status != 0);
+
        nvhost_dbg_fn("done");
        return 0;
 }
@@ -2674,7 +2680,8 @@ static int gk20a_pmu_disable_elpg_defer_enable(struct gk20a *g, bool enable)
 
                if (pmu->elpg_stat != PMU_ELPG_STAT_ON) {
                        nvhost_err(dev_from_gk20a(g),
-                               "ELPG_ALLOW_ACK failed");
+                               "ELPG_ALLOW_ACK failed, elpg_stat=%d",
+                               pmu->elpg_stat);
                        pmu_dump_elpg_stats(pmu);
                        pmu_dump_falcon_stats(pmu);
                        ret = -EBUSY;
index 29bf381..cecbc8a 100644 (file)
@@ -677,6 +677,7 @@ struct pmu_gk20a {
        u32 mutex_cnt;
 
        struct mutex pmu_copy_lock;
+       struct mutex pmu_seq_lock;
 
        struct nvhost_allocator dmem;