From 2a2c16af5f9f1ccfc93a13e820d5381e5c881e92 Mon Sep 17 00:00:00 2001 From: Terje Bergstrom Date: Wed, 18 Apr 2018 12:59:00 -0700 Subject: gpu: nvgpu: Move Linux files away from common Move all Linux source code files to drivers/gpu/nvgpu/os/linux from drivers/gpu/nvgpu/common/linux. This changes the meaning of common to be OS independent. JIRA NVGPU-598 JIRA NVGPU-601 Change-Id: Ib7f2a43d3688bb0d0b7dcc48469a6783fd988ce9 Signed-off-by: Terje Bergstrom Reviewed-on: https://git-master.nvidia.com/r/1747714 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/os/linux/vidmem.c | 262 ++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 drivers/gpu/nvgpu/os/linux/vidmem.c (limited to 'drivers/gpu/nvgpu/os/linux/vidmem.c') diff --git a/drivers/gpu/nvgpu/os/linux/vidmem.c b/drivers/gpu/nvgpu/os/linux/vidmem.c new file mode 100644 index 00000000..136d4a10 --- /dev/null +++ b/drivers/gpu/nvgpu/os/linux/vidmem.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2017, 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 + +#ifdef CONFIG_NVGPU_USE_TEGRA_ALLOC_FD +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "gk20a/gk20a.h" +#include "gk20a/mm_gk20a.h" + +bool nvgpu_addr_is_vidmem_page_alloc(u64 addr) +{ + return !!(addr & 1ULL); +} + +void nvgpu_vidmem_set_page_alloc(struct scatterlist *sgl, u64 addr) +{ + /* set bit 0 to indicate vidmem allocation */ + sg_dma_address(sgl) = (addr | 1ULL); +} + +struct nvgpu_page_alloc *nvgpu_vidmem_get_page_alloc(struct scatterlist *sgl) +{ + u64 addr; + + addr = sg_dma_address(sgl); + + if (nvgpu_addr_is_vidmem_page_alloc(addr)) + addr = addr & ~1ULL; + else + WARN_ON(1); + + return (struct nvgpu_page_alloc *)(uintptr_t)addr; +} + +static struct sg_table *gk20a_vidbuf_map_dma_buf( + struct dma_buf_attachment *attach, enum dma_data_direction dir) +{ + struct nvgpu_vidmem_buf *buf = attach->dmabuf->priv; + + return buf->mem->priv.sgt; +} + +static void gk20a_vidbuf_unmap_dma_buf(struct dma_buf_attachment *attach, + struct sg_table *sgt, + enum dma_data_direction dir) +{ +} + +static void gk20a_vidbuf_release(struct dma_buf *dmabuf) +{ + struct nvgpu_vidmem_buf *buf = dmabuf->priv; + struct nvgpu_vidmem_linux *linux_buf = buf->priv; + struct gk20a *g = buf->g; + + vidmem_dbg(g, "Releasing Linux VIDMEM buf: dmabuf=0x%p size=%zuKB", + dmabuf, buf->mem->size >> 10); + + if (linux_buf && linux_buf->dmabuf_priv_delete) + linux_buf->dmabuf_priv_delete(linux_buf->dmabuf_priv); + + nvgpu_kfree(g, linux_buf); + nvgpu_vidmem_buf_free(g, buf); + + gk20a_put(g); +} + +static void *gk20a_vidbuf_kmap(struct dma_buf *dmabuf, unsigned long page_num) +{ + WARN_ON("Not supported"); + return NULL; +} + +static void *gk20a_vidbuf_kmap_atomic(struct dma_buf *dmabuf, + unsigned long page_num) +{ + WARN_ON("Not supported"); + return NULL; +} + +static int gk20a_vidbuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) +{ + return -EINVAL; +} + +static int gk20a_vidbuf_set_private(struct dma_buf *dmabuf, + struct device *dev, void *priv, void (*delete)(void *priv)) +{ + struct nvgpu_vidmem_buf *buf = dmabuf->priv; + struct nvgpu_vidmem_linux *linux_buf = buf->priv; + + linux_buf->dmabuf_priv = priv; + linux_buf->dmabuf_priv_delete = delete; + + return 0; +} + +static void *gk20a_vidbuf_get_private(struct dma_buf *dmabuf, + struct device *dev) +{ + struct nvgpu_vidmem_buf *buf = dmabuf->priv; + struct nvgpu_vidmem_linux *linux_buf = buf->priv; + + return linux_buf->dmabuf_priv; +} + +static const struct dma_buf_ops gk20a_vidbuf_ops = { + .map_dma_buf = gk20a_vidbuf_map_dma_buf, + .unmap_dma_buf = gk20a_vidbuf_unmap_dma_buf, + .release = gk20a_vidbuf_release, + .kmap_atomic = gk20a_vidbuf_kmap_atomic, + .kmap = gk20a_vidbuf_kmap, + .mmap = gk20a_vidbuf_mmap, + .set_drvdata = gk20a_vidbuf_set_private, + .get_drvdata = gk20a_vidbuf_get_private, +}; + +static struct dma_buf *gk20a_vidbuf_export(struct nvgpu_vidmem_buf *buf) +{ + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.priv = buf; + exp_info.ops = &gk20a_vidbuf_ops; + exp_info.size = buf->mem->size; + exp_info.flags = O_RDWR; + + return dma_buf_export(&exp_info); +} + +struct gk20a *nvgpu_vidmem_buf_owner(struct dma_buf *dmabuf) +{ + struct nvgpu_vidmem_buf *buf = dmabuf->priv; + + if (dmabuf->ops != &gk20a_vidbuf_ops) + return NULL; + + return buf->g; +} + +int nvgpu_vidmem_export_linux(struct gk20a *g, size_t bytes) +{ + struct nvgpu_vidmem_buf *buf = NULL; + struct nvgpu_vidmem_linux *priv; + int err, fd; + + /* + * This ref is released when the dma_buf is closed. + */ + if (!gk20a_get(g)) + return -ENODEV; + + vidmem_dbg(g, "Allocating vidmem buf: %zu bytes", bytes); + + priv = nvgpu_kzalloc(g, sizeof(*priv)); + if (!priv) { + err = -ENOMEM; + goto fail; + } + + buf = nvgpu_vidmem_user_alloc(g, bytes); + if (IS_ERR(buf)) { + err = PTR_ERR(buf); + goto fail; + } + + priv->dmabuf = gk20a_vidbuf_export(buf); + if (IS_ERR(priv->dmabuf)) { + err = PTR_ERR(priv->dmabuf); + goto fail; + } + + buf->priv = priv; + +#ifdef CONFIG_NVGPU_USE_TEGRA_ALLOC_FD + fd = tegra_alloc_fd(current->files, 1024, O_RDWR); +#else + fd = get_unused_fd_flags(O_RDWR); +#endif + if (fd < 0) { + /* ->release frees what we have done */ + dma_buf_put(priv->dmabuf); + return fd; + } + + /* fclose() on this drops one ref, freeing the dma buf */ + fd_install(fd, priv->dmabuf->file); + + vidmem_dbg(g, "Alloced Linux VIDMEM buf: dmabuf=0x%p size=%zuKB", + priv->dmabuf, buf->mem->size >> 10); + + return fd; + +fail: + nvgpu_vidmem_buf_free(g, buf); + nvgpu_kfree(g, priv); + gk20a_put(g); + + vidmem_dbg(g, "Failed to alloc Linux VIDMEM buf: %d", err); + return err; +} + +int nvgpu_vidmem_buf_access_memory(struct gk20a *g, struct dma_buf *dmabuf, + void *buffer, u64 offset, u64 size, u32 cmd) +{ + struct nvgpu_vidmem_buf *vidmem_buf; + struct nvgpu_mem *mem; + int err = 0; + + if (gk20a_dmabuf_aperture(g, dmabuf) != APERTURE_VIDMEM) + return -EINVAL; + + vidmem_buf = dmabuf->priv; + mem = vidmem_buf->mem; + + switch (cmd) { + case NVGPU_DBG_GPU_IOCTL_ACCESS_FB_MEMORY_CMD_READ: + nvgpu_mem_rd_n(g, mem, offset, buffer, size); + break; + + case NVGPU_DBG_GPU_IOCTL_ACCESS_FB_MEMORY_CMD_WRITE: + nvgpu_mem_wr_n(g, mem, offset, buffer, size); + break; + + default: + err = -EINVAL; + } + + return err; +} + +void __nvgpu_mem_free_vidmem_alloc(struct gk20a *g, struct nvgpu_mem *vidmem) +{ + nvgpu_free(vidmem->allocator, + (u64)nvgpu_vidmem_get_page_alloc(vidmem->priv.sgt->sgl)); + nvgpu_free_sgtable(g, &vidmem->priv.sgt); +} -- cgit v1.2.2