Cross-subsystem Changes:

- Overflow: add range_overflows and range_end_overflows (Jani)
 
 Core Changes:
 - Get rid of dev->struct_mutex (Luiz)
 
 Non-display related:
  - GVT: Remove redundant ternary operators (Liao)
  - Various i915_utils clean-ups (Jani)
 
  Display related:
  - Wait PSR idle before on dsb commit (Jouni)
  - Fix size for for_each_set_bit() in abox iteration (Jani)
  - Abstract figuring out encoder name (Jani)
  - Remove FBC modulo 4 restriction for ADL-P+ (Uma)
  - Panic: refactor framebuffer allocation (Jani)
  - Backlight luminance control improvements (Suraj, Aaron)
  - Add intel_display_device_present (Jani)
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEbSBwaO7dZQkcLOKj+mJfZA7rE8oFAmjEIKwACgkQ+mJfZA7r
 E8o0+wf+Ora59wlwzifwcTCGxz6AoCFqdWLrsG//WACiB80fAj2/adABZsDjAoT9
 1BFFYUzqmmWXKfeRjKTiO3uMF42aKpp87oDW5BvVr4lxB50Qf8hZWxrFT1NfLb7e
 7pGlJvJKPN8IaHtJ3ObgOL8uDZtynucQE8z+FuOxXWY+IQFFNtkUSWwEu+TQfgUM
 Osr004NtfjfJH1ZqvhzlQVyys1EnoldaqPtc0g8gqYKY9CyihUn29YnJ8cmBa4cn
 M1VD7+3H0Ekgd5khiwyYg9oIoMFlBFppDVsr8vdl0YAZNaE7gZPSk86iBw0KhEb/
 Z49FlYwMTktY5d++qjBXjNACObePUg==
 =MUrL
 -----END PGP SIGNATURE-----

Merge tag 'drm-intel-next-2025-09-12' of https://gitlab.freedesktop.org/drm/i915/kernel into drm-next

Cross-subsystem Changes:
- Overflow: add range_overflows and range_end_overflows (Jani)

Core Changes:
- Get rid of dev->struct_mutex (Luiz)

Non-display related:
 - GVT: Remove redundant ternary operators (Liao)
 - Various i915_utils clean-ups (Jani)

 Display related:
 - Wait PSR idle before on dsb commit (Jouni)
 - Fix size for for_each_set_bit() in abox iteration (Jani)
 - Abstract figuring out encoder name (Jani)
 - Remove FBC modulo 4 restriction for ADL-P+ (Uma)
 - Panic: refactor framebuffer allocation (Jani)
 - Backlight luminance control improvements (Suraj, Aaron)
 - Add intel_display_device_present (Jani)

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://lore.kernel.org/r/aMxX_lBxm7wd5wmi@intel.com
This commit is contained in:
Dave Airlie 2025-09-19 12:59:29 +10:00
commit 748f41f353
82 changed files with 771 additions and 622 deletions

View File

@ -358,8 +358,6 @@ Locking Guidelines
#. All locking rules and interface contracts with cross-driver interfaces
(dma-buf, dma_fence) need to be followed.
#. No struct_mutex anywhere in the code
#. dma_resv will be the outermost lock (when needed) and ww_acquire_ctx
is to be hoisted at highest level and passed down within i915_gem_ctx
in the call chain
@ -367,11 +365,6 @@ Locking Guidelines
#. While holding lru/memory manager (buddy, drm_mm, whatever) locks
system memory allocations are not allowed
* Enforce this by priming lockdep (with fs_reclaim). If we
allocate memory while holding these looks we get a rehash
of the shrinker vs. struct_mutex saga, and that would be
real bad.
#. Do not nest different lru/memory manager locks within each other.
Take them in turn to update memory allocations, relying on the objects
dma_resv ww_mutex to serialize against other operations.

View File

@ -173,31 +173,6 @@ Contact: Simona Vetter
Level: Intermediate
Get rid of dev->struct_mutex from GEM drivers
---------------------------------------------
``dev->struct_mutex`` is the Big DRM Lock from legacy days and infested
everything. Nowadays in modern drivers the only bit where it's mandatory is
serializing GEM buffer object destruction. Which unfortunately means drivers
have to keep track of that lock and either call ``unreference`` or
``unreference_locked`` depending upon context.
Core GEM doesn't have a need for ``struct_mutex`` any more since kernel 4.8,
and there's a GEM object ``free`` callback for any drivers which are
entirely ``struct_mutex`` free.
For drivers that need ``struct_mutex`` it should be replaced with a driver-
private lock. The tricky part is the BO free functions, since those can't
reliably take that lock any more. Instead state needs to be protected with
suitable subordinate locks or some cleanup work pushed to a worker thread. For
performance-critical drivers it might also be better to go with a more
fine-grained per-buffer object and per-context lockings scheme. Currently only
the ``msm`` and `i915` drivers use ``struct_mutex``.
Contact: Simona Vetter, respective driver maintainers
Level: Advanced
Move Buffer Object Locking to dma_resv_lock()
---------------------------------------------

View File

@ -696,7 +696,6 @@ static void drm_dev_init_release(struct drm_device *dev, void *res)
mutex_destroy(&dev->master_mutex);
mutex_destroy(&dev->clientlist_mutex);
mutex_destroy(&dev->filelist_mutex);
mutex_destroy(&dev->struct_mutex);
}
static int drm_dev_init(struct drm_device *dev,
@ -737,7 +736,6 @@ static int drm_dev_init(struct drm_device *dev,
INIT_LIST_HEAD(&dev->vblank_event_list);
spin_lock_init(&dev->event_lock);
mutex_init(&dev->struct_mutex);
mutex_init(&dev->filelist_mutex);
mutex_init(&dev->clientlist_mutex);
mutex_init(&dev->master_mutex);

View File

@ -32,6 +32,7 @@ i915-y += \
i915_scatterlist.o \
i915_switcheroo.o \
i915_sysfs.o \
i915_timer_util.o \
i915_utils.o \
intel_clock_gating.o \
intel_cpu_info.o \
@ -280,6 +281,7 @@ i915-y += \
display/intel_modeset_setup.o \
display/intel_modeset_verify.o \
display/intel_overlay.o \
display/intel_panic.o \
display/intel_pch.o \
display/intel_pch_display.o \
display/intel_pch_refclk.o \

View File

@ -15,7 +15,6 @@
#include "i9xx_plane.h"
#include "i9xx_plane_regs.h"
#include "intel_atomic.h"
#include "intel_bo.h"
#include "intel_de.h"
#include "intel_display_irq.h"
#include "intel_display_regs.h"
@ -23,6 +22,7 @@
#include "intel_fb.h"
#include "intel_fbc.h"
#include "intel_frontbuffer.h"
#include "intel_panic.h"
#include "intel_plane.h"
#include "intel_sprite.h"
@ -1178,7 +1178,7 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc,
drm_WARN_ON(display->drm, pipe != crtc->pipe);
intel_fb = intel_bo_alloc_framebuffer();
intel_fb = intel_framebuffer_alloc();
if (!intel_fb) {
drm_dbg_kms(display->drm, "failed to alloc fb\n");
return;

View File

@ -59,18 +59,3 @@ void intel_bo_describe(struct seq_file *m, struct drm_gem_object *obj)
{
i915_debugfs_describe_obj(m, to_intel_bo(obj));
}
struct intel_framebuffer *intel_bo_alloc_framebuffer(void)
{
return i915_gem_object_alloc_framebuffer();
}
int intel_bo_panic_setup(struct drm_scanout_buffer *sb)
{
return i915_gem_object_panic_setup(sb);
}
void intel_bo_panic_finish(struct intel_framebuffer *fb)
{
return i915_gem_object_panic_finish(fb);
}

View File

@ -25,8 +25,5 @@ struct intel_frontbuffer *intel_bo_set_frontbuffer(struct drm_gem_object *obj,
struct intel_frontbuffer *front);
void intel_bo_describe(struct seq_file *m, struct drm_gem_object *obj);
struct intel_framebuffer *intel_bo_alloc_framebuffer(void);
int intel_bo_panic_setup(struct drm_scanout_buffer *sb);
void intel_bo_panic_finish(struct intel_framebuffer *fb);
#endif /* __INTEL_BO__ */

View File

@ -26,6 +26,7 @@
*/
#include <linux/iopoll.h>
#include <linux/seq_buf.h>
#include <linux/string_helpers.h>
#include <drm/display/drm_dp_helper.h>
@ -5067,11 +5068,45 @@ static bool port_in_use(struct intel_display *display, enum port port)
return false;
}
static const char *intel_ddi_encoder_name(struct intel_display *display,
enum port port, enum phy phy,
struct seq_buf *s)
{
if (DISPLAY_VER(display) >= 13 && port >= PORT_D_XELPD) {
seq_buf_printf(s, "DDI %c/PHY %c",
port_name(port - PORT_D_XELPD + PORT_D),
phy_name(phy));
} else if (DISPLAY_VER(display) >= 12) {
enum tc_port tc_port = intel_port_to_tc(display, port);
seq_buf_printf(s, "DDI %s%c/PHY %s%c",
port >= PORT_TC1 ? "TC" : "",
port >= PORT_TC1 ? port_tc_name(port) : port_name(port),
tc_port != TC_PORT_NONE ? "TC" : "",
tc_port != TC_PORT_NONE ? tc_port_name(tc_port) : phy_name(phy));
} else if (DISPLAY_VER(display) >= 11) {
enum tc_port tc_port = intel_port_to_tc(display, port);
seq_buf_printf(s, "DDI %c%s/PHY %s%c",
port_name(port),
port >= PORT_C ? " (TC)" : "",
tc_port != TC_PORT_NONE ? "TC" : "",
tc_port != TC_PORT_NONE ? tc_port_name(tc_port) : phy_name(phy));
} else {
seq_buf_printf(s, "DDI %c/PHY %c", port_name(port), phy_name(phy));
}
drm_WARN_ON(display->drm, seq_buf_has_overflowed(s));
return seq_buf_str(s);
}
void intel_ddi_init(struct intel_display *display,
const struct intel_bios_encoder_data *devdata)
{
struct intel_digital_port *dig_port;
struct intel_encoder *encoder;
DECLARE_SEQ_BUF(encoder_name, 20);
bool init_hdmi, init_dp;
enum port port;
enum phy phy;
@ -5156,37 +5191,9 @@ void intel_ddi_init(struct intel_display *display,
encoder = &dig_port->base;
encoder->devdata = devdata;
if (DISPLAY_VER(display) >= 13 && port >= PORT_D_XELPD) {
drm_encoder_init(display->drm, &encoder->base, &intel_ddi_funcs,
DRM_MODE_ENCODER_TMDS,
"DDI %c/PHY %c",
port_name(port - PORT_D_XELPD + PORT_D),
phy_name(phy));
} else if (DISPLAY_VER(display) >= 12) {
enum tc_port tc_port = intel_port_to_tc(display, port);
drm_encoder_init(display->drm, &encoder->base, &intel_ddi_funcs,
DRM_MODE_ENCODER_TMDS,
"DDI %s%c/PHY %s%c",
port >= PORT_TC1 ? "TC" : "",
port >= PORT_TC1 ? port_tc_name(port) : port_name(port),
tc_port != TC_PORT_NONE ? "TC" : "",
tc_port != TC_PORT_NONE ? tc_port_name(tc_port) : phy_name(phy));
} else if (DISPLAY_VER(display) >= 11) {
enum tc_port tc_port = intel_port_to_tc(display, port);
drm_encoder_init(display->drm, &encoder->base, &intel_ddi_funcs,
DRM_MODE_ENCODER_TMDS,
"DDI %c%s/PHY %s%c",
port_name(port),
port >= PORT_C ? " (TC)" : "",
tc_port != TC_PORT_NONE ? "TC" : "",
tc_port != TC_PORT_NONE ? tc_port_name(tc_port) : phy_name(phy));
} else {
drm_encoder_init(display->drm, &encoder->base, &intel_ddi_funcs,
DRM_MODE_ENCODER_TMDS,
"DDI %c/PHY %c", port_name(port), phy_name(phy));
}
drm_encoder_init(display->drm, &encoder->base, &intel_ddi_funcs,
DRM_MODE_ENCODER_TMDS, "%s",
intel_ddi_encoder_name(display, port, phy, &encoder_name));
intel_encoder_link_check_init(encoder, intel_ddi_link_check);

View File

@ -7271,6 +7271,9 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state,
intel_psr_trigger_frame_change_event(new_crtc_state->dsb_commit,
state, crtc);
intel_psr_wait_for_idle_dsb(new_crtc_state->dsb_commit,
new_crtc_state);
if (new_crtc_state->use_dsb)
intel_dsb_vblank_evade(state, new_crtc_state->dsb_commit);

View File

@ -1944,6 +1944,11 @@ void intel_display_device_info_print(const struct intel_display_device_info *inf
drm_printf(p, "rawclk rate: %u kHz\n", runtime->rawclk_freq);
}
bool intel_display_device_present(struct intel_display *display)
{
return display && HAS_DISPLAY(display);
}
/*
* Assuming the device has display hardware, should it be enabled?
*

View File

@ -306,6 +306,7 @@ struct intel_display_device_info {
} color;
};
bool intel_display_device_present(struct intel_display *display);
bool intel_display_device_enabled(struct intel_display *display);
struct intel_display *intel_display_device_probe(struct pci_dev *pdev);
void intel_display_device_remove(struct intel_display *display);

View File

@ -60,6 +60,7 @@ struct intel_ddi_buf_trans;
struct intel_fbc;
struct intel_global_objs_state;
struct intel_hdcp_shim;
struct intel_panic;
struct intel_tc_port;
/*
@ -149,6 +150,7 @@ struct intel_framebuffer {
unsigned int vtd_guard;
unsigned int (*panic_tiling)(unsigned int x, unsigned int y, unsigned int width);
struct intel_panic *panic;
};
enum intel_hotplug_state {

View File

@ -508,9 +508,6 @@ static void intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state
struct intel_panel *panel = &connector->panel;
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
if (panel->backlight.edp.vesa.luminance_control_support)
return;
drm_edp_backlight_disable(&intel_dp->aux, &panel->backlight.edp.vesa.info);
if (!panel->backlight.edp.vesa.info.aux_enable)
@ -533,7 +530,7 @@ static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector,
luminance_range->max_luminance,
panel->vbt.backlight.pwm_freq_hz,
intel_dp->edp_dpcd, &current_level, &current_mode,
false);
panel->backlight.edp.vesa.luminance_control_support);
if (ret < 0)
return ret;

View File

@ -20,6 +20,7 @@
#include "intel_fb.h"
#include "intel_fb_bo.h"
#include "intel_frontbuffer.h"
#include "intel_panic.h"
#include "intel_plane.h"
#define check_array_bounds(display, a, i) drm_WARN_ON((display)->drm, (i) >= ARRAY_SIZE(a))
@ -2343,6 +2344,26 @@ intel_user_framebuffer_create(struct drm_device *dev,
return fb;
}
struct intel_framebuffer *intel_framebuffer_alloc(void)
{
struct intel_framebuffer *intel_fb;
struct intel_panic *panic;
intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
if (!intel_fb)
return NULL;
panic = intel_panic_alloc();
if (!panic) {
kfree(intel_fb);
return NULL;
}
intel_fb->panic = panic;
return intel_fb;
}
struct drm_framebuffer *
intel_framebuffer_create(struct drm_gem_object *obj,
const struct drm_format_info *info,
@ -2351,7 +2372,7 @@ intel_framebuffer_create(struct drm_gem_object *obj,
struct intel_framebuffer *intel_fb;
int ret;
intel_fb = intel_bo_alloc_framebuffer();
intel_fb = intel_framebuffer_alloc();
if (!intel_fb)
return ERR_PTR(-ENOMEM);

View File

@ -104,6 +104,9 @@ int intel_framebuffer_init(struct intel_framebuffer *ifb,
struct drm_gem_object *obj,
const struct drm_format_info *info,
struct drm_mode_fb_cmd2 *mode_cmd);
struct intel_framebuffer *intel_framebuffer_alloc(void);
struct drm_framebuffer *
intel_framebuffer_create(struct drm_gem_object *obj,
const struct drm_format_info *info,

View File

@ -98,11 +98,7 @@ struct intel_fbc {
struct intel_display *display;
const struct intel_fbc_funcs *funcs;
/*
* This is always the inner lock when overlapping with
* struct_mutex and it's the outer lock when overlapping
* with stolen_lock.
*/
/* This is always the outer lock when overlapping with stolen_lock */
struct mutex lock;
unsigned int busy_bits;
@ -383,11 +379,11 @@ static void i8xx_fbc_program_cfb(struct intel_fbc *fbc)
struct drm_i915_private *i915 = to_i915(display->drm);
drm_WARN_ON(display->drm,
range_overflows_end_t(u64, i915_gem_stolen_area_address(i915),
range_end_overflows_t(u64, i915_gem_stolen_area_address(i915),
i915_gem_stolen_node_offset(&fbc->compressed_fb),
U32_MAX));
drm_WARN_ON(display->drm,
range_overflows_end_t(u64, i915_gem_stolen_area_address(i915),
range_end_overflows_t(u64, i915_gem_stolen_area_address(i915),
i915_gem_stolen_node_offset(&fbc->compressed_llb),
U32_MAX));
intel_de_write(display, FBC_CFB_BASE,
@ -1550,14 +1546,14 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state,
* having a Y offset that isn't divisible by 4 causes FIFO underrun
* and screen flicker.
*/
if (DISPLAY_VER(display) >= 9 &&
if (IS_DISPLAY_VER(display, 9, 12) &&
plane_state->view.color_plane[0].y & 3) {
plane_state->no_fbc_reason = "plane start Y offset misaligned";
return 0;
}
/* Wa_22010751166: icl, ehl, tgl, dg1, rkl */
if (DISPLAY_VER(display) >= 11 &&
if (IS_DISPLAY_VER(display, 9, 12) &&
(plane_state->view.color_plane[0].y +
(drm_rect_height(&plane_state->uapi.src) >> 16)) & 3) {
plane_state->no_fbc_reason = "plane end Y offset misaligned";

View File

@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT
/* Copyright © 2025 Intel Corporation */
#include <drm/drm_panic.h>
#include "gem/i915_gem_object.h"
#include "intel_display_types.h"
#include "intel_fb.h"
#include "intel_panic.h"
struct intel_panic *intel_panic_alloc(void)
{
return i915_gem_object_alloc_panic();
}
int intel_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb)
{
struct intel_framebuffer *fb = sb->private;
struct drm_gem_object *obj = intel_fb_bo(&fb->base);
return i915_gem_object_panic_setup(panic, sb, obj, fb->panic_tiling);
}
void intel_panic_finish(struct intel_panic *panic)
{
return i915_gem_object_panic_finish(panic);
}

View File

@ -0,0 +1,14 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2025 Intel Corporation */
#ifndef __INTEL_PANIC_H__
#define __INTEL_PANIC_H__
struct drm_scanout_buffer;
struct intel_panic;
struct intel_panic *intel_panic_alloc(void);
int intel_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb);
void intel_panic_finish(struct intel_panic *panic);
#endif /* __INTEL_PANIC_H__ */

View File

@ -47,7 +47,6 @@
#include "gem/i915_gem_object.h"
#include "i915_scheduler_types.h"
#include "i9xx_plane_regs.h"
#include "intel_bo.h"
#include "intel_cdclk.h"
#include "intel_cursor.h"
#include "intel_display_rps.h"
@ -56,6 +55,7 @@
#include "intel_fb.h"
#include "intel_fb_pin.h"
#include "intel_fbdev.h"
#include "intel_panic.h"
#include "intel_plane.h"
#include "intel_psr.h"
#include "skl_scaler.h"
@ -1326,7 +1326,7 @@ static void intel_panic_flush(struct drm_plane *plane)
struct drm_framebuffer *fb = plane_state->hw.fb;
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
intel_bo_panic_finish(intel_fb);
intel_panic_finish(intel_fb->panic);
if (crtc_state->enable_psr2_sel_fetch) {
/* Force a full update for psr2 */
@ -1409,7 +1409,7 @@ static int intel_get_scanout_buffer(struct drm_plane *plane,
return -EOPNOTSUPP;
}
sb->private = intel_fb;
ret = intel_bo_panic_setup(sb);
ret = intel_panic_setup(intel_fb->panic, sb);
if (ret)
return ret;
}

View File

@ -42,6 +42,7 @@
#include "intel_dmc.h"
#include "intel_dp.h"
#include "intel_dp_aux.h"
#include "intel_dsb.h"
#include "intel_frontbuffer.h"
#include "intel_hdmi.h"
#include "intel_psr.h"
@ -494,12 +495,14 @@ static u8 intel_dp_get_su_capability(struct intel_dp *intel_dp)
{
u8 su_capability = 0;
if (intel_dp->psr.sink_panel_replay_su_support)
drm_dp_dpcd_readb(&intel_dp->aux,
DP_PANEL_REPLAY_CAP_CAPABILITY,
&su_capability);
else
if (intel_dp->psr.sink_panel_replay_su_support) {
if (drm_dp_dpcd_read_byte(&intel_dp->aux,
DP_PANEL_REPLAY_CAP_CAPABILITY,
&su_capability) < 0)
return 0;
} else {
su_capability = intel_dp->psr_dpcd[1];
}
return su_capability;
}
@ -2997,35 +3000,57 @@ void intel_psr_post_plane_update(struct intel_atomic_state *state,
}
}
static int _psr2_ready_for_pipe_update_locked(struct intel_dp *intel_dp)
/*
* From bspec: Panel Self Refresh (BDW+)
* Max. time for PSR to idle = Inverse of the refresh rate + 6 ms of
* exit training time + 1.5 ms of aux channel handshake. 50 ms is
* defensive enough to cover everything.
*/
#define PSR_IDLE_TIMEOUT_MS 50
static int
_psr2_ready_for_pipe_update_locked(const struct intel_crtc_state *new_crtc_state,
struct intel_dsb *dsb)
{
struct intel_display *display = to_intel_display(intel_dp);
enum transcoder cpu_transcoder = intel_dp->psr.transcoder;
struct intel_display *display = to_intel_display(new_crtc_state);
enum transcoder cpu_transcoder = new_crtc_state->cpu_transcoder;
/*
* Any state lower than EDP_PSR2_STATUS_STATE_DEEP_SLEEP is enough.
* As all higher states has bit 4 of PSR2 state set we can just wait for
* EDP_PSR2_STATUS_STATE_DEEP_SLEEP to be cleared.
*/
if (dsb) {
intel_dsb_poll(dsb, EDP_PSR2_STATUS(display, cpu_transcoder),
EDP_PSR2_STATUS_STATE_DEEP_SLEEP, 0, 200,
PSR_IDLE_TIMEOUT_MS * 1000 / 200);
return true;
}
return intel_de_wait_for_clear(display,
EDP_PSR2_STATUS(display, cpu_transcoder),
EDP_PSR2_STATUS_STATE_DEEP_SLEEP, 50);
EDP_PSR2_STATUS_STATE_DEEP_SLEEP,
PSR_IDLE_TIMEOUT_MS);
}
static int _psr1_ready_for_pipe_update_locked(struct intel_dp *intel_dp)
static int
_psr1_ready_for_pipe_update_locked(const struct intel_crtc_state *new_crtc_state,
struct intel_dsb *dsb)
{
struct intel_display *display = to_intel_display(intel_dp);
enum transcoder cpu_transcoder = intel_dp->psr.transcoder;
struct intel_display *display = to_intel_display(new_crtc_state);
enum transcoder cpu_transcoder = new_crtc_state->cpu_transcoder;
if (dsb) {
intel_dsb_poll(dsb, psr_status_reg(display, cpu_transcoder),
EDP_PSR_STATUS_STATE_MASK, 0, 200,
PSR_IDLE_TIMEOUT_MS * 1000 / 200);
return true;
}
/*
* From bspec: Panel Self Refresh (BDW+)
* Max. time for PSR to idle = Inverse of the refresh rate + 6 ms of
* exit training time + 1.5 ms of aux channel handshake. 50 ms is
* defensive enough to cover everything.
*/
return intel_de_wait_for_clear(display,
psr_status_reg(display, cpu_transcoder),
EDP_PSR_STATUS_STATE_MASK, 50);
EDP_PSR_STATUS_STATE_MASK,
PSR_IDLE_TIMEOUT_MS);
}
/**
@ -3054,9 +3079,11 @@ void intel_psr_wait_for_idle_locked(const struct intel_crtc_state *new_crtc_stat
continue;
if (intel_dp->psr.sel_update_enabled)
ret = _psr2_ready_for_pipe_update_locked(intel_dp);
ret = _psr2_ready_for_pipe_update_locked(new_crtc_state,
NULL);
else
ret = _psr1_ready_for_pipe_update_locked(intel_dp);
ret = _psr1_ready_for_pipe_update_locked(new_crtc_state,
NULL);
if (ret)
drm_err(display->drm,
@ -3064,6 +3091,18 @@ void intel_psr_wait_for_idle_locked(const struct intel_crtc_state *new_crtc_stat
}
}
void intel_psr_wait_for_idle_dsb(struct intel_dsb *dsb,
const struct intel_crtc_state *new_crtc_state)
{
if (!new_crtc_state->has_psr || new_crtc_state->has_panel_replay)
return;
if (new_crtc_state->has_sel_update)
_psr2_ready_for_pipe_update_locked(new_crtc_state, dsb);
else
_psr1_ready_for_pipe_update_locked(new_crtc_state, dsb);
}
static bool __psr_wait_for_idle_locked(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);

View File

@ -52,6 +52,8 @@ void intel_psr_get_config(struct intel_encoder *encoder,
void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir);
void intel_psr_short_pulse(struct intel_dp *intel_dp);
void intel_psr_wait_for_idle_locked(const struct intel_crtc_state *new_crtc_state);
void intel_psr_wait_for_idle_dsb(struct intel_dsb *dsb,
const struct intel_crtc_state *new_crtc_state);
bool intel_psr_enabled(struct intel_dp *intel_dp);
int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
struct intel_crtc *crtc);

View File

@ -20,6 +20,7 @@
#include "intel_fb.h"
#include "intel_fbc.h"
#include "intel_frontbuffer.h"
#include "intel_panic.h"
#include "intel_plane.h"
#include "intel_psr.h"
#include "intel_psr_regs.h"
@ -3028,7 +3029,7 @@ skl_get_initial_plane_config(struct intel_crtc *crtc,
return;
}
intel_fb = intel_bo_alloc_framebuffer();
intel_fb = intel_framebuffer_alloc();
if (!intel_fb) {
drm_dbg_kms(display->drm, "failed to alloc fb\n");
return;

View File

@ -182,7 +182,7 @@ enum {
* the object. Simple! ... The relocation entries are stored in user memory
* and so to access them we have to copy them into a local buffer. That copy
* has to avoid taking any pagefaults as they may lead back to a GEM object
* requiring the struct_mutex (i.e. recursive deadlock). So once again we split
* requiring the vm->mutex (i.e. recursive deadlock). So once again we split
* the relocation into multiple passes. First we try to do everything within an
* atomic context (avoid the pagefaults) which requires that we never wait. If
* we detect that we may wait, or if we need to fault, then we have to fallback

View File

@ -459,8 +459,8 @@ static void i915_gem_free_object(struct drm_gem_object *gem_obj)
atomic_inc(&i915->mm.free_count);
/*
* Since we require blocking on struct_mutex to unbind the freed
* object from the GPU before releasing resources back to the
* Since we require blocking on drm_i915_gem_object->vma.lock to unbind
* the freed object from the GPU before releasing resources back to the
* system, we can not do that directly from the RCU callback (which may
* be a softirq context), but must instead then defer that work onto a
* kthread. We use the RCU callback rather than move the freed object

View File

@ -16,9 +16,9 @@
#include "i915_gem_ww.h"
#include "i915_vma_types.h"
struct drm_scanout_buffer;
enum intel_region_id;
struct intel_framebuffer;
struct drm_scanout_buffer;
struct intel_panic;
#define obj_to_i915(obj__) to_i915((obj__)->base.dev)
@ -693,9 +693,10 @@ i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj)
int __i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
int i915_gem_object_truncate(struct drm_i915_gem_object *obj);
struct intel_framebuffer *i915_gem_object_alloc_framebuffer(void);
int i915_gem_object_panic_setup(struct drm_scanout_buffer *sb);
void i915_gem_object_panic_finish(struct intel_framebuffer *fb);
struct intel_panic *i915_gem_object_alloc_panic(void);
int i915_gem_object_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb,
struct drm_gem_object *_obj, bool panic_tiling);
void i915_gem_object_panic_finish(struct intel_panic *panic);
/**
* i915_gem_object_pin_map - return a contiguous mapping of the entire object

View File

@ -357,23 +357,13 @@ static void *i915_gem_object_map_pfn(struct drm_i915_gem_object *obj,
return vaddr ?: ERR_PTR(-ENOMEM);
}
struct i915_panic_data {
struct intel_panic {
struct page **pages;
int page;
void *vaddr;
};
struct i915_framebuffer {
struct intel_framebuffer base;
struct i915_panic_data panic;
};
static inline struct i915_panic_data *to_i915_panic_data(struct intel_framebuffer *fb)
{
return &container_of_const(fb, struct i915_framebuffer, base)->panic;
}
static void i915_panic_kunmap(struct i915_panic_data *panic)
static void i915_panic_kunmap(struct intel_panic *panic)
{
if (panic->vaddr) {
drm_clflush_virt_range(panic->vaddr, PAGE_SIZE);
@ -420,7 +410,7 @@ static void i915_gem_object_panic_page_set_pixel(struct drm_scanout_buffer *sb,
unsigned int new_page;
unsigned int offset;
struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
struct i915_panic_data *panic = to_i915_panic_data(fb);
struct intel_panic *panic = fb->panic;
if (fb->panic_tiling)
offset = fb->panic_tiling(sb->width, x, y);
@ -441,14 +431,13 @@ static void i915_gem_object_panic_page_set_pixel(struct drm_scanout_buffer *sb,
}
}
struct intel_framebuffer *i915_gem_object_alloc_framebuffer(void)
struct intel_panic *i915_gem_object_alloc_panic(void)
{
struct i915_framebuffer *i915_fb;
struct intel_panic *panic;
i915_fb = kzalloc(sizeof(*i915_fb), GFP_KERNEL);
if (i915_fb)
return &i915_fb->base;
return NULL;
panic = kzalloc(sizeof(*panic), GFP_KERNEL);
return panic;
}
/*
@ -456,12 +445,11 @@ struct intel_framebuffer *i915_gem_object_alloc_framebuffer(void)
* Use current vaddr if it exists, or setup a list of pages.
* pfn is not supported yet.
*/
int i915_gem_object_panic_setup(struct drm_scanout_buffer *sb)
int i915_gem_object_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb,
struct drm_gem_object *_obj, bool panic_tiling)
{
enum i915_map_type has_type;
struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
struct i915_panic_data *panic = to_i915_panic_data(fb);
struct drm_i915_gem_object *obj = to_intel_bo(intel_fb_bo(&fb->base));
struct drm_i915_gem_object *obj = to_intel_bo(_obj);
void *ptr;
ptr = page_unpack_bits(obj->mm.mapping, &has_type);
@ -471,7 +459,7 @@ int i915_gem_object_panic_setup(struct drm_scanout_buffer *sb)
else
iosys_map_set_vaddr(&sb->map[0], ptr);
if (fb->panic_tiling)
if (panic_tiling)
sb->set_pixel = i915_gem_object_panic_map_set_pixel;
return 0;
}
@ -486,10 +474,8 @@ int i915_gem_object_panic_setup(struct drm_scanout_buffer *sb)
return -EOPNOTSUPP;
}
void i915_gem_object_panic_finish(struct intel_framebuffer *fb)
void i915_gem_object_panic_finish(struct intel_panic *panic)
{
struct i915_panic_data *panic = to_i915_panic_data(fb);
i915_panic_kunmap(panic);
panic->page = -1;
kfree(panic->pages);

View File

@ -170,7 +170,7 @@ i915_gem_shrink(struct i915_gem_ww_ctx *ww,
* Also note that although these lists do not hold a reference to
* the object we can safely grab one here: The final object
* unreferencing and the bound_list are both protected by the
* dev->struct_mutex and so we won't ever be able to observe an
* i915->mm.obj_lock and so we won't ever be able to observe an
* object on the bound_list with a reference count equals 0.
*/
for (phase = phases; phase->list; phase++) {
@ -185,7 +185,7 @@ i915_gem_shrink(struct i915_gem_ww_ctx *ww,
/*
* We serialize our access to unreferenced objects through
* the use of the struct_mutex. While the objects are not
* the use of the obj_lock. While the objects are not
* yet freed (due to RCU then a workqueue) we still want
* to be able to shrink their pages, so they remain on
* the unbound/bound list until actually freed.

View File

@ -217,10 +217,10 @@ static unsigned long to_wait_timeout(s64 timeout_ns)
*
* The wait ioctl with a timeout of 0 reimplements the busy ioctl. With any
* non-zero timeout parameter the wait ioctl will wait for the given number of
* nanoseconds on an object becoming unbusy. Since the wait itself does so
* without holding struct_mutex the object may become re-busied before this
* function completes. A similar but shorter * race condition exists in the busy
* ioctl
* nanoseconds on an object becoming unbusy. Since the wait occurs without
* holding a global or exclusive lock the object may become re-busied before
* this function completes. A similar but shorter * race condition exists
* in the busy ioctl
*/
int
i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)

View File

@ -5,7 +5,7 @@
#include "i915_selftest.h"
#include "display/intel_display_core.h"
#include "display/intel_display_device.h"
#include "gt/intel_context.h"
#include "gt/intel_engine_regs.h"
#include "gt/intel_engine_user.h"
@ -122,7 +122,7 @@ static bool fastblit_supports_x_tiling(const struct drm_i915_private *i915)
if (GRAPHICS_VER_FULL(i915) < IP_VER(12, 55))
return false;
return HAS_DISPLAY(display);
return intel_display_device_present(display);
}
static bool fast_blit_ok(const struct blit_buffer *buf)

View File

@ -14,7 +14,6 @@
#include "i915_active_types.h"
#include "i915_sw_fence.h"
#include "i915_utils.h"
#include "intel_engine_types.h"
#include "intel_sseu.h"
#include "intel_wakeref.h"

View File

@ -106,14 +106,18 @@
* preemption, but just sampling the new tail pointer).
*
*/
#include <linux/interrupt.h>
#include <linux/string_helpers.h>
#include "gen8_engine_cs.h"
#include "i915_drv.h"
#include "i915_list_util.h"
#include "i915_reg.h"
#include "i915_timer_util.h"
#include "i915_trace.h"
#include "i915_vgpu.h"
#include "gen8_engine_cs.h"
#include "i915_wait_util.h"
#include "intel_breadcrumbs.h"
#include "intel_context.h"
#include "intel_engine_heartbeat.h"

View File

@ -7,6 +7,7 @@
#include "gem/i915_gem_object.h"
#include "i915_drv.h"
#include "i915_list_util.h"
#include "intel_engine_pm.h"
#include "intel_gt_buffer_pool.h"

View File

@ -4,6 +4,7 @@
*/
#include "i915_drv.h"
#include "i915_wait_util.h"
#include "intel_gt.h"
#include "intel_gt_mcr.h"
#include "intel_gt_print.h"

View File

@ -341,7 +341,7 @@ static int vlv_rc6_init(struct intel_rc6 *rc6)
return PTR_ERR(pctx);
}
GEM_BUG_ON(range_overflows_end_t(u64,
GEM_BUG_ON(range_end_overflows_t(u64,
i915->dsm.stolen.start,
pctx->stolen->start,
U32_MAX));

View File

@ -9,18 +9,17 @@
#include "display/intel_display_reset.h"
#include "display/intel_overlay.h"
#include "gem/i915_gem_context.h"
#include "gt/intel_gt_regs.h"
#include "gt/uc/intel_gsc_fw.h"
#include "uc/intel_guc.h"
#include "i915_drv.h"
#include "i915_file_private.h"
#include "i915_gpu_error.h"
#include "i915_irq.h"
#include "i915_reg.h"
#include "i915_wait_util.h"
#include "intel_breadcrumbs.h"
#include "intel_engine_pm.h"
#include "intel_engine_regs.h"
@ -32,8 +31,6 @@
#include "intel_pci_config.h"
#include "intel_reset.h"
#include "uc/intel_guc.h"
#define RESET_MAX_RETRIES 3
static void client_mark_guilty(struct i915_gem_context *ctx, bool banned)

View File

@ -20,7 +20,7 @@ struct intel_reset {
* FENCE registers).
*
* #I915_RESET_ENGINE[num_engines] - Since the driver doesn't need to
* acquire the struct_mutex to reset an engine, we need an explicit
* acquire a global lock to reset an engine, we need an explicit
* flag to prevent two concurrent reset attempts in the same engine.
* As the number of engines continues to grow, allocate the flags from
* the most significant bits.

View File

@ -15,18 +15,19 @@
#include "i915_irq.h"
#include "i915_mitigations.h"
#include "i915_reg.h"
#include "i915_wait_util.h"
#include "intel_breadcrumbs.h"
#include "intel_context.h"
#include "intel_engine_heartbeat.h"
#include "intel_engine_pm.h"
#include "intel_engine_regs.h"
#include "intel_gt.h"
#include "intel_gt_irq.h"
#include "intel_gt_print.h"
#include "intel_gt_regs.h"
#include "intel_reset.h"
#include "intel_ring.h"
#include "shmem_utils.h"
#include "intel_engine_heartbeat.h"
#include "intel_engine_pm.h"
#include "intel_gt_print.h"
/* Rough estimate of the typical request size, performing a flush,
* set-context and then emitting the batch.

View File

@ -10,9 +10,11 @@
#include "display/intel_display.h"
#include "display/intel_display_rps.h"
#include "soc/intel_dram.h"
#include "i915_drv.h"
#include "i915_irq.h"
#include "i915_reg.h"
#include "i915_wait_util.h"
#include "intel_breadcrumbs.h"
#include "intel_gt.h"
#include "intel_gt_clock_utils.h"

View File

@ -9,6 +9,7 @@
#include <linux/lockdep.h>
#include "i915_active.h"
#include "i915_list_util.h"
#include "i915_syncmap.h"
#include "intel_timeline_types.h"

View File

@ -3,17 +3,17 @@
* Copyright © 2022 Intel Corporation
*/
#include "i915_selftest.h"
#include "gem/i915_gem_internal.h"
#include "gem/i915_gem_lmem.h"
#include "gem/i915_gem_region.h"
#include "gen8_engine_cs.h"
#include "i915_gem_ww.h"
#include "i915_selftest.h"
#include "i915_wait_util.h"
#include "intel_context.h"
#include "intel_engine_regs.h"
#include "intel_gpu_commands.h"
#include "intel_context.h"
#include "intel_gt.h"
#include "intel_ring.h"

View File

@ -7,6 +7,7 @@
#include <linux/sysfs.h>
#include "i915_drv.h"
#include "i915_timer_util.h"
#include "intel_engine.h"
#include "intel_engine_heartbeat.h"
#include "sysfs_engines.h"

View File

@ -10,11 +10,13 @@
#include "gt/intel_gt.h"
#include "gt/intel_gt_print.h"
#include "i915_drv.h"
#include "i915_reg.h"
#include "i915_wait_util.h"
#include "intel_gsc_proxy.h"
#include "intel_gsc_uc.h"
#include "intel_gsc_uc_heci_cmd_submit.h"
#include "i915_drv.h"
#include "i915_reg.h"
/*
* GSC proxy:

View File

@ -8,6 +8,8 @@
#include "gt/intel_gpu_commands.h"
#include "gt/intel_gt.h"
#include "gt/intel_ring.h"
#include "i915_wait_util.h"
#include "intel_gsc_uc_heci_cmd_submit.h"
struct gsc_heci_pkt {

View File

@ -8,15 +8,17 @@
#include "gt/intel_gt_irq.h"
#include "gt/intel_gt_pm_irq.h"
#include "gt/intel_gt_regs.h"
#include "i915_drv.h"
#include "i915_irq.h"
#include "i915_reg.h"
#include "i915_wait_util.h"
#include "intel_guc.h"
#include "intel_guc_ads.h"
#include "intel_guc_capture.h"
#include "intel_guc_print.h"
#include "intel_guc_slpc.h"
#include "intel_guc_submission.h"
#include "i915_drv.h"
#include "i915_irq.h"
#include "i915_reg.h"
/**
* DOC: GuC

View File

@ -5,11 +5,12 @@
#include <linux/circ_buf.h>
#include <linux/ktime.h>
#include <linux/time64.h>
#include <linux/string_helpers.h>
#include <linux/time64.h>
#include <linux/timekeeping.h>
#include "i915_drv.h"
#include "i915_wait_util.h"
#include "intel_guc_ct.h"
#include "intel_guc_print.h"

View File

@ -13,9 +13,11 @@
#include "gt/intel_gt_mcr.h"
#include "gt/intel_gt_regs.h"
#include "gt/intel_rps.h"
#include "i915_drv.h"
#include "i915_wait_util.h"
#include "intel_guc_fw.h"
#include "intel_guc_print.h"
#include "i915_drv.h"
static void guc_prepare_xfer(struct intel_gt *gt)
{

View File

@ -6,6 +6,8 @@
#include <linux/debugfs.h>
#include <linux/string_helpers.h>
#include <drm/drm_managed.h>
#include "gt/intel_gt.h"
#include "i915_drv.h"
#include "i915_irq.h"
@ -511,7 +513,11 @@ static void guc_log_relay_unmap(struct intel_guc_log *log)
void intel_guc_log_init_early(struct intel_guc_log *log)
{
mutex_init(&log->relay.lock);
struct intel_guc *guc = log_to_guc(log);
struct drm_i915_private *i915 = guc_to_i915(guc);
drmm_mutex_init(&i915->drm, &log->relay.lock);
drmm_mutex_init(&i915->drm, &log->guc_lock);
INIT_WORK(&log->relay.flush_work, copy_debug_logs_work);
log->relay.started = false;
}
@ -677,7 +683,7 @@ int intel_guc_log_set_level(struct intel_guc_log *log, u32 level)
if (level < GUC_LOG_LEVEL_DISABLED || level > GUC_LOG_LEVEL_MAX)
return -EINVAL;
mutex_lock(&i915->drm.struct_mutex);
mutex_lock(&log->guc_lock);
if (log->level == level)
goto out_unlock;
@ -695,7 +701,7 @@ int intel_guc_log_set_level(struct intel_guc_log *log, u32 level)
log->level = level;
out_unlock:
mutex_unlock(&i915->drm.struct_mutex);
mutex_unlock(&log->guc_lock);
return ret;
}

View File

@ -42,6 +42,14 @@ enum {
struct intel_guc_log {
u32 level;
/*
* Protects concurrent access and modification of intel_guc_log->level.
*
* This lock replaces the legacy struct_mutex usage in
* intel_guc_log system.
*/
struct mutex guc_lock;
/* Allocation settings */
struct {
s32 bytes; /* Size in bytes */

View File

@ -3,18 +3,21 @@
* Copyright © 2021 Intel Corporation
*/
#include <drm/drm_cache.h>
#include <linux/string_helpers.h>
#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_guc_slpc.h"
#include "intel_guc_print.h"
#include "intel_mchbar_regs.h"
#include <drm/drm_cache.h>
#include "gt/intel_gt.h"
#include "gt/intel_gt_regs.h"
#include "gt/intel_rps.h"
#include "i915_drv.h"
#include "i915_reg.h"
#include "i915_wait_util.h"
#include "intel_guc_print.h"
#include "intel_guc_slpc.h"
#include "intel_mchbar_regs.h"
/**
* DOC: SLPC - Dynamic Frequency management
*

View File

@ -25,16 +25,16 @@
#include "gt/intel_mocs.h"
#include "gt/intel_ring.h"
#include "i915_drv.h"
#include "i915_irq.h"
#include "i915_reg.h"
#include "i915_trace.h"
#include "i915_wait_util.h"
#include "intel_guc_ads.h"
#include "intel_guc_capture.h"
#include "intel_guc_print.h"
#include "intel_guc_submission.h"
#include "i915_drv.h"
#include "i915_reg.h"
#include "i915_irq.h"
#include "i915_trace.h"
/**
* DOC: GuC-based command submission
*

View File

@ -1921,7 +1921,7 @@ static int perform_bb_shadow(struct parser_exec_state *s)
if (!bb)
return -ENOMEM;
bb->ppgtt = (s->buf_addr_type == GTT_BUFFER) ? false : true;
bb->ppgtt = s->buf_addr_type != GTT_BUFFER;
/*
* The start_offset stores the batch buffer's start gma's

View File

@ -33,14 +33,16 @@
*
*/
#include "i915_drv.h"
#include "i915_reg.h"
#include "gt/intel_context.h"
#include "gt/intel_engine_regs.h"
#include "gt/intel_gpu_commands.h"
#include "gt/intel_gt_regs.h"
#include "gt/intel_ring.h"
#include "gvt.h"
#include "i915_drv.h"
#include "i915_reg.h"
#include "i915_wait_util.h"
#include "trace.h"
#define GEN9_MOCS_SIZE 64

View File

@ -26,11 +26,11 @@
*
*/
#include <linux/debugfs.h>
#include <linux/sched/mm.h>
#include <linux/sort.h>
#include <linux/string_helpers.h>
#include <linux/debugfs.h>
#include <drm/drm_debugfs.h>
#include "gem/i915_gem_context.h"
@ -54,6 +54,7 @@
#include "i915_irq.h"
#include "i915_reg.h"
#include "i915_scheduler.h"
#include "i915_wait_util.h"
#include "intel_mchbar_regs.h"
static inline struct drm_i915_private *node_to_i915(struct drm_info_node *node)

View File

@ -51,13 +51,15 @@
#include "display/intel_bw.h"
#include "display/intel_cdclk.h"
#include "display/intel_crtc.h"
#include "display/intel_display_core.h"
#include "display/intel_display_device.h"
#include "display/intel_display_driver.h"
#include "display/intel_display_power.h"
#include "display/intel_dmc.h"
#include "display/intel_dp.h"
#include "display/intel_dpt.h"
#include "display/intel_encoder.h"
#include "display/intel_fbdev.h"
#include "display/intel_gmbus.h"
#include "display/intel_hotplug.h"
#include "display/intel_opregion.h"
#include "display/intel_overlay.h"
@ -977,7 +979,7 @@ void i915_driver_shutdown(struct drm_i915_private *i915)
intel_power_domains_disable(display);
drm_client_dev_suspend(&i915->drm, false);
if (HAS_DISPLAY(display)) {
if (intel_display_device_present(display)) {
drm_kms_helper_poll_disable(&i915->drm);
intel_display_driver_disable_user_access(display);
@ -989,7 +991,7 @@ void i915_driver_shutdown(struct drm_i915_private *i915)
intel_irq_suspend(i915);
intel_hpd_cancel_work(display);
if (HAS_DISPLAY(display))
if (intel_display_device_present(display))
intel_display_driver_suspend_access(display);
intel_encoder_suspend_all(display);
@ -1060,7 +1062,7 @@ static int i915_drm_suspend(struct drm_device *dev)
* properly. */
intel_power_domains_disable(display);
drm_client_dev_suspend(dev, false);
if (HAS_DISPLAY(display)) {
if (intel_display_device_present(display)) {
drm_kms_helper_poll_disable(dev);
intel_display_driver_disable_user_access(display);
}
@ -1072,7 +1074,7 @@ static int i915_drm_suspend(struct drm_device *dev)
intel_irq_suspend(dev_priv);
intel_hpd_cancel_work(display);
if (HAS_DISPLAY(display))
if (intel_display_device_present(display))
intel_display_driver_suspend_access(display);
intel_encoder_suspend_all(display);
@ -1219,7 +1221,7 @@ static int i915_drm_resume(struct drm_device *dev)
*/
intel_irq_resume(dev_priv);
if (HAS_DISPLAY(display))
if (intel_display_device_present(display))
drm_mode_config_reset(dev);
i915_gem_resume(dev_priv);
@ -1228,14 +1230,14 @@ static int i915_drm_resume(struct drm_device *dev)
intel_clock_gating_init(dev_priv);
if (HAS_DISPLAY(display))
if (intel_display_device_present(display))
intel_display_driver_resume_access(display);
intel_hpd_init(display);
intel_display_driver_resume(display);
if (HAS_DISPLAY(display)) {
if (intel_display_device_present(display)) {
intel_display_driver_enable_user_access(display);
drm_kms_helper_poll_enable(dev);
}

View File

@ -114,8 +114,7 @@ struct i915_gem_mm {
struct intel_memory_region *stolen_region;
/** Memory allocator for GTT stolen memory */
struct drm_mm stolen;
/** Protects the usage of the GTT stolen memory allocator. This is
* always the inner lock when overlapping with struct_mutex. */
/** Protects the usage of the GTT stolen memory allocator */
struct mutex stolen_lock;
/* Protects bound_list/unbound_list and #drm_i915_gem_object.mm.link */
@ -222,6 +221,9 @@ struct drm_i915_private {
bool irqs_enabled;
/* LPT/WPT IOSF sideband protection */
struct mutex sbi_lock;
/* VLV/CHV IOSF sideband */
struct {
struct mutex lock; /* protect sideband access */

View File

@ -847,8 +847,7 @@ void i915_gem_runtime_suspend(struct drm_i915_private *i915)
/*
* Only called during RPM suspend. All users of the userfault_list
* must be holding an RPM wakeref to ensure that this can not
* run concurrently with themselves (and use the struct_mutex for
* protection between themselves).
* run concurrently with themselves.
*/
list_for_each_entry_safe(obj, on,

View File

@ -163,11 +163,6 @@ static void ivb_parity_work(struct work_struct *work)
u32 misccpctl;
u8 slice = 0;
/* We must turn off DOP level clock gating to access the L3 registers.
* In order to prevent a get/put style interface, acquire struct mutex
* any time we access those registers.
*/
mutex_lock(&dev_priv->drm.struct_mutex);
/* If we've screwed up tracking, just let the interrupt fire again */
if (drm_WARN_ON(&dev_priv->drm, !dev_priv->l3_parity.which_slice))
@ -225,7 +220,6 @@ static void ivb_parity_work(struct work_struct *work)
gen5_gt_enable_irq(gt, GT_PARITY_ERROR(dev_priv));
spin_unlock_irq(gt->irq_lock);
mutex_unlock(&dev_priv->drm.struct_mutex);
}
static irqreturn_t valleyview_irq_handler(int irq, void *arg)

View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2025 Intel Corporation */
#ifndef __I915_LIST_UTIL_H__
#define __I915_LIST_UTIL_H__
#include <linux/list.h>
#include <asm/rwonce.h>
static inline void __list_del_many(struct list_head *head,
struct list_head *first)
{
first->prev = head;
WRITE_ONCE(head->next, first);
}
static inline int list_is_last_rcu(const struct list_head *list,
const struct list_head *head)
{
return READ_ONCE(list->next) == head;
}
#endif /* __I915_LIST_UTIL_H__ */

View File

@ -0,0 +1,66 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2025 Intel Corporation */
#ifndef __I915_PTR_UTIL_H__
#define __I915_PTR_UTIL_H__
#include <linux/types.h>
#define ptr_mask_bits(ptr, n) ({ \
unsigned long __v = (unsigned long)(ptr); \
(typeof(ptr))(__v & -BIT(n)); \
})
#define ptr_unmask_bits(ptr, n) ((unsigned long)(ptr) & (BIT(n) - 1))
#define ptr_unpack_bits(ptr, bits, n) ({ \
unsigned long __v = (unsigned long)(ptr); \
*(bits) = __v & (BIT(n) - 1); \
(typeof(ptr))(__v & -BIT(n)); \
})
#define ptr_pack_bits(ptr, bits, n) ({ \
unsigned long __bits = (bits); \
GEM_BUG_ON(__bits & -BIT(n)); \
((typeof(ptr))((unsigned long)(ptr) | __bits)); \
})
#define ptr_dec(ptr) ({ \
unsigned long __v = (unsigned long)(ptr); \
(typeof(ptr))(__v - 1); \
})
#define ptr_inc(ptr) ({ \
unsigned long __v = (unsigned long)(ptr); \
(typeof(ptr))(__v + 1); \
})
#define page_mask_bits(ptr) ptr_mask_bits(ptr, PAGE_SHIFT)
#define page_unmask_bits(ptr) ptr_unmask_bits(ptr, PAGE_SHIFT)
#define page_pack_bits(ptr, bits) ptr_pack_bits(ptr, bits, PAGE_SHIFT)
#define page_unpack_bits(ptr, bits) ptr_unpack_bits(ptr, bits, PAGE_SHIFT)
static __always_inline ptrdiff_t ptrdiff(const void *a, const void *b)
{
return a - b;
}
#define u64_to_ptr(T, x) ({ \
typecheck(u64, x); \
(T *)(uintptr_t)(x); \
})
/*
* container_of_user: Extract the superclass from a pointer to a member.
*
* Exactly like container_of() with the exception that it plays nicely
* with sparse for __user @ptr.
*/
#define container_of_user(ptr, type, member) ({ \
void __user *__mptr = (void __user *)(ptr); \
BUILD_BUG_ON_MSG(!__same_type(*(ptr), typeof_member(type, member)) && \
!__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type __user *)(__mptr - offsetof(type, member))); })
#endif /* __I915_PTR_UTIL_H__ */

View File

@ -31,19 +31,20 @@
#include <linux/llist.h>
#include <linux/lockdep.h>
#include <uapi/drm/i915_drm.h>
#include "gem/i915_gem_context_types.h"
#include "gt/intel_context_types.h"
#include "gt/intel_engine_types.h"
#include "gt/intel_timeline_types.h"
#include "i915_gem.h"
#include "i915_ptr_util.h"
#include "i915_scheduler.h"
#include "i915_selftest.h"
#include "i915_sw_fence.h"
#include "i915_vma_resource.h"
#include <uapi/drm/i915_drm.h>
struct drm_file;
struct drm_i915_gem_object;
struct drm_printer;

View File

@ -5,7 +5,7 @@
#include <linux/vga_switcheroo.h>
#include "display/intel_display_core.h"
#include "display/intel_display_device.h"
#include "i915_driver.h"
#include "i915_drv.h"
@ -22,7 +22,7 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev,
dev_err(&pdev->dev, "DRM not initialized, aborting switch.\n");
return;
}
if (!HAS_DISPLAY(display)) {
if (!intel_display_device_present(display)) {
dev_err(&pdev->dev, "Device state not initialized, aborting switch.\n");
return;
}
@ -52,7 +52,8 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
* locking inversion with the driver load path. And the access here is
* completely racy anyway. So don't bother with locking for now.
*/
return i915 && HAS_DISPLAY(display) && atomic_read(&i915->drm.open_count) == 0;
return i915 && intel_display_device_present(display) &&
atomic_read(&i915->drm.open_count) == 0;
}
static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {

View File

@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT
/* Copyright © 2025 Intel Corporation */
#include <linux/jiffies.h>
#include "i915_timer_util.h"
void cancel_timer(struct timer_list *t)
{
if (!timer_active(t))
return;
timer_delete(t);
WRITE_ONCE(t->expires, 0);
}
void set_timer_ms(struct timer_list *t, unsigned long timeout)
{
if (!timeout) {
cancel_timer(t);
return;
}
timeout = msecs_to_jiffies(timeout);
/*
* Paranoia to make sure the compiler computes the timeout before
* loading 'jiffies' as jiffies is volatile and may be updated in
* the background by a timer tick. All to reduce the complexity
* of the addition and reduce the risk of losing a jiffy.
*/
barrier();
/* Keep t->expires = 0 reserved to indicate a canceled timer. */
mod_timer(t, jiffies + timeout ?: 1);
}

View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2025 Intel Corporation */
#ifndef __I915_TIMER_UTIL_H__
#define __I915_TIMER_UTIL_H__
#include <linux/timer.h>
#include <asm/rwonce.h>
void cancel_timer(struct timer_list *t);
void set_timer_ms(struct timer_list *t, unsigned long timeout);
static inline bool timer_active(const struct timer_list *t)
{
return READ_ONCE(t->expires);
}
static inline bool timer_expired(const struct timer_list *t)
{
return timer_active(t) && !timer_pending(t);
}
#endif /* __I915_TIMER_UTIL_H__ */

View File

@ -47,36 +47,6 @@ bool i915_error_injected(void)
#endif
void cancel_timer(struct timer_list *t)
{
if (!timer_active(t))
return;
timer_delete(t);
WRITE_ONCE(t->expires, 0);
}
void set_timer_ms(struct timer_list *t, unsigned long timeout)
{
if (!timeout) {
cancel_timer(t);
return;
}
timeout = msecs_to_jiffies(timeout);
/*
* Paranoia to make sure the compiler computes the timeout before
* loading 'jiffies' as jiffies is volatile and may be updated in
* the background by a timer tick. All to reduce the complexity
* of the addition and reduce the risk of losing a jiffy.
*/
barrier();
/* Keep t->expires = 0 reserved to indicate a canceled timer. */
mod_timer(t, jiffies + timeout ?: 1);
}
bool i915_vtd_active(struct drm_i915_private *i915)
{
if (device_iommu_mapped(i915->drm.dev))

View File

@ -25,7 +25,6 @@
#ifndef __I915_UTILS_H
#define __I915_UTILS_H
#include <linux/list.h>
#include <linux/overflow.h>
#include <linux/sched.h>
#include <linux/string_helpers.h>
@ -38,7 +37,6 @@
#endif
struct drm_i915_private;
struct timer_list;
#define MISSING_CASE(x) WARN(1, "Missing case (%s == %ld)\n", \
__stringify(x), (long)(x))
@ -67,88 +65,12 @@ bool i915_error_injected(void);
drm_err(&(i915)->drm, fmt, ##__VA_ARGS__); \
})
#define range_overflows(start, size, max) ({ \
typeof(start) start__ = (start); \
typeof(size) size__ = (size); \
typeof(max) max__ = (max); \
(void)(&start__ == &size__); \
(void)(&start__ == &max__); \
start__ >= max__ || size__ > max__ - start__; \
})
#define range_overflows_t(type, start, size, max) \
range_overflows((type)(start), (type)(size), (type)(max))
#define range_overflows_end(start, size, max) ({ \
typeof(start) start__ = (start); \
typeof(size) size__ = (size); \
typeof(max) max__ = (max); \
(void)(&start__ == &size__); \
(void)(&start__ == &max__); \
start__ > max__ || size__ > max__ - start__; \
})
#define range_overflows_end_t(type, start, size, max) \
range_overflows_end((type)(start), (type)(size), (type)(max))
#define ptr_mask_bits(ptr, n) ({ \
unsigned long __v = (unsigned long)(ptr); \
(typeof(ptr))(__v & -BIT(n)); \
})
#define ptr_unmask_bits(ptr, n) ((unsigned long)(ptr) & (BIT(n) - 1))
#define ptr_unpack_bits(ptr, bits, n) ({ \
unsigned long __v = (unsigned long)(ptr); \
*(bits) = __v & (BIT(n) - 1); \
(typeof(ptr))(__v & -BIT(n)); \
})
#define ptr_pack_bits(ptr, bits, n) ({ \
unsigned long __bits = (bits); \
GEM_BUG_ON(__bits & -BIT(n)); \
((typeof(ptr))((unsigned long)(ptr) | __bits)); \
})
#define ptr_dec(ptr) ({ \
unsigned long __v = (unsigned long)(ptr); \
(typeof(ptr))(__v - 1); \
})
#define ptr_inc(ptr) ({ \
unsigned long __v = (unsigned long)(ptr); \
(typeof(ptr))(__v + 1); \
})
#define page_mask_bits(ptr) ptr_mask_bits(ptr, PAGE_SHIFT)
#define page_unmask_bits(ptr) ptr_unmask_bits(ptr, PAGE_SHIFT)
#define page_pack_bits(ptr, bits) ptr_pack_bits(ptr, bits, PAGE_SHIFT)
#define page_unpack_bits(ptr, bits) ptr_unpack_bits(ptr, bits, PAGE_SHIFT)
#define fetch_and_zero(ptr) ({ \
typeof(*ptr) __T = *(ptr); \
*(ptr) = (typeof(*ptr))0; \
__T; \
})
static __always_inline ptrdiff_t ptrdiff(const void *a, const void *b)
{
return a - b;
}
/*
* container_of_user: Extract the superclass from a pointer to a member.
*
* Exactly like container_of() with the exception that it plays nicely
* with sparse for __user @ptr.
*/
#define container_of_user(ptr, type, member) ({ \
void __user *__mptr = (void __user *)(ptr); \
BUILD_BUG_ON_MSG(!__same_type(*(ptr), typeof_member(type, member)) && \
!__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type __user *)(__mptr - offsetof(type, member))); })
/*
* check_user_mbz: Check that a user value exists and is zero
*
@ -167,11 +89,6 @@ static __always_inline ptrdiff_t ptrdiff(const void *a, const void *b)
get_user(mbz__, (U)) ? -EFAULT : mbz__ ? -EINVAL : 0; \
})
#define u64_to_ptr(T, x) ({ \
typecheck(u64, x); \
(T *)(uintptr_t)(x); \
})
#define __mask_next_bit(mask) ({ \
int __idx = ffs(mask) - 1; \
mask &= ~BIT(__idx); \
@ -183,19 +100,6 @@ static inline bool is_power_of_2_u64(u64 n)
return (n != 0 && ((n & (n - 1)) == 0));
}
static inline void __list_del_many(struct list_head *head,
struct list_head *first)
{
first->prev = head;
WRITE_ONCE(head->next, first);
}
static inline int list_is_last_rcu(const struct list_head *list,
const struct list_head *head)
{
return READ_ONCE(list->next) == head;
}
static inline unsigned long msecs_to_jiffies_timeout(const unsigned int m)
{
unsigned long j = msecs_to_jiffies(m);
@ -230,112 +134,6 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms)
}
}
/*
* __wait_for - magic wait macro
*
* Macro to help avoid open coding check/wait/timeout patterns. Note that it's
* important that we check the condition again after having timed out, since the
* timeout could be due to preemption or similar and we've never had a chance to
* check the condition before the timeout.
*/
#define __wait_for(OP, COND, US, Wmin, Wmax) ({ \
const ktime_t end__ = ktime_add_ns(ktime_get_raw(), 1000ll * (US)); \
long wait__ = (Wmin); /* recommended min for usleep is 10 us */ \
int ret__; \
might_sleep(); \
for (;;) { \
const bool expired__ = ktime_after(ktime_get_raw(), end__); \
OP; \
/* Guarantee COND check prior to timeout */ \
barrier(); \
if (COND) { \
ret__ = 0; \
break; \
} \
if (expired__) { \
ret__ = -ETIMEDOUT; \
break; \
} \
usleep_range(wait__, wait__ * 2); \
if (wait__ < (Wmax)) \
wait__ <<= 1; \
} \
ret__; \
})
#define _wait_for(COND, US, Wmin, Wmax) __wait_for(, (COND), (US), (Wmin), \
(Wmax))
#define wait_for(COND, MS) _wait_for((COND), (MS) * 1000, 10, 1000)
/*
* If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false.
* On PREEMPT_RT the context isn't becoming atomic because it is used in an
* interrupt handler or because a spinlock_t is acquired. This leads to
* warnings which don't occur otherwise and therefore the check is disabled.
*/
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) && IS_ENABLED(CONFIG_PREEMPT_COUNT) && !defined(CONFIG_PREEMPT_RT)
# define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) WARN_ON_ONCE((ATOMIC) && !in_atomic())
#else
# define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) do { } while (0)
#endif
#define _wait_for_atomic(COND, US, ATOMIC) \
({ \
int cpu, ret, timeout = (US) * 1000; \
u64 base; \
_WAIT_FOR_ATOMIC_CHECK(ATOMIC); \
if (!(ATOMIC)) { \
preempt_disable(); \
cpu = smp_processor_id(); \
} \
base = local_clock(); \
for (;;) { \
u64 now = local_clock(); \
if (!(ATOMIC)) \
preempt_enable(); \
/* Guarantee COND check prior to timeout */ \
barrier(); \
if (COND) { \
ret = 0; \
break; \
} \
if (now - base >= timeout) { \
ret = -ETIMEDOUT; \
break; \
} \
cpu_relax(); \
if (!(ATOMIC)) { \
preempt_disable(); \
if (unlikely(cpu != smp_processor_id())) { \
timeout -= now - base; \
cpu = smp_processor_id(); \
base = local_clock(); \
} \
} \
} \
ret; \
})
#define wait_for_us(COND, US) \
({ \
int ret__; \
BUILD_BUG_ON(!__builtin_constant_p(US)); \
if ((US) > 10) \
ret__ = _wait_for((COND), (US), 10, 10); \
else \
ret__ = _wait_for_atomic((COND), (US), 0); \
ret__; \
})
#define wait_for_atomic_us(COND, US) \
({ \
BUILD_BUG_ON(!__builtin_constant_p(US)); \
BUILD_BUG_ON((US) > 50000); \
_wait_for_atomic((COND), (US), 1); \
})
#define wait_for_atomic(COND, MS) wait_for_atomic_us((COND), (MS) * 1000)
#define KHz(x) (1000 * (x))
#define MHz(x) KHz(1000 * (x))
@ -351,19 +149,6 @@ static inline void __add_taint_for_CI(unsigned int taint)
add_taint(taint, LOCKDEP_STILL_OK);
}
void cancel_timer(struct timer_list *t);
void set_timer_ms(struct timer_list *t, unsigned long timeout);
static inline bool timer_active(const struct timer_list *t)
{
return READ_ONCE(t->expires);
}
static inline bool timer_expired(const struct timer_list *t)
{
return timer_active(t) && !timer_pending(t);
}
static inline bool i915_run_as_guest(void)
{
#if IS_ENABLED(CONFIG_X86)

View File

@ -30,12 +30,12 @@
#include <drm/drm_mm.h>
#include "gt/intel_ggtt_fencing.h"
#include "gem/i915_gem_object.h"
#include "i915_gem_gtt.h"
#include "gt/intel_ggtt_fencing.h"
#include "i915_active.h"
#include "i915_gem_gtt.h"
#include "i915_ptr_util.h"
#include "i915_request.h"
#include "i915_vma_resource.h"
#include "i915_vma_types.h"

View File

@ -0,0 +1,119 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2025 Intel Corporation */
#ifndef __I915_WAIT_UTIL_H__
#define __I915_WAIT_UTIL_H__
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/sched/clock.h>
#include <linux/smp.h>
/*
* __wait_for - magic wait macro
*
* Macro to help avoid open coding check/wait/timeout patterns. Note that it's
* important that we check the condition again after having timed out, since the
* timeout could be due to preemption or similar and we've never had a chance to
* check the condition before the timeout.
*/
#define __wait_for(OP, COND, US, Wmin, Wmax) ({ \
const ktime_t end__ = ktime_add_ns(ktime_get_raw(), 1000ll * (US)); \
long wait__ = (Wmin); /* recommended min for usleep is 10 us */ \
int ret__; \
might_sleep(); \
for (;;) { \
const bool expired__ = ktime_after(ktime_get_raw(), end__); \
OP; \
/* Guarantee COND check prior to timeout */ \
barrier(); \
if (COND) { \
ret__ = 0; \
break; \
} \
if (expired__) { \
ret__ = -ETIMEDOUT; \
break; \
} \
usleep_range(wait__, wait__ * 2); \
if (wait__ < (Wmax)) \
wait__ <<= 1; \
} \
ret__; \
})
#define _wait_for(COND, US, Wmin, Wmax) __wait_for(, (COND), (US), (Wmin), \
(Wmax))
#define wait_for(COND, MS) _wait_for((COND), (MS) * 1000, 10, 1000)
/*
* If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false.
* On PREEMPT_RT the context isn't becoming atomic because it is used in an
* interrupt handler or because a spinlock_t is acquired. This leads to
* warnings which don't occur otherwise and therefore the check is disabled.
*/
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) && IS_ENABLED(CONFIG_PREEMPT_COUNT) && !defined(CONFIG_PREEMPT_RT)
# define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) WARN_ON_ONCE((ATOMIC) && !in_atomic())
#else
# define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) do { } while (0)
#endif
#define _wait_for_atomic(COND, US, ATOMIC) \
({ \
int cpu, ret, timeout = (US) * 1000; \
u64 base; \
_WAIT_FOR_ATOMIC_CHECK(ATOMIC); \
if (!(ATOMIC)) { \
preempt_disable(); \
cpu = smp_processor_id(); \
} \
base = local_clock(); \
for (;;) { \
u64 now = local_clock(); \
if (!(ATOMIC)) \
preempt_enable(); \
/* Guarantee COND check prior to timeout */ \
barrier(); \
if (COND) { \
ret = 0; \
break; \
} \
if (now - base >= timeout) { \
ret = -ETIMEDOUT; \
break; \
} \
cpu_relax(); \
if (!(ATOMIC)) { \
preempt_disable(); \
if (unlikely(cpu != smp_processor_id())) { \
timeout -= now - base; \
cpu = smp_processor_id(); \
base = local_clock(); \
} \
} \
} \
ret; \
})
#define wait_for_us(COND, US) \
({ \
int ret__; \
BUILD_BUG_ON(!__builtin_constant_p(US)); \
if ((US) > 10) \
ret__ = _wait_for((COND), (US), 10, 10); \
else \
ret__ = _wait_for_atomic((COND), (US), 0); \
ret__; \
})
#define wait_for_atomic_us(COND, US) \
({ \
BUILD_BUG_ON(!__builtin_constant_p(US)); \
BUILD_BUG_ON((US) > 50000); \
_wait_for_atomic((COND), (US), 1); \
})
#define wait_for_atomic(COND, MS) wait_for_atomic_us((COND), (MS) * 1000)
#endif /* __I915_WAIT_UTIL_H__ */

View File

@ -5,6 +5,7 @@
#include "i915_drv.h"
#include "i915_reg.h"
#include "i915_wait_util.h"
#include "intel_pcode.h"
static int gen6_check_mailbox_status(u32 mbox)

View File

@ -21,19 +21,20 @@
* IN THE SOFTWARE.
*/
#include <drm/drm_managed.h>
#include <linux/pm_runtime.h>
#include "display/intel_display_core.h"
#include <drm/drm_managed.h>
#include "gt/intel_gt.h"
#include "display/intel_display_core.h"
#include "gt/intel_engine_regs.h"
#include "gt/intel_gt.h"
#include "gt/intel_gt_regs.h"
#include "i915_drv.h"
#include "i915_iosf_mbi.h"
#include "i915_reg.h"
#include "i915_vgpu.h"
#include "i915_wait_util.h"
#include "intel_uncore_trace.h"
#define FORCEWAKE_ACK_TIMEOUT_MS 50

View File

@ -2,15 +2,15 @@
/*
* Copyright(c) 2020 Intel Corporation.
*/
#include <linux/workqueue.h>
#include "gem/i915_gem_context.h"
#include "gt/intel_context.h"
#include "gt/intel_gt.h"
#include "i915_drv.h"
#include "i915_wait_util.h"
#include "intel_pxp.h"
#include "intel_pxp_gsccs.h"
#include "intel_pxp_irq.h"

View File

@ -22,14 +22,13 @@
*
*/
#include <linux/prime_numbers.h>
#include <linux/pm_qos.h>
#include <linux/prime_numbers.h>
#include <linux/sort.h>
#include "gem/i915_gem_internal.h"
#include "gem/i915_gem_pm.h"
#include "gem/selftests/mock_context.h"
#include "gt/intel_engine_heartbeat.h"
#include "gt/intel_engine_pm.h"
#include "gt/intel_engine_user.h"
@ -40,11 +39,11 @@
#include "i915_random.h"
#include "i915_selftest.h"
#include "i915_wait_util.h"
#include "igt_flush_test.h"
#include "igt_live_test.h"
#include "igt_spinner.h"
#include "lib_sw_fence.h"
#include "mock_drm.h"
#include "mock_gem_device.h"

View File

@ -31,7 +31,7 @@
#include "i915_driver.h"
#include "i915_drv.h"
#include "i915_selftest.h"
#include "i915_wait_util.h"
#include "igt_flush_test.h"
struct i915_selftest i915_selftest __read_mostly = {

View File

@ -3,12 +3,13 @@
*
* Copyright © 2018 Intel Corporation
*/
#include "gt/intel_gpu_commands.h"
#include "gt/intel_gt.h"
#include "gem/i915_gem_internal.h"
#include "gem/selftests/igt_gem_utils.h"
#include "gt/intel_gpu_commands.h"
#include "gt/intel_gt.h"
#include "i915_wait_util.h"
#include "igt_spinner.h"
int igt_spinner_init(struct igt_spinner *spin, struct intel_gt *gt)

View File

@ -732,7 +732,7 @@ int intel_dram_detect(struct drm_i915_private *i915)
struct dram_info *dram_info;
int ret;
if (IS_DG2(i915) || !HAS_DISPLAY(display))
if (IS_DG2(i915) || !intel_display_device_present(display))
return 0;
dram_info = drmm_kzalloc(&i915->drm, sizeof(*dram_info), GFP_KERNEL);

View File

@ -8,16 +8,17 @@
#include <drm/drm_print.h>
#include "gt/intel_gt_regs.h"
#include "i915_drv.h"
#include "i915_reg.h"
#include "i915_trace.h"
#include "i915_utils.h"
#include "i915_wait_util.h"
#include "intel_clock_gating.h"
#include "intel_uncore_trace.h"
#include "vlv_suspend.h"
#include "gt/intel_gt_regs.h"
struct vlv_s0ix_state {
/* GAM */
u32 wr_watermark;

View File

@ -210,6 +210,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
display/xe_dsb_buffer.o \
display/xe_fb_pin.o \
display/xe_hdcp_gsc.o \
display/xe_panic.o \
display/xe_plane_initial.o \
display/xe_tdf.o

View File

@ -1,12 +1,7 @@
// SPDX-License-Identifier: MIT
/* Copyright © 2024 Intel Corporation */
#include <drm/drm_cache.h>
#include <drm/drm_gem.h>
#include <drm/drm_panic.h>
#include "intel_fb.h"
#include "intel_display_types.h"
#include "xe_bo.h"
#include "intel_bo.h"
@ -64,89 +59,3 @@ void intel_bo_describe(struct seq_file *m, struct drm_gem_object *obj)
{
/* FIXME */
}
struct xe_panic_data {
struct page **pages;
int page;
void *vaddr;
};
struct xe_framebuffer {
struct intel_framebuffer base;
struct xe_panic_data panic;
};
static inline struct xe_panic_data *to_xe_panic_data(struct intel_framebuffer *fb)
{
return &container_of_const(fb, struct xe_framebuffer, base)->panic;
}
static void xe_panic_kunmap(struct xe_panic_data *panic)
{
if (panic->vaddr) {
drm_clflush_virt_range(panic->vaddr, PAGE_SIZE);
kunmap_local(panic->vaddr);
panic->vaddr = NULL;
}
}
/*
* The scanout buffer pages are not mapped, so for each pixel,
* use kmap_local_page_try_from_panic() to map the page, and write the pixel.
* Try to keep the map from the previous pixel, to avoid too much map/unmap.
*/
static void xe_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int x,
unsigned int y, u32 color)
{
struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
struct xe_panic_data *panic = to_xe_panic_data(fb);
struct xe_bo *bo = gem_to_xe_bo(intel_fb_bo(&fb->base));
unsigned int new_page;
unsigned int offset;
if (fb->panic_tiling)
offset = fb->panic_tiling(sb->width, x, y);
else
offset = y * sb->pitch[0] + x * sb->format->cpp[0];
new_page = offset >> PAGE_SHIFT;
offset = offset % PAGE_SIZE;
if (new_page != panic->page) {
xe_panic_kunmap(panic);
panic->page = new_page;
panic->vaddr = ttm_bo_kmap_try_from_panic(&bo->ttm,
panic->page);
}
if (panic->vaddr) {
u32 *pix = panic->vaddr + offset;
*pix = color;
}
}
struct intel_framebuffer *intel_bo_alloc_framebuffer(void)
{
struct xe_framebuffer *xe_fb;
xe_fb = kzalloc(sizeof(*xe_fb), GFP_KERNEL);
if (xe_fb)
return &xe_fb->base;
return NULL;
}
int intel_bo_panic_setup(struct drm_scanout_buffer *sb)
{
struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
struct xe_panic_data *panic = to_xe_panic_data(fb);
panic->page = -1;
sb->set_pixel = xe_panic_page_set_pixel;
return 0;
}
void intel_bo_panic_finish(struct intel_framebuffer *fb)
{
struct xe_panic_data *panic = to_xe_panic_data(fb);
xe_panic_kunmap(panic);
panic->page = -1;
}

View File

@ -20,7 +20,7 @@
#include "intel_audio.h"
#include "intel_bw.h"
#include "intel_display.h"
#include "intel_display_core.h"
#include "intel_display_device.h"
#include "intel_display_driver.h"
#include "intel_display_irq.h"
#include "intel_display_types.h"
@ -37,13 +37,6 @@
/* Xe device functions */
static bool has_display(struct xe_device *xe)
{
struct intel_display *display = xe->display;
return HAS_DISPLAY(display);
}
/**
* xe_display_driver_probe_defer - Detect if we need to wait for other drivers
* early on
@ -290,7 +283,7 @@ static void xe_display_enable_d3cold(struct xe_device *xe)
intel_dmc_suspend(display);
if (has_display(xe))
if (intel_display_device_present(display))
intel_hpd_poll_enable(display);
}
@ -303,14 +296,14 @@ static void xe_display_disable_d3cold(struct xe_device *xe)
intel_dmc_resume(display);
if (has_display(xe))
if (intel_display_device_present(display))
drm_mode_config_reset(&xe->drm);
intel_display_driver_init_hw(display);
intel_hpd_init(display);
if (has_display(xe))
if (intel_display_device_present(display))
intel_hpd_poll_disable(display);
intel_opregion_resume(display);
@ -333,7 +326,7 @@ void xe_display_pm_suspend(struct xe_device *xe)
intel_power_domains_disable(display);
drm_client_dev_suspend(&xe->drm, false);
if (has_display(xe)) {
if (intel_display_device_present(display)) {
drm_kms_helper_poll_disable(&xe->drm);
intel_display_driver_disable_user_access(display);
intel_display_driver_suspend(display);
@ -345,7 +338,7 @@ void xe_display_pm_suspend(struct xe_device *xe)
intel_hpd_cancel_work(display);
if (has_display(xe)) {
if (intel_display_device_present(display)) {
intel_display_driver_suspend_access(display);
intel_encoder_suspend_all(display);
}
@ -365,7 +358,7 @@ void xe_display_pm_shutdown(struct xe_device *xe)
intel_power_domains_disable(display);
drm_client_dev_suspend(&xe->drm, false);
if (has_display(xe)) {
if (intel_display_device_present(display)) {
drm_kms_helper_poll_disable(&xe->drm);
intel_display_driver_disable_user_access(display);
intel_display_driver_suspend(display);
@ -376,7 +369,7 @@ void xe_display_pm_shutdown(struct xe_device *xe)
intel_encoder_block_all_hpds(display);
intel_hpd_cancel_work(display);
if (has_display(xe))
if (intel_display_device_present(display))
intel_display_driver_suspend_access(display);
intel_encoder_suspend_all(display);
@ -465,25 +458,25 @@ void xe_display_pm_resume(struct xe_device *xe)
intel_dmc_resume(display);
if (has_display(xe))
if (intel_display_device_present(display))
drm_mode_config_reset(&xe->drm);
intel_display_driver_init_hw(display);
if (has_display(xe))
if (intel_display_device_present(display))
intel_display_driver_resume_access(display);
intel_hpd_init(display);
intel_encoder_unblock_all_hpds(display);
if (has_display(xe)) {
if (intel_display_device_present(display)) {
intel_display_driver_resume(display);
drm_kms_helper_poll_enable(&xe->drm);
intel_display_driver_enable_user_access(display);
}
if (has_display(xe))
if (intel_display_device_present(display))
intel_hpd_poll_disable(display);
intel_opregion_resume(display);
@ -548,7 +541,7 @@ int xe_display_probe(struct xe_device *xe)
xe->display = display;
if (has_display(xe))
if (intel_display_device_present(display))
return 0;
no_display:

View File

@ -0,0 +1,80 @@
// SPDX-License-Identifier: MIT
/* Copyright © 2025 Intel Corporation */
#include <drm/drm_cache.h>
#include <drm/drm_panic.h>
#include "intel_display_types.h"
#include "intel_fb.h"
#include "intel_panic.h"
#include "xe_bo.h"
struct intel_panic {
struct page **pages;
int page;
void *vaddr;
};
static void xe_panic_kunmap(struct intel_panic *panic)
{
if (panic->vaddr) {
drm_clflush_virt_range(panic->vaddr, PAGE_SIZE);
kunmap_local(panic->vaddr);
panic->vaddr = NULL;
}
}
/*
* The scanout buffer pages are not mapped, so for each pixel,
* use kmap_local_page_try_from_panic() to map the page, and write the pixel.
* Try to keep the map from the previous pixel, to avoid too much map/unmap.
*/
static void xe_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int x,
unsigned int y, u32 color)
{
struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
struct intel_panic *panic = fb->panic;
struct xe_bo *bo = gem_to_xe_bo(intel_fb_bo(&fb->base));
unsigned int new_page;
unsigned int offset;
if (fb->panic_tiling)
offset = fb->panic_tiling(sb->width, x, y);
else
offset = y * sb->pitch[0] + x * sb->format->cpp[0];
new_page = offset >> PAGE_SHIFT;
offset = offset % PAGE_SIZE;
if (new_page != panic->page) {
xe_panic_kunmap(panic);
panic->page = new_page;
panic->vaddr = ttm_bo_kmap_try_from_panic(&bo->ttm,
panic->page);
}
if (panic->vaddr) {
u32 *pix = panic->vaddr + offset;
*pix = color;
}
}
struct intel_panic *intel_panic_alloc(void)
{
struct intel_panic *panic;
panic = kzalloc(sizeof(*panic), GFP_KERNEL);
return panic;
}
int intel_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb)
{
panic->page = -1;
sb->set_pixel = xe_panic_page_set_pixel;
return 0;
}
void intel_panic_finish(struct intel_panic *panic)
{
xe_panic_kunmap(panic);
panic->page = -1;
}

View File

@ -13,15 +13,6 @@
#include <drm/drm_print.h>
#define range_overflows(start, size, max) ({ \
typeof(start) start__ = (start); \
typeof(size) size__ = (size); \
typeof(max) max__ = (max); \
(void)(&start__ == &size__); \
(void)(&start__ == &max__); \
start__ >= max__ || size__ > max__ - start__; \
})
#define DRM_BUDDY_RANGE_ALLOCATION BIT(0)
#define DRM_BUDDY_TOPDOWN_ALLOCATION BIT(1)
#define DRM_BUDDY_CONTIGUOUS_ALLOCATION BIT(2)

View File

@ -192,16 +192,6 @@ struct drm_device {
/** @unique: Unique name of the device */
char *unique;
/**
* @struct_mutex:
*
* Lock for others (not &drm_minor.master and &drm_file.is_master)
*
* TODO: This lock used to be the BKL of the DRM subsystem. Move the
* lock into i915, which is the only remaining user.
*/
struct mutex struct_mutex;
/**
* @master_mutex:
*

View File

@ -238,6 +238,76 @@ static inline bool __must_check __must_check_overflow(bool overflow)
__overflows_type_constexpr(n, T), \
__overflows_type(n, T))
/**
* range_overflows() - Check if a range is out of bounds
* @start: Start of the range.
* @size: Size of the range.
* @max: Exclusive upper boundary.
*
* A strict check to determine if the range [@start, @start + @size) is
* invalid with respect to the allowable range [0, @max). Any range
* starting at or beyond @max is considered an overflow, even if @size is 0.
*
* Returns: true if the range is out of bounds.
*/
#define range_overflows(start, size, max) ({ \
typeof(start) start__ = (start); \
typeof(size) size__ = (size); \
typeof(max) max__ = (max); \
(void)(&start__ == &size__); \
(void)(&start__ == &max__); \
start__ >= max__ || size__ > max__ - start__; \
})
/**
* range_overflows_t() - Check if a range is out of bounds
* @type: Data type to use.
* @start: Start of the range.
* @size: Size of the range.
* @max: Exclusive upper boundary.
*
* Same as range_overflows() but forcing the parameters to @type.
*
* Returns: true if the range is out of bounds.
*/
#define range_overflows_t(type, start, size, max) \
range_overflows((type)(start), (type)(size), (type)(max))
/**
* range_end_overflows() - Check if a range's endpoint is out of bounds
* @start: Start of the range.
* @size: Size of the range.
* @max: Exclusive upper boundary.
*
* Checks only if the endpoint of a range (@start + @size) exceeds @max.
* Unlike range_overflows(), a zero-sized range at the boundary (@start == @max)
* is not considered an overflow. Useful for iterator-style checks.
*
* Returns: true if the endpoint exceeds the boundary.
*/
#define range_end_overflows(start, size, max) ({ \
typeof(start) start__ = (start); \
typeof(size) size__ = (size); \
typeof(max) max__ = (max); \
(void)(&start__ == &size__); \
(void)(&start__ == &max__); \
start__ > max__ || size__ > max__ - start__; \
})
/**
* range_end_overflows_t() - Check if a range's endpoint is out of bounds
* @type: Data type to use.
* @start: Start of the range.
* @size: Size of the range.
* @max: Exclusive upper boundary.
*
* Same as range_end_overflows() but forcing the parameters to @type.
*
* Returns: true if the endpoint exceeds the boundary.
*/
#define range_end_overflows_t(type, start, size, max) \
range_end_overflows((type)(start), (type)(size), (type)(max))
/**
* castable_to_type - like __same_type(), but also allows for casted literals
*