mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
088880ddc0
With softpin we allow the userspace to take control over the GPU virtual address space. The new capability is relected by a bump of the minor DRM version. There are a few restrictions for userspace to take into account: 1. The kernel reserves a bit of the address space to implement zero page faulting and mapping of the kernel internal ring buffer. Userspace can query the kernel for the first usable GPU VM address via ETNAVIV_PARAM_SOFTPIN_START_ADDR. 2. We only allow softpin on GPUs, which implement proper process separation via PPAS. If softpin is not available the softpin start address will be set to ~0. 3. Softpin is all or nothing. A submit using softpin must not use any address fixups via relocs. Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de> Reviewed-by: Guido Günther <agx@sigxcpu.org>
143 lines
3.5 KiB
C
143 lines
3.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2017-2018 Etnaviv Project
|
|
*/
|
|
|
|
#include <linux/dma-mapping.h>
|
|
|
|
#include <drm/drm_mm.h>
|
|
|
|
#include "etnaviv_cmdbuf.h"
|
|
#include "etnaviv_gem.h"
|
|
#include "etnaviv_gpu.h"
|
|
#include "etnaviv_mmu.h"
|
|
#include "etnaviv_perfmon.h"
|
|
|
|
#define SUBALLOC_SIZE SZ_512K
|
|
#define SUBALLOC_GRANULE SZ_4K
|
|
#define SUBALLOC_GRANULES (SUBALLOC_SIZE / SUBALLOC_GRANULE)
|
|
|
|
struct etnaviv_cmdbuf_suballoc {
|
|
/* suballocated dma buffer properties */
|
|
struct device *dev;
|
|
void *vaddr;
|
|
dma_addr_t paddr;
|
|
|
|
/* allocation management */
|
|
struct mutex lock;
|
|
DECLARE_BITMAP(granule_map, SUBALLOC_GRANULES);
|
|
int free_space;
|
|
wait_queue_head_t free_event;
|
|
};
|
|
|
|
struct etnaviv_cmdbuf_suballoc *
|
|
etnaviv_cmdbuf_suballoc_new(struct device *dev)
|
|
{
|
|
struct etnaviv_cmdbuf_suballoc *suballoc;
|
|
int ret;
|
|
|
|
suballoc = kzalloc(sizeof(*suballoc), GFP_KERNEL);
|
|
if (!suballoc)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
suballoc->dev = dev;
|
|
mutex_init(&suballoc->lock);
|
|
init_waitqueue_head(&suballoc->free_event);
|
|
|
|
BUILD_BUG_ON(ETNAVIV_SOFTPIN_START_ADDRESS < SUBALLOC_SIZE);
|
|
suballoc->vaddr = dma_alloc_wc(dev, SUBALLOC_SIZE,
|
|
&suballoc->paddr, GFP_KERNEL);
|
|
if (!suballoc->vaddr) {
|
|
ret = -ENOMEM;
|
|
goto free_suballoc;
|
|
}
|
|
|
|
return suballoc;
|
|
|
|
free_suballoc:
|
|
kfree(suballoc);
|
|
|
|
return ERR_PTR(ret);
|
|
}
|
|
|
|
int etnaviv_cmdbuf_suballoc_map(struct etnaviv_cmdbuf_suballoc *suballoc,
|
|
struct etnaviv_iommu_context *context,
|
|
struct etnaviv_vram_mapping *mapping,
|
|
u32 memory_base)
|
|
{
|
|
return etnaviv_iommu_get_suballoc_va(context, mapping, memory_base,
|
|
suballoc->paddr, SUBALLOC_SIZE);
|
|
}
|
|
|
|
void etnaviv_cmdbuf_suballoc_unmap(struct etnaviv_iommu_context *context,
|
|
struct etnaviv_vram_mapping *mapping)
|
|
{
|
|
etnaviv_iommu_put_suballoc_va(context, mapping);
|
|
}
|
|
|
|
void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc)
|
|
{
|
|
dma_free_wc(suballoc->dev, SUBALLOC_SIZE, suballoc->vaddr,
|
|
suballoc->paddr);
|
|
kfree(suballoc);
|
|
}
|
|
|
|
int etnaviv_cmdbuf_init(struct etnaviv_cmdbuf_suballoc *suballoc,
|
|
struct etnaviv_cmdbuf *cmdbuf, u32 size)
|
|
{
|
|
int granule_offs, order, ret;
|
|
|
|
cmdbuf->suballoc = suballoc;
|
|
cmdbuf->size = size;
|
|
|
|
order = order_base_2(ALIGN(size, SUBALLOC_GRANULE) / SUBALLOC_GRANULE);
|
|
retry:
|
|
mutex_lock(&suballoc->lock);
|
|
granule_offs = bitmap_find_free_region(suballoc->granule_map,
|
|
SUBALLOC_GRANULES, order);
|
|
if (granule_offs < 0) {
|
|
suballoc->free_space = 0;
|
|
mutex_unlock(&suballoc->lock);
|
|
ret = wait_event_interruptible_timeout(suballoc->free_event,
|
|
suballoc->free_space,
|
|
msecs_to_jiffies(10 * 1000));
|
|
if (!ret) {
|
|
dev_err(suballoc->dev,
|
|
"Timeout waiting for cmdbuf space\n");
|
|
return -ETIMEDOUT;
|
|
}
|
|
goto retry;
|
|
}
|
|
mutex_unlock(&suballoc->lock);
|
|
cmdbuf->suballoc_offset = granule_offs * SUBALLOC_GRANULE;
|
|
cmdbuf->vaddr = suballoc->vaddr + cmdbuf->suballoc_offset;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
|
|
{
|
|
struct etnaviv_cmdbuf_suballoc *suballoc = cmdbuf->suballoc;
|
|
int order = order_base_2(ALIGN(cmdbuf->size, SUBALLOC_GRANULE) /
|
|
SUBALLOC_GRANULE);
|
|
|
|
mutex_lock(&suballoc->lock);
|
|
bitmap_release_region(suballoc->granule_map,
|
|
cmdbuf->suballoc_offset / SUBALLOC_GRANULE,
|
|
order);
|
|
suballoc->free_space = 1;
|
|
mutex_unlock(&suballoc->lock);
|
|
wake_up_all(&suballoc->free_event);
|
|
}
|
|
|
|
u32 etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf,
|
|
struct etnaviv_vram_mapping *mapping)
|
|
{
|
|
return mapping->iova + buf->suballoc_offset;
|
|
}
|
|
|
|
dma_addr_t etnaviv_cmdbuf_get_pa(struct etnaviv_cmdbuf *buf)
|
|
{
|
|
return buf->suballoc->paddr + buf->suballoc_offset;
|
|
}
|