diff options
author | Terje Bergstrom <tbergstrom@nvidia.com> | 2013-12-02 11:05:54 +0200 |
---|---|---|
committer | Terje Bergstrom <tbergstrom@nvidia.com> | 2013-12-22 22:06:14 -0800 |
commit | cc7c41286f198fd220fad1bdb5391195136cb55e (patch) | |
tree | a2691546ad99a34c3368747f5213775abca96574 /drivers/video/tegra | |
parent | 90c045c1b135d2cf908a8384c8c68aeeb167075c (diff) |
video: tegra: host: Support non-stalling interrupt
Add support for non-stalling interrupt, and enable it. Also adds some
new interrupt debug prints for gr and fifo interrupts and handles FE
exception and device interrupt.
Change-Id: I32f876784c6f27e7db97a979f765645b9b67ca1b
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/337266
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'drivers/video/tegra')
-rw-r--r-- | drivers/video/tegra/host/gk20a/channel_gk20a.c | 14 | ||||
-rw-r--r-- | drivers/video/tegra/host/gk20a/channel_gk20a.h | 1 | ||||
-rw-r--r-- | drivers/video/tegra/host/gk20a/fifo_gk20a.c | 37 | ||||
-rw-r--r-- | drivers/video/tegra/host/gk20a/fifo_gk20a.h | 1 | ||||
-rw-r--r-- | drivers/video/tegra/host/gk20a/gk20a.c | 76 | ||||
-rw-r--r-- | drivers/video/tegra/host/gk20a/gr_gk20a.c | 18 | ||||
-rw-r--r-- | drivers/video/tegra/host/gk20a/gr_gk20a.h | 1 | ||||
-rw-r--r-- | drivers/video/tegra/host/gk20a/hw_gr_gk20a.h | 8 | ||||
-rw-r--r-- | drivers/video/tegra/host/gk20a/hw_mc_gk20a.h | 16 | ||||
-rw-r--r-- | drivers/video/tegra/host/gk20a/pmu_gk20a.c | 5 |
10 files changed, 152 insertions, 25 deletions
diff --git a/drivers/video/tegra/host/gk20a/channel_gk20a.c b/drivers/video/tegra/host/gk20a/channel_gk20a.c index 2c7761617b5d..e1543dfd804f 100644 --- a/drivers/video/tegra/host/gk20a/channel_gk20a.c +++ b/drivers/video/tegra/host/gk20a/channel_gk20a.c @@ -1978,3 +1978,17 @@ int gk20a_channel_resume(struct gk20a *g) nvhost_dbg_fn("done"); return 0; } + +void gk20a_channel_semaphore_wakeup(struct gk20a *g) +{ + struct fifo_gk20a *f = &g->fifo; + u32 chid; + + nvhost_dbg_fn(""); + + for (chid = 0; chid < f->num_channels; chid++) { + struct channel_gk20a *c = g->fifo.channel+chid; + if (c->in_use) + wake_up_interruptible_all(&c->semaphore_wq); + } +} diff --git a/drivers/video/tegra/host/gk20a/channel_gk20a.h b/drivers/video/tegra/host/gk20a/channel_gk20a.h index 933c00996cb4..40b04107e092 100644 --- a/drivers/video/tegra/host/gk20a/channel_gk20a.h +++ b/drivers/video/tegra/host/gk20a/channel_gk20a.h @@ -186,6 +186,7 @@ int gk20a_channel_finish(struct channel_gk20a *ch, unsigned long timeout); void gk20a_set_error_notifier(struct nvhost_hwctx *ctx, __u32 error); int gk20a_channel_wait(struct channel_gk20a *ch, struct nvhost_wait_args *args); +void gk20a_channel_semaphore_wakeup(struct gk20a *g); int gk20a_channel_zcull_bind(struct channel_gk20a *ch, struct nvhost_zcull_bind_args *args); int gk20a_channel_zbc_set_table(struct channel_gk20a *ch, diff --git a/drivers/video/tegra/host/gk20a/fifo_gk20a.c b/drivers/video/tegra/host/gk20a/fifo_gk20a.c index f09ff98b8431..8b88619bc462 100644 --- a/drivers/video/tegra/host/gk20a/fifo_gk20a.c +++ b/drivers/video/tegra/host/gk20a/fifo_gk20a.c @@ -393,8 +393,8 @@ int gk20a_init_fifo_reset_enable_hw(struct gk20a *g) /* enable pfifo interrupt */ gk20a_writel(g, fifo_intr_0_r(), 0xFFFFFFFF); - gk20a_writel(g, fifo_intr_en_0_r(), 0xFFFFFFFF); /* TBD: alternative intr tree*/ - gk20a_writel(g, fifo_intr_en_1_r(), 0xFFFFFFFF); /* TBD: alternative intr tree*/ + gk20a_writel(g, fifo_intr_en_0_r(), 0x7FFFFFFF); + gk20a_writel(g, fifo_intr_en_1_r(), 0x80000000); /* enable pbdma interrupt */ mask = 0; @@ -465,7 +465,6 @@ static void gk20a_init_fifo_pbdma_intr_descs(struct fifo_gk20a *f) pbdma_intr_0_pbcrc_pending_f() | pbdma_intr_0_method_pending_f() | pbdma_intr_0_methodcrc_pending_f() | - pbdma_intr_0_semaphore_pending_f() | pbdma_intr_0_pbseg_pending_f() | pbdma_intr_0_signature_pending_f(); @@ -1297,6 +1296,8 @@ static u32 gk20a_fifo_handle_pbdma_intr(struct device *dev, nvhost_dbg_fn(""); + nvhost_dbg(dbg_intr, "pbdma id intr pending %d %08x %08x", pbdma_id, + pbdma_intr_0, pbdma_intr_1); if (pbdma_intr_0) { if (f->intr.pbdma.device_fatal_0 & pbdma_intr_0) { dev_err(dev, "unrecoverable device error: " @@ -1331,14 +1332,7 @@ static u32 gk20a_fifo_handle_pbdma_intr(struct device *dev, static u32 fifo_channel_isr(struct gk20a *g, u32 fifo_intr) { - struct device *dev = dev_from_gk20a(g); - /* Note: we don't have any of these in use (yet) for gk20a. - * These are usually if not always coming from non-stall, - * notification type interrupts. It isn't necessarily - * anything to do with the channel currently running. - * Clear it and warn... - */ - dev_warn(dev, "unexpected channel (non-stall?) interrupt"); + gk20a_channel_semaphore_wakeup(g); return fifo_intr_0_channel_intr_pending_f(); } @@ -1352,7 +1346,7 @@ static u32 fifo_pbdma_isr(struct gk20a *g, u32 fifo_intr) for (i = 0; i < fifo_intr_pbdma_id_status__size_1_v(); i++) { if (fifo_intr_pbdma_id_status_f(pbdma_pending, i)) { - nvhost_dbg_fn("pbdma id %d intr pending", i); + nvhost_dbg(dbg_intr, "pbdma id %d intr pending", i); clear_intr |= gk20a_fifo_handle_pbdma_intr(dev, g, f, i); } @@ -1379,6 +1373,7 @@ void gk20a_fifo_isr(struct gk20a *g) * in a threaded interrupt context... */ mutex_lock(&g->fifo.intr.isr.mutex); + nvhost_dbg(dbg_intr, "fifo isr %08x\n", fifo_intr); /* handle runlist update */ if (fifo_intr & fifo_intr_0_runlist_event_pending_f()) { @@ -1388,9 +1383,6 @@ void gk20a_fifo_isr(struct gk20a *g) if (fifo_intr & fifo_intr_0_pbdma_intr_pending_f()) clear_intr |= fifo_pbdma_isr(g, fifo_intr); - if (fifo_intr & fifo_intr_0_channel_intr_pending_f()) - clear_intr |= fifo_channel_isr(g, fifo_intr); - if (unlikely(fifo_intr & error_intr_mask)) clear_intr = fifo_error_isr(g, fifo_intr); @@ -1401,6 +1393,21 @@ void gk20a_fifo_isr(struct gk20a *g) return; } +void gk20a_fifo_nonstall_isr(struct gk20a *g) +{ + u32 fifo_intr = gk20a_readl(g, fifo_intr_0_r()); + u32 clear_intr = 0; + + nvhost_dbg(dbg_intr, "fifo nonstall isr %08x\n", fifo_intr); + + if (fifo_intr & fifo_intr_0_channel_intr_pending_f()) + clear_intr |= fifo_channel_isr(g, fifo_intr); + + gk20a_writel(g, fifo_intr_0_r(), clear_intr); + + return; +} + int gk20a_fifo_preempt_channel(struct gk20a *g, u32 hw_chid) { struct fifo_gk20a *f = &g->fifo; diff --git a/drivers/video/tegra/host/gk20a/fifo_gk20a.h b/drivers/video/tegra/host/gk20a/fifo_gk20a.h index 43dca120e126..71f9d5226889 100644 --- a/drivers/video/tegra/host/gk20a/fifo_gk20a.h +++ b/drivers/video/tegra/host/gk20a/fifo_gk20a.h @@ -140,6 +140,7 @@ struct fifo_gk20a { int gk20a_init_fifo_support(struct gk20a *g); void gk20a_fifo_isr(struct gk20a *g); +void gk20a_fifo_nonstall_isr(struct gk20a *g); int gk20a_fifo_preempt_channel(struct gk20a *g, u32 hw_chid); diff --git a/drivers/video/tegra/host/gk20a/gk20a.c b/drivers/video/tegra/host/gk20a/gk20a.c index 8c045f6ff5fd..6dcb0d43cd1f 100644 --- a/drivers/video/tegra/host/gk20a/gk20a.c +++ b/drivers/video/tegra/host/gk20a/gk20a.c @@ -446,7 +446,7 @@ int gk20a_sim_esc_read(struct gk20a *g, char *path, u32 index, u32 count, u32 *d return err; } -static irqreturn_t gk20a_intr_isr(int irq, void *dev_id) +static irqreturn_t gk20a_intr_isr_stall(int irq, void *dev_id) { struct gk20a *g = dev_id; u32 mc_intr_0; @@ -468,6 +468,28 @@ static irqreturn_t gk20a_intr_isr(int irq, void *dev_id) return IRQ_WAKE_THREAD; } +static irqreturn_t gk20a_intr_isr_nonstall(int irq, void *dev_id) +{ + struct gk20a *g = dev_id; + u32 mc_intr_1; + + if (!g->power_on) + return IRQ_NONE; + + /* not from gpu when sharing irq with others */ + mc_intr_1 = gk20a_readl(g, mc_intr_1_r()); + if (unlikely(!mc_intr_1)) + return IRQ_NONE; + + gk20a_writel(g, mc_intr_en_1_r(), + mc_intr_en_1_inta_disabled_f()); + + /* flush previous write */ + gk20a_readl(g, mc_intr_en_1_r()); + + return IRQ_WAKE_THREAD; +} + static void gk20a_pbus_isr(struct gk20a *g) { u32 val; @@ -496,7 +518,7 @@ static void gk20a_pbus_isr(struct gk20a *g) gk20a_writel(g, bus_intr_0_r(), val); } -static irqreturn_t gk20a_intr_thread(int irq, void *dev_id) +static irqreturn_t gk20a_intr_thread_stall(int irq, void *dev_id) { struct gk20a *g = dev_id; u32 mc_intr_0; @@ -505,6 +527,8 @@ static irqreturn_t gk20a_intr_thread(int irq, void *dev_id) mc_intr_0 = gk20a_readl(g, mc_intr_0_r()); + nvhost_dbg(dbg_intr, "stall intr %08x\n", mc_intr_0); + if (mc_intr_0 & mc_intr_0_pgraph_pending_f()) gr_gk20a_elpg_protected_call(g, gk20a_gr_isr(g)); if (mc_intr_0 & mc_intr_0_pfifo_pending_f()) @@ -517,9 +541,6 @@ static irqreturn_t gk20a_intr_thread(int irq, void *dev_id) gk20a_mm_ltc_isr(g); if (mc_intr_0 & mc_intr_0_pbus_pending_f()) gk20a_pbus_isr(g); - if (mc_intr_0) - nvhost_dbg_info("leaving isr with interrupt pending 0x%08x", - mc_intr_0); gk20a_writel(g, mc_intr_en_0_r(), mc_intr_en_0_inta_hardware_f()); @@ -530,6 +551,31 @@ static irqreturn_t gk20a_intr_thread(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t gk20a_intr_thread_nonstall(int irq, void *dev_id) +{ + struct gk20a *g = dev_id; + u32 mc_intr_1; + + nvhost_dbg(dbg_intr, "interrupt thread launched"); + + mc_intr_1 = gk20a_readl(g, mc_intr_1_r()); + + nvhost_dbg(dbg_intr, "non-stall intr %08x\n", mc_intr_1); + + if (mc_intr_1 & mc_intr_0_pfifo_pending_f()) + gk20a_fifo_nonstall_isr(g); + if (mc_intr_1 & mc_intr_0_pgraph_pending_f()) + gk20a_gr_nonstall_isr(g); + + gk20a_writel(g, mc_intr_en_1_r(), + mc_intr_en_1_inta_hardware_f()); + + /* flush previous write */ + gk20a_readl(g, mc_intr_en_1_r()); + + return IRQ_HANDLED; +} + static void gk20a_remove_support(struct platform_device *dev) { struct gk20a *g = get_gk20a(dev); @@ -555,6 +601,7 @@ static void gk20a_remove_support(struct platform_device *dev) if (g->irq_requested) { free_irq(gk20a_intr.start, g); + free_irq(gk20a_intr.start+1, g); g->irq_requested = false; } @@ -729,6 +776,7 @@ int nvhost_gk20a_prepare_poweroff(struct platform_device *dev) */ if (g->irq_requested) { free_irq(gk20a_intr.start, g); + free_irq(gk20a_intr.start+1, g); g->irq_requested = false; } @@ -754,26 +802,36 @@ int nvhost_gk20a_finalize_poweron(struct platform_device *dev) if (!g->irq_requested) { err = request_threaded_irq(gk20a_intr.start, - gk20a_intr_isr, gk20a_intr_thread, - 0, "gk20a", g); + gk20a_intr_isr_stall, + gk20a_intr_thread_stall, + 0, "gk20a_stall", g); if (err) { dev_err(dev_from_gk20a(g), "failed to request stall intr irq @ %lld\n", (u64)gk20a_intr.start); goto done; } + err = request_threaded_irq(gk20a_intr.start+1, + gk20a_intr_isr_nonstall, + gk20a_intr_thread_nonstall, + 0, "gk20a_nonstall", g); + if (err) { + dev_err(dev_from_gk20a(g), + "failed to request non-stall intr irq @ %lld\n", + (u64)gk20a_intr.start+1); + goto done; + } g->irq_requested = true; } g->power_on = true; gk20a_writel(g, mc_intr_en_1_r(), - mc_intr_en_1_inta_disabled_f()); + mc_intr_en_1_inta_hardware_f()); gk20a_writel(g, mc_intr_en_0_r(), mc_intr_en_0_inta_hardware_f()); - gk20a_writel(g, bus_intr_en_0_r(), bus_intr_en_0_pri_squash_m() | bus_intr_en_0_pri_fecserr_m() | diff --git a/drivers/video/tegra/host/gk20a/gr_gk20a.c b/drivers/video/tegra/host/gk20a/gr_gk20a.c index b182291f25ca..5a5c80612f75 100644 --- a/drivers/video/tegra/host/gk20a/gr_gk20a.c +++ b/drivers/video/tegra/host/gk20a/gr_gk20a.c @@ -5145,6 +5145,7 @@ int gk20a_gr_isr(struct gk20a *g) u32 gr_intr = gk20a_readl(g, gr_intr_r()); nvhost_dbg_fn(""); + nvhost_dbg(dbg_intr, "pgraph intr %08x", gr_intr); if (!gr_intr) return 0; @@ -5295,6 +5296,23 @@ clean_up: return 0; } +int gk20a_gr_nonstall_isr(struct gk20a *g) +{ + u32 gr_intr = gk20a_readl(g, gr_intr_nonstall_r()); + u32 clear_intr = 0; + + nvhost_dbg(dbg_intr, "pgraph nonstall intr %08x", gr_intr); + + if (gr_intr & gr_intr_nonstall_trap_pending_f()) { + gk20a_channel_semaphore_wakeup(g); + clear_intr |= gr_intr_nonstall_trap_pending_f(); + } + + gk20a_writel(g, gr_intr_nonstall_r(), clear_intr); + + return 0; +} + int gr_gk20a_fecs_get_reglist_img_size(struct gk20a *g, u32 *size) { BUG_ON(size == NULL); diff --git a/drivers/video/tegra/host/gk20a/gr_gk20a.h b/drivers/video/tegra/host/gk20a/gr_gk20a.h index 6465fcf79ba9..f11532311638 100644 --- a/drivers/video/tegra/host/gk20a/gr_gk20a.h +++ b/drivers/video/tegra/host/gk20a/gr_gk20a.h @@ -317,6 +317,7 @@ int gk20a_free_obj_ctx(struct channel_gk20a *c, void gk20a_free_channel_ctx(struct channel_gk20a *c); int gk20a_gr_isr(struct gk20a *g); +int gk20a_gr_nonstall_isr(struct gk20a *g); int gk20a_gr_clear_comptags(struct gk20a *g, u32 min, u32 max); /* zcull */ diff --git a/drivers/video/tegra/host/gk20a/hw_gr_gk20a.h b/drivers/video/tegra/host/gk20a/hw_gr_gk20a.h index ef2823f28c6c..1247a93e987c 100644 --- a/drivers/video/tegra/host/gk20a/hw_gr_gk20a.h +++ b/drivers/video/tegra/host/gk20a/hw_gr_gk20a.h @@ -122,6 +122,14 @@ static inline u32 gr_intr_exception_reset_f(void) { return 0x200000; } +static inline u32 gr_intr_nonstall_r(void) +{ + return 0x00400120; +} +static inline u32 gr_intr_nonstall_trap_pending_f(void) +{ + return 0x2; +} static inline u32 gr_intr_en_r(void) { return 0x0040013c; diff --git a/drivers/video/tegra/host/gk20a/hw_mc_gk20a.h b/drivers/video/tegra/host/gk20a/hw_mc_gk20a.h index 53fdc4d133ee..646312871814 100644 --- a/drivers/video/tegra/host/gk20a/hw_mc_gk20a.h +++ b/drivers/video/tegra/host/gk20a/hw_mc_gk20a.h @@ -78,6 +78,10 @@ static inline u32 mc_intr_0_pbus_pending_f(void) { return 0x10000000; } +static inline u32 mc_intr_1_r(void) +{ + return 0x00000104; +} static inline u32 mc_intr_mask_0_r(void) { return 0x00000640; @@ -86,6 +90,14 @@ static inline u32 mc_intr_mask_0_pmu_enabled_f(void) { return 0x1000000; } +static inline u32 mc_intr_mask_1_r(void) +{ + return 0x00000644; +} +static inline u32 mc_intr_mask_1_pmu_enabled_f(void) +{ + return 0x1000000; +} static inline u32 mc_intr_en_0_r(void) { return 0x00000140; @@ -106,6 +118,10 @@ static inline u32 mc_intr_en_1_inta_disabled_f(void) { return 0x0; } +static inline u32 mc_intr_en_1_inta_hardware_f(void) +{ + return 0x1; +} static inline u32 mc_enable_r(void) { return 0x00000200; diff --git a/drivers/video/tegra/host/gk20a/pmu_gk20a.c b/drivers/video/tegra/host/gk20a/pmu_gk20a.c index fdd90b703bcc..02361884a95a 100644 --- a/drivers/video/tegra/host/gk20a/pmu_gk20a.c +++ b/drivers/video/tegra/host/gk20a/pmu_gk20a.c @@ -185,6 +185,9 @@ static void pmu_enable_irq(struct pmu_gk20a *pmu, bool enable) gk20a_writel(g, mc_intr_mask_0_r(), gk20a_readl(g, mc_intr_mask_0_r()) & ~mc_intr_mask_0_pmu_enabled_f()); + gk20a_writel(g, mc_intr_mask_1_r(), + gk20a_readl(g, mc_intr_mask_0_r()) & + ~mc_intr_mask_1_pmu_enabled_f()); gk20a_writel(g, pwr_falcon_irqmclr_r(), pwr_falcon_irqmclr_gptmr_f(1) | @@ -216,7 +219,7 @@ static void pmu_enable_irq(struct pmu_gk20a *pmu, bool enable) pwr_falcon_irqdest_target_halt_f(0) | pwr_falcon_irqdest_target_exterr_f(0) | pwr_falcon_irqdest_target_swgen0_f(0) | - pwr_falcon_irqdest_target_swgen1_f(1) | + pwr_falcon_irqdest_target_swgen1_f(0) | pwr_falcon_irqdest_target_ext_f(0xff)); /* 0=disable, 1=enable */ |