mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux
Pull drm fixes from Dave Airlie: "Some final few intel fixes, all regressions, all stable cc, and one exynos oops fixer. The biggest is probably the intel display error irqs one, but it seems to fix a few crashes on startup, and one use after free in drm core" * 'drm-fixes' of git://people.freedesktop.org/~airlied/linux: drm/exynos: Fix (more) freeing issues in exynos_drm_drv.c drm/i915: Disable stolen memory when DMAR is active Revert "drm/i915: don't touch the VDD when disabling the panel" drm: Fix use-after-free in the shadow-attache exit code drm/i915: Don't enable display error interrupts from the start drm/i915: Fix scanline counter fixup on BDW drm/i915: Add a workaround for HSW scanline counter weirdness drm/i915: Fix PSR programming
This commit is contained in:
commit
08edb33c4e
6 changed files with 66 additions and 35 deletions
|
@ -468,8 +468,8 @@ void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
|
||||||
} else {
|
} else {
|
||||||
list_for_each_entry_safe(dev, tmp, &driver->legacy_dev_list,
|
list_for_each_entry_safe(dev, tmp, &driver->legacy_dev_list,
|
||||||
legacy_dev_list) {
|
legacy_dev_list) {
|
||||||
drm_put_dev(dev);
|
|
||||||
list_del(&dev->legacy_dev_list);
|
list_del(&dev->legacy_dev_list);
|
||||||
|
drm_put_dev(dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DRM_INFO("Module unloaded\n");
|
DRM_INFO("Module unloaded\n");
|
||||||
|
|
|
@ -172,20 +172,24 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
|
||||||
|
|
||||||
ret = exynos_drm_subdrv_open(dev, file);
|
ret = exynos_drm_subdrv_open(dev, file);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto err_file_priv_free;
|
||||||
|
|
||||||
anon_filp = anon_inode_getfile("exynos_gem", &exynos_drm_gem_fops,
|
anon_filp = anon_inode_getfile("exynos_gem", &exynos_drm_gem_fops,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
if (IS_ERR(anon_filp)) {
|
if (IS_ERR(anon_filp)) {
|
||||||
ret = PTR_ERR(anon_filp);
|
ret = PTR_ERR(anon_filp);
|
||||||
goto out;
|
goto err_subdrv_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
anon_filp->f_mode = FMODE_READ | FMODE_WRITE;
|
anon_filp->f_mode = FMODE_READ | FMODE_WRITE;
|
||||||
file_priv->anon_filp = anon_filp;
|
file_priv->anon_filp = anon_filp;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
out:
|
|
||||||
|
err_subdrv_close:
|
||||||
|
exynos_drm_subdrv_close(dev, file);
|
||||||
|
|
||||||
|
err_file_priv_free:
|
||||||
kfree(file_priv);
|
kfree(file_priv);
|
||||||
file->driver_priv = NULL;
|
file->driver_priv = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -214,6 +214,13 @@ int i915_gem_init_stolen(struct drm_device *dev)
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
int bios_reserved = 0;
|
int bios_reserved = 0;
|
||||||
|
|
||||||
|
#ifdef CONFIG_INTEL_IOMMU
|
||||||
|
if (intel_iommu_gfx_mapped) {
|
||||||
|
DRM_INFO("DMAR active, disabling use of stolen memory\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (dev_priv->gtt.stolen_size == 0)
|
if (dev_priv->gtt.stolen_size == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -618,33 +618,25 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
|
||||||
|
|
||||||
/* raw reads, only for fast reads of display block, no need for forcewake etc. */
|
/* raw reads, only for fast reads of display block, no need for forcewake etc. */
|
||||||
#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
|
#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
|
||||||
#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__))
|
|
||||||
|
|
||||||
static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
|
static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
|
int reg;
|
||||||
|
|
||||||
if (INTEL_INFO(dev)->gen < 7) {
|
if (INTEL_INFO(dev)->gen >= 8) {
|
||||||
status = pipe == PIPE_A ?
|
status = GEN8_PIPE_VBLANK;
|
||||||
DE_PIPEA_VBLANK :
|
reg = GEN8_DE_PIPE_ISR(pipe);
|
||||||
DE_PIPEB_VBLANK;
|
} else if (INTEL_INFO(dev)->gen >= 7) {
|
||||||
|
status = DE_PIPE_VBLANK_IVB(pipe);
|
||||||
|
reg = DEISR;
|
||||||
} else {
|
} else {
|
||||||
switch (pipe) {
|
status = DE_PIPE_VBLANK(pipe);
|
||||||
default:
|
reg = DEISR;
|
||||||
case PIPE_A:
|
|
||||||
status = DE_PIPEA_VBLANK_IVB;
|
|
||||||
break;
|
|
||||||
case PIPE_B:
|
|
||||||
status = DE_PIPEB_VBLANK_IVB;
|
|
||||||
break;
|
|
||||||
case PIPE_C:
|
|
||||||
status = DE_PIPEC_VBLANK_IVB;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return __raw_i915_read32(dev_priv, DEISR) & status;
|
return __raw_i915_read32(dev_priv, reg) & status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
|
static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
|
||||||
|
@ -702,7 +694,28 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
|
||||||
else
|
else
|
||||||
position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
|
position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
|
||||||
|
|
||||||
if (HAS_PCH_SPLIT(dev)) {
|
if (HAS_DDI(dev)) {
|
||||||
|
/*
|
||||||
|
* On HSW HDMI outputs there seems to be a 2 line
|
||||||
|
* difference, whereas eDP has the normal 1 line
|
||||||
|
* difference that earlier platforms have. External
|
||||||
|
* DP is unknown. For now just check for the 2 line
|
||||||
|
* difference case on all output types on HSW+.
|
||||||
|
*
|
||||||
|
* This might misinterpret the scanline counter being
|
||||||
|
* one line too far along on eDP, but that's less
|
||||||
|
* dangerous than the alternative since that would lead
|
||||||
|
* the vblank timestamp code astray when it sees a
|
||||||
|
* scanline count before vblank_start during a vblank
|
||||||
|
* interrupt.
|
||||||
|
*/
|
||||||
|
in_vbl = ilk_pipe_in_vblank_locked(dev, pipe);
|
||||||
|
if ((in_vbl && (position == vbl_start - 2 ||
|
||||||
|
position == vbl_start - 1)) ||
|
||||||
|
(!in_vbl && (position == vbl_end - 2 ||
|
||||||
|
position == vbl_end - 1)))
|
||||||
|
position = (position + 2) % vtotal;
|
||||||
|
} else if (HAS_PCH_SPLIT(dev)) {
|
||||||
/*
|
/*
|
||||||
* The scanline counter increments at the leading edge
|
* The scanline counter increments at the leading edge
|
||||||
* of hsync, ie. it completely misses the active portion
|
* of hsync, ie. it completely misses the active portion
|
||||||
|
@ -2769,10 +2782,9 @@ static void ibx_irq_postinstall(struct drm_device *dev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (HAS_PCH_IBX(dev)) {
|
if (HAS_PCH_IBX(dev)) {
|
||||||
mask = SDE_GMBUS | SDE_AUX_MASK | SDE_TRANSB_FIFO_UNDER |
|
mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON;
|
||||||
SDE_TRANSA_FIFO_UNDER | SDE_POISON;
|
|
||||||
} else {
|
} else {
|
||||||
mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT;
|
mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
|
||||||
|
|
||||||
I915_WRITE(SERR_INT, I915_READ(SERR_INT));
|
I915_WRITE(SERR_INT, I915_READ(SERR_INT));
|
||||||
}
|
}
|
||||||
|
@ -2832,20 +2844,19 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
|
||||||
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
|
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
|
||||||
DE_PCH_EVENT_IVB | DE_PLANEC_FLIP_DONE_IVB |
|
DE_PCH_EVENT_IVB | DE_PLANEC_FLIP_DONE_IVB |
|
||||||
DE_PLANEB_FLIP_DONE_IVB |
|
DE_PLANEB_FLIP_DONE_IVB |
|
||||||
DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB |
|
DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB);
|
||||||
DE_ERR_INT_IVB);
|
|
||||||
extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
|
extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
|
||||||
DE_PIPEA_VBLANK_IVB);
|
DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB);
|
||||||
|
|
||||||
I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
|
I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
|
||||||
} else {
|
} else {
|
||||||
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
|
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
|
||||||
DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
|
DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
|
||||||
DE_AUX_CHANNEL_A |
|
DE_AUX_CHANNEL_A |
|
||||||
DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN |
|
|
||||||
DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE |
|
DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE |
|
||||||
DE_POISON);
|
DE_POISON);
|
||||||
extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT;
|
extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT |
|
||||||
|
DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_priv->irq_mask = ~display_mask;
|
dev_priv->irq_mask = ~display_mask;
|
||||||
|
@ -2961,9 +2972,9 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
|
||||||
struct drm_device *dev = dev_priv->dev;
|
struct drm_device *dev = dev_priv->dev;
|
||||||
uint32_t de_pipe_masked = GEN8_PIPE_FLIP_DONE |
|
uint32_t de_pipe_masked = GEN8_PIPE_FLIP_DONE |
|
||||||
GEN8_PIPE_CDCLK_CRC_DONE |
|
GEN8_PIPE_CDCLK_CRC_DONE |
|
||||||
GEN8_PIPE_FIFO_UNDERRUN |
|
|
||||||
GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
|
GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
|
||||||
uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK;
|
uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
|
||||||
|
GEN8_PIPE_FIFO_UNDERRUN;
|
||||||
int pipe;
|
int pipe;
|
||||||
dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_masked;
|
dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_masked;
|
||||||
dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked;
|
dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked;
|
||||||
|
|
|
@ -1244,6 +1244,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
|
||||||
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
|
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
|
||||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||||
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
|
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
|
||||||
|
ironlake_edp_panel_vdd_on(intel_dp);
|
||||||
ironlake_edp_panel_off(intel_dp);
|
ironlake_edp_panel_off(intel_dp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1249,17 +1249,24 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp)
|
||||||
|
|
||||||
DRM_DEBUG_KMS("Turn eDP power off\n");
|
DRM_DEBUG_KMS("Turn eDP power off\n");
|
||||||
|
|
||||||
|
WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
|
||||||
|
|
||||||
pp = ironlake_get_pp_control(intel_dp);
|
pp = ironlake_get_pp_control(intel_dp);
|
||||||
/* We need to switch off panel power _and_ force vdd, for otherwise some
|
/* We need to switch off panel power _and_ force vdd, for otherwise some
|
||||||
* panels get very unhappy and cease to work. */
|
* panels get very unhappy and cease to work. */
|
||||||
pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE);
|
pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);
|
||||||
|
|
||||||
pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
|
pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
|
||||||
|
|
||||||
I915_WRITE(pp_ctrl_reg, pp);
|
I915_WRITE(pp_ctrl_reg, pp);
|
||||||
POSTING_READ(pp_ctrl_reg);
|
POSTING_READ(pp_ctrl_reg);
|
||||||
|
|
||||||
|
intel_dp->want_panel_vdd = false;
|
||||||
|
|
||||||
ironlake_wait_panel_off(intel_dp);
|
ironlake_wait_panel_off(intel_dp);
|
||||||
|
|
||||||
|
/* We got a reference when we enabled the VDD. */
|
||||||
|
intel_runtime_pm_put(dev_priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
|
void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
|
||||||
|
@ -1639,7 +1646,7 @@ static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
|
||||||
val |= EDP_PSR_LINK_DISABLE;
|
val |= EDP_PSR_LINK_DISABLE;
|
||||||
|
|
||||||
I915_WRITE(EDP_PSR_CTL(dev), val |
|
I915_WRITE(EDP_PSR_CTL(dev), val |
|
||||||
IS_BROADWELL(dev) ? 0 : link_entry_time |
|
(IS_BROADWELL(dev) ? 0 : link_entry_time) |
|
||||||
max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
|
max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
|
||||||
idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |
|
idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |
|
||||||
EDP_PSR_ENABLE);
|
EDP_PSR_ENABLE);
|
||||||
|
@ -1784,6 +1791,7 @@ static void intel_disable_dp(struct intel_encoder *encoder)
|
||||||
|
|
||||||
/* Make sure the panel is off before trying to change the mode. But also
|
/* Make sure the panel is off before trying to change the mode. But also
|
||||||
* ensure that we have vdd while we switch off the panel. */
|
* ensure that we have vdd while we switch off the panel. */
|
||||||
|
ironlake_edp_panel_vdd_on(intel_dp);
|
||||||
ironlake_edp_backlight_off(intel_dp);
|
ironlake_edp_backlight_off(intel_dp);
|
||||||
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
|
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
|
||||||
ironlake_edp_panel_off(intel_dp);
|
ironlake_edp_panel_off(intel_dp);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue