From 255b6f0b8936112beed3dcd403b2a57a163aa215 Mon Sep 17 00:00:00 2001 From: Terje Bergstrom Date: Wed, 22 Aug 2012 15:03:07 +0300 Subject: video: tegra: host: Clear intr list at intr_put 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 Reviewed-on: http://git-master/r/125230 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Juha Tukkinen --- drivers/video/tegra/host/chip_support.h | 1 + drivers/video/tegra/host/host1x/host1x_channel.c | 5 +++-- drivers/video/tegra/host/host1x/host1x_intr.c | 11 +++++++++++ drivers/video/tegra/host/nvhost_intr.c | 12 ++++++++++-- drivers/video/tegra/host/nvhost_intr.h | 2 +- drivers/video/tegra/host/nvhost_syncpt.c | 2 +- 6 files changed, 27 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/video/tegra/host/chip_support.h b/drivers/video/tegra/host/chip_support.h index f5d2811f143f..412ce8b65466 100644 --- a/drivers/video/tegra/host/chip_support.h +++ b/drivers/video/tegra/host/chip_support.h @@ -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 *); diff --git a/drivers/video/tegra/host/host1x/host1x_channel.c b/drivers/video/tegra/host/host1x/host1x_channel.c index 3c074604b675..0274413ff698 100644 --- a/drivers/video/tegra/host/host1x/host1x_channel.c +++ b/drivers/video/tegra/host/host1x/host1x_channel.c @@ -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); diff --git a/drivers/video/tegra/host/host1x/host1x_intr.c b/drivers/video/tegra/host/host1x/host1x_intr.c index 2afbcbfa6393..facb818a0c24 100644 --- a/drivers/video/tegra/host/host1x/host1x_intr.c +++ b/drivers/video/tegra/host/host1x/host1x_intr.c @@ -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, diff --git a/drivers/video/tegra/host/nvhost_intr.c b/drivers/video/tegra/host/nvhost_intr.c index 38a04f151e87..9788d32bd4a9 100644 --- a/drivers/video/tegra/host/nvhost_intr.c +++ b/drivers/video/tegra/host/nvhost_intr.c @@ -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); } diff --git a/drivers/video/tegra/host/nvhost_intr.h b/drivers/video/tegra/host/nvhost_intr.h index cf0b6b9e8934..d4a6157eced1 100644 --- a/drivers/video/tegra/host/nvhost_intr.h +++ b/drivers/video/tegra/host/nvhost_intr.h @@ -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); diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c index 9fa7d0652c1f..d30028b0c7a4 100644 --- a/drivers/video/tegra/host/nvhost_syncpt.c +++ b/drivers/video/tegra/host/nvhost_syncpt.c @@ -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); -- cgit v1.2.3