[PATCH 10/13] drm/xe/guc: Introduce the GuC Buffer Cache

Matthew Brost matthew.brost at intel.com
Thu Dec 12 03:30:56 UTC 2024


On Thu, Dec 12, 2024 at 02:01:38AM +0100, Michal Wajdeczko wrote:
> The purpose of the GuC Buffer Cache is to maintain a set ofreusable
> buffers that could be used while sending some of the CTB H2G actions
> that require separate buffer with indirect data. Currently only few
> PF actions need this so initialize it only when running as a PF.
> 
> Signed-off-by: Michal Wajdeczko <michal.wajdeczko at intel.com>
> Cc: Matthew Brost <matthew.brost at intel.com>
> Cc: Rodrigo Vivi <rodrigo.vivi at intel.com>
> ---
> v2: base it on xe_sa_manager instead (Matt, Rodrigo)
> ---
>  drivers/gpu/drm/xe/Makefile           |   1 +
>  drivers/gpu/drm/xe/xe_guc.c           |   5 +
>  drivers/gpu/drm/xe/xe_guc_buf.c       | 172 ++++++++++++++++++++++++++
>  drivers/gpu/drm/xe/xe_guc_buf.h       |  47 +++++++
>  drivers/gpu/drm/xe/xe_guc_buf_types.h |  28 +++++
>  drivers/gpu/drm/xe/xe_guc_types.h     |   3 +
>  6 files changed, 256 insertions(+)
>  create mode 100644 drivers/gpu/drm/xe/xe_guc_buf.c
>  create mode 100644 drivers/gpu/drm/xe/xe_guc_buf.h
>  create mode 100644 drivers/gpu/drm/xe/xe_guc_buf_types.h
> 
> diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
> index 7730e0596299..2e50a697f549 100644
> --- a/drivers/gpu/drm/xe/Makefile
> +++ b/drivers/gpu/drm/xe/Makefile
> @@ -56,6 +56,7 @@ xe-y += xe_bb.o \
>  	xe_gt_topology.o \
>  	xe_guc.o \
>  	xe_guc_ads.o \
> +	xe_guc_buf.o \
>  	xe_guc_capture.o \
>  	xe_guc_ct.o \
>  	xe_guc_db_mgr.o \
> diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c
> index 4e2868efb620..af62586f3528 100644
> --- a/drivers/gpu/drm/xe/xe_guc.c
> +++ b/drivers/gpu/drm/xe/xe_guc.c
> @@ -23,6 +23,7 @@
>  #include "xe_gt_sriov_vf.h"
>  #include "xe_gt_throttle.h"
>  #include "xe_guc_ads.h"
> +#include "xe_guc_buf.h"
>  #include "xe_guc_capture.h"
>  #include "xe_guc_ct.h"
>  #include "xe_guc_db_mgr.h"
> @@ -654,6 +655,10 @@ int xe_guc_init(struct xe_guc *guc)
>  	if (ret)
>  		goto out;
>  
> +	ret = xe_guc_buf_cache_init(&guc->buf);
> +	if (ret)
> +		goto out;
> +
>  	xe_uc_fw_change_status(&guc->fw, XE_UC_FIRMWARE_LOADABLE);
>  
>  	ret = devm_add_action_or_reset(xe->drm.dev, guc_fini_hw, guc);
> diff --git a/drivers/gpu/drm/xe/xe_guc_buf.c b/drivers/gpu/drm/xe/xe_guc_buf.c
> new file mode 100644
> index 000000000000..261c7c74417f
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_guc_buf.c
> @@ -0,0 +1,172 @@
> +// 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"
> +
> +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));
> +}
> +
> +/**
> + * 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
> + * indirect H2G data to 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)
> +{
> +	struct xe_gt *gt = cache_to_gt(cache);
> +	struct xe_sa_manager *sam;
> +
> +	/* XXX: currently it's useful only for the PF actions */
> +	if (!IS_SRIOV_PF(gt_to_xe(gt)))
> +		return 0;
> +
> +	sam = __xe_sa_bo_manager_init(gt_to_tile(gt), SZ_8K, 0, sizeof(u32));

Same comment on patch #8, let's reach an agreement on guard usage before RBing this.

> +	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_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(32), 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_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 cache->sam->gpu_addr + offset;
> +}
> diff --git a/drivers/gpu/drm/xe/xe_guc_buf.h b/drivers/gpu/drm/xe/xe_guc_buf.h
> new file mode 100644
> index 000000000000..0d67604d96bd
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_guc_buf.h
> @@ -0,0 +1,47 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2024 Intel Corporation
> + */
> +
> +#ifndef _XE_GUC_BUF_H_
> +#define _XE_GUC_BUF_H_
> +
> +#include <linux/cleanup.h>
> +#include <linux/err.h>
> +
> +#include "xe_guc_buf_types.h"
> +
> +int xe_guc_buf_cache_init(struct xe_guc_buf_cache *cache);
> +u32 xe_guc_buf_cache_dwords(struct xe_guc_buf_cache *cache);
> +struct xe_guc_buf xe_guc_buf_reserve(struct xe_guc_buf_cache *cache, u32 dwords);
> +struct xe_guc_buf xe_guc_buf_from_data(struct xe_guc_buf_cache *cache,
> +				       const void *data, size_t size);
> +void xe_guc_buf_release(const struct xe_guc_buf buf);
> +
> +/**
> + * xe_guc_buf_is_valid() - Check if a buffer reference is valid.
> + * @buf: the &xe_guc_buf reference to check
> + *
> + * Return: true if @ref represents a valid sub-allication.
> + */
> +static inline bool xe_guc_buf_is_valid(const struct xe_guc_buf buf)
> +{
> +	return !IS_ERR_OR_NULL(buf.sa);
> +}
> +
> +void *xe_guc_buf_cpu_ptr(const struct xe_guc_buf buf);
> +u64 xe_guc_buf_flush(const struct xe_guc_buf buf);
> +u64 xe_guc_buf_gpu_addr(const struct xe_guc_buf buf);
> +u64 xe_guc_cache_gpu_addr_from_ptr(struct xe_guc_buf_cache *cache, const void *ptr, u32 size);
> +
> +DEFINE_CLASS(xe_guc_buf, struct xe_guc_buf,
> +	     xe_guc_buf_release(_T),
> +	     xe_guc_buf_reserve(cache, num),
> +	     struct xe_guc_buf_cache *cache, u32 num);
> +
> +DEFINE_CLASS(xe_guc_buf_from_data, struct xe_guc_buf,
> +	     xe_guc_buf_release(_T),
> +	     xe_guc_buf_from_data(cache, data, size),
> +	     struct xe_guc_buf_cache *cache, const void *data, size_t size);
> +
> +#endif
> diff --git a/drivers/gpu/drm/xe/xe_guc_buf_types.h b/drivers/gpu/drm/xe/xe_guc_buf_types.h
> new file mode 100644
> index 000000000000..9e123d71c064
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_guc_buf_types.h
> @@ -0,0 +1,28 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2024 Intel Corporation
> + */
> +
> +#ifndef _XE_GUC_BUF_TYPES_H_
> +#define _XE_GUC_BUF_TYPES_H_
> +
> +struct drm_suballoc;
> +struct xe_sa_manager;
> +
> +/**
> + * struct xe_guc_buf_cache - GuC Data Buffer Cache.
> + */
> +struct xe_guc_buf_cache {
> +	/* private: internal sub-allocation manager */

I think this generate kerenl doc complaints.

i.e. Should be:

/* @sam: private - internal sub-allocation manager */

> +	struct xe_sa_manager *sam;
> +};
> +
> +/**
> + * struct xe_guc_buf - GuC Data Buffer Reference.
> + */
> +struct xe_guc_buf {
> +	/* private: internal sub-allocation reference */

Same here.

Matt

> +	struct drm_suballoc *sa;
> +};
> +
> +#endif
> diff --git a/drivers/gpu/drm/xe/xe_guc_types.h b/drivers/gpu/drm/xe/xe_guc_types.h
> index 83a41ebcdc91..573aa6308380 100644
> --- a/drivers/gpu/drm/xe/xe_guc_types.h
> +++ b/drivers/gpu/drm/xe/xe_guc_types.h
> @@ -11,6 +11,7 @@
>  
>  #include "regs/xe_reg_defs.h"
>  #include "xe_guc_ads_types.h"
> +#include "xe_guc_buf_types.h"
>  #include "xe_guc_ct_types.h"
>  #include "xe_guc_fwif.h"
>  #include "xe_guc_log_types.h"
> @@ -58,6 +59,8 @@ struct xe_guc {
>  	struct xe_guc_ads ads;
>  	/** @ct: GuC ct */
>  	struct xe_guc_ct ct;
> +	/** @buf: GuC Buffer Cache manager */
> +	struct xe_guc_buf_cache buf;
>  	/** @capture: the error-state-capture module's data and objects */
>  	struct xe_guc_state_capture *capture;
>  	/** @pc: GuC Power Conservation */
> -- 
> 2.47.1
> 


More information about the Intel-xe mailing list