summaryrefslogtreecommitdiff
path: root/drivers/video/tegra
diff options
context:
space:
mode:
authorTerje Bergstrom <tbergstrom@nvidia.com>2013-12-02 11:05:54 +0200
committerTerje Bergstrom <tbergstrom@nvidia.com>2013-12-22 22:06:14 -0800
commitcc7c41286f198fd220fad1bdb5391195136cb55e (patch)
treea2691546ad99a34c3368747f5213775abca96574 /drivers/video/tegra
parent90c045c1b135d2cf908a8384c8c68aeeb167075c (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.c14
-rw-r--r--drivers/video/tegra/host/gk20a/channel_gk20a.h1
-rw-r--r--drivers/video/tegra/host/gk20a/fifo_gk20a.c37
-rw-r--r--drivers/video/tegra/host/gk20a/fifo_gk20a.h1
-rw-r--r--drivers/video/tegra/host/gk20a/gk20a.c76
-rw-r--r--drivers/video/tegra/host/gk20a/gr_gk20a.c18
-rw-r--r--drivers/video/tegra/host/gk20a/gr_gk20a.h1
-rw-r--r--drivers/video/tegra/host/gk20a/hw_gr_gk20a.h8
-rw-r--r--drivers/video/tegra/host/gk20a/hw_mc_gk20a.h16
-rw-r--r--drivers/video/tegra/host/gk20a/pmu_gk20a.c5
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 */