mirror of
https://github.com/torvalds/linux.git
synced 2026-04-20 07:43:57 -04:00
An upcoming change will use GuC buffer cache as a place where GuC migration data will be stored, and the memory requirement for that is larger than indirect data. Allow the caller to pass the size based on the intended usecase. Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Link: https://patch.msgid.link/20251112132220.516975-12-michal.winiarski@intel.com Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
208 lines
5.5 KiB
C
208 lines
5.5 KiB
C
// SPDX-License-Identifier: MIT
|
|
/*
|
|
* Copyright © 2024 Intel Corporation
|
|
*/
|
|
|
|
#include <linux/cleanup.h>
|
|
#include <drm/drm_managed.h>
|
|
|
|
#include "xe_assert.h"
|
|
#include "xe_bo.h"
|
|
#include "xe_gt_printk.h"
|
|
#include "xe_guc.h"
|
|
#include "xe_guc_buf.h"
|
|
#include "xe_sa.h"
|
|
|
|
#define XE_GUC_BUF_CACHE_DEFAULT_SIZE SZ_8K
|
|
|
|
static struct xe_guc *cache_to_guc(struct xe_guc_buf_cache *cache)
|
|
{
|
|
return container_of(cache, struct xe_guc, buf);
|
|
}
|
|
|
|
static struct xe_gt *cache_to_gt(struct xe_guc_buf_cache *cache)
|
|
{
|
|
return guc_to_gt(cache_to_guc(cache));
|
|
}
|
|
|
|
static int guc_buf_cache_init(struct xe_guc_buf_cache *cache, u32 size)
|
|
{
|
|
struct xe_gt *gt = cache_to_gt(cache);
|
|
struct xe_sa_manager *sam;
|
|
|
|
sam = __xe_sa_bo_manager_init(gt_to_tile(gt), size, 0, sizeof(u32));
|
|
if (IS_ERR(sam))
|
|
return PTR_ERR(sam);
|
|
cache->sam = sam;
|
|
|
|
xe_gt_dbg(gt, "reusable buffer with %u dwords at %#x for %ps\n",
|
|
xe_guc_buf_cache_dwords(cache), xe_bo_ggtt_addr(sam->bo),
|
|
__builtin_return_address(0));
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* xe_guc_buf_cache_init() - Initialize the GuC Buffer Cache.
|
|
* @cache: the &xe_guc_buf_cache to initialize
|
|
*
|
|
* The Buffer Cache allows to obtain a reusable buffer that can be used to pass
|
|
* data to GuC or read data from GuC without a need to create a ad-hoc allocation.
|
|
*
|
|
* Return: 0 on success or a negative error code on failure.
|
|
*/
|
|
int xe_guc_buf_cache_init(struct xe_guc_buf_cache *cache)
|
|
{
|
|
return guc_buf_cache_init(cache, XE_GUC_BUF_CACHE_DEFAULT_SIZE);
|
|
}
|
|
|
|
/**
|
|
* xe_guc_buf_cache_init_with_size() - Initialize the GuC Buffer Cache.
|
|
* @cache: the &xe_guc_buf_cache to initialize
|
|
* @size: size in bytes
|
|
*
|
|
* Like xe_guc_buf_cache_init(), except it allows the caller to make the cache
|
|
* buffer larger, allowing to accommodate larger objects.
|
|
*
|
|
* Return: 0 on success or a negative error code on failure.
|
|
*/
|
|
int xe_guc_buf_cache_init_with_size(struct xe_guc_buf_cache *cache, u32 size)
|
|
{
|
|
return guc_buf_cache_init(cache, max(XE_GUC_BUF_CACHE_DEFAULT_SIZE, size));
|
|
}
|
|
|
|
/**
|
|
* xe_guc_buf_cache_dwords() - Number of dwords the GuC Buffer Cache supports.
|
|
* @cache: the &xe_guc_buf_cache to query
|
|
*
|
|
* Return: a size of the largest reusable buffer (in dwords)
|
|
*/
|
|
u32 xe_guc_buf_cache_dwords(struct xe_guc_buf_cache *cache)
|
|
{
|
|
return cache->sam ? cache->sam->base.size / sizeof(u32) : 0;
|
|
}
|
|
|
|
/**
|
|
* xe_guc_buf_reserve() - Reserve a new sub-allocation.
|
|
* @cache: the &xe_guc_buf_cache where reserve sub-allocation
|
|
* @dwords: the requested size of the buffer in dwords
|
|
*
|
|
* Use xe_guc_buf_is_valid() to check if returned buffer reference is valid.
|
|
* Must use xe_guc_buf_release() to release a sub-allocation.
|
|
*
|
|
* Return: a &xe_guc_buf of new sub-allocation.
|
|
*/
|
|
struct xe_guc_buf xe_guc_buf_reserve(struct xe_guc_buf_cache *cache, u32 dwords)
|
|
{
|
|
struct drm_suballoc *sa;
|
|
|
|
if (cache->sam)
|
|
sa = __xe_sa_bo_new(cache->sam, dwords * sizeof(u32), GFP_ATOMIC);
|
|
else
|
|
sa = ERR_PTR(-EOPNOTSUPP);
|
|
|
|
return (struct xe_guc_buf){ .sa = sa };
|
|
}
|
|
|
|
/**
|
|
* xe_guc_buf_from_data() - Reserve a new sub-allocation using data.
|
|
* @cache: the &xe_guc_buf_cache where reserve sub-allocation
|
|
* @data: the data to flush the sub-allocation
|
|
* @size: the size of the data
|
|
*
|
|
* Similar to xe_guc_buf_reserve() but flushes @data to the GPU memory.
|
|
*
|
|
* Return: a &xe_guc_buf of new sub-allocation.
|
|
*/
|
|
struct xe_guc_buf xe_guc_buf_from_data(struct xe_guc_buf_cache *cache,
|
|
const void *data, size_t size)
|
|
{
|
|
struct drm_suballoc *sa;
|
|
|
|
sa = __xe_sa_bo_new(cache->sam, size, GFP_ATOMIC);
|
|
if (!IS_ERR(sa))
|
|
memcpy(xe_sa_bo_cpu_addr(sa), data, size);
|
|
|
|
return (struct xe_guc_buf){ .sa = sa };
|
|
}
|
|
|
|
/**
|
|
* xe_guc_buf_release() - Release a sub-allocation.
|
|
* @buf: the &xe_guc_buf to release
|
|
*
|
|
* Releases a sub-allocation reserved by the xe_guc_buf_reserve().
|
|
*/
|
|
void xe_guc_buf_release(const struct xe_guc_buf buf)
|
|
{
|
|
if (xe_guc_buf_is_valid(buf))
|
|
xe_sa_bo_free(buf.sa, NULL);
|
|
}
|
|
|
|
/**
|
|
* xe_guc_buf_sync_read() - Copy the data from the GPU memory to the sub-allocation.
|
|
* @buf: the &xe_guc_buf to sync
|
|
*
|
|
* Return: a CPU pointer of the sub-allocation.
|
|
*/
|
|
void *xe_guc_buf_sync_read(const struct xe_guc_buf buf)
|
|
{
|
|
xe_sa_bo_sync_read(buf.sa);
|
|
|
|
return xe_sa_bo_cpu_addr(buf.sa);
|
|
}
|
|
|
|
/**
|
|
* xe_guc_buf_flush() - Copy the data from the sub-allocation to the GPU memory.
|
|
* @buf: the &xe_guc_buf to flush
|
|
*
|
|
* Return: a GPU address of the sub-allocation.
|
|
*/
|
|
u64 xe_guc_buf_flush(const struct xe_guc_buf buf)
|
|
{
|
|
xe_sa_bo_flush_write(buf.sa);
|
|
return xe_sa_bo_gpu_addr(buf.sa);
|
|
}
|
|
|
|
/**
|
|
* xe_guc_buf_cpu_ptr() - Obtain a CPU pointer to the sub-allocation.
|
|
* @buf: the &xe_guc_buf to query
|
|
*
|
|
* Return: a CPU pointer of the sub-allocation.
|
|
*/
|
|
void *xe_guc_buf_cpu_ptr(const struct xe_guc_buf buf)
|
|
{
|
|
return xe_sa_bo_cpu_addr(buf.sa);
|
|
}
|
|
|
|
/**
|
|
* xe_guc_buf_gpu_addr() - Obtain a GPU address of the sub-allocation.
|
|
* @buf: the &xe_guc_buf to query
|
|
*
|
|
* Return: a GPU address of the sub-allocation.
|
|
*/
|
|
u64 xe_guc_buf_gpu_addr(const struct xe_guc_buf buf)
|
|
{
|
|
return xe_sa_bo_gpu_addr(buf.sa);
|
|
}
|
|
|
|
/**
|
|
* xe_guc_cache_gpu_addr_from_ptr() - Lookup a GPU address using the pointer.
|
|
* @cache: the &xe_guc_buf_cache with sub-allocations
|
|
* @ptr: the CPU pointer of the sub-allocation
|
|
* @size: the size of the data
|
|
*
|
|
* Return: a GPU address on success or 0 if the pointer was unrelated.
|
|
*/
|
|
u64 xe_guc_cache_gpu_addr_from_ptr(struct xe_guc_buf_cache *cache, const void *ptr, u32 size)
|
|
{
|
|
ptrdiff_t offset = ptr - cache->sam->cpu_ptr;
|
|
|
|
if (offset < 0 || offset + size > cache->sam->base.size)
|
|
return 0;
|
|
|
|
return xe_sa_manager_gpu_addr(cache->sam) + offset;
|
|
}
|
|
|
|
#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST)
|
|
#include "tests/xe_guc_buf_kunit.c"
|
|
#endif
|