diff --git a/arch/nvgpu-common.yaml b/arch/nvgpu-common.yaml index 44bd5ced3..20d946ffd 100644 --- a/arch/nvgpu-common.yaml +++ b/arch/nvgpu-common.yaml @@ -496,6 +496,7 @@ gr: safe: yes sources: [ common/gr/gr_intr.c, common/gr/gr_intr_priv.h, + include/nvgpu/interrupts.h, include/nvgpu/gr/gr_intr.h ] setup: safe: yes diff --git a/drivers/gpu/nvgpu/include/nvgpu/interrupts.h b/drivers/gpu/nvgpu/include/nvgpu/interrupts.h new file mode 100644 index 000000000..172946c29 --- /dev/null +++ b/drivers/gpu/nvgpu/include/nvgpu/interrupts.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#ifndef NVGPU_INTERRUPTS_H +#define NVGPU_INTERRUPTS_H + +#include + +#define NVGPU_MAX_INTERRUPTS_STALL 0x3U +#define NVGPU_MAX_INTERRUPTS_NONSTALL 0x1U +#define NVGPU_MAX_INTERRUPTS (NVGPU_MAX_INTERRUPTS_STALL + \ + NVGPU_MAX_INTERRUPTS_NONSTALL) + +struct nvgpu_interrupts { + bool enabled; + + u32 stall_size; + u32 nonstall_size; + + u32 stall_lines[NVGPU_MAX_INTERRUPTS_STALL]; + u32 nonstall_line; /* FIXME: if multiple nonstall lines are needed */ +}; + +#endif /* NVGPU_INTERRUPTS_H */ diff --git a/drivers/gpu/nvgpu/include/nvgpu/mc.h b/drivers/gpu/nvgpu/include/nvgpu/mc.h index d47f49140..8c2b2417d 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/mc.h +++ b/drivers/gpu/nvgpu/include/nvgpu/mc.h @@ -276,28 +276,8 @@ struct nvgpu_mc { */ nvgpu_atomic_t sw_irq_nonstall_pending; - /** nvgpu interrupts enabled status from host OS perspective */ - bool irqs_enabled; - - /** - * Interrupt line for stalling interrupts. - * Can be same as irq_nonstall in case of PCI. - */ - u32 irq_stall; - - /** Interrupt line for non-stalling interrupts. */ - u32 irq_nonstall; - /** @cond DOXYGEN_SHOULD_SKIP_THIS */ - /** Total number of stall interrupt lines */ - u32 irq_stall_count; - /** - * Array to store irq_stall interrupt number for upto 4 - * stall irq lines. - */ - u32 irq_stall_lines[4]; - #if defined(CONFIG_NVGPU_NON_FUSA) && defined(CONFIG_NVGPU_NEXT) struct nvgpu_next_mc nvgpu_next; #endif diff --git a/drivers/gpu/nvgpu/os/linux/module.c b/drivers/gpu/nvgpu/os/linux/module.c index 870a336e7..59c77287a 100644 --- a/drivers/gpu/nvgpu/os/linux/module.c +++ b/drivers/gpu/nvgpu/os/linux/module.c @@ -564,15 +564,15 @@ static int gk20a_lockout_registers(struct gk20a *g) int nvgpu_enable_irqs(struct gk20a *g) { + struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); u32 i; - if (!g->mc.irqs_enabled) { - for (i = 0U; i < g->mc.irq_stall_count; i++) { - enable_irq(g->mc.irq_stall_lines[i]); - } - if (g->mc.irq_stall != g->mc.irq_nonstall) - enable_irq(g->mc.irq_nonstall); - g->mc.irqs_enabled = true; + for (i = 0U; i < l->interrupts.stall_size; i++) { + enable_irq(l->interrupts.stall_lines[i]); + } + + if (l->interrupts.nonstall_size > 0) { + enable_irq(l->interrupts.nonstall_line); } return 0; @@ -580,15 +580,15 @@ int nvgpu_enable_irqs(struct gk20a *g) void nvgpu_disable_irqs(struct gk20a *g) { + struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); u32 i; - if (g->mc.irqs_enabled) { - for (i = 0U; i < g->mc.irq_stall_count; i++) { - disable_irq(g->mc.irq_stall_lines[i]); - } - if (g->mc.irq_stall != g->mc.irq_nonstall) - disable_irq(g->mc.irq_nonstall); - g->mc.irqs_enabled = false; + for (i = 0U; i < l->interrupts.stall_size; i++) { + disable_irq(l->interrupts.stall_lines[i]); + } + + if (l->interrupts.nonstall_size > 0) { + disable_irq(l->interrupts.nonstall_line); } } @@ -660,8 +660,7 @@ static int gk20a_pm_prepare_poweroff(struct device *dev) struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); #endif struct gk20a_platform *platform = gk20a_get_platform(dev); - bool irqs_enabled; - int ret = 0, err = 0; + int ret = 0; nvgpu_log_fn(g, " "); @@ -670,8 +669,6 @@ static int gk20a_pm_prepare_poweroff(struct device *dev) if (nvgpu_is_powered_off(g)) goto done; - /* disable IRQs and wait for completion */ - irqs_enabled = g->mc.irqs_enabled; nvgpu_disable_irqs(g); gk20a_scale_suspend(dev); @@ -699,13 +696,8 @@ static int gk20a_pm_prepare_poweroff(struct device *dev) return 0; error: - /* re-enabled IRQs if previously enabled */ - if (irqs_enabled) { - err = nvgpu_enable_irqs(g); - if (err) { - nvgpu_err(g, "failed to enable irqs %d", err); - } - } + /* Re-enable IRQs on error. This doesn't fail on Linux. */ + (void) nvgpu_enable_irqs(g); gk20a_scale_resume(dev); done: @@ -1191,13 +1183,15 @@ static int gk20a_pm_unrailgate(struct device *dev) void nvgpu_free_irq(struct gk20a *g) { struct device *dev = dev_from_gk20a(g); + struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); u32 i; - for (i = 0U; i < g->mc.irq_stall_count; i++) { - devm_free_irq(dev, g->mc.irq_stall_lines[i], g); + for (i = 0U; i < l->interrupts.stall_size; i++) { + devm_free_irq(dev, l->interrupts.stall_lines[i], g); + } + if (l->interrupts.nonstall_size > 0) { + devm_free_irq(dev, l->interrupts.nonstall_line, g); } - if (g->mc.irq_stall != g->mc.irq_nonstall) - devm_free_irq(dev, g->mc.irq_nonstall, g); } /* @@ -1587,7 +1581,7 @@ static int gk20a_probe(struct platform_device *dev) int err; struct gk20a_platform *platform = NULL; struct device_node *np; - u32 i; + u32 i, intr_size, irq_idx; if (dev->dev.of_node) { const struct of_device_id *match; @@ -1640,56 +1634,62 @@ static int gk20a_probe(struct platform_device *dev) if (nvgpu_platform_is_simulation(gk20a)) nvgpu_set_enabled(gk20a, NVGPU_IS_FMODEL, true); - /* Number of stall interrupt lines = total irq - 1 (for nonstall irq) */ - gk20a->mc.irq_stall_count = platform_irq_count(dev) - 1; + intr_size = platform_irq_count(dev); + if (intr_size > 0U && intr_size <= NVGPU_MAX_INTERRUPTS) { + irq_idx = 0U; - gk20a->mc.irq_stall = platform_get_irq(dev, 0); - gk20a->mc.irq_stall_lines[0] = gk20a->mc.irq_stall; + /* Single interrupt line could be a stall line*/ + l->interrupts.nonstall_size = intr_size == 1U ? 0U : 1U; + l->interrupts.stall_size = intr_size - l->interrupts.nonstall_size; - gk20a->mc.irq_nonstall = platform_get_irq(dev, 1); - if ((int)gk20a->mc.irq_stall < 0 || (int)gk20a->mc.irq_nonstall < 0) { + for (i = 0U; i < l->interrupts.stall_size; i++) { + l->interrupts.stall_lines[i] = platform_get_irq(dev, i); + if ((int)l->interrupts.stall_lines[i] < 0) { + err = -ENXIO; + goto return_err; + } + } + if (l->interrupts.nonstall_size > 0U) { + l->interrupts.nonstall_line = platform_get_irq(dev, i); + if ((int)l->interrupts.nonstall_line < 0) { + err = -ENXIO; + goto return_err; + } + } + } else { + dev_err(&dev->dev, "Invalid intr lines\n"); err = -ENXIO; goto return_err; } - if (gk20a->mc.irq_stall_count > 1) { - for (i = 1U; i < gk20a->mc.irq_stall_count; i++) { - gk20a->mc.irq_stall_lines[i] = - platform_get_irq(dev, i + 1); - } - } - for (i = 0U; i < gk20a->mc.irq_stall_count; i++) { + for (i = 0U; i < l->interrupts.stall_size; i++) { err = devm_request_threaded_irq(&dev->dev, - gk20a->mc.irq_stall_lines[i], + l->interrupts.stall_lines[i], gk20a_intr_isr_stall, gk20a_intr_thread_stall, 0, "gk20a_stall", gk20a); if (err) { dev_err(&dev->dev, "failed to request stall intr irq @ %d\n", - gk20a->mc.irq_stall_lines[i]); + l->interrupts.stall_lines[i]); goto return_err; } } - if (gk20a->mc.irq_stall != gk20a->mc.irq_nonstall) { + if (l->interrupts.nonstall_size > 0) { err = devm_request_irq(&dev->dev, - gk20a->mc.irq_nonstall, + l->interrupts.nonstall_line, gk20a_intr_isr_nonstall, 0, "gk20a_nonstall", gk20a); if (err) { dev_err(&dev->dev, "failed to request non-stall intr irq @ %d\n", - gk20a->mc.irq_nonstall); + l->interrupts.nonstall_line); goto return_err; } } - for (i = 0U; i < gk20a->mc.irq_stall_count; i++) { - disable_irq(gk20a->mc.irq_stall_lines[i]); - } - if (gk20a->mc.irq_stall != gk20a->mc.irq_nonstall) - disable_irq(gk20a->mc.irq_nonstall); + nvgpu_disable_irqs(gk20a); err = gk20a_init_support(dev); if (err) diff --git a/drivers/gpu/nvgpu/os/linux/os_linux.h b/drivers/gpu/nvgpu/os/linux/os_linux.h index d833773ec..effed9e04 100644 --- a/drivers/gpu/nvgpu/os/linux/os_linux.h +++ b/drivers/gpu/nvgpu/os/linux/os_linux.h @@ -24,6 +24,7 @@ #include #include +#include #include "cde.h" #include "sched.h" @@ -74,6 +75,7 @@ struct nvgpu_os_linux { struct gk20a g; struct device *dev; struct dgpu_thermal_alert thermal_alert; + struct nvgpu_interrupts interrupts; struct { struct cdev cdev; struct device *node; diff --git a/drivers/gpu/nvgpu/os/linux/pci.c b/drivers/gpu/nvgpu/os/linux/pci.c index 451ed7d62..264717b7f 100644 --- a/drivers/gpu/nvgpu/os/linux/pci.c +++ b/drivers/gpu/nvgpu/os/linux/pci.c @@ -599,20 +599,20 @@ static int nvgpu_pci_probe(struct pci_dev *pdev, g->msi_enabled = true; #endif - g->mc.irq_stall = pdev->irq; - g->mc.irq_nonstall = pdev->irq; - if ((int)g->mc.irq_stall < 0) { + /* Number of stall interrupt line = 1 (for dgpu <= tu10x) */ + l->interrupts.stall_size = 1U; + l->interrupts.nonstall_size = 0U; + + l->interrupts.stall_lines[0] = pdev->irq; + l->interrupts.nonstall_line = pdev->irq; + + if ((int)l->interrupts.stall_lines[0] < 0) { err = -ENXIO; goto err_disable_msi; } - /* Number of stall interrupt line = 1 (for dgpu <= tu10x) */ - g->mc.irq_stall_count = 1; - - g->mc.irq_stall_lines[0] = g->mc.irq_stall; - err = devm_request_threaded_irq(&pdev->dev, - g->mc.irq_stall, + l->interrupts.stall_lines[0], nvgpu_pci_isr, nvgpu_pci_intr_thread, #if defined(CONFIG_PCI_MSI) @@ -621,10 +621,10 @@ static int nvgpu_pci_probe(struct pci_dev *pdev, IRQF_SHARED, "nvgpu", g); if (err) { nvgpu_err(g, - "failed to request irq @ %d", g->mc.irq_stall); + "failed to request irq @ %d", l->interrupts.stall_lines[0]); goto err_disable_msi; } - disable_irq(g->mc.irq_stall); + nvgpu_disable_irqs(g); err = nvgpu_pci_init_support(pdev); if (err) @@ -763,9 +763,9 @@ static void nvgpu_pci_remove(struct pci_dev *pdev) pci_disable_msi(pdev); else { /* IRQ does not need to be enabled in MSI as the line is not - * shared + * shared. nonstall_size = 0, so only stall intr are enabled. */ - enable_irq(g->mc.irq_stall); + nvgpu_enable_irqs(g); } #endif nvgpu_pci_pm_deinit(&pdev->dev); diff --git a/drivers/gpu/nvgpu/os/posix/nvgpu.c b/drivers/gpu/nvgpu/os/posix/nvgpu.c index 02f883818..0331223bf 100644 --- a/drivers/gpu/nvgpu/os/posix/nvgpu.c +++ b/drivers/gpu/nvgpu/os/posix/nvgpu.c @@ -100,13 +100,11 @@ void nvgpu_start_gpu_idle(struct gk20a *g) int nvgpu_enable_irqs(struct gk20a *g) { - g->mc.irqs_enabled = true; return 0; } void nvgpu_disable_irqs(struct gk20a *g) { - g->mc.irqs_enabled = false; } void nvgpu_set_power_state(struct gk20a *g, u32 state)