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/pci.c | 264 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 drivers/gpu/nvgpu/pci.c (limited to 'drivers/gpu/nvgpu/pci.c') 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); +} -- cgit v1.2.2