video: tegra: host: Clear intr list at intr_put
Terje Bergstrom [Wed, 22 Aug 2012 12:03:07 +0000 (15:03 +0300)]
Process wait list when removing a waiter. This clears the interrupt
once it is no longer needed.

Bug 1031724

Change-Id: Ifb46672f70c8bbd6359d0a8aeaac0d718a5394b2
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/125230
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Juha Tukkinen <jtukkinen@nvidia.com>

drivers/video/tegra/host/chip_support.h
drivers/video/tegra/host/host1x/host1x_channel.c
drivers/video/tegra/host/host1x/host1x_intr.c
drivers/video/tegra/host/nvhost_intr.c
drivers/video/tegra/host/nvhost_intr.h
drivers/video/tegra/host/nvhost_syncpt.c

index f5d2811..412ce8b 100644 (file)
@@ -125,6 +125,7 @@ struct nvhost_intr_ops {
        void (*set_syncpt_threshold)(
                struct nvhost_intr *, u32 id, u32 thresh);
        void (*enable_syncpt_intr)(struct nvhost_intr *, u32 id);
+       void (*disable_syncpt_intr)(struct nvhost_intr *, u32 id);
        void (*disable_all_syncpt_intrs)(struct nvhost_intr *);
        int  (*request_host_general_irq)(struct nvhost_intr *);
        void (*free_host_general_irq)(struct nvhost_intr *);
index 3c07460..0274413 100644 (file)
@@ -470,7 +470,8 @@ static int host1x_channel_read_3d_reg(
        wait_event(wq,
                nvhost_syncpt_is_expired(&nvhost_get_host(channel->dev)->syncpt,
                                p->syncpt, syncval - 2));
-       nvhost_intr_put_ref(&nvhost_get_host(channel->dev)->intr, ref);
+       nvhost_intr_put_ref(&nvhost_get_host(channel->dev)->intr, p->syncpt,
+                       ref);
 
        /* Read the register value from FIFO */
        err = host1x_drain_read_fifo(channel, value, 1, &pending);
@@ -622,7 +623,7 @@ static int host1x_save_context(struct nvhost_channel *ch)
                nvhost_syncpt_is_expired(&nvhost_get_host(ch->dev)->syncpt,
                                syncpt_id, syncpt_val));
 
-       nvhost_intr_put_ref(&nvhost_get_host(ch->dev)->intr, ref);
+       nvhost_intr_put_ref(&nvhost_get_host(ch->dev)->intr, syncpt_id, ref);
 
        nvhost_cdma_update(&ch->cdma);
 
index 2afbcbf..facb818 100644 (file)
@@ -131,6 +131,16 @@ static void t20_intr_enable_syncpt_intr(struct nvhost_intr *intr, u32 id)
                        BIT_WORD(id) * REGISTER_STRIDE);
 }
 
+static void t20_intr_disable_syncpt_intr(struct nvhost_intr *intr, u32 id)
+{
+       struct nvhost_master *dev = intr_to_dev(intr);
+       void __iomem *sync_regs = dev->sync_aperture;
+
+       writel(BIT_MASK(id), sync_regs +
+                       host1x_sync_syncpt_thresh_int_disable_r() +
+                       BIT_WORD(id) * REGISTER_STRIDE);
+}
+
 static void t20_intr_disable_all_syncpt_intrs(struct nvhost_intr *intr)
 {
        struct nvhost_master *dev = intr_to_dev(intr);
@@ -276,6 +286,7 @@ static const struct nvhost_intr_ops host1x_intr_ops = {
        .set_host_clocks_per_usec = t20_intr_set_host_clocks_per_usec,
        .set_syncpt_threshold = t20_intr_set_syncpt_threshold,
        .enable_syncpt_intr = t20_intr_enable_syncpt_intr,
+       .disable_syncpt_intr = t20_intr_disable_syncpt_intr,
        .disable_all_syncpt_intrs = t20_intr_disable_all_syncpt_intrs,
        .request_host_general_irq = t20_intr_request_host_general_irq,
        .free_host_general_irq = t20_intr_free_host_general_irq,
index 38a04f1..9788d32 100644 (file)
@@ -210,7 +210,9 @@ static int process_wait_list(struct nvhost_intr *intr,
        remove_completed_waiters(&syncpt->wait_head, threshold, completed);
 
        empty = list_empty(&syncpt->wait_head);
-       if (!empty)
+       if (empty)
+               intr_op().disable_syncpt_intr(intr, syncpt->id);
+       else
                reset_threshold_interrupt(intr, &syncpt->wait_head,
                                          syncpt->id);
 
@@ -327,14 +329,20 @@ void *nvhost_intr_alloc_waiter()
                        GFP_KERNEL|__GFP_REPEAT);
 }
 
-void nvhost_intr_put_ref(struct nvhost_intr *intr, void *ref)
+void nvhost_intr_put_ref(struct nvhost_intr *intr, u32 id, void *ref)
 {
        struct nvhost_waitlist *waiter = ref;
+       struct nvhost_intr_syncpt *syncpt;
+       struct nvhost_master *host = intr_to_dev(intr);
 
        while (atomic_cmpxchg(&waiter->state,
                                WLS_PENDING, WLS_CANCELLED) == WLS_REMOVED)
                schedule();
 
+       syncpt = intr->syncpt + id;
+       (void)process_wait_list(intr, syncpt,
+                               nvhost_syncpt_update_min(&host->syncpt, id));
+
        kref_put(&waiter->refcount, waiter_release);
 }
 
index cf0b6b9..d4a6157 100644 (file)
@@ -104,7 +104,7 @@ void *nvhost_intr_alloc_waiter(void);
  * You must call this if you passed non-NULL as ref.
  * @ref the ref returned from nvhost_intr_add_action()
  */
-void nvhost_intr_put_ref(struct nvhost_intr *intr, void *ref);
+void nvhost_intr_put_ref(struct nvhost_intr *intr, u32 id, void *ref);
 
 int nvhost_intr_init(struct nvhost_intr *intr, u32 irq_gen, u32 irq_sync);
 void nvhost_intr_deinit(struct nvhost_intr *intr);
index 9fa7d06..d30028b 100644 (file)
@@ -235,7 +235,7 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
                        check_count++;
                }
        }
-       nvhost_intr_put_ref(&(syncpt_to_dev(sp)->intr), ref);
+       nvhost_intr_put_ref(&(syncpt_to_dev(sp)->intr), id, ref);
 
 done:
        nvhost_module_idle(syncpt_to_dev(sp)->dev);