mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 05:04:02 +02:00
drm/xe/guc_ads: allocate UM queues in a separate BO
Move the UM queues into a dedicated BO (ads->um_queue_bo) and avoid
CPU memset operations on it, which eliminates the CPU as a potential
cacheline-polluting agent and helps maintain consistency between GAM
writes and GuC reads.
We also need to ensure the base_dpa for the queue is contiguous on hw
where this is used instead of a GGTT address. Another good reason to
split this out to a separate BO.
Fixes: 9c57bc0865 ("drm/xe/lnl: Drop force_probe requirement")
Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Cc: Matthew Auld <matthew.auld@intel.com>
Cc: <stable@vger.kernel.org> # v6.12+
Signed-off-by: Jia Yao <jia.yao@intel.com>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Link: https://patch.msgid.link/20260804165057.129529-2-jia.yao@intel.com
(cherry picked from commit 6af05de0dc19bbf3aaeec2020fe48b37c834b811)
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
This commit is contained in:
parent
fc64875790
commit
99b0181595
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef _XE_BO_H_
|
||||
#define _XE_BO_H_
|
||||
|
||||
#include <drm/drm_prime.h>
|
||||
#include <drm/ttm/ttm_tt.h>
|
||||
|
||||
#include "xe_bo_types.h"
|
||||
|
|
@ -548,6 +549,19 @@ void xe_bo_dev_fini(struct xe_bo_dev *bo_device);
|
|||
|
||||
struct sg_table *xe_bo_sg(struct xe_bo *bo);
|
||||
|
||||
/**
|
||||
* xe_bo_sg_is_contiguous() - Check if a BO's DMA address space is contiguous.
|
||||
* @bo: the BO to check (must have a valid sg table, i.e. !xe_bo_is_vram())
|
||||
* @len: required contiguous length in bytes
|
||||
*
|
||||
* Returns true if the first @len bytes of the BO are mapped to a contiguous
|
||||
* DMA address range.
|
||||
*/
|
||||
static inline bool xe_bo_sg_is_contiguous(struct xe_bo *bo, size_t len)
|
||||
{
|
||||
return drm_prime_get_contiguous_size(xe_bo_sg(bo)) >= len;
|
||||
}
|
||||
|
||||
/*
|
||||
* xe_sg_segment_size() - Provides upper limit for sg segment size.
|
||||
* @dev: device pointer
|
||||
|
|
|
|||
|
|
@ -714,6 +714,12 @@ static int xe_guc_realloc_post_hwconfig(struct xe_guc *guc)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (guc->ads.um_queue_bo) {
|
||||
ret = xe_managed_bo_reinit_in_vram(xe, tile, &guc->ads.um_queue_bo);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,10 +63,14 @@ ads_to_map(struct xe_guc_ads *ads)
|
|||
|
||||
/*
|
||||
* The Additional Data Struct (ADS) has pointers for different buffers used by
|
||||
* the GuC. One single gem object contains the ADS struct itself (guc_ads) and
|
||||
* all the extra buffers indirectly linked via the ADS struct's entries.
|
||||
* the GuC. One gem object (ads->bo) contains the ADS struct itself (guc_ads)
|
||||
* and most of the extra buffers linked via the ADS struct's entries. The UM
|
||||
* fault queues (PAGE_FAULT, PAGE_FAULT_RESPONSE, ACCESS_COUNTER rings) are
|
||||
* kept in a separate BO (ads->um_queue_bo) so that the full memset of ads->bo
|
||||
* performed on every GT reset does not discard fault descriptors already
|
||||
* written into the rings by the GPU.
|
||||
*
|
||||
* Layout of the ADS blob allocated for the GuC:
|
||||
* Layout of the ADS blob (ads->bo):
|
||||
*
|
||||
* +---------------------------------------+ <== base
|
||||
* | guc_ads |
|
||||
|
|
@ -98,10 +102,6 @@ ads_to_map(struct xe_guc_ads *ads)
|
|||
* +---------------------------------------+
|
||||
* | padding |
|
||||
* +---------------------------------------+ <== 4K aligned
|
||||
* | UM queues |
|
||||
* +---------------------------------------+
|
||||
* | padding |
|
||||
* +---------------------------------------+ <== 4K aligned
|
||||
* | private data |
|
||||
* +---------------------------------------+
|
||||
* | padding |
|
||||
|
|
@ -155,16 +155,6 @@ static size_t guc_ads_capture_size(struct xe_guc_ads *ads)
|
|||
return PAGE_ALIGN(ads->capture_size);
|
||||
}
|
||||
|
||||
static size_t guc_ads_um_queues_size(struct xe_guc_ads *ads)
|
||||
{
|
||||
struct xe_device *xe = ads_to_xe(ads);
|
||||
|
||||
if (!xe->info.has_usm)
|
||||
return 0;
|
||||
|
||||
return GUC_UM_QUEUE_SIZE * GUC_UM_HW_QUEUE_MAX;
|
||||
}
|
||||
|
||||
static size_t guc_ads_private_data_size(struct xe_guc_ads *ads)
|
||||
{
|
||||
return PAGE_ALIGN(ads_to_guc(ads)->fw.private_data_size);
|
||||
|
|
@ -205,22 +195,12 @@ static size_t guc_ads_capture_offset(struct xe_guc_ads *ads)
|
|||
return PAGE_ALIGN(offset);
|
||||
}
|
||||
|
||||
static size_t guc_ads_um_queues_offset(struct xe_guc_ads *ads)
|
||||
{
|
||||
u32 offset;
|
||||
|
||||
offset = guc_ads_capture_offset(ads) +
|
||||
guc_ads_capture_size(ads);
|
||||
|
||||
return PAGE_ALIGN(offset);
|
||||
}
|
||||
|
||||
static size_t guc_ads_private_data_offset(struct xe_guc_ads *ads)
|
||||
{
|
||||
size_t offset;
|
||||
|
||||
offset = guc_ads_um_queues_offset(ads) +
|
||||
guc_ads_um_queues_size(ads);
|
||||
offset = guc_ads_capture_offset(ads) +
|
||||
guc_ads_capture_size(ads);
|
||||
|
||||
return PAGE_ALIGN(offset);
|
||||
}
|
||||
|
|
@ -409,6 +389,46 @@ int xe_guc_ads_init(struct xe_guc_ads *ads)
|
|||
|
||||
ads->bo = bo;
|
||||
|
||||
if (xe->info.has_usm) {
|
||||
/*
|
||||
* Allocate a separate BO for the HW fault ring (UM queues).
|
||||
*
|
||||
* Round the size up to the next power of two so that
|
||||
* (system memory, no IOMMU) the TTM pool issues a single
|
||||
* alloc_pages(order=N) call, maximising the chance of getting
|
||||
* a physically contiguous block. GuC requires contiguous DPA.
|
||||
*/
|
||||
size_t um_size = roundup_pow_of_two(GUC_UM_QUEUE_SIZE *
|
||||
GUC_UM_HW_QUEUE_MAX);
|
||||
|
||||
u32 um_flags = XE_BO_FLAG_SYSTEM |
|
||||
XE_BO_FLAG_GGTT |
|
||||
XE_BO_FLAG_GGTT_INVALIDATE |
|
||||
XE_BO_FLAG_PINNED_NORESTORE;
|
||||
|
||||
bo = xe_managed_bo_create_pin_map(xe, tile, um_size, um_flags);
|
||||
if (IS_ERR(bo))
|
||||
return PTR_ERR(bo);
|
||||
|
||||
/*
|
||||
* On pre-Xe3p platforms, GAM (not GuC) accesses the UM queue
|
||||
* ring via base_dpa, which must be a contiguous DMA address
|
||||
* range. Verify that the allocated pages are contiguous in
|
||||
* DMA address space.
|
||||
*/
|
||||
if (!xe_bo_is_vram(bo) &&
|
||||
!xe_guc_using_main_gamctrl_queues(ads_to_guc(ads)) &&
|
||||
unlikely(!xe_bo_sg_is_contiguous(bo,
|
||||
GUC_UM_QUEUE_SIZE *
|
||||
GUC_UM_HW_QUEUE_MAX))) {
|
||||
drm_err(&xe->drm,
|
||||
"UM fault queue memory is not contiguous in DMA address space; GAM requires contiguous DPA\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ads->um_queue_bo = bo;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
ALLOW_ERROR_INJECTION(xe_guc_ads_init, ERRNO); /* See xe_pci_probe() */
|
||||
|
|
@ -820,7 +840,7 @@ static void guc_mmio_reg_state_init(struct xe_guc_ads *ads)
|
|||
|
||||
static void guc_um_init_params(struct xe_guc_ads *ads)
|
||||
{
|
||||
u32 um_queue_offset = guc_ads_um_queues_offset(ads);
|
||||
struct xe_bo *um_bo = ads->um_queue_bo;
|
||||
struct xe_guc *guc = ads_to_guc(ads);
|
||||
struct xe_device *xe = ads_to_xe(ads);
|
||||
u64 base_dpa;
|
||||
|
|
@ -830,8 +850,14 @@ static void guc_um_init_params(struct xe_guc_ads *ads)
|
|||
|
||||
with_dpa = !xe_guc_using_main_gamctrl_queues(guc);
|
||||
|
||||
base_ggtt = xe_bo_ggtt_addr(ads->bo) + um_queue_offset;
|
||||
base_dpa = xe_bo_main_addr(ads->bo, PAGE_SIZE) + um_queue_offset;
|
||||
if (um_bo) {
|
||||
/* All USM platforms: UM queues in dedicated um_queue_bo */
|
||||
base_ggtt = xe_bo_ggtt_addr(um_bo);
|
||||
base_dpa = xe_bo_main_addr(um_bo, PAGE_SIZE);
|
||||
} else {
|
||||
/* Platform does not support USM: no UM queues, nothing to do */
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < GUC_UM_HW_QUEUE_MAX; ++i) {
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@ struct xe_bo;
|
|||
struct xe_guc_ads {
|
||||
/** @bo: Xe BO for GuC ads blob */
|
||||
struct xe_bo *bo;
|
||||
/**
|
||||
* @um_queue_bo: Dedicated BO for the HW fault ring (UM queues).
|
||||
* NULL if the platform does not support USM.
|
||||
*/
|
||||
struct xe_bo *um_queue_bo;
|
||||
/** @golden_lrc_size: golden LRC size */
|
||||
size_t golden_lrc_size;
|
||||
/** @regset_size: size of register set passed to GuC for save/restore */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user