Skip to content

Commit 0162411

Browse files
committed
drm/i915/uc: use different ggtt pin offsets for uc loads
Our current FW loading process is the same for all FWs: - Pin FW to GGTT at the start of the ggtt->uc_fw node - Load the FW - Unpin This worked because we didn't have a case where 2 FWs would be loaded on the same GGTT at the same time. On MTL, however, this can happen if both GTs are reset at the same time, so we can't pin everything in the same spot and we need to use separate offset. For simplicity, instead of calculating the exact required size, we reserve a 2MB slot for each fw. v2: fail fetch if FW is > 2MBs, improve comments (John) v3: more comment improvements (John) Signed-off-by: Daniele Ceraolo Spurio <[email protected]> Cc: John Harrison <[email protected]> Cc: Alan Previn <[email protected]> Reviewed-by: John Harrison <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 9deca79 commit 0162411

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed

drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,17 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
575575
err = firmware_request_nowarn(&fw, uc_fw->file_selected.path, dev);
576576
memcpy(&file_ideal, &uc_fw->file_wanted, sizeof(file_ideal));
577577

578+
if (!err && fw->size > INTEL_UC_RSVD_GGTT_PER_FW) {
579+
drm_err(&i915->drm,
580+
"%s firmware %s: size (%zuKB) exceeds max supported size (%uKB)\n",
581+
intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
582+
fw->size / SZ_1K, INTEL_UC_RSVD_GGTT_PER_FW / SZ_1K);
583+
584+
/* try to find another blob to load */
585+
release_firmware(fw);
586+
err = -ENOENT;
587+
}
588+
578589
/* Any error is terminal if overriding. Don't bother searching for older versions */
579590
if (err && intel_uc_fw_is_overridden(uc_fw))
580591
goto fail;
@@ -677,14 +688,30 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
677688

678689
static u32 uc_fw_ggtt_offset(struct intel_uc_fw *uc_fw)
679690
{
680-
struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt;
691+
struct intel_gt *gt = __uc_fw_to_gt(uc_fw);
692+
struct i915_ggtt *ggtt = gt->ggtt;
681693
struct drm_mm_node *node = &ggtt->uc_fw;
694+
u32 offset = uc_fw->type * INTEL_UC_RSVD_GGTT_PER_FW;
695+
696+
/*
697+
* The media GT shares the GGTT with the root GT, which means that
698+
* we need to use different offsets for the binaries on the media GT.
699+
* To keep the math simple, we use 8MB for the root tile and 8MB for
700+
* the media one. This will need to be updated if we ever have more
701+
* than 1 media GT.
702+
*/
703+
BUILD_BUG_ON(INTEL_UC_FW_NUM_TYPES * INTEL_UC_RSVD_GGTT_PER_FW > SZ_8M);
704+
GEM_BUG_ON(gt->type == GT_MEDIA && gt->info.id > 1);
705+
if (gt->type == GT_MEDIA)
706+
offset += SZ_8M;
682707

683708
GEM_BUG_ON(!drm_mm_node_allocated(node));
684709
GEM_BUG_ON(upper_32_bits(node->start));
685710
GEM_BUG_ON(upper_32_bits(node->start + node->size - 1));
711+
GEM_BUG_ON(offset + uc_fw->obj->base.size > node->size);
712+
GEM_BUG_ON(uc_fw->obj->base.size > INTEL_UC_RSVD_GGTT_PER_FW);
686713

687-
return lower_32_bits(node->start);
714+
return lower_32_bits(node->start + offset);
688715
}
689716

690717
static void uc_fw_bind_ggtt(struct intel_uc_fw *uc_fw)
@@ -699,7 +726,6 @@ static void uc_fw_bind_ggtt(struct intel_uc_fw *uc_fw)
699726
dummy->bi.pages = obj->mm.pages;
700727

701728
GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
702-
GEM_BUG_ON(dummy->node_size > ggtt->uc_fw.size);
703729

704730
/* uc_fw->obj cache domains were not controlled across suspend */
705731
if (i915_gem_object_has_struct_page(obj))

drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#ifndef _INTEL_UC_FW_H_
77
#define _INTEL_UC_FW_H_
88

9+
#include <linux/sizes.h>
910
#include <linux/types.h>
1011
#include "intel_uc_fw_abi.h"
1112
#include "intel_device_info.h"
@@ -114,6 +115,19 @@ struct intel_uc_fw {
114115
(uc)->fw.file_selected.minor_ver, \
115116
(uc)->fw.file_selected.patch_ver))
116117

118+
/*
119+
* When we load the uC binaries, we pin them in a reserved section at the top of
120+
* the GGTT, which is ~18 MBs. On multi-GT systems where the GTs share the GGTT,
121+
* we also need to make sure that each binary is pinned to a unique location
122+
* during load, because the different GT can go through the FW load at the same
123+
* time (see uc_fw_ggtt_offset() for details).
124+
* Given that the available space is much greater than what is required by the
125+
* binaries, to keep things simple instead of dynamically partitioning the
126+
* reserved section to make space for all the blobs we can just reserve a static
127+
* chunk for each binary.
128+
*/
129+
#define INTEL_UC_RSVD_GGTT_PER_FW SZ_2M
130+
117131
#ifdef CONFIG_DRM_I915_DEBUG_GUC
118132
void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
119133
enum intel_uc_fw_status status);

0 commit comments

Comments
 (0)