Sun Dec 19 12:28:55 2021 UTC ()
i915: Backport fix for locking-against-self on attach.

commit d1b2828af0cc414356c18d7814b83ba33b472054
Author: Ville Syrj辰l辰 <ville.syrjala@linux.intel.com>
Date:   Wed Jan 22 22:43:29 2020 +0200

    drm/i915: Fix modeset locks in sanitize_watermarks()

    We've added more internal things that use modeset locks and
    thus we need to be prepared for intel_atomic_check() grabbing
    more locks than what our initial drm_modeset_lock_all_ctx()
    took. So we're missing the backoff handling here.

    Also drm_atomic_helper_duplicate_state() works against us
    by clearing state->acquire_ctx in anticipation of
    drm_atomic_helper_commit_duplicated_state() being used to
    commit the state.

    We could probably just reset acquire_ctx back, but instead
    let's just rewrite the whole thing without using either of
    those "helpers". There's also no need to add any connectors
    to the state here since we just want the new watermarks
    which don't depend on connectors.

    Cc: Chris Wilson <chris@chris-wilson.co.uk>
    Signed-off-by: Ville Syrj辰l辰 <ville.syrjala@linux.intel.com>
    Link: https://patchwork.freedesktop.org/patch/msgid/20200122204329.2477-1-ville.syrjala@linux.intel.com
    Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>


(riastradh)
diff -r1.9 -r1.10 src/sys/external/bsd/drm2/dist/drm/i915/display/intel_display.c

cvs diff -r1.9 -r1.10 src/sys/external/bsd/drm2/dist/drm/i915/display/intel_display.c (expand / switch to unified diff)

--- src/sys/external/bsd/drm2/dist/drm/i915/display/intel_display.c 2021/12/19 12:11:46 1.9
+++ src/sys/external/bsd/drm2/dist/drm/i915/display/intel_display.c 2021/12/19 12:28:55 1.10
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: intel_display.c,v 1.9 2021/12/19 12:11:46 riastradh Exp $ */ 1/* $NetBSD: intel_display.c,v 1.10 2021/12/19 12:28:55 riastradh Exp $ */
2 2
3/* 3/*
4 * Copyright © 2006-2007 Intel Corporation 4 * Copyright © 2006-2007 Intel Corporation
5 * 5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a 6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"), 7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation 8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the 10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions: 11 * Software is furnished to do so, subject to the following conditions:
12 * 12 *
13 * The above copyright notice and this permission notice (including the next 13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the 14 * paragraph) shall be included in all copies or substantial portions of the
@@ -17,27 +17,27 @@ @@ -17,27 +17,27 @@
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE. 23 * DEALINGS IN THE SOFTWARE.
24 * 24 *
25 * Authors: 25 * Authors:
26 * Eric Anholt <eric@anholt.net> 26 * Eric Anholt <eric@anholt.net>
27 */ 27 */
28 28
29#include <sys/cdefs.h> 29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: intel_display.c,v 1.9 2021/12/19 12:11:46 riastradh Exp $"); 30__KERNEL_RCSID(0, "$NetBSD: intel_display.c,v 1.10 2021/12/19 12:28:55 riastradh Exp $");
31 31
32#include "intel_display.h" /* for pipe_drmhack */ 32#include "intel_display.h" /* for pipe_drmhack */
33 33
34#include <linux/i2c.h> 34#include <linux/i2c.h>
35#include <linux/input.h> 35#include <linux/input.h>
36#include <linux/intel-iommu.h> 36#include <linux/intel-iommu.h>
37#include <linux/kernel.h> 37#include <linux/kernel.h>
38#include <linux/module.h> 38#include <linux/module.h>
39#include <linux/dma-resv.h> 39#include <linux/dma-resv.h>
40#include <linux/slab.h> 40#include <linux/slab.h>
41 41
42#include <drm/drm_atomic.h> 42#include <drm/drm_atomic.h>
43#include <drm/drm_atomic_helper.h> 43#include <drm/drm_atomic_helper.h>
@@ -17319,107 +17319,131 @@ void intel_init_display_hooks(struct drm @@ -17319,107 +17319,131 @@ void intel_init_display_hooks(struct drm
17319 dev_priv->display.commit_modeset_enables = skl_commit_modeset_enables; 17319 dev_priv->display.commit_modeset_enables = skl_commit_modeset_enables;
17320 else 17320 else
17321 dev_priv->display.commit_modeset_enables = intel_commit_modeset_enables; 17321 dev_priv->display.commit_modeset_enables = intel_commit_modeset_enables;
17322 17322
17323} 17323}
17324 17324
17325void intel_modeset_init_hw(struct drm_i915_private *i915) 17325void intel_modeset_init_hw(struct drm_i915_private *i915)
17326{ 17326{
17327 intel_update_cdclk(i915); 17327 intel_update_cdclk(i915);
17328 intel_dump_cdclk_state(&i915->cdclk.hw, "Current CDCLK"); 17328 intel_dump_cdclk_state(&i915->cdclk.hw, "Current CDCLK");
17329 i915->cdclk.logical = i915->cdclk.actual = i915->cdclk.hw; 17329 i915->cdclk.logical = i915->cdclk.actual = i915->cdclk.hw;
17330} 17330}
17331 17331
 17332static int sanitize_watermarks_add_affected(struct drm_atomic_state *state)
 17333{
 17334 struct drm_plane *plane;
 17335 struct drm_crtc *crtc;
 17336
 17337 drm_for_each_crtc(crtc, state->dev) {
 17338 struct drm_crtc_state *crtc_state;
 17339
 17340 crtc_state = drm_atomic_get_crtc_state(state, crtc);
 17341 if (IS_ERR(crtc_state))
 17342 return PTR_ERR(crtc_state);
 17343 }
 17344
 17345 drm_for_each_plane(plane, state->dev) {
 17346 struct drm_plane_state *plane_state;
 17347
 17348 plane_state = drm_atomic_get_plane_state(state, plane);
 17349 if (IS_ERR(plane_state))
 17350 return PTR_ERR(plane_state);
 17351 }
 17352
 17353 return 0;
 17354}
 17355
17332/* 17356/*
17333 * Calculate what we think the watermarks should be for the state we've read 17357 * Calculate what we think the watermarks should be for the state we've read
17334 * out of the hardware and then immediately program those watermarks so that 17358 * out of the hardware and then immediately program those watermarks so that
17335 * we ensure the hardware settings match our internal state. 17359 * we ensure the hardware settings match our internal state.
17336 * 17360 *
17337 * We can calculate what we think WM's should be by creating a duplicate of the 17361 * We can calculate what we think WM's should be by creating a duplicate of the
17338 * current state (which was constructed during hardware readout) and running it 17362 * current state (which was constructed during hardware readout) and running it
17339 * through the atomic check code to calculate new watermark values in the 17363 * through the atomic check code to calculate new watermark values in the
17340 * state object. 17364 * state object.
17341 */ 17365 */
17342static void sanitize_watermarks(struct drm_device *dev) 17366static void sanitize_watermarks(struct drm_i915_private *dev_priv)
17343{ 17367{
17344 struct drm_i915_private *dev_priv = to_i915(dev); 
17345 struct drm_atomic_state *state; 17368 struct drm_atomic_state *state;
17346 struct intel_atomic_state *intel_state; 17369 struct intel_atomic_state *intel_state;
17347 struct intel_crtc *crtc; 17370 struct intel_crtc *crtc;
17348 struct intel_crtc_state *crtc_state; 17371 struct intel_crtc_state *crtc_state;
17349 struct drm_modeset_acquire_ctx ctx; 17372 struct drm_modeset_acquire_ctx ctx;
17350 int ret; 17373 int ret;
17351 int i; 17374 int i;
17352 17375
17353 /* Only supported on platforms that use atomic watermark design */ 17376 /* Only supported on platforms that use atomic watermark design */
17354 if (!dev_priv->display.optimize_watermarks) 17377 if (!dev_priv->display.optimize_watermarks)
17355 return; 17378 return;
17356 17379
17357 /* 17380 state = drm_atomic_state_alloc(&dev_priv->drm);
17358 * We need to hold connection_mutex before calling duplicate_state so 17381 if (WARN_ON(!state))
17359 * that the connector loop is protected. 17382 return;
17360 */ 
17361 drm_modeset_acquire_init(&ctx, 0); 
17362retry: 
17363 ret = drm_modeset_lock_all_ctx(dev, &ctx); 
17364 if (ret == -EDEADLK) { 
17365 drm_modeset_backoff(&ctx); 
17366 goto retry; 
17367 } else if (WARN_ON(ret)) { 
17368 goto fail; 
17369 } 
17370 
17371 state = drm_atomic_helper_duplicate_state(dev, &ctx); 
17372 if (WARN_ON(IS_ERR(state))) 
17373 goto fail; 
17374 17383
17375 intel_state = to_intel_atomic_state(state); 17384 intel_state = to_intel_atomic_state(state);
17376 17385
 17386 drm_modeset_acquire_init(&ctx, 0);
 17387
 17388retry:
 17389 state->acquire_ctx = &ctx;
 17390
17377 /* 17391 /*
17378 * Hardware readout is the only time we don't want to calculate 17392 * Hardware readout is the only time we don't want to calculate
17379 * intermediate watermarks (since we don't trust the current 17393 * intermediate watermarks (since we don't trust the current
17380 * watermarks). 17394 * watermarks).
17381 */ 17395 */
17382 if (!HAS_GMCH(dev_priv)) 17396 if (!HAS_GMCH(dev_priv))
17383 intel_state->skip_intermediate_wm = true; 17397 intel_state->skip_intermediate_wm = true;
17384 17398
17385 ret = intel_atomic_check(dev, state); 17399 ret = sanitize_watermarks_add_affected(state);
17386 if (ret) { 17400 if (ret)
17387 /* 17401 goto fail;
17388 * If we fail here, it means that the hardware appears to be 17402
17389 * programmed in a way that shouldn't be possible, given our 17403 ret = intel_atomic_check(&dev_priv->drm, state);
17390 * understanding of watermark requirements. This might mean a 17404 if (ret)
17391 * mistake in the hardware readout code or a mistake in the 17405 goto fail;
17392 * watermark calculations for a given platform. Raise a WARN 
17393 * so that this is noticeable. 
17394 * 
17395 * If this actually happens, we'll have to just leave the 
17396 * BIOS-programmed watermarks untouched and hope for the best. 
17397 */ 
17398 WARN(true, "Could not determine valid watermarks for inherited state\n"); 
17399 goto put_state; 
17400 } 
17401 17406
17402 /* Write calculated watermark values back */ 17407 /* Write calculated watermark values back */
17403 for_each_new_intel_crtc_in_state(intel_state, crtc, crtc_state, i) { 17408 for_each_new_intel_crtc_in_state(intel_state, crtc, crtc_state, i) {
17404 crtc_state->wm.need_postvbl_update = true; 17409 crtc_state->wm.need_postvbl_update = true;
17405 dev_priv->display.optimize_watermarks(intel_state, crtc); 17410 dev_priv->display.optimize_watermarks(intel_state, crtc);
17406 17411
17407 to_intel_crtc_state(crtc->base.state)->wm = crtc_state->wm; 17412 to_intel_crtc_state(crtc->base.state)->wm = crtc_state->wm;
17408 } 17413 }
17409 17414
17410put_state: 
17411 drm_atomic_state_put(state); 
17412fail: 17415fail:
 17416 if (ret == -EDEADLK) {
 17417 drm_atomic_state_clear(state);
 17418 drm_modeset_backoff(&ctx);
 17419 goto retry;
 17420 }
 17421
 17422 /*
 17423 * If we fail here, it means that the hardware appears to be
 17424 * programmed in a way that shouldn't be possible, given our
 17425 * understanding of watermark requirements. This might mean a
 17426 * mistake in the hardware readout code or a mistake in the
 17427 * watermark calculations for a given platform. Raise a WARN
 17428 * so that this is noticeable.
 17429 *
 17430 * If this actually happens, we'll have to just leave the
 17431 * BIOS-programmed watermarks untouched and hope for the best.
 17432 */
 17433 WARN(ret, "Could not determine valid watermarks for inherited state\n");
 17434
 17435 drm_atomic_state_put(state);
 17436
17413 drm_modeset_drop_locks(&ctx); 17437 drm_modeset_drop_locks(&ctx);
17414 drm_modeset_acquire_fini(&ctx); 17438 drm_modeset_acquire_fini(&ctx);
17415} 17439}
17416 17440
17417static void intel_update_fdi_pll_freq(struct drm_i915_private *dev_priv) 17441static void intel_update_fdi_pll_freq(struct drm_i915_private *dev_priv)
17418{ 17442{
17419 if (IS_GEN(dev_priv, 5)) { 17443 if (IS_GEN(dev_priv, 5)) {
17420 u32 fdi_pll_clk = 17444 u32 fdi_pll_clk =
17421 I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK; 17445 I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK;
17422 17446
17423 dev_priv->fdi_pll_freq = (fdi_pll_clk + 2) * 10000; 17447 dev_priv->fdi_pll_freq = (fdi_pll_clk + 2) * 10000;
17424 } else if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv)) { 17448 } else if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv)) {
17425 dev_priv->fdi_pll_freq = 270000; 17449 dev_priv->fdi_pll_freq = 270000;
@@ -17640,27 +17664,27 @@ int intel_modeset_init(struct drm_i915_p @@ -17640,27 +17664,27 @@ int intel_modeset_init(struct drm_i915_p
17640 /* 17664 /*
17641 * If the fb is shared between multiple heads, we'll 17665 * If the fb is shared between multiple heads, we'll
17642 * just get the first one. 17666 * just get the first one.
17643 */ 17667 */
17644 intel_find_initial_plane_obj(crtc, &plane_config); 17668 intel_find_initial_plane_obj(crtc, &plane_config);
17645 } 17669 }
17646 17670
17647 /* 17671 /*
17648 * Make sure hardware watermarks really match the state we read out. 17672 * Make sure hardware watermarks really match the state we read out.
17649 * Note that we need to do this after reconstructing the BIOS fb's 17673 * Note that we need to do this after reconstructing the BIOS fb's
17650 * since the watermark calculation done here will use pstate->fb. 17674 * since the watermark calculation done here will use pstate->fb.
17651 */ 17675 */
17652 if (!HAS_GMCH(i915)) 17676 if (!HAS_GMCH(i915))
17653 sanitize_watermarks(dev); 17677 sanitize_watermarks(i915);
17654 17678
17655 /* 17679 /*
17656 * Force all active planes to recompute their states. So that on 17680 * Force all active planes to recompute their states. So that on
17657 * mode_setcrtc after probe, all the intel_plane_state variables 17681 * mode_setcrtc after probe, all the intel_plane_state variables
17658 * are already calculated and there is no assert_plane warnings 17682 * are already calculated and there is no assert_plane warnings
17659 * during bootup. 17683 * during bootup.
17660 */ 17684 */
17661 ret = intel_initial_commit(dev); 17685 ret = intel_initial_commit(dev);
17662 if (ret) 17686 if (ret)
17663 DRM_DEBUG_KMS("Initial commit in probe failed.\n"); 17687 DRM_DEBUG_KMS("Initial commit in probe failed.\n");
17664 17688
17665 return 0; 17689 return 0;
17666} 17690}