linux/drivers/gpu/drm/i915/display/intel_plane_initial.c

434 lines
11 KiB
C
Raw Permalink Normal View History

// SPDX-License-Identifier: MIT
/*
* Copyright © 2021 Intel Corporation
*/
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
#include "gem/i915_gem_lmem.h"
#include "gem/i915_gem_region.h"
#include "i915_drv.h"
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
#include "intel_crtc.h"
#include "intel_display.h"
#include "intel_display_core.h"
#include "intel_display_types.h"
#include "intel_fb.h"
#include "intel_frontbuffer.h"
#include "intel_plane.h"
#include "intel_plane_initial.h"
void intel_plane_initial_vblank_wait(struct intel_crtc *crtc)
{
intel_crtc_wait_for_next_vblank(crtc);
}
static bool
intel_reuse_initial_plane_obj(struct intel_crtc *this,
const struct intel_initial_plane_config plane_configs[],
struct drm_framebuffer **fb,
struct i915_vma **vma)
{
struct intel_display *display = to_intel_display(this);
struct intel_crtc *crtc;
for_each_intel_crtc(display->drm, crtc) {
struct intel_plane *plane =
to_intel_plane(crtc->base.primary);
const struct intel_plane_state *plane_state =
to_intel_plane_state(plane->base.state);
const struct intel_crtc_state *crtc_state =
to_intel_crtc_state(crtc->base.state);
if (!crtc_state->uapi.active)
continue;
if (!plane_state->ggtt_vma)
continue;
if (plane_configs[this->pipe].base == plane_configs[crtc->pipe].base) {
*fb = plane_state->hw.fb;
*vma = plane_state->ggtt_vma;
return true;
}
}
return false;
}
static enum intel_memory_type
initial_plane_memory_type(struct intel_display *display)
{
struct drm_i915_private *i915 = to_i915(display->drm);
if (display->platform.dgfx)
return INTEL_MEMORY_LOCAL;
else if (HAS_LMEMBAR_SMEM_STOLEN(i915))
return INTEL_MEMORY_STOLEN_LOCAL;
else
return INTEL_MEMORY_STOLEN_SYSTEM;
}
static bool
initial_plane_phys(struct intel_display *display,
struct intel_initial_plane_config *plane_config)
{
struct drm_i915_private *i915 = to_i915(display->drm);
struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
struct intel_memory_region *mem;
enum intel_memory_type mem_type;
bool is_present, is_local;
dma_addr_t dma_addr;
u32 base;
mem_type = initial_plane_memory_type(display);
mem = intel_memory_region_by_type(i915, mem_type);
if (!mem) {
drm_dbg_kms(display->drm,
"Initial plane memory region (type %s) not initialized\n",
intel_memory_type_str(mem_type));
return false;
}
base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT);
dma_addr = intel_ggtt_read_entry(&ggtt->vm, base, &is_present, &is_local);
if (!is_present) {
drm_err(display->drm,
"Initial plane FB PTE not present\n");
return false;
}
if (intel_memory_type_is_local(mem->type) != is_local) {
drm_err(display->drm,
"Initial plane FB PTE unsuitable for %s\n",
mem->region.name);
return false;
}
if (dma_addr < mem->region.start || dma_addr > mem->region.end) {
drm_err(display->drm,
"Initial plane programming using invalid range, dma_addr=%pa (%s [%pa-%pa])\n",
&dma_addr, mem->region.name, &mem->region.start, &mem->region.end);
return false;
}
drm_dbg(display->drm,
"Using dma_addr=%pa, based on initial plane programming\n",
&dma_addr);
plane_config->phys_base = dma_addr - mem->region.start;
plane_config->mem = mem;
return true;
}
static struct i915_vma *
initial_plane_vma(struct intel_display *display,
struct intel_initial_plane_config *plane_config)
{
struct drm_i915_private *i915 = to_i915(display->drm);
struct intel_memory_region *mem;
struct drm_i915_gem_object *obj;
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
struct drm_mm_node orig_mm = {};
struct i915_vma *vma;
resource_size_t phys_base;
u32 base, size;
u64 pinctl;
if (plane_config->size == 0)
return NULL;
if (!initial_plane_phys(display, plane_config))
return NULL;
phys_base = plane_config->phys_base;
mem = plane_config->mem;
base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT);
size = round_up(plane_config->base + plane_config->size,
mem->min_page_size);
size -= base;
/*
* If the FB is too big, just don't use it since fbdev is not very
* important and we should probably use that space with FBC or other
* features.
*/
if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) &&
mem == i915->mm.stolen_region &&
size * 2 > i915->dsm.usable_size) {
drm_dbg_kms(display->drm, "Initial FB size exceeds half of stolen, discarding\n");
return NULL;
}
obj = i915_gem_object_create_region_at(mem, phys_base, size,
I915_BO_ALLOC_USER |
I915_BO_PREALLOC);
if (IS_ERR(obj)) {
drm_dbg_kms(display->drm, "Failed to preallocate initial FB in %s\n",
mem->region.name);
return NULL;
}
/*
* Mark it WT ahead of time to avoid changing the
* cache_level during fbdev initialization. The
* unbind there would get stuck waiting for rcu.
*/
i915_gem_object_set_cache_coherency(obj, HAS_WT(i915) ?
I915_CACHE_WT : I915_CACHE_NONE);
switch (plane_config->tiling) {
case I915_TILING_NONE:
break;
case I915_TILING_X:
case I915_TILING_Y:
obj->tiling_and_stride =
plane_config->fb->base.pitches[0] |
plane_config->tiling;
break;
default:
MISSING_CASE(plane_config->tiling);
goto err_obj;
}
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
/*
* MTL GOP likes to place the framebuffer high up in ggtt,
* which can cause problems for ggtt_reserve_guc_top().
* Try to pin it to a low ggtt address instead to avoid that.
*/
base = 0;
if (base != plane_config->base) {
struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
int ret;
/*
* Make sure the original and new locations
* can't overlap. That would corrupt the original
* PTEs which are still being used for scanout.
*/
ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &orig_mm,
size, plane_config->base,
I915_COLOR_UNEVICTABLE, PIN_NOEVICT);
if (ret)
goto err_obj;
}
vma = i915_vma_instance(obj, &to_gt(i915)->ggtt->vm, NULL);
if (IS_ERR(vma))
goto err_obj;
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
retry:
pinctl = PIN_GLOBAL | PIN_OFFSET_FIXED | base;
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
if (!i915_gem_object_is_lmem(obj))
pinctl |= PIN_MAPPABLE;
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
if (i915_vma_pin(vma, 0, 0, pinctl)) {
if (drm_mm_node_allocated(&orig_mm)) {
drm_mm_remove_node(&orig_mm);
/*
* Try again, but this time pin
* it to its original location.
*/
base = plane_config->base;
goto retry;
}
goto err_obj;
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
}
if (i915_gem_object_is_tiled(obj) &&
!i915_vma_is_map_and_fenceable(vma))
goto err_obj;
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
if (drm_mm_node_allocated(&orig_mm))
drm_mm_remove_node(&orig_mm);
drm_dbg_kms(display->drm,
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
"Initial plane fb bound to 0x%x in the ggtt (original 0x%x)\n",
i915_ggtt_offset(vma), plane_config->base);
return vma;
err_obj:
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
if (drm_mm_node_allocated(&orig_mm))
drm_mm_remove_node(&orig_mm);
i915_gem_object_put(obj);
return NULL;
}
static bool
intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
struct intel_initial_plane_config *plane_config)
{
struct intel_display *display = to_intel_display(crtc);
struct drm_mode_fb_cmd2 mode_cmd = {};
struct drm_framebuffer *fb = &plane_config->fb->base;
struct i915_vma *vma;
switch (fb->modifier) {
case DRM_FORMAT_MOD_LINEAR:
case I915_FORMAT_MOD_X_TILED:
case I915_FORMAT_MOD_Y_TILED:
case I915_FORMAT_MOD_4_TILED:
break;
default:
drm_dbg(display->drm,
"Unsupported modifier for initial FB: 0x%llx\n",
fb->modifier);
return false;
}
vma = initial_plane_vma(display, plane_config);
if (!vma)
return false;
mode_cmd.pixel_format = fb->format->format;
mode_cmd.width = fb->width;
mode_cmd.height = fb->height;
mode_cmd.pitches[0] = fb->pitches[0];
mode_cmd.modifier[0] = fb->modifier;
mode_cmd.flags = DRM_MODE_FB_MODIFIERS;
if (intel_framebuffer_init(to_intel_framebuffer(fb),
intel_bo_to_drm_bo(vma->obj),
fb->format, &mode_cmd)) {
drm_dbg_kms(display->drm, "intel fb init failed\n");
goto err_vma;
}
plane_config->vma = vma;
return true;
err_vma:
i915_vma_put(vma);
return false;
}
static void
intel_find_initial_plane_obj(struct intel_crtc *crtc,
struct intel_initial_plane_config plane_configs[])
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
struct intel_initial_plane_config *plane_config =
&plane_configs[crtc->pipe];
struct intel_plane *plane =
to_intel_plane(crtc->base.primary);
struct intel_plane_state *plane_state =
to_intel_plane_state(plane->base.state);
struct drm_framebuffer *fb;
struct i915_vma *vma;
/*
* TODO:
* Disable planes if get_initial_plane_config() failed.
* Make sure things work if the surface base is not page aligned.
*/
if (!plane_config->fb)
return;
if (intel_alloc_initial_plane_obj(crtc, plane_config)) {
fb = &plane_config->fb->base;
vma = plane_config->vma;
goto valid_fb;
}
/*
* Failed to alloc the obj, check to see if we should share
* an fb with another CRTC instead
*/
if (intel_reuse_initial_plane_obj(crtc, plane_configs, &fb, &vma))
goto valid_fb;
/*
* We've failed to reconstruct the BIOS FB. Current display state
* indicates that the primary plane is visible, but has a NULL FB,
* which will lead to problems later if we don't fix it up. The
* simplest solution is to just disable the primary plane now and
* pretend the BIOS never had it enabled.
*/
intel_plane_disable_noatomic(crtc, plane);
return;
valid_fb:
plane_state->uapi.rotation = plane_config->rotation;
intel_fb_fill_view(to_intel_framebuffer(fb),
plane_state->uapi.rotation, &plane_state->view);
__i915_vma_pin(vma);
plane_state->ggtt_vma = i915_vma_get(vma);
if (intel_plane_uses_fence(plane_state) &&
i915_vma_pin_fence(vma) == 0 && vma->fence)
plane_state->flags |= PLANE_HAS_FENCE;
plane_state->uapi.src_x = 0;
plane_state->uapi.src_y = 0;
plane_state->uapi.src_w = fb->width << 16;
plane_state->uapi.src_h = fb->height << 16;
plane_state->uapi.crtc_x = 0;
plane_state->uapi.crtc_y = 0;
plane_state->uapi.crtc_w = fb->width;
plane_state->uapi.crtc_h = fb->height;
if (plane_config->tiling)
dev_priv->preserve_bios_swizzle = true;
plane_state->uapi.fb = fb;
drm_framebuffer_get(fb);
plane_state->uapi.crtc = &crtc->base;
intel_plane_copy_uapi_to_hw_state(plane_state, plane_state, crtc);
atomic_or(plane->frontbuffer_bit, &to_intel_frontbuffer(fb)->bits);
}
static void plane_config_fini(struct intel_initial_plane_config *plane_config)
{
if (plane_config->fb) {
struct drm_framebuffer *fb = &plane_config->fb->base;
/* We may only have the stub and not a full framebuffer */
if (drm_framebuffer_read_refcount(fb))
drm_framebuffer_put(fb);
else
kfree(fb);
}
if (plane_config->vma)
i915_vma_put(plane_config->vma);
}
void intel_initial_plane_config(struct intel_display *display)
{
struct intel_initial_plane_config plane_configs[I915_MAX_PIPES] = {};
struct intel_crtc *crtc;
for_each_intel_crtc(display->drm, crtc) {
struct intel_initial_plane_config *plane_config =
&plane_configs[crtc->pipe];
if (!to_intel_crtc_state(crtc->base.state)->uapi.active)
continue;
/*
* Note that reserving the BIOS fb up front prevents us
* from stuffing other stolen allocations like the ring
* on top. This prevents some ugliness at boot time, and
* can even allow for smooth boot transitions if the BIOS
* fb is large enough for the active pipe configuration.
*/
display->funcs.display->get_initial_plane_config(crtc, plane_config);
/*
* If the fb is shared between multiple heads, we'll
* just get the first one.
*/
intel_find_initial_plane_obj(crtc, plane_configs);
if (display->funcs.display->fixup_initial_plane_config(crtc, plane_config))
intel_plane_initial_vblank_wait(crtc);
drm/i915: Try to relocate the BIOS fb to the start of ggtt On MTL the GOP (for whatever reason) likes to bind its framebuffer high up in the ggtt address space. This can conflict with whatever ggtt_reserve_guc_top() is trying to do, and the result is that ggtt_reserve_guc_top() fails and then we proceed to explode when trying to tear down the driver. Thus far I haven't analyzed what causes the actual fireworks, but it's not super important as even if it didn't explode we'd still fail the driver load and the user would be left with an unusable GPU. To remedy this (without having to figure out exactly what ggtt_reserve_guc_top() is trying to achieve) we can attempt to relocate the BIOS framebuffer to a lower ggtt address. We can do this at this early point in driver init because nothing else is supposed to be clobbering the ggtt yet. So we simply change where in the ggtt we pin the vma, the original PTEs will be left as is, and the new PTEs will get written with the same dma addresses. The plane will keep on scanning out from the original PTEs until we are done with the whole process, and at that point we rewrite the plane's surface address register to point at the new ggtt address. Since we don't need a specific ggtt address for the plane (apart from needing it to land in the mappable region for normal stolen objects) we'll just try to pin it without a fixed offset first. It should end up at the lowest available address (which really should be 0 at this point in the driver init). If that fails we'll fall back to just pinning it exactly to the origianal address. To make sure we don't accidentlally pin it partially over the original ggtt range (as that would corrupt the original PTEs) we reserve the original range temporarily during this process. v2: Try to pin explicitly to ggtt offset 0 as otherwise DG2 puts it even higher (atm we have no PIN_LOW flag to force it low) v3: "fix" xe Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com> Tested-by: Paz Zcharya <pazz@chromium.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240202224340.30647-16-ville.syrjala@linux.intel.com Acked-by: Lucas De Marchi <lucas.demarchi@intel.com>
2024-02-03 00:43:39 +02:00
plane_config_fini(plane_config);
}
}