gpu: nvgpu: Prepare for adding host1x support

To prepare for supporting the upstream host1x driver with NVGPU,
move functions that are common using either the upstream host1x
driver or the downstream nvhost driver into a common file.

Bug 3156385

Change-Id: I33a3b55cfa3eb4c03b7047b62f26a75f407b2dd4
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2429980
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: Alex Waterman <alexw@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Jon Hunter
2020-10-09 16:17:00 +01:00
committed by Alex Waterman
parent 29dc4e509a
commit d16259ccc9
4 changed files with 158 additions and 126 deletions

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#include <linux/dma-mapping.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
#include <nvgpu/gk20a.h>
#include <nvgpu/nvhost.h>
#include <nvgpu/dma.h>
#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;
}