diff --git a/arch/nvgpu-linux.yaml b/arch/nvgpu-linux.yaml index e4e074389..def0b35bd 100644 --- a/arch/nvgpu-linux.yaml +++ b/arch/nvgpu-linux.yaml @@ -232,6 +232,8 @@ vgpu: os/linux/vgpu/platform_vgpu_tegra.c, os/linux/vgpu/platform_vgpu_tegra.h, os/linux/vgpu/sysfs_vgpu.c, + os/linux/vgpu/vf_linux.c, + os/linux/vgpu/vf_linux.h, os/linux/vgpu/vgpu_common.c, os/linux/vgpu/vgpu_common.h, os/linux/vgpu/vgpu_ivc.c, diff --git a/drivers/gpu/nvgpu/Makefile b/drivers/gpu/nvgpu/Makefile index bb0fbfc02..c1c261134 100644 --- a/drivers/gpu/nvgpu/Makefile +++ b/drivers/gpu/nvgpu/Makefile @@ -627,6 +627,9 @@ nvgpu-$(CONFIG_NVGPU_GR_VIRTUALIZATION) += \ os/linux/vgpu/vgpu_linux.o \ os/linux/vgpu/gv11b/platform_gv11b_vgpu_tegra.o +nvgpu-$(CONFIG_NVGPU_GR_VIRTUALIZATION) += \ + os/linux/vgpu/vf_linux.o + ifeq ($(CONFIG_NVGPU_FECS_TRACE),y) nvgpu-$(CONFIG_NVGPU_GR_VIRTUALIZATION) += \ os/linux/vgpu/fecs_trace_vgpu_linux.o diff --git a/drivers/gpu/nvgpu/os/linux/pci.c b/drivers/gpu/nvgpu/os/linux/pci.c index ab611632f..42ab33f41 100644 --- a/drivers/gpu/nvgpu/os/linux/pci.c +++ b/drivers/gpu/nvgpu/os/linux/pci.c @@ -52,6 +52,8 @@ #include "driver_common.h" #include "dmabuf_priv.h" +#include "vgpu/vf_linux.h" + #if defined(CONFIG_NVGPU_HAL_NON_FUSA) && defined(CONFIG_NVGPU_NEXT) #include #endif @@ -564,10 +566,30 @@ static int nvgpu_pci_probe(struct pci_dev *pdev, u32 device_index = PCI_DEVICE_INDEX(pent->driver_data); u32 device_flags = PCI_DEVICE_FLAGS(pent->driver_data); + /* Allocate memory to hold platform data*/ + platform = (struct gk20a_platform *)kzalloc( + sizeof(struct gk20a_platform), GFP_KERNEL); + if (!platform) { + dev_err(&pdev->dev, "couldn't allocate platform data"); + return -ENOMEM; + } + + /* copy detected device data to allocated platform space*/ + err = nvgpu_pci_get_platform_data(platform, device_index); + if (err) + goto err_free_platform; + + if (platform->virtual_dev) { + err = vf_probe(pdev, platform); + if (err) + goto err_free_platform; + } + l = kzalloc(sizeof(*l), GFP_KERNEL); if (!l) { dev_err(&pdev->dev, "couldn't allocate gk20a support"); - return -ENOMEM; + err = -ENOMEM; + goto err_free_platform; } g = &l->g; @@ -578,27 +600,13 @@ static int nvgpu_pci_probe(struct pci_dev *pdev, nvgpu_kmem_init(g); - /* Allocate memory to hold platform data*/ - platform = (struct gk20a_platform *)nvgpu_kzalloc( g, - sizeof(struct gk20a_platform)); - if (!platform) { - dev_err(&pdev->dev, "couldn't allocate platform data"); - err = -ENOMEM; - goto err_free_l; - } - - /* copy detected device data to allocated platform space*/ - err = nvgpu_pci_get_platform_data(platform, device_index); - if (err) - goto err_free_platform; - g->is_pci_igpu = platform->is_pci_igpu; nvgpu_info(g, "is_pci_igpu: %s", g->is_pci_igpu ? "true" : "false"); pci_set_drvdata(pdev, platform); err = nvgpu_init_errata_flags(g); if (err) - goto err_free_platform; + goto err_free_l; err = nvgpu_init_enabled_flags(g); if (err) { @@ -783,13 +791,13 @@ err_disable_msi: nvgpu_free_enabled_flags(g); err_free_errata: nvgpu_free_errata_flags(g); -err_free_platform: - nvgpu_kfree(g, platform); err_free_l: if (g->is_pci_igpu) nvgpu_kmem_fini(g, NVGPU_KMEM_FINI_FORCE_CLEANUP); kfree(l); +err_free_platform: + kfree(platform); return err; } diff --git a/drivers/gpu/nvgpu/os/linux/vgpu/vf_linux.c b/drivers/gpu/nvgpu/os/linux/vgpu/vf_linux.c new file mode 100644 index 000000000..21844da1b --- /dev/null +++ b/drivers/gpu/nvgpu/os/linux/vgpu/vf_linux.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2023, 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 "os/linux/module.h" +#include "os/linux/os_linux.h" +#include "os/linux/platform_gk20a.h" +#include "os/linux/vgpu/vgpu_common.h" + +static irqreturn_t vf_isr(int irq, void *dev_id) +{ + struct gk20a *g = dev_id; + u32 ret_nonstall = nvgpu_cic_mon_intr_nonstall_isr(g); + + if (ret_nonstall == NVGPU_CIC_INTR_HANDLE) { + return IRQ_WAKE_THREAD; + } + + return IRQ_NONE; +} + +static irqreturn_t vf_intr_thread(int irq, void *dev_id) +{ + struct gk20a *g = dev_id; + + nvgpu_cic_mon_intr_nonstall_handle(g); + return IRQ_HANDLED; +} + +static int vf_pci_init_support(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + struct gk20a *g = get_gk20a(dev); + void __iomem *addr; + int err; + + addr = devm_ioremap(dev, pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (IS_ERR(addr)) { + nvgpu_err(g, "failed to remap gk20a registers"); + err = PTR_ERR(addr); + return err; + } + g->func_regs = (uintptr_t)addr; + + g->regs_bus_addr = pci_resource_start(pdev, 0); + if (!g->regs_bus_addr) { + nvgpu_err(g, "failed to read register bus offset"); + err = -ENODEV; + return err; + } + + addr = devm_ioremap(dev, pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); + if (IS_ERR(addr)) { + nvgpu_err(g, "failed to remap gk20a bar1"); + err = PTR_ERR(addr); + return err; + } + g->bar1 = (uintptr_t)addr; + + return 0; +} + +int vf_probe(struct pci_dev *pdev, struct gk20a_platform *platform) +{ + struct nvgpu_os_linux *l; + struct gk20a *g; + struct device_node *np; + int err; + + l = devm_kzalloc(&pdev->dev, sizeof(*l), GFP_KERNEL); + if (l == NULL) { + dev_err(&pdev->dev, "couldn't allocate gk20a support"); + return -ENOMEM; + } + + g = &l->g; + platform->g = g; + l->dev = &pdev->dev; + + g->log_mask = NVGPU_DEFAULT_DBG_MASK; + g->is_pci_igpu = platform->is_pci_igpu; + + pci_set_drvdata(pdev, platform); + + np = nvgpu_get_node(g); + if (of_dma_is_coherent(np)) { + nvgpu_set_enabled(g, NVGPU_USE_COHERENT_SYSMEM, true); + nvgpu_set_enabled(g, NVGPU_SUPPORT_IO_COHERENCE, true); + } + + err = pci_enable_device(pdev); + if (err) { + nvgpu_err(g, "enable device failed err=%d", err); + return err; + } + pci_set_master(pdev); + + g->pci_vendor_id = pdev->vendor; + g->pci_device_id = pdev->device; + g->pci_subsystem_vendor_id = pdev->subsystem_vendor; + g->pci_subsystem_device_id = pdev->subsystem_device; + g->pci_class = (pdev->class >> 8) & 0xFFFFU; // we only want base/sub + g->pci_revision = pdev->revision; + + err = pci_alloc_irq_vectors(pdev, 1, 64, PCI_IRQ_MSIX); + if (err < 0) { + nvgpu_err(g, + "MSI-X alloc failed, err=%d", err); + return err; + } + /* TODO: separate stall/non-stall interrupts once support multi-vector */ + l->interrupts.nonstall_size = err; + g->msi_enabled = true; + + /* TODO: support multiple nonstall irqs */ + l->interrupts.nonstall_line = pci_irq_vector(pdev, 0); + + err = devm_request_threaded_irq(&pdev->dev, + l->interrupts.nonstall_line, + vf_isr, + vf_intr_thread, + 0, "nvgpu", g); + if (err) { + nvgpu_err(g, + "failed to request irq @ %d err=%d", + l->interrupts.nonstall_line, err); + return err; + } + nvgpu_disable_irqs(g); + + err = vf_pci_init_support(pdev); + if (err) + return err; + + err = vgpu_probe_common(l); + if (err) { + nvgpu_err(g, "common probe failed, err=%d", err); + return err; + } + + g->probe_done = true; + + return 0; +} \ No newline at end of file diff --git a/drivers/gpu/nvgpu/os/linux/vgpu/vf_linux.h b/drivers/gpu/nvgpu/os/linux/vgpu/vf_linux.h new file mode 100644 index 000000000..51b34a89b --- /dev/null +++ b/drivers/gpu/nvgpu/os/linux/vgpu/vf_linux.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023, 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_VF_LINUX_H +#define NVGPU_VF_LINUX_H + +struct pci_dev; +struct gk20a_platform; + +#ifdef CONFIG_NVGPU_GR_VIRTUALIZATION +int vf_probe(struct pci_dev *pdev, struct gk20a_platform *platform); +#else +static inline int vf_probe(struct pci_dev *pdev, + struct gk20a_platform *platform) +{ + return -ENOSYS; +} +#endif + +#endif \ No newline at end of file