diff --git a/arch/nvgpu-linux.yaml b/arch/nvgpu-linux.yaml index 143175232..54881f0d6 100644 --- a/arch/nvgpu-linux.yaml +++ b/arch/nvgpu-linux.yaml @@ -137,6 +137,7 @@ nvgpu_mem: nvhost: sources: [ os/linux/nvhost.c, + os/linux/nvhost_common.c, os/linux/nvhost_priv.h ] nvlink: diff --git a/drivers/gpu/nvgpu/Makefile b/drivers/gpu/nvgpu/Makefile index afc26dbe2..930c3d3af 100644 --- a/drivers/gpu/nvgpu/Makefile +++ b/drivers/gpu/nvgpu/Makefile @@ -472,6 +472,7 @@ endif nvgpu-$(CONFIG_TEGRA_GK20A_NVHOST) += \ os/linux/nvhost.o \ + os/linux/nvhost_common.o \ hal/sync/syncpt_cmdbuf_gk20a.o \ hal/sync/syncpt_cmdbuf_gv11b.o \ hal/sync/syncpt_cmdbuf_gv11b_fusa.o \ diff --git a/drivers/gpu/nvgpu/os/linux/nvhost.c b/drivers/gpu/nvgpu/os/linux/nvhost.c index 35ee8f9a8..853bf8cef 100644 --- a/drivers/gpu/nvgpu/os/linux/nvhost.c +++ b/drivers/gpu/nvgpu/os/linux/nvhost.c @@ -21,6 +21,8 @@ #include #include +#include +#include #include #include #include @@ -64,28 +66,6 @@ int nvgpu_get_nvhost_dev(struct gk20a *g) return 0; } -void nvgpu_free_nvhost_dev(struct gk20a *g) -{ - if (nvgpu_iommuable(g) && !nvgpu_is_enabled(g, NVGPU_SUPPORT_NVLINK)) { - struct device *dev = dev_from_gk20a(g); - struct nvgpu_mem *mem = &g->syncpt_mem; - - dma_unmap_sg_attrs(dev, mem->priv.sgt->sgl, 1, - DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); - sg_free_table(mem->priv.sgt); - nvgpu_kfree(g, mem->priv.sgt); - } - nvgpu_kfree(g, g->nvhost); -} - -bool nvgpu_has_syncpoints(struct gk20a *g) -{ - struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); - - return nvgpu_is_enabled(g, NVGPU_HAS_SYNCPOINTS) && - !l->disable_syncpoints; -} - int nvgpu_nvhost_module_busy_ext( struct nvgpu_nvhost_dev *nvhost_dev) { @@ -190,32 +170,6 @@ void nvgpu_nvhost_syncpt_set_safe_state( } } -int nvgpu_nvhost_create_symlink(struct gk20a *g) -{ - struct device *dev = dev_from_gk20a(g); - int err = 0; - - if (g->nvhost && - (dev->parent != &g->nvhost->host1x_pdev->dev)) { - err = sysfs_create_link(&g->nvhost->host1x_pdev->dev.kobj, - &dev->kobj, - dev_name(dev)); - } - - return err; -} - -void nvgpu_nvhost_remove_symlink(struct gk20a *g) -{ - struct device *dev = dev_from_gk20a(g); - - if (g->nvhost && - (dev->parent != &g->nvhost->host1x_pdev->dev)) { - sysfs_remove_link(&g->nvhost->host1x_pdev->dev.kobj, - dev_name(dev)); - } -} - int nvgpu_nvhost_get_syncpt_aperture( struct nvgpu_nvhost_dev *nvhost_dev, u64 *base, size_t *size) @@ -229,81 +183,3 @@ u32 nvgpu_nvhost_syncpt_unit_interface_get_byte_offset(struct gk20a *g, { return nvhost_syncpt_unit_interface_get_byte_offset(syncpt_id); } - -int nvgpu_nvhost_syncpt_init(struct gk20a *g) -{ - int err = 0; - struct nvgpu_mem *mem = &g->syncpt_mem; - - if (!nvgpu_has_syncpoints(g)) - return -ENOSYS; - - err = nvgpu_get_nvhost_dev(g); - if (err) { - nvgpu_err(g, "host1x device not available"); - err = -ENOSYS; - goto fail_sync; - } - - err = nvgpu_nvhost_get_syncpt_aperture( - g->nvhost, - &g->syncpt_unit_base, - &g->syncpt_unit_size); - if (err) { - nvgpu_err(g, "Failed to get syncpt interface"); - err = -ENOSYS; - goto fail_sync; - } - - /* - * If IOMMU is enabled, create iova for syncpt region. This iova is then - * used to create nvgpu_mem for syncpt by nvgpu_mem_create_from_phys. - * For entire syncpt shim read-only mapping full iova range is used and - * for a given syncpt read-write mapping only a part of iova range is - * used. Instead of creating another variable to store the sgt, - * g->syncpt_mem's priv field is used which later on is needed for - * freeing the mapping in deinit. - */ - if (nvgpu_iommuable(g) && !nvgpu_is_enabled(g, NVGPU_SUPPORT_NVLINK)) { - struct device *dev = dev_from_gk20a(g); - struct scatterlist *sg; - - mem->priv.sgt = nvgpu_kzalloc(g, sizeof(struct sg_table)); - if (!mem->priv.sgt) { - err = -ENOMEM; - goto fail_sync; - } - - err = sg_alloc_table(mem->priv.sgt, 1, GFP_KERNEL); - if (err) { - err = -ENOMEM; - goto fail_kfree; - } - sg = mem->priv.sgt->sgl; - sg_set_page(sg, phys_to_page(g->syncpt_unit_base), - g->syncpt_unit_size, 0); - err = dma_map_sg_attrs(dev, sg, 1, - DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); - /* dma_map_sg_attrs returns 0 on errors */ - if (err == 0) { - nvgpu_err(g, "iova creation for syncpoint failed"); - err = -ENOMEM; - goto fail_sgt; - } - g->syncpt_unit_base = sg_dma_address(sg); - } - - g->syncpt_size = - nvgpu_nvhost_syncpt_unit_interface_get_byte_offset(g, 1); - nvgpu_info(g, "syncpt_unit_base %llx syncpt_unit_size %zx size %x\n", - g->syncpt_unit_base, g->syncpt_unit_size, - g->syncpt_size); - return 0; -fail_sgt: - sg_free_table(mem->priv.sgt); -fail_kfree: - nvgpu_kfree(g, mem->priv.sgt); -fail_sync: - nvgpu_set_enabled(g, NVGPU_HAS_SYNCPOINTS, false); - return err; -} diff --git a/drivers/gpu/nvgpu/os/linux/nvhost_common.c b/drivers/gpu/nvgpu/os/linux/nvhost_common.c new file mode 100644 index 000000000..0a3c8d687 --- /dev/null +++ b/drivers/gpu/nvgpu/os/linux/nvhost_common.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2017-2020, 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 +#include +#include + +#include "nvhost_priv.h" + +#include "os_linux.h" +#include "module.h" + +void nvgpu_free_nvhost_dev(struct gk20a *g) +{ + if (nvgpu_iommuable(g) && !nvgpu_is_enabled(g, NVGPU_SUPPORT_NVLINK)) { + struct device *dev = dev_from_gk20a(g); + struct nvgpu_mem *mem = &g->syncpt_mem; + + dma_unmap_sg_attrs(dev, mem->priv.sgt->sgl, 1, + DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); + sg_free_table(mem->priv.sgt); + nvgpu_kfree(g, mem->priv.sgt); + } + nvgpu_kfree(g, g->nvhost); +} + +bool nvgpu_has_syncpoints(struct gk20a *g) +{ + struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); + + return nvgpu_is_enabled(g, NVGPU_HAS_SYNCPOINTS) && + !l->disable_syncpoints; +} + +int nvgpu_nvhost_create_symlink(struct gk20a *g) +{ + struct device *dev = dev_from_gk20a(g); + int err = 0; + + if (g->nvhost && + (dev->parent != &g->nvhost->host1x_pdev->dev)) { + err = sysfs_create_link(&g->nvhost->host1x_pdev->dev.kobj, + &dev->kobj, + dev_name(dev)); + } + + return err; +} + +void nvgpu_nvhost_remove_symlink(struct gk20a *g) +{ + struct device *dev = dev_from_gk20a(g); + + if (g->nvhost && + (dev->parent != &g->nvhost->host1x_pdev->dev)) { + sysfs_remove_link(&g->nvhost->host1x_pdev->dev.kobj, + dev_name(dev)); + } +} + +int nvgpu_nvhost_syncpt_init(struct gk20a *g) +{ + int err = 0; + struct nvgpu_mem *mem = &g->syncpt_mem; + + if (!nvgpu_has_syncpoints(g)) + return -ENOSYS; + + err = nvgpu_get_nvhost_dev(g); + if (err) { + nvgpu_err(g, "host1x device not available"); + err = -ENOSYS; + goto fail_sync; + } + + err = nvgpu_nvhost_get_syncpt_aperture( + g->nvhost, + &g->syncpt_unit_base, + &g->syncpt_unit_size); + if (err) { + nvgpu_err(g, "Failed to get syncpt interface"); + err = -ENOSYS; + goto fail_sync; + } + + /* + * If IOMMU is enabled, create iova for syncpt region. This iova is then + * used to create nvgpu_mem for syncpt by nvgpu_mem_create_from_phys. + * For entire syncpt shim read-only mapping full iova range is used and + * for a given syncpt read-write mapping only a part of iova range is + * used. Instead of creating another variable to store the sgt, + * g->syncpt_mem's priv field is used which later on is needed for + * freeing the mapping in deinit. + */ + if (nvgpu_iommuable(g) && !nvgpu_is_enabled(g, NVGPU_SUPPORT_NVLINK)) { + struct device *dev = dev_from_gk20a(g); + struct scatterlist *sg; + + mem->priv.sgt = nvgpu_kzalloc(g, sizeof(struct sg_table)); + if (!mem->priv.sgt) { + err = -ENOMEM; + goto fail_sync; + } + + err = sg_alloc_table(mem->priv.sgt, 1, GFP_KERNEL); + if (err) { + err = -ENOMEM; + goto fail_kfree; + } + sg = mem->priv.sgt->sgl; + sg_set_page(sg, phys_to_page(g->syncpt_unit_base), + g->syncpt_unit_size, 0); + err = dma_map_sg_attrs(dev, sg, 1, + DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); + /* dma_map_sg_attrs returns 0 on errors */ + if (err == 0) { + nvgpu_err(g, "iova creation for syncpoint failed"); + err = -ENOMEM; + goto fail_sgt; + } + g->syncpt_unit_base = sg_dma_address(sg); + } + + g->syncpt_size = + nvgpu_nvhost_syncpt_unit_interface_get_byte_offset(g, 1); + nvgpu_info(g, "syncpt_unit_base %llx syncpt_unit_size %zx size %x\n", + g->syncpt_unit_base, g->syncpt_unit_size, + g->syncpt_size); + return 0; +fail_sgt: + sg_free_table(mem->priv.sgt); +fail_kfree: + nvgpu_kfree(g, mem->priv.sgt); +fail_sync: + nvgpu_set_enabled(g, NVGPU_HAS_SYNCPOINTS, false); + return err; +}