From 6d888006aa7ed87b1589198369180e7e69f9f1d2 Mon Sep 17 00:00:00 2001 From: Terje Bergstrom Date: Fri, 15 Apr 2016 14:45:35 -0700 Subject: gpu: nvgpu: Add PCIe device support Add support for probing PCIe graphics cards. JIRA DNVGPU-7 Change-Id: Iad3d31a1dc0ca6575d8a9916857022cac9181948 Signed-off-by: Terje Bergstrom Reviewed-on: http://git-master/r/1127684 --- drivers/gpu/nvgpu/Kconfig | 8 ++ drivers/gpu/nvgpu/Makefile | 1 + drivers/gpu/nvgpu/gk20a/gk20a.c | 12 +- drivers/gpu/nvgpu/gk20a/gk20a.h | 4 + drivers/gpu/nvgpu/pci.c | 264 ++++++++++++++++++++++++++++++++++++++++ drivers/gpu/nvgpu/pci.h | 27 ++++ 6 files changed, 313 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/nvgpu/pci.c create mode 100644 drivers/gpu/nvgpu/pci.h diff --git a/drivers/gpu/nvgpu/Kconfig b/drivers/gpu/nvgpu/Kconfig index 94173976..127bb3f7 100644 --- a/drivers/gpu/nvgpu/Kconfig +++ b/drivers/gpu/nvgpu/Kconfig @@ -91,3 +91,11 @@ config TEGRA_USE_NA_GPCPLL Enable noise aware (NA) mode of GM20b GPCPLL. In this mode PLL output frequency is automatically adjusted when GM20b voltage is fluctuating because of transient PMIC or power distribution tree noise. + +config GK20A_PCI + bool "Support PCIe NVIDIA GPUs on nvgpu" + depends on PCI && GK20A + default y if ARM64 + default n + help + Enable support for GPUs on PCIe bus. diff --git a/drivers/gpu/nvgpu/Makefile b/drivers/gpu/nvgpu/Makefile index 8cd5cc7c..57e32006 100644 --- a/drivers/gpu/nvgpu/Makefile +++ b/drivers/gpu/nvgpu/Makefile @@ -76,6 +76,7 @@ nvgpu-y := \ gm20b/therm_gm20b.o nvgpu-$(CONFIG_TEGRA_GK20A) += gk20a/platform_gk20a_tegra.o nvgpu-$(CONFIG_SYNC) += gk20a/sync_gk20a.o +nvgpu-$(CONFIG_GK20A_PCI) += pci.o nvgpu-$(CONFIG_TEGRA_GR_VIRTUALIZATION) += \ gk20a/platform_vgpu_tegra.o \ diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c index a865b078..7b0db89e 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a.c @@ -62,6 +62,7 @@ #include "gk20a_allocator.h" #include "hal.h" #include "vgpu/vgpu.h" +#include "pci.h" #define CREATE_TRACE_POINTS #include @@ -601,7 +602,7 @@ static irqreturn_t gk20a_intr_thread_nonstall(int irq, void *dev_id) return g->ops.mc.isr_thread_nonstall(g); } -static void gk20a_remove_support(struct device *dev) +void gk20a_remove_support(struct device *dev) { struct gk20a *g = get_gk20a(dev); @@ -765,7 +766,7 @@ static int gk20a_detect_chip(struct gk20a *g) return gpu_init_hal(g); } -static int gk20a_pm_finalize_poweron(struct device *dev) +int gk20a_pm_finalize_poweron(struct device *dev) { struct gk20a *g = get_gk20a(dev); struct gk20a_platform *platform = gk20a_get_platform(dev); @@ -1326,7 +1327,7 @@ static int gk20a_pm_initialise_domain(struct device *dev) } #endif -static int gk20a_pm_init(struct device *dev) +int gk20a_pm_init(struct device *dev) { struct gk20a_platform *platform = dev_get_drvdata(dev); int err = 0; @@ -1764,11 +1765,16 @@ static int __init gk20a_init(void) if (ret) return ret; + ret = nvgpu_pci_init(); + if (ret) + return ret; + return platform_driver_register(&gk20a_driver); } static void __exit gk20a_exit(void) { + nvgpu_pci_exit(); platform_driver_unregister(&gk20a_driver); class_unregister(&nvgpu_class); } diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h index 47adcc14..15f838d9 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a.h @@ -1070,4 +1070,8 @@ extern struct class nvgpu_class; #define INTERFACE_NAME "nvhost%s-gpu" +int gk20a_pm_init(struct device *dev); +int gk20a_pm_finalize_poweron(struct device *dev); +void gk20a_remove_support(struct device *dev); + #endif /* GK20A_H */ diff --git a/drivers/gpu/nvgpu/pci.c b/drivers/gpu/nvgpu/pci.c new file mode 100644 index 00000000..bc8cb510 --- /dev/null +++ b/drivers/gpu/nvgpu/pci.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2016, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include "pci.h" +#include "gk20a/gk20a.h" +#include "gk20a/platform_gk20a.h" + +#define PCI_INTERFACE_NAME "nvgpu-pci%s" + +static int nvgpu_pci_tegra_probe(struct device *dev) +{ + return 0; +} + +static int nvgpu_pci_tegra_remove(struct device *dev) +{ + return 0; +} + +static bool nvgpu_pci_tegra_is_railgated(struct device *pdev) +{ + return false; +} + +static int nvgpu_pci_busy(struct device *dev) +{ + struct gk20a *g = get_gk20a(dev); + int err = 0; + + if (!g->power_on) + err = gk20a_pm_finalize_poweron(dev); + + return err; +} + +struct gk20a_platform nvgpu_pci_device = { + /* ptimer src frequency in hz */ + .ptimer_src_freq = 31250000, + + .probe = nvgpu_pci_tegra_probe, + .remove = nvgpu_pci_tegra_remove, + .busy = nvgpu_pci_busy, + + /* power management callbacks */ + .is_railgated = nvgpu_pci_tegra_is_railgated, + + .default_big_page_size = SZ_64K, +}; + +static struct pci_device_id nvgpu_pci_table[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), + .class = PCI_BASE_CLASS_DISPLAY << 16, + .class_mask = 0xff << 16, + }, + {} +}; + +static irqreturn_t nvgpu_pci_isr(int irq, void *dev_id) +{ + struct gk20a *g = dev_id; + irqreturn_t ret_stall; + irqreturn_t ret_nonstall; + + ret_stall = g->ops.mc.isr_stall(g); + ret_nonstall = g->ops.mc.isr_nonstall(g); + + return (ret_stall == IRQ_NONE && ret_nonstall == IRQ_NONE) ? + IRQ_NONE : IRQ_WAKE_THREAD; +} + +static irqreturn_t nvgpu_pci_intr_thread(int irq, void *dev_id) +{ + struct gk20a *g = dev_id; + + g->ops.mc.isr_thread_stall(g); + g->ops.mc.isr_thread_nonstall(g); + + return IRQ_HANDLED; +} + +static int nvgpu_pci_init_support(struct pci_dev *pdev) +{ + int err = 0; + struct gk20a *g = get_gk20a(&pdev->dev); + + g->regs = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (IS_ERR(g->regs)) { + gk20a_err(dev_from_gk20a(g), "failed to remap gk20a registers"); + err = PTR_ERR(g->regs); + goto fail; + } + + g->bar1 = ioremap(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); + if (IS_ERR(g->bar1)) { + gk20a_err(dev_from_gk20a(g), "failed to remap gk20a bar1"); + err = PTR_ERR(g->regs); + goto fail; + } + + g->regs_saved = g->regs; + g->bar1_saved = g->bar1; + + mutex_init(&g->dbg_sessions_lock); + mutex_init(&g->client_lock); + mutex_init(&g->ch_wdt_lock); + mutex_init(&g->poweroff_lock); + + g->remove_support = gk20a_remove_support; + return 0; + + fail: + gk20a_remove_support(&pdev->dev); + return err; +} + +static int nvgpu_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *pent) +{ + struct gk20a_platform *platform = &nvgpu_pci_device; + struct gk20a *g; + int err; + + pci_set_drvdata(pdev, platform); + + g = kzalloc(sizeof(struct gk20a), GFP_KERNEL); + if (!g) { + gk20a_err(&pdev->dev, "couldn't allocate gk20a support"); + return -ENOMEM; + } + + init_waitqueue_head(&g->sw_irq_stall_last_handled_wq); + init_waitqueue_head(&g->sw_irq_nonstall_last_handled_wq); + + platform->g = g; + g->dev = &pdev->dev; + + err = pci_enable_device(pdev); + if (err) + return err; + pci_set_master(pdev); + + g->irq_stall = pdev->irq; + g->irq_nonstall = pdev->irq; + if (g->irq_stall < 0) + return -ENXIO; + err = devm_request_threaded_irq(&pdev->dev, + g->irq_stall, + nvgpu_pci_isr, + nvgpu_pci_intr_thread, + IRQF_SHARED, "nvgpu", g); + if (err) { + gk20a_err(&pdev->dev, + "failed to request irq @ %d", g->irq_stall); + return err; + } + disable_irq(g->irq_stall); + + err = gk20a_user_init(&pdev->dev, PCI_INTERFACE_NAME); + if (err) + return err; + + err = nvgpu_pci_init_support(pdev); + if (err) + return err; + + init_rwsem(&g->busy_lock); + mutex_init(&platform->railgate_lock); + + spin_lock_init(&g->mc_enable_lock); + + gk20a_debug_init(&pdev->dev); + + /* Initialize the platform interface. */ + err = platform->probe(&pdev->dev); + if (err) { + gk20a_err(&pdev->dev, "platform probe failed"); + return err; + } + + /* Set DMA parameters to allow larger sgt lists */ + pdev->dev.dma_parms = &g->dma_parms; + dma_set_max_seg_size(&pdev->dev, UINT_MAX); + + g->gr_idle_timeout_default = + CONFIG_GK20A_DEFAULT_TIMEOUT; + if (tegra_platform_is_silicon()) + g->timeouts_enabled = true; + + g->runlist_interleave = true; + + g->timeslice_low_priority_us = 1300; + g->timeslice_medium_priority_us = 2600; + g->timeslice_high_priority_us = 5200; + + gk20a_create_sysfs(&pdev->dev); + + g->mm.has_physical_mode = false; + g->mm.vidmem_is_vidmem = true; + g->mm.ltc_enabled = true; + g->mm.ltc_enabled_debug = true; + g->mm.bypass_smmu = platform->bypass_smmu; + g->mm.disable_bigpage = platform->disable_bigpage; + + gk20a_init_gr(g); + + return 0; +} + +static void nvgpu_pci_remove(struct pci_dev *pdev) +{ + struct gk20a_platform *platform = gk20a_get_platform(&pdev->dev); + struct gk20a *g = get_gk20a(&pdev->dev); + + if (g->remove_support) + g->remove_support(g->dev); + + gk20a_user_deinit(g->dev); + + debugfs_remove_recursive(platform->debugfs); + debugfs_remove_recursive(platform->debugfs_alias); + + gk20a_remove_sysfs(g->dev); + + if (platform->remove) + platform->remove(g->dev); + + kfree(g); +} + +static struct pci_driver nvgpu_pci_driver = { + .name = "nvgpu", + .id_table = nvgpu_pci_table, + .probe = nvgpu_pci_probe, + .remove = nvgpu_pci_remove, +}; + +int __init nvgpu_pci_init(void) +{ + return pci_register_driver(&nvgpu_pci_driver); +} + +void __exit nvgpu_pci_exit(void) +{ + pci_unregister_driver(&nvgpu_pci_driver); +} diff --git a/drivers/gpu/nvgpu/pci.h b/drivers/gpu/nvgpu/pci.h new file mode 100644 index 00000000..cc6b77b1 --- /dev/null +++ b/drivers/gpu/nvgpu/pci.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef NVGPU_PCI_H +#define NVGPU_PCI_H + +#ifdef CONFIG_GK20A_PCI +int nvgpu_pci_init(void); +void nvgpu_pci_exit(void); +#else +static inline int nvgpu_pci_init(void) { return 0; } +static inline void nvgpu_pci_exit(void) {} +#endif + +#endif -- cgit v1.2.2