From 726900b8433294fd89a6d730d2fec9de8e33afda Mon Sep 17 00:00:00 2001 From: Terje Bergstrom Date: Thu, 11 May 2017 13:12:03 -0700 Subject: gpu: nvgpu: Split stalling interrupt handling Split handling of stalling interrupt to Linux specific chip agnostic and OS independent chip specific parts. Linux specific chip independent part contains handler for ISR and passing the control to a bottom half. It uses the new MC HALs intr_stall (query interrupt status), intr_pause (pause interrupts) and intr_resume (resume interrupts). MC HAL isr_stall now returns void and gets called in thread context and thus remove isr_thread_stall and replace the implementation with isr_stall. JIRA NVGPU-26 Change-Id: I206f330f6fc4a1f4def47c5f986585ac4080216d Signed-off-by: Terje Bergstrom Reviewed-on: http://git-master/r/1480243 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/Makefile.nvgpu | 1 + drivers/gpu/nvgpu/common/linux/intr.c | 58 +++++++++++++++++++++++++ drivers/gpu/nvgpu/common/linux/intr.h | 20 +++++++++ drivers/gpu/nvgpu/common/linux/module.c | 5 ++- drivers/gpu/nvgpu/common/linux/pci.c | 7 ++- drivers/gpu/nvgpu/gk20a/gk20a.h | 6 ++- drivers/gpu/nvgpu/gk20a/mc_gk20a.c | 76 +++++++++++++-------------------- drivers/gpu/nvgpu/gk20a/mc_gk20a.h | 5 ++- drivers/gpu/nvgpu/gm20b/mc_gm20b.c | 4 +- drivers/gpu/nvgpu/gp10b/mc_gp10b.c | 49 +++++++++------------ drivers/gpu/nvgpu/gp10b/mc_gp10b.h | 5 +-- 11 files changed, 147 insertions(+), 89 deletions(-) create mode 100644 drivers/gpu/nvgpu/common/linux/intr.c create mode 100644 drivers/gpu/nvgpu/common/linux/intr.h (limited to 'drivers/gpu/nvgpu') diff --git a/drivers/gpu/nvgpu/Makefile.nvgpu b/drivers/gpu/nvgpu/Makefile.nvgpu index c2d98559..109d1e4d 100644 --- a/drivers/gpu/nvgpu/Makefile.nvgpu +++ b/drivers/gpu/nvgpu/Makefile.nvgpu @@ -41,6 +41,7 @@ nvgpu-y := \ common/linux/firmware.o \ common/linux/thread.o \ common/linux/vm.o \ + common/linux/intr.o \ common/mm/nvgpu_allocator.o \ common/mm/bitmap_allocator.o \ common/mm/buddy_allocator.o \ diff --git a/drivers/gpu/nvgpu/common/linux/intr.c b/drivers/gpu/nvgpu/common/linux/intr.c new file mode 100644 index 00000000..77e44dd9 --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/intr.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include + +#include "gk20a/gk20a.h" + +#include + +irqreturn_t nvgpu_intr_stall(struct gk20a *g) +{ + u32 mc_intr_0; + + trace_mc_gk20a_intr_stall(g->name); + + if (!g->power_on) + return IRQ_NONE; + + /* not from gpu when sharing irq with others */ + mc_intr_0 = g->ops.mc.intr_stall(g); + if (unlikely(!mc_intr_0)) + return IRQ_NONE; + + g->ops.mc.intr_stall_pause(g); + + atomic_inc(&g->hw_irq_stall_count); + + trace_mc_gk20a_intr_stall_done(g->name); + + return IRQ_WAKE_THREAD; +} + +irqreturn_t nvgpu_intr_thread_stall(struct gk20a *g) +{ + gk20a_dbg(gpu_dbg_intr, "interrupt thread launched"); + + trace_mc_gk20a_intr_thread_stall(g->name); + + g->ops.mc.isr_stall(g); + g->ops.mc.intr_stall_resume(g); + + wake_up_all(&g->sw_irq_stall_last_handled_wq); + + trace_mc_gk20a_intr_thread_stall_done(g->name); + + return IRQ_HANDLED; +} + diff --git a/drivers/gpu/nvgpu/common/linux/intr.h b/drivers/gpu/nvgpu/common/linux/intr.h new file mode 100644 index 00000000..243d8f51 --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/intr.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef __NVGPU_LINUX_INTR_H__ +#define __NVGPU_LINUX_INTR_H__ +struct gk20a; + +irqreturn_t nvgpu_intr_stall(struct gk20a *g); +irqreturn_t nvgpu_intr_thread_stall(struct gk20a *g); +#endif diff --git a/drivers/gpu/nvgpu/common/linux/module.c b/drivers/gpu/nvgpu/common/linux/module.c index ab99bef0..5e8af065 100644 --- a/drivers/gpu/nvgpu/common/linux/module.c +++ b/drivers/gpu/nvgpu/common/linux/module.c @@ -36,6 +36,7 @@ #include "gk20a/ctxsw_trace_gk20a.h" #include "pci.h" #include "module.h" +#include "intr.h" #ifdef CONFIG_TEGRA_19x_GPU #include "nvgpu_gpuid_t19x.h" #endif @@ -482,7 +483,7 @@ static irqreturn_t gk20a_intr_isr_stall(int irq, void *dev_id) { struct gk20a *g = dev_id; - return g->ops.mc.isr_stall(g); + return nvgpu_intr_stall(g); } static irqreturn_t gk20a_intr_isr_nonstall(int irq, void *dev_id) @@ -496,7 +497,7 @@ static irqreturn_t gk20a_intr_thread_stall(int irq, void *dev_id) { struct gk20a *g = dev_id; - return g->ops.mc.isr_thread_stall(g); + return nvgpu_intr_thread_stall(g); } void gk20a_remove_support(struct gk20a *g) diff --git a/drivers/gpu/nvgpu/common/linux/pci.c b/drivers/gpu/nvgpu/common/linux/pci.c index d729d273..767e9d47 100644 --- a/drivers/gpu/nvgpu/common/linux/pci.c +++ b/drivers/gpu/nvgpu/common/linux/pci.c @@ -25,6 +25,7 @@ #include "gk20a/platform_gk20a.h" #include "clk/clk.h" #include "module.h" +#include "intr.h" #include "pci.h" @@ -232,7 +233,7 @@ static irqreturn_t nvgpu_pci_isr(int irq, void *dev_id) irqreturn_t ret_stall; irqreturn_t ret_nonstall; - ret_stall = g->ops.mc.isr_stall(g); + ret_stall = nvgpu_intr_stall(g); ret_nonstall = g->ops.mc.isr_nonstall(g); #if defined(CONFIG_PCI_MSI) @@ -248,9 +249,7 @@ static irqreturn_t nvgpu_pci_intr_thread(int irq, void *dev_id) { struct gk20a *g = dev_id; - g->ops.mc.isr_thread_stall(g); - - return IRQ_HANDLED; + return nvgpu_intr_thread_stall(g); } static int nvgpu_pci_init_support(struct pci_dev *pdev) diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h index ceadbae2..29ac4763 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a.h @@ -812,13 +812,15 @@ struct gpu_ops { void (*intr_enable)(struct gk20a *g); void (*intr_unit_config)(struct gk20a *g, bool enable, bool is_stalling, u32 unit); - irqreturn_t (*isr_stall)(struct gk20a *g); + void (*isr_stall)(struct gk20a *g); irqreturn_t (*isr_nonstall)(struct gk20a *g); - irqreturn_t (*isr_thread_stall)(struct gk20a *g); void (*isr_thread_nonstall)(struct gk20a *g, u32 intr); void (*isr_nonstall_cb)(struct work_struct *work); bool (*is_intr_hub_pending)(struct gk20a *g, u32 mc_intr); u32 intr_mask_restore[4]; + u32 (*intr_stall)(struct gk20a *g); + void (*intr_stall_pause)(struct gk20a *g); + void (*intr_stall_resume)(struct gk20a *g); void (*enable)(struct gk20a *g, u32 units); void (*disable)(struct gk20a *g, u32 units); void (*reset)(struct gk20a *g, u32 units); diff --git a/drivers/gpu/nvgpu/gk20a/mc_gk20a.c b/drivers/gpu/nvgpu/gk20a/mc_gk20a.c index ca7189cc..bc11b14d 100644 --- a/drivers/gpu/nvgpu/gk20a/mc_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/mc_gk20a.c @@ -1,7 +1,7 @@ /* * GK20A Master Control * - * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -41,33 +41,6 @@ void mc_gk20a_nonstall_cb(struct work_struct *work) } while (atomic_read(&g->nonstall_ops) != 0); } -irqreturn_t mc_gk20a_isr_stall(struct gk20a *g) -{ - u32 mc_intr_0; - - trace_mc_gk20a_intr_stall(g->name); - - if (!g->power_on) - return IRQ_NONE; - - /* not from gpu when sharing irq with others */ - mc_intr_0 = gk20a_readl(g, mc_intr_0_r()); - if (unlikely(!mc_intr_0)) - return IRQ_NONE; - - gk20a_writel(g, mc_intr_en_0_r(), - mc_intr_en_0_inta_disabled_f()); - - /* flush previous write */ - gk20a_readl(g, mc_intr_en_0_r()); - - atomic_inc(&g->hw_irq_stall_count); - - trace_mc_gk20a_intr_stall_done(g->name); - - return IRQ_WAKE_THREAD; -} - irqreturn_t mc_gk20a_isr_nonstall(struct gk20a *g) { u32 mc_intr_1; @@ -106,7 +79,7 @@ irqreturn_t mc_gk20a_isr_nonstall(struct gk20a *g) return IRQ_HANDLED; } -irqreturn_t mc_gk20a_intr_thread_stall(struct gk20a *g) +void mc_gk20a_isr_stall(struct gk20a *g) { u32 mc_intr_0; int hw_irq_count; @@ -114,11 +87,7 @@ irqreturn_t mc_gk20a_intr_thread_stall(struct gk20a *g) u32 active_engine_id = 0; u32 engine_enum = ENGINE_INVAL_GK20A; - gk20a_dbg(gpu_dbg_intr, "interrupt thread launched"); - - trace_mc_gk20a_intr_thread_stall(g->name); - - mc_intr_0 = gk20a_readl(g, mc_intr_0_r()); + mc_intr_0 = g->ops.mc.intr_stall(g); hw_irq_count = atomic_read(&g->hw_irq_stall_count); gk20a_dbg(gpu_dbg_intr, "stall intr %08x\n", mc_intr_0); @@ -156,18 +125,6 @@ irqreturn_t mc_gk20a_intr_thread_stall(struct gk20a *g) /* sync handled irq counter before re-enabling interrupts */ atomic_set(&g->sw_irq_stall_last_handled, hw_irq_count); - - gk20a_writel(g, mc_intr_en_0_r(), - mc_intr_en_0_inta_hardware_f()); - - /* flush previous write */ - gk20a_readl(g, mc_intr_en_0_r()); - - wake_up_all(&g->sw_irq_stall_last_handled_wq); - - trace_mc_gk20a_intr_thread_stall_done(g->name); - - return IRQ_HANDLED; } void mc_gk20a_intr_thread_nonstall(struct gk20a *g, u32 mc_intr_1) @@ -250,6 +207,29 @@ void mc_gk20a_intr_unit_config(struct gk20a *g, bool enable, } } +void mc_gk20a_intr_stall_pause(struct gk20a *g) +{ + gk20a_writel(g, mc_intr_en_0_r(), + mc_intr_en_0_inta_disabled_f()); + + /* flush previous write */ + gk20a_readl(g, mc_intr_en_0_r()); +} + +void mc_gk20a_intr_stall_resume(struct gk20a *g) +{ + gk20a_writel(g, mc_intr_en_0_r(), + mc_intr_en_0_inta_hardware_f()); + + /* flush previous write */ + gk20a_readl(g, mc_intr_en_0_r()); +} + +u32 mc_gk20a_intr_stall(struct gk20a *g) +{ + return gk20a_readl(g, mc_intr_0_r()); +} + void gk20a_mc_disable(struct gk20a *g, u32 units) { u32 pmc; @@ -312,8 +292,10 @@ void gk20a_init_mc(struct gpu_ops *gops) gops->mc.intr_enable = mc_gk20a_intr_enable; gops->mc.intr_unit_config = mc_gk20a_intr_unit_config; gops->mc.isr_stall = mc_gk20a_isr_stall; + gops->mc.intr_stall = mc_gk20a_intr_stall; + gops->mc.intr_stall_pause = mc_gk20a_intr_stall_pause; + gops->mc.intr_stall_resume = mc_gk20a_intr_stall_resume; gops->mc.isr_nonstall = mc_gk20a_isr_nonstall; - gops->mc.isr_thread_stall = mc_gk20a_intr_thread_stall; gops->mc.isr_thread_nonstall = mc_gk20a_intr_thread_nonstall; gops->mc.isr_nonstall_cb = mc_gk20a_nonstall_cb; gops->mc.enable = gk20a_mc_enable; diff --git a/drivers/gpu/nvgpu/gk20a/mc_gk20a.h b/drivers/gpu/nvgpu/gk20a/mc_gk20a.h index 9c70eba1..2b4a183e 100644 --- a/drivers/gpu/nvgpu/gk20a/mc_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/mc_gk20a.h @@ -19,7 +19,10 @@ void gk20a_init_mc(struct gpu_ops *gops); void mc_gk20a_intr_enable(struct gk20a *g); void mc_gk20a_intr_unit_config(struct gk20a *g, bool enable, bool is_stalling, u32 mask); -irqreturn_t mc_gk20a_isr_stall(struct gk20a *g); +void mc_gk20a_isr_stall(struct gk20a *g); +u32 mc_gk20a_intr_stall(struct gk20a *g); +void mc_gk20a_intr_stall_pause(struct gk20a *g); +void mc_gk20a_intr_stall_resume(struct gk20a *g); irqreturn_t mc_gk20a_isr_nonstall(struct gk20a *g); irqreturn_t mc_gk20a_intr_thread_stall(struct gk20a *g); void mc_gk20a_intr_thread_nonstall(struct gk20a *g, u32 intr); diff --git a/drivers/gpu/nvgpu/gm20b/mc_gm20b.c b/drivers/gpu/nvgpu/gm20b/mc_gm20b.c index 05504e82..ebb9780d 100644 --- a/drivers/gpu/nvgpu/gm20b/mc_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/mc_gm20b.c @@ -22,8 +22,10 @@ void gm20b_init_mc(struct gpu_ops *gops) gops->mc.intr_enable = mc_gk20a_intr_enable; gops->mc.intr_unit_config = mc_gk20a_intr_unit_config; gops->mc.isr_stall = mc_gk20a_isr_stall; + gops->mc.intr_stall = mc_gk20a_intr_stall; + gops->mc.intr_stall_pause = mc_gk20a_intr_stall_pause; + gops->mc.intr_stall_resume = mc_gk20a_intr_stall_resume; gops->mc.isr_nonstall = mc_gk20a_isr_nonstall; - gops->mc.isr_thread_stall = mc_gk20a_intr_thread_stall; gops->mc.isr_thread_nonstall = mc_gk20a_intr_thread_nonstall; gops->mc.isr_nonstall_cb = mc_gk20a_nonstall_cb; gops->mc.enable = gk20a_mc_enable; diff --git a/drivers/gpu/nvgpu/gp10b/mc_gp10b.c b/drivers/gpu/nvgpu/gp10b/mc_gp10b.c index 4a48d7fa..bfc7a3d4 100644 --- a/drivers/gpu/nvgpu/gp10b/mc_gp10b.c +++ b/drivers/gpu/nvgpu/gp10b/mc_gp10b.c @@ -1,7 +1,7 @@ /* - * GP20B master + * GP10B master * - * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -67,25 +67,6 @@ void mc_gp10b_intr_unit_config(struct gk20a *g, bool enable, gk20a_writel(g, reg, mask); } -irqreturn_t mc_gp10b_isr_stall(struct gk20a *g) -{ - u32 mc_intr_0; - - if (!g->power_on) - return IRQ_NONE; - - /* not from gpu when sharing irq with others */ - mc_intr_0 = gk20a_readl(g, mc_intr_r(0)); - if (unlikely(!mc_intr_0)) - return IRQ_NONE; - - gk20a_writel(g, mc_intr_en_clear_r(0), 0xffffffff); - - atomic_inc(&g->hw_irq_stall_count); - - return IRQ_WAKE_THREAD; -} - irqreturn_t mc_gp10b_isr_nonstall(struct gk20a *g) { u32 mc_intr_1; @@ -117,7 +98,7 @@ irqreturn_t mc_gp10b_isr_nonstall(struct gk20a *g) return IRQ_HANDLED; } -irqreturn_t mc_gp10b_intr_thread_stall(struct gk20a *g) +void mc_gp10b_isr_stall(struct gk20a *g) { u32 mc_intr_0; int hw_irq_count; @@ -126,8 +107,6 @@ irqreturn_t mc_gp10b_intr_thread_stall(struct gk20a *g) u32 active_engine_id = 0; u32 engine_enum = ENGINE_INVAL_GK20A; - gk20a_dbg(gpu_dbg_intr, "interrupt thread launched"); - mc_intr_0 = gk20a_readl(g, mc_intr_r(0)); hw_irq_count = atomic_read(&g->hw_irq_stall_count); @@ -172,12 +151,22 @@ irqreturn_t mc_gp10b_intr_thread_stall(struct gk20a *g) gk20a_dbg(gpu_dbg_intr, "stall intr done 0x%08x\n", mc_intr_0); - gk20a_writel(g, mc_intr_en_set_r(NVGPU_MC_INTR_STALLING), - g->ops.mc.intr_mask_restore[NVGPU_MC_INTR_STALLING]); +} - wake_up_all(&g->sw_irq_stall_last_handled_wq); +u32 mc_gp10b_intr_stall(struct gk20a *g) +{ + return gk20a_readl(g, mc_intr_r(NVGPU_MC_INTR_STALLING)); +} - return IRQ_HANDLED; +void mc_gp10b_intr_stall_pause(struct gk20a *g) +{ + gk20a_writel(g, mc_intr_en_clear_r(NVGPU_MC_INTR_STALLING), 0xffffffff); +} + +void mc_gp10b_intr_stall_resume(struct gk20a *g) +{ + gk20a_writel(g, mc_intr_en_set_r(NVGPU_MC_INTR_STALLING), + g->ops.mc.intr_mask_restore[NVGPU_MC_INTR_STALLING]); } void gp10b_init_mc(struct gpu_ops *gops) @@ -185,8 +174,10 @@ void gp10b_init_mc(struct gpu_ops *gops) gops->mc.intr_enable = mc_gp10b_intr_enable; gops->mc.intr_unit_config = mc_gp10b_intr_unit_config; gops->mc.isr_stall = mc_gp10b_isr_stall; + gops->mc.intr_stall = mc_gp10b_intr_stall; + gops->mc.intr_stall_pause = mc_gp10b_intr_stall_pause; + gops->mc.intr_stall_resume = mc_gp10b_intr_stall_resume; gops->mc.isr_nonstall = mc_gp10b_isr_nonstall; - gops->mc.isr_thread_stall = mc_gp10b_intr_thread_stall; gops->mc.isr_thread_nonstall = mc_gk20a_intr_thread_nonstall; gops->mc.isr_nonstall_cb = mc_gk20a_nonstall_cb; gops->mc.enable = gk20a_mc_enable; diff --git a/drivers/gpu/nvgpu/gp10b/mc_gp10b.h b/drivers/gpu/nvgpu/gp10b/mc_gp10b.h index b2ec4be4..31867a88 100644 --- a/drivers/gpu/nvgpu/gp10b/mc_gp10b.h +++ b/drivers/gpu/nvgpu/gp10b/mc_gp10b.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -24,8 +24,7 @@ void gp10b_init_mc(struct gpu_ops *gops); void mc_gp10b_intr_enable(struct gk20a *g); void mc_gp10b_intr_unit_config(struct gk20a *g, bool enable, bool is_stalling, u32 mask); -irqreturn_t mc_gp10b_isr_stall(struct gk20a *g); +void mc_gp10b_isr_stall(struct gk20a *g); irqreturn_t mc_gp10b_isr_nonstall(struct gk20a *g); -irqreturn_t mc_gp10b_intr_thread_stall(struct gk20a *g); irqreturn_t mc_gp10b_intr_thread_nonstall(struct gk20a *g); #endif -- cgit v1.2.2