From f09d675f029723981c48603b3f214c71d6e019e8 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Fri, 13 May 2016 15:36:29 +0100 Subject: drm/i915/guc: rename loader entry points The GuC initialisation code could do other things apart from loading firmware, so here we rename the three primary entry points to remove any specific reference to "ucode" (no functional changes, just renaming). Signed-off-by: Dave Gordon Reviewed-by: Tvrtko Ursulin Signed-off-by: Tvrtko Ursulin diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a8c79f6..36685fe 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -507,7 +507,7 @@ static int i915_load_modeset_init(struct drm_device *dev) * working irqs for e.g. gmbus and dp aux transfers. */ intel_modeset_init(dev); - intel_guc_ucode_init(dev); + intel_guc_init(dev); ret = i915_gem_init(dev); if (ret) @@ -547,7 +547,7 @@ static int i915_load_modeset_init(struct drm_device *dev) cleanup_gem: i915_gem_fini(dev); cleanup_irq: - intel_guc_ucode_fini(dev); + intel_guc_fini(dev); drm_irq_uninstall(dev); intel_teardown_gmbus(dev); cleanup_csr: @@ -1530,7 +1530,7 @@ int i915_driver_unload(struct drm_device *dev) /* Flush any outstanding unpin_work. */ flush_workqueue(dev_priv->wq); - intel_guc_ucode_fini(dev); + intel_guc_fini(dev); i915_gem_fini(dev); intel_fbc_cleanup_cfb(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3251dec..261b7e9 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4884,7 +4884,7 @@ i915_gem_init_hw(struct drm_device *dev) /* We can't enable contexts until all firmware is loaded */ if (HAS_GUC_UCODE(dev)) { - ret = intel_guc_ucode_load(dev); + ret = intel_guc_setup(dev); if (ret) { DRM_ERROR("Failed to initialize GuC, error %d\n", ret); ret = -EIO; diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 9d79c4c..3984136 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -138,9 +138,9 @@ struct intel_guc { }; /* intel_guc_loader.c */ -extern void intel_guc_ucode_init(struct drm_device *dev); -extern int intel_guc_ucode_load(struct drm_device *dev); -extern void intel_guc_ucode_fini(struct drm_device *dev); +extern void intel_guc_init(struct drm_device *dev); +extern int intel_guc_setup(struct drm_device *dev); +extern void intel_guc_fini(struct drm_device *dev); extern const char *intel_guc_fw_status_repr(enum intel_guc_fw_status status); extern int intel_guc_suspend(struct drm_device *dev); extern int intel_guc_resume(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c index 34405de..30ec820 100644 --- a/drivers/gpu/drm/i915/intel_guc_loader.c +++ b/drivers/gpu/drm/i915/intel_guc_loader.c @@ -386,18 +386,19 @@ static int i915_reset_guc(struct drm_i915_private *dev_priv) } /** - * intel_guc_ucode_load() - load GuC uCode into the device + * intel_guc_setup() - finish preparing the GuC for activity * @dev: drm device * * Called from gem_init_hw() during driver loading and also after a GPU reset. * + * The main action required here it to load the GuC uCode into the device. * The firmware image should have already been fetched into memory by the - * earlier call to intel_guc_ucode_init(), so here we need only check that - * is succeeded, and then transfer the image to the h/w. + * earlier call to intel_guc_init(), so here we need only check that worked, + * and then transfer the image to the h/w. * * Return: non-zero code on error */ -int intel_guc_ucode_load(struct drm_device *dev) +int intel_guc_setup(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw; @@ -629,15 +630,15 @@ fail: } /** - * intel_guc_ucode_init() - define parameters and fetch firmware + * intel_guc_init() - define parameters and fetch firmware * @dev: drm device * * Called early during driver load, but after GEM is initialised. * * The firmware will be transferred to the GuC's memory later, - * when intel_guc_ucode_load() is called. + * when intel_guc_setup() is called. */ -void intel_guc_ucode_init(struct drm_device *dev) +void intel_guc_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw; @@ -685,10 +686,10 @@ void intel_guc_ucode_init(struct drm_device *dev) } /** - * intel_guc_ucode_fini() - clean up all allocated resources + * intel_guc_fini() - clean up all allocated resources * @dev: drm device */ -void intel_guc_ucode_fini(struct drm_device *dev) +void intel_guc_fini(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw; -- cgit v0.10.2 From 1a3d1898375224f02a3e257cff4619d5a2492f1f Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Fri, 13 May 2016 15:36:30 +0100 Subject: drm/i915/guc: distinguish HAS_GUC() from HAS_GUC_UCODE/HAS_GUC_SCHED For now, anything with a GuC requires uCode loading, and then supports command submission once loaded. But these are logically distinct from simply "having a GuC", so we need a separate macro for the latter. Then, various tests should use this new macro rather than HAS_GUC_UCODE() or testing enable_guc_submission. v4: Added a couple more uses of the new macro. Signed-off-by: Dave Gordon Reviewed-by: Tvrtko Ursulin Signed-off-by: Tvrtko Ursulin diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 255d4c3..5ada5c9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2802,8 +2802,14 @@ struct drm_i915_cmd_table { #define HAS_CSR(dev) (IS_GEN9(dev)) -#define HAS_GUC_UCODE(dev) (IS_GEN9(dev) && !IS_KABYLAKE(dev)) -#define HAS_GUC_SCHED(dev) (IS_GEN9(dev) && !IS_KABYLAKE(dev)) +/* + * For now, anything with a GuC requires uCode loading, and then supports + * command submission once loaded. But these are logically independent + * properties, so we have separate macros to test them. + */ +#define HAS_GUC(dev) (IS_GEN9(dev) && !IS_KABYLAKE(dev)) +#define HAS_GUC_UCODE(dev) (HAS_GUC(dev)) +#define HAS_GUC_SCHED(dev) (HAS_GUC(dev)) #define HAS_RESOURCE_STREAMER(dev) (IS_HASWELL(dev) || \ INTEL_INFO(dev)->gen >= 8) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 261b7e9..963f031 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4883,7 +4883,7 @@ i915_gem_init_hw(struct drm_device *dev) intel_mocs_init_l3cc_table(dev); /* We can't enable contexts until all firmware is loaded */ - if (HAS_GUC_UCODE(dev)) { + if (HAS_GUC(dev)) { ret = intel_guc_setup(dev); if (ret) { DRM_ERROR("Failed to initialize GuC, error %d\n", ret); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 29bdd79..b6dfd02 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5039,7 +5039,7 @@ static void gen9_enable_rc6(struct drm_i915_private *dev_priv) for_each_engine(engine, dev_priv) I915_WRITE(RING_MAX_IDLE(engine->mmio_base), 10); - if (HAS_GUC_UCODE(dev_priv)) + if (HAS_GUC(dev_priv)) I915_WRITE(GUC_MAX_IDLE_COUNT, 0xA); I915_WRITE(GEN6_RC_SLEEP, 0); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 385114b..c1ca458 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1715,7 +1715,7 @@ int intel_guc_reset(struct drm_i915_private *dev_priv) int ret; unsigned long irqflags; - if (!i915.enable_guc_submission) + if (!HAS_GUC(dev_priv)) return -EINVAL; intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); -- cgit v0.10.2 From fce91f22ff31601a03bdeb5f09b525b035021259 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Fri, 20 May 2016 11:42:42 +0100 Subject: drm/i915/guc: add enable_guc_loading parameter Split the function of "enable_guc_submission" into two separate options. The new one ("enable_guc_loading") controls only the *fetching and loading* of the GuC firmware image. The existing one is redefined to control only the *use* of the GuC for batch submission once the firmware is loaded. In addition, the degree of control has been refined from a simple bool to an integer key, allowing several options: -1 (default) whatever the platform default is 0 DISABLE don't load/use the GuC 1 BEST EFFORT try to load/use the GuC, fallback if not available 2 REQUIRE must load/use the GuC, else leave the GPU wedged The new platform default (as coded here) will be to attempt to load the GuC iff the device has a GuC that requires firmware, but not yet to use it for submission. A later patch will change to enable it if appropriate. v4: Changed some error-message levels, mostly ERROR->INFO, per review comments by Tvrtko Ursulin. v5: Dropped one more error message, disabled GuC submission on hypothetical firmware-free devices [Tvrtko Ursulin]. v6: Logging tidy by Tvrtko Ursulin: * Do not log falling back to execlists when wedging the GPU. * Do not log fw load errors when load was disabled by user. * Pass down some error code from fw load for log message to make more sense. Signed-off-by: Dave Gordon Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin (v5) Signed-off-by: Tvrtko Ursulin Tested-by: Fiedorowicz, Lukasz Signed-off-by: Dave Gordon Reviewed-by: Tvrtko Ursulin (v5) Signed-off-by: Tvrtko Ursulin Reviewed-by: Nick Hoath (v6) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 963f031..f78d4ca 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4885,11 +4885,8 @@ i915_gem_init_hw(struct drm_device *dev) /* We can't enable contexts until all firmware is loaded */ if (HAS_GUC(dev)) { ret = intel_guc_setup(dev); - if (ret) { - DRM_ERROR("Failed to initialize GuC, error %d\n", ret); - ret = -EIO; + if (ret) goto out; - } } /* diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c index 169242a..916cd67 100644 --- a/drivers/gpu/drm/i915/i915_guc_submission.c +++ b/drivers/gpu/drm/i915/i915_guc_submission.c @@ -969,7 +969,7 @@ int intel_guc_suspend(struct drm_device *dev) struct intel_context *ctx; u32 data[3]; - if (!i915.enable_guc_submission) + if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS) return 0; ctx = dev_priv->kernel_context; @@ -995,7 +995,7 @@ int intel_guc_resume(struct drm_device *dev) struct intel_context *ctx; u32 data[3]; - if (!i915.enable_guc_submission) + if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS) return 0; ctx = dev_priv->kernel_context; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index cd74fb8..21a323c 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -53,7 +53,8 @@ struct i915_params i915 __read_mostly = { .verbose_state_checks = 1, .nuclear_pageflip = 0, .edp_vswing = 0, - .enable_guc_submission = false, + .enable_guc_loading = -1, + .enable_guc_submission = 0, .guc_log_level = -1, .enable_dp_mst = true, .inject_load_failure = 0, @@ -193,8 +194,15 @@ MODULE_PARM_DESC(edp_vswing, "(0=use value from vbt [default], 1=low power swing(200mV)," "2=default swing(400mV))"); -module_param_named_unsafe(enable_guc_submission, i915.enable_guc_submission, bool, 0400); -MODULE_PARM_DESC(enable_guc_submission, "Enable GuC submission (default:false)"); +module_param_named_unsafe(enable_guc_loading, i915.enable_guc_loading, int, 0400); +MODULE_PARM_DESC(enable_guc_loading, + "Enable GuC firmware loading " + "(-1=auto [default], 0=never, 1=if available, 2=required)"); + +module_param_named_unsafe(enable_guc_submission, i915.enable_guc_submission, int, 0400); +MODULE_PARM_DESC(enable_guc_submission, + "Enable GuC submission " + "(-1=auto, 0=never [default], 1=if available, 2=required)"); module_param_named(guc_log_level, i915.guc_log_level, int, 0400); MODULE_PARM_DESC(guc_log_level, diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index dd0d0bb..658ce73 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -45,6 +45,8 @@ struct i915_params { int enable_ips; int invert_brightness; int enable_cmd_parser; + int enable_guc_loading; + int enable_guc_submission; int guc_log_level; int mmio_debug; int edp_vswing; @@ -56,7 +58,6 @@ struct i915_params { bool load_detect_test; bool reset; bool disable_display; - bool enable_guc_submission; bool verbose_state_checks; bool nuclear_pageflip; bool enable_dp_mst; diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c index 30ec820..29273e5 100644 --- a/drivers/gpu/drm/i915/intel_guc_loader.c +++ b/drivers/gpu/drm/i915/intel_guc_loader.c @@ -402,50 +402,42 @@ int intel_guc_setup(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw; - int retries, err = 0; + const char *fw_path = guc_fw->guc_fw_path; + int retries, ret, err; - if (!i915.enable_guc_submission) - return 0; - - DRM_DEBUG_DRIVER("GuC fw status: fetch %s, load %s\n", + DRM_DEBUG_DRIVER("GuC fw status: path %s, fetch %s, load %s\n", + fw_path, intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status), intel_guc_fw_status_repr(guc_fw->guc_fw_load_status)); - direct_interrupts_to_host(dev_priv); - - if (guc_fw->guc_fw_fetch_status == GUC_FIRMWARE_NONE) - return 0; - - if (guc_fw->guc_fw_fetch_status == GUC_FIRMWARE_SUCCESS && - guc_fw->guc_fw_load_status == GUC_FIRMWARE_FAIL) - return -ENOEXEC; - - guc_fw->guc_fw_load_status = GUC_FIRMWARE_PENDING; - - DRM_DEBUG_DRIVER("GuC fw fetch status %s\n", - intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status)); + /* Loading forbidden, or no firmware to load? */ + if (!i915.enable_guc_loading) { + err = 0; + goto fail; + } else if (fw_path == NULL || *fw_path == '\0') { + if (*fw_path == '\0') + DRM_INFO("No GuC firmware known for this platform\n"); + err = -ENODEV; + goto fail; + } - switch (guc_fw->guc_fw_fetch_status) { - case GUC_FIRMWARE_FAIL: - /* something went wrong :( */ + /* Fetch failed, or already fetched but failed to load? */ + if (guc_fw->guc_fw_fetch_status != GUC_FIRMWARE_SUCCESS) { err = -EIO; goto fail; - - case GUC_FIRMWARE_NONE: - case GUC_FIRMWARE_PENDING: - default: - /* "can't happen" */ - WARN_ONCE(1, "GuC fw %s invalid guc_fw_fetch_status %s [%d]\n", - guc_fw->guc_fw_path, - intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status), - guc_fw->guc_fw_fetch_status); - err = -ENXIO; + } else if (guc_fw->guc_fw_load_status == GUC_FIRMWARE_FAIL) { + err = -ENOEXEC; goto fail; - - case GUC_FIRMWARE_SUCCESS: - break; } + direct_interrupts_to_host(dev_priv); + + guc_fw->guc_fw_load_status = GUC_FIRMWARE_PENDING; + + DRM_DEBUG_DRIVER("GuC fw status: fetch %s, load %s\n", + intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status), + intel_guc_fw_status_repr(guc_fw->guc_fw_load_status)); + err = i915_guc_submission_init(dev); if (err) goto fail; @@ -463,7 +455,7 @@ int intel_guc_setup(struct drm_device *dev) */ err = i915_reset_guc(dev_priv); if (err) { - DRM_ERROR("GuC reset failed, err %d\n", err); + DRM_ERROR("GuC reset failed: %d\n", err); goto fail; } @@ -474,8 +466,8 @@ int intel_guc_setup(struct drm_device *dev) if (--retries == 0) goto fail; - DRM_INFO("GuC fw load failed, err %d; will reset and " - "retry %d more time(s)\n", err, retries); + DRM_INFO("GuC fw load failed: %d; will reset and " + "retry %d more time(s)\n", err, retries); } guc_fw->guc_fw_load_status = GUC_FIRMWARE_SUCCESS; @@ -497,7 +489,6 @@ int intel_guc_setup(struct drm_device *dev) return 0; fail: - DRM_ERROR("GuC firmware load failed, err %d\n", err); if (guc_fw->guc_fw_load_status == GUC_FIRMWARE_PENDING) guc_fw->guc_fw_load_status = GUC_FIRMWARE_FAIL; @@ -505,7 +496,41 @@ fail: i915_guc_submission_disable(dev); i915_guc_submission_fini(dev); - return err; + /* + * We've failed to load the firmware :( + * + * Decide whether to disable GuC submission and fall back to + * execlist mode, and whether to hide the error by returning + * zero or to return -EIO, which the caller will treat as a + * nonfatal error (i.e. it doesn't prevent driver load, but + * marks the GPU as wedged until reset). + */ + if (i915.enable_guc_loading > 1) { + ret = -EIO; + } else if (i915.enable_guc_submission > 1) { + ret = -EIO; + } else { + ret = 0; + } + + if (err == 0) + DRM_INFO("GuC firmware load skipped\n"); + else if (ret == -EIO) + DRM_ERROR("GuC firmware load failed: %d\n", err); + else + DRM_INFO("GuC firmware load failed: %d\n", err); + + if (i915.enable_guc_submission) { + if (fw_path == NULL) + DRM_INFO("GuC submission without firmware not supported\n"); + if (ret == 0) + DRM_INFO("Falling back to execlist mode\n"); + else + DRM_ERROR("GuC init failed: %d\n", ret); + } + i915.enable_guc_submission = 0; + + return ret; } static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw) @@ -644,8 +669,11 @@ void intel_guc_init(struct drm_device *dev) struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw; const char *fw_path; - if (!HAS_GUC_SCHED(dev)) - i915.enable_guc_submission = false; + /* A negative value means "use platform default" */ + if (i915.enable_guc_loading < 0) + i915.enable_guc_loading = HAS_GUC_UCODE(dev); + if (i915.enable_guc_submission < 0) + i915.enable_guc_submission = HAS_GUC_SCHED(dev); if (!HAS_GUC_UCODE(dev)) { fw_path = NULL; @@ -658,26 +686,21 @@ void intel_guc_init(struct drm_device *dev) guc_fw->guc_fw_major_wanted = 8; guc_fw->guc_fw_minor_wanted = 7; } else { - i915.enable_guc_submission = false; fw_path = ""; /* unknown device */ } - if (!i915.enable_guc_submission) - return; - guc_fw->guc_dev = dev; guc_fw->guc_fw_path = fw_path; guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE; guc_fw->guc_fw_load_status = GUC_FIRMWARE_NONE; + /* Early (and silent) return if GuC loading is disabled */ + if (!i915.enable_guc_loading) + return; if (fw_path == NULL) return; - - if (*fw_path == '\0') { - DRM_ERROR("No GuC firmware known for this platform\n"); - guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_FAIL; + if (*fw_path == '\0') return; - } guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_PENDING; DRM_DEBUG_DRIVER("GuC firmware pending, path %s\n", fw_path); -- cgit v0.10.2 From 7c2c270d27dd4e52529deee9814493c27f956218 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Fri, 13 May 2016 15:36:32 +0100 Subject: drm/i915/guc: pass request (not client) to i915_guc_{wq_check_space, submit}() The knowledge of how to derive the relevant client from the request should be localised within i915_guc_submission.c; the LRC code shouldn't have to know about the internal details of the GuC submission process. And all the information the GuC code needs should be encapsulated in (or reachable from) the request. v2: GEM_BUG_ON() for bad GuC client (Tvrtko Ursulin). Add/update kerneldoc explaining check_space/submit protocol Signed-off-by: Dave Gordon Reviewed-by: Tvrtko Ursulin Signed-off-by: Tvrtko Ursulin diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c index 916cd67..87cb739 100644 --- a/drivers/gpu/drm/i915/i915_guc_submission.c +++ b/drivers/gpu/drm/i915/i915_guc_submission.c @@ -450,14 +450,30 @@ static void guc_fini_ctx_desc(struct intel_guc *guc, sizeof(desc) * client->ctx_index); } -int i915_guc_wq_check_space(struct i915_guc_client *gc) +/** + * i915_guc_wq_check_space() - check that the GuC can accept a request + * @request: request associated with the commands + * + * Return: 0 if space is available + * -EAGAIN if space is not currently available + * + * This function must be called (and must return 0) before a request + * is submitted to the GuC via i915_guc_submit() below. Once a result + * of 0 has been returned, it remains valid until (but only until) + * the next call to submit(). + * + * This precheck allows the caller to determine in advance that space + * will be available for the next submission before committing resources + * to it, and helps avoid late failures with complicated recovery paths. + */ +int i915_guc_wq_check_space(struct drm_i915_gem_request *request) { + const size_t size = sizeof(struct guc_wq_item); + struct i915_guc_client *gc = request->i915->guc.execbuf_client; struct guc_process_desc *desc; - u32 size = sizeof(struct guc_wq_item); int ret = -ETIMEDOUT, timeout_counter = 200; - if (!gc) - return 0; + GEM_BUG_ON(gc == NULL); desc = gc->client_base + gc->proc_desc_offset; @@ -531,16 +547,28 @@ static int guc_add_workqueue_item(struct i915_guc_client *gc, /** * i915_guc_submit() - Submit commands through GuC - * @client: the guc client where commands will go through * @rq: request associated with the commands * - * Return: 0 if succeed + * Return: 0 on success, otherwise an errno. + * (Note: nonzero really shouldn't happen!) + * + * The caller must have already called i915_guc_wq_check_space() above + * with a result of 0 (success) since the last request submission. This + * guarantees that there is space in the work queue for the new request, + * so enqueuing the item cannot fail. + * + * Bad Things Will Happen if the caller violates this protocol e.g. calls + * submit() when check() says there's no space, or calls submit() multiple + * times with no intervening check(). + * + * The only error here arises if the doorbell hardware isn't functioning + * as expected, which really shouln't happen. */ -int i915_guc_submit(struct i915_guc_client *client, - struct drm_i915_gem_request *rq) +int i915_guc_submit(struct drm_i915_gem_request *rq) { - struct intel_guc *guc = client->guc; unsigned int engine_id = rq->engine->guc_id; + struct intel_guc *guc = &rq->i915->guc; + struct i915_guc_client *client = guc->execbuf_client; int q_ret, b_ret; q_ret = guc_add_workqueue_item(client, rq); diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 3984136..91f315c 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -148,10 +148,9 @@ extern int intel_guc_resume(struct drm_device *dev); /* i915_guc_submission.c */ int i915_guc_submission_init(struct drm_device *dev); int i915_guc_submission_enable(struct drm_device *dev); -int i915_guc_submit(struct i915_guc_client *client, - struct drm_i915_gem_request *rq); +int i915_guc_wq_check_space(struct drm_i915_gem_request *rq); +int i915_guc_submit(struct drm_i915_gem_request *rq); void i915_guc_submission_disable(struct drm_device *dev); void i915_guc_submission_fini(struct drm_device *dev); -int i915_guc_wq_check_space(struct i915_guc_client *client); #endif diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index affca6d..0d1772a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -696,9 +696,7 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request * going any further, as the i915_add_request() call * later on mustn't fail ... */ - struct intel_guc *guc = &request->i915->guc; - - ret = i915_guc_wq_check_space(guc->execbuf_client); + ret = i915_guc_wq_check_space(request); if (ret) return ret; } @@ -747,7 +745,6 @@ static int intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request) { struct intel_ringbuffer *ringbuf = request->ringbuf; - struct drm_i915_private *dev_priv = request->i915; struct intel_engine_cs *engine = request->engine; intel_logical_ring_advance(ringbuf); @@ -775,8 +772,8 @@ intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request) request->previous_context = engine->last_context; engine->last_context = request->ctx; - if (dev_priv->guc.execbuf_client) - i915_guc_submit(dev_priv->guc.execbuf_client, request); + if (i915.enable_guc_submission) + i915_guc_submit(request); else execlists_context_queue(request); -- cgit v0.10.2 From 551aaecd8873b728a85c1fcb2b8ca502e9ffc49c Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Fri, 13 May 2016 15:36:33 +0100 Subject: drm/i915/guc: don't spinwait if the GuC's workqueue is full Rather than wait to see whether more space becomes available in the GuC submission workqueue, we can just return -EAGAIN and let the caller try again in a little while. This gets rid of an uninterruptable sleep in the polling code :) We'll also add a counter to the GuC client statistics, to see how often we find the WQ full. v2: Flag the likely() code path (Tvtrko Ursulin). v4: Add/update comments about failure counters (Tvtrko Ursulin). Signed-off-by: Dave Gordon Reviewed-by: Tvrtko Ursulin Signed-off-by: Tvrtko Ursulin diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 4c6b48d..e606c6a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2515,6 +2515,7 @@ static void i915_guc_client_info(struct seq_file *m, seq_printf(m, "\tWQ size %d, offset: 0x%x, tail %d\n", client->wq_size, client->wq_offset, client->wq_tail); + seq_printf(m, "\tWork queue full: %u\n", client->no_wq_space); seq_printf(m, "\tFailed to queue: %u\n", client->q_fail); seq_printf(m, "\tFailed doorbell: %u\n", client->b_fail); seq_printf(m, "\tLast submission result: %d\n", client->retcode); diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c index 87cb739..85b2b89 100644 --- a/drivers/gpu/drm/i915/i915_guc_submission.c +++ b/drivers/gpu/drm/i915/i915_guc_submission.c @@ -468,26 +468,22 @@ static void guc_fini_ctx_desc(struct intel_guc *guc, */ int i915_guc_wq_check_space(struct drm_i915_gem_request *request) { - const size_t size = sizeof(struct guc_wq_item); + const size_t wqi_size = sizeof(struct guc_wq_item); struct i915_guc_client *gc = request->i915->guc.execbuf_client; struct guc_process_desc *desc; - int ret = -ETIMEDOUT, timeout_counter = 200; + u32 freespace; GEM_BUG_ON(gc == NULL); desc = gc->client_base + gc->proc_desc_offset; - while (timeout_counter-- > 0) { - if (CIRC_SPACE(gc->wq_tail, desc->head, gc->wq_size) >= size) { - ret = 0; - break; - } + freespace = CIRC_SPACE(gc->wq_tail, desc->head, gc->wq_size); + if (likely(freespace >= wqi_size)) + return 0; - if (timeout_counter) - usleep_range(1000, 2000); - }; + gc->no_wq_space += 1; - return ret; + return -EAGAIN; } static int guc_add_workqueue_item(struct i915_guc_client *gc, diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 91f315c..380a743 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -48,9 +48,18 @@ struct drm_i915_gem_request; * queue (a circular array of work items), again described in the process * descriptor. Work queue pages are mapped momentarily as required. * - * Finally, we also keep a few statistics here, including the number of - * submissions to each engine, and a record of the last submission failure - * (if any). + * We also keep a few statistics on failures. Ideally, these should all + * be zero! + * no_wq_space: times that the submission pre-check found no space was + * available in the work queue (note, the queue is shared, + * not per-engine). It is OK for this to be nonzero, but + * it should not be huge! + * q_fail: failed to enqueue a work item. This should never happen, + * because we check for space beforehand. + * b_fail: failed to ring the doorbell. This should never happen, unless + * somehow the hardware misbehaves, or maybe if the GuC firmware + * crashes? We probably need to reset the GPU to recover. + * retcode: errno from last guc_submit() */ struct i915_guc_client { struct drm_i915_gem_object *client_obj; @@ -71,12 +80,13 @@ struct i915_guc_client { uint32_t wq_tail; uint32_t unused; /* Was 'wq_head' */ - /* GuC submission statistics & status */ - uint64_t submissions[GUC_MAX_ENGINES_NUM]; + uint32_t no_wq_space; uint32_t q_fail; uint32_t b_fail; int retcode; - int spare; /* pad to 32 DWords */ + + /* Per-engine counts of GuC submissions */ + uint64_t submissions[GUC_MAX_ENGINES_NUM]; }; enum intel_guc_fw_status { -- cgit v0.10.2 From 0a31afbc0f87c734cb1688eb626ee9abee63d723 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Fri, 13 May 2016 15:36:34 +0100 Subject: drm/i915/guc: rework guc_add_workqueue_item() Mostly little optimisations and future-proofing against code breakage. For instance, if the driver is correctly following the submission protocol, the "out of space" condition is impossible, so the previous runtime WARN_ON() is promoted to a GEM_BUG_ON() for a more dramatic effect in development and less impact in end-user systems. Similarly we can make alignment checking more stringent and replace other WARN_ON() conditions that don't relate to the runtime hardware state with either BUILD_BUG_ON() for compile-time-detectable issues, or GEM_BUG_ON() for logical "can't happen" errors. With those changes, we can convert it to void, as suggested by Chris Wilson, and update the calling code appropriately. v2: Note that we're now putting the request seqno in the "fence_id" field of each GuC-work-item, in case it turns up somewhere useful (e.g. in a GuC log) [Tvrtko Ursulin]. Signed-off-by: Dave Gordon Reviewed-by: Tvrtko Ursulin Signed-off-by: Tvrtko Ursulin diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c index 85b2b89..42a8508 100644 --- a/drivers/gpu/drm/i915/i915_guc_submission.c +++ b/drivers/gpu/drm/i915/i915_guc_submission.c @@ -486,23 +486,28 @@ int i915_guc_wq_check_space(struct drm_i915_gem_request *request) return -EAGAIN; } -static int guc_add_workqueue_item(struct i915_guc_client *gc, - struct drm_i915_gem_request *rq) +static void guc_add_workqueue_item(struct i915_guc_client *gc, + struct drm_i915_gem_request *rq) { + /* wqi_len is in DWords, and does not include the one-word header */ + const size_t wqi_size = sizeof(struct guc_wq_item); + const u32 wqi_len = wqi_size/sizeof(u32) - 1; struct guc_process_desc *desc; struct guc_wq_item *wqi; void *base; - u32 tail, wq_len, wq_off, space; + u32 freespace, tail, wq_off, wq_page; desc = gc->client_base + gc->proc_desc_offset; - space = CIRC_SPACE(gc->wq_tail, desc->head, gc->wq_size); - if (WARN_ON(space < sizeof(struct guc_wq_item))) - return -ENOSPC; /* shouldn't happen */ - /* postincrement WQ tail for next time */ - wq_off = gc->wq_tail; - gc->wq_tail += sizeof(struct guc_wq_item); - gc->wq_tail &= gc->wq_size - 1; + /* Free space is guaranteed, see i915_guc_wq_check_space() above */ + freespace = CIRC_SPACE(gc->wq_tail, desc->head, gc->wq_size); + GEM_BUG_ON(freespace < wqi_size); + + /* The GuC firmware wants the tail index in QWords, not bytes */ + tail = rq->tail; + GEM_BUG_ON(tail & 7); + tail >>= 3; + GEM_BUG_ON(tail > WQ_RING_TAIL_MAX); /* For now workqueue item is 4 DWs; workqueue buffer is 2 pages. So we * should not have the case where structure wqi is across page, neither @@ -511,19 +516,23 @@ static int guc_add_workqueue_item(struct i915_guc_client *gc, * XXX: if not the case, we need save data to a temp wqi and copy it to * workqueue buffer dw by dw. */ - WARN_ON(sizeof(struct guc_wq_item) != 16); - WARN_ON(wq_off & 3); + BUILD_BUG_ON(wqi_size != 16); + + /* postincrement WQ tail for next time */ + wq_off = gc->wq_tail; + gc->wq_tail += wqi_size; + gc->wq_tail &= gc->wq_size - 1; + GEM_BUG_ON(wq_off & (wqi_size - 1)); - /* wq starts from the page after doorbell / process_desc */ - base = kmap_atomic(i915_gem_object_get_page(gc->client_obj, - (wq_off + GUC_DB_SIZE) >> PAGE_SHIFT)); + /* WQ starts from the page after doorbell / process_desc */ + wq_page = (wq_off + GUC_DB_SIZE) >> PAGE_SHIFT; wq_off &= PAGE_SIZE - 1; + base = kmap_atomic(i915_gem_object_get_page(gc->client_obj, wq_page)); wqi = (struct guc_wq_item *)((char *)base + wq_off); - /* len does not include the header */ - wq_len = sizeof(struct guc_wq_item) / sizeof(u32) - 1; + /* Now fill in the 4-word work queue item */ wqi->header = WQ_TYPE_INORDER | - (wq_len << WQ_LEN_SHIFT) | + (wqi_len << WQ_LEN_SHIFT) | (rq->engine->guc_id << WQ_TARGET_SHIFT) | WQ_NO_WCFLUSH_WAIT; @@ -531,14 +540,10 @@ static int guc_add_workqueue_item(struct i915_guc_client *gc, wqi->context_desc = (u32)intel_lr_context_descriptor(rq->ctx, rq->engine); - /* The GuC firmware wants the tail index in QWords, not bytes */ - tail = rq->ringbuf->tail >> 3; wqi->ring_tail = tail << WQ_RING_TAIL_SHIFT; - wqi->fence_id = 0; /*XXX: what fence to be here */ + wqi->fence_id = rq->seqno; kunmap_atomic(base); - - return 0; } /** @@ -565,26 +570,20 @@ int i915_guc_submit(struct drm_i915_gem_request *rq) unsigned int engine_id = rq->engine->guc_id; struct intel_guc *guc = &rq->i915->guc; struct i915_guc_client *client = guc->execbuf_client; - int q_ret, b_ret; + int b_ret; - q_ret = guc_add_workqueue_item(client, rq); - if (q_ret == 0) - b_ret = guc_ring_doorbell(client); + guc_add_workqueue_item(client, rq); + b_ret = guc_ring_doorbell(client); client->submissions[engine_id] += 1; - if (q_ret) { - client->q_fail += 1; - client->retcode = q_ret; - } else if (b_ret) { + client->retcode = b_ret; + if (b_ret) client->b_fail += 1; - client->retcode = q_ret = b_ret; - } else { - client->retcode = 0; - } + guc->submissions[engine_id] += 1; guc->last_seqno[engine_id] = rq->seqno; - return q_ret; + return b_ret; } /* diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 380a743..7b1a5a3 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -81,7 +81,7 @@ struct i915_guc_client { uint32_t unused; /* Was 'wq_head' */ uint32_t no_wq_space; - uint32_t q_fail; + uint32_t q_fail; /* No longer used */ uint32_t b_fail; int retcode; diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h index 2de57ff..944786d 100644 --- a/drivers/gpu/drm/i915/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -71,7 +71,8 @@ #define WQ_WORKLOAD_TOUCH (2 << WQ_WORKLOAD_SHIFT) #define WQ_RING_TAIL_SHIFT 20 -#define WQ_RING_TAIL_MASK (0x7FF << WQ_RING_TAIL_SHIFT) +#define WQ_RING_TAIL_MAX 0x7FF /* 2^11 QWords */ +#define WQ_RING_TAIL_MASK (WQ_RING_TAIL_MAX << WQ_RING_TAIL_SHIFT) #define GUC_DOORBELL_ENABLED 1 #define GUC_DOORBELL_DISABLED 0 -- cgit v0.10.2 From 11825b0dba78b2f26a6ff9a6acb5d5b6b186e741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 19 May 2016 12:14:43 +0300 Subject: drm/i915: Enable GSE interrupt on BDW+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We've never actually enabled or unmasked the GSE interrupt on BDW+, even though the interrupt handler was always prepared for it. Let's enable it and see what happens. Credit to Mark Kettenis who fixed this in the OpenBSD fork of the driver. He reports that it fixed the "ACPI _BCM/_BCQ-based brightness mechanism on a MacBookPro12,1 and a 3rd gen Lenovo X1 Carbon" for them. Mark says: "FWIW, this *is* needed if you want ACPI-based backlight control to work. On Linux you probably don't notice, since "hardware" backlight control is preferred over "firmware" or "platform" backlight control. It would help me if this did land in the Linux tree though, as it will make future imports of the i915 driver into OpenBSD easier." So even though we don't really need this, let's put it in to help Mark with future porting efforts. Should be harmless to have it enabled in any case. Reviewed-by: Daniel Vetter References: http://lists.freedesktop.org/archives/intel-gfx/2015-December/081799.html Reported-by: Mark Kettenis Cc: Mark Kettenis Cc: Jani Nikula Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463649283-28698-1-git-send-email-ville.syrjala@linux.intel.com Acked-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 5513c4c..fc2b2a7 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3794,6 +3794,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) uint32_t de_pipe_enables; u32 de_port_masked = GEN8_AUX_CHANNEL_A; u32 de_port_enables; + u32 de_misc_masked = GEN8_DE_MISC_GSE; enum pipe pipe; if (INTEL_INFO(dev_priv)->gen >= 9) { @@ -3829,6 +3830,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) de_pipe_enables); GEN5_IRQ_INIT(GEN8_DE_PORT_, ~de_port_masked, de_port_enables); + GEN5_IRQ_INIT(GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked); } static int gen8_irq_postinstall(struct drm_device *dev) -- cgit v0.10.2 From 6f9f4b7a2cf7c5047f4d31bb00b0a48fb0a674e3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 23 May 2016 15:08:09 +0100 Subject: drm/i915/opregion: Convert to using native drm_i915_private Prefer passing struct drm_i915_private to internal interfaces as this saves us having to dance between drm_device and our native struct. The savings hare are small (only 70 bytes of unrequired dancing), but progressive! Signed-off-by: Chris Wilson Cc: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1464012490-30961-1-git-send-email-chris@chris-wilson.co.uk Reviewed-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 36685fe..3489c2b 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1310,7 +1310,7 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv) intel_uncore_sanitize(dev_priv); - intel_opregion_setup(dev); + intel_opregion_setup(dev_priv); i915_gem_load_init_fences(dev_priv); @@ -1379,7 +1379,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) if (INTEL_INFO(dev_priv)->num_pipes) { /* Must be done after probing outputs */ - intel_opregion_init(dev); + intel_opregion_init(dev_priv); acpi_video_register(); } @@ -1398,7 +1398,7 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv) i915_audio_component_cleanup(dev_priv); intel_gpu_ips_teardown(); acpi_video_unregister(); - intel_opregion_fini(dev_priv->dev); + intel_opregion_fini(dev_priv); i915_teardown_sysfs(dev_priv->dev); i915_gem_shrinker_cleanup(dev_priv); } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index dba03c0..7627bbe 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -628,10 +628,10 @@ static int i915_drm_suspend(struct drm_device *dev) i915_save_state(dev); opregion_target_state = suspend_to_idle(dev_priv) ? PCI_D1 : PCI_D3cold; - intel_opregion_notify_adapter(dev, opregion_target_state); + intel_opregion_notify_adapter(dev_priv, opregion_target_state); intel_uncore_forcewake_reset(dev_priv, false); - intel_opregion_fini(dev); + intel_opregion_fini(dev_priv); intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true); @@ -749,7 +749,7 @@ static int i915_drm_resume(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); i915_restore_state(dev); - intel_opregion_setup(dev); + intel_opregion_setup(dev_priv); intel_init_pch_refclk(dev); drm_mode_config_reset(dev); @@ -794,7 +794,7 @@ static int i915_drm_resume(struct drm_device *dev) /* Config may have changed between suspend and resume */ drm_helper_hpd_irq_event(dev); - intel_opregion_init(dev); + intel_opregion_init(dev_priv); intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING, false); @@ -802,7 +802,7 @@ static int i915_drm_resume(struct drm_device *dev) dev_priv->modeset_restore = MODESET_DONE; mutex_unlock(&dev_priv->modeset_restore_lock); - intel_opregion_notify_adapter(dev, PCI_D0); + intel_opregion_notify_adapter(dev_priv, PCI_D0); drm_kms_helper_poll_enable(dev); @@ -1596,14 +1596,14 @@ static int intel_runtime_suspend(struct device *device) * FIXME: We really should find a document that references the arguments * used below! */ - if (IS_BROADWELL(dev)) { + if (IS_BROADWELL(dev_priv)) { /* * On Broadwell, if we use PCI_D1 the PCH DDI ports will stop * being detected, and the call we do at intel_runtime_resume() * won't be able to restore them. Since PCI_D3hot matches the * actual specification and appears to be working, use it. */ - intel_opregion_notify_adapter(dev, PCI_D3hot); + intel_opregion_notify_adapter(dev_priv, PCI_D3hot); } else { /* * current versions of firmware which depend on this opregion @@ -1612,7 +1612,7 @@ static int intel_runtime_suspend(struct device *device) * to distinguish it from notifications that might be sent via * the suspend path. */ - intel_opregion_notify_adapter(dev, PCI_D1); + intel_opregion_notify_adapter(dev_priv, PCI_D1); } assert_forcewakes_inactive(dev_priv); @@ -1636,7 +1636,7 @@ static int intel_runtime_resume(struct device *device) WARN_ON_ONCE(atomic_read(&dev_priv->pm.wakeref_count)); disable_rpm_wakeref_asserts(dev_priv); - intel_opregion_notify_adapter(dev, PCI_D0); + intel_opregion_notify_adapter(dev_priv, PCI_D0); dev_priv->pm.suspended = false; if (intel_uncore_unclaimed_mmio(dev_priv)) DRM_DEBUG_DRIVER("Unclaimed access during suspend, bios?\n"); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5ada5c9..caf7e45 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3608,19 +3608,19 @@ bool intel_bios_is_port_hpd_inverted(struct drm_i915_private *dev_priv, /* intel_opregion.c */ #ifdef CONFIG_ACPI -extern int intel_opregion_setup(struct drm_device *dev); -extern void intel_opregion_init(struct drm_device *dev); -extern void intel_opregion_fini(struct drm_device *dev); +extern int intel_opregion_setup(struct drm_i915_private *dev_priv); +extern void intel_opregion_init(struct drm_i915_private *dev_priv); +extern void intel_opregion_fini(struct drm_i915_private *dev_priv); extern void intel_opregion_asle_intr(struct drm_i915_private *dev_priv); extern int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, bool enable); -extern int intel_opregion_notify_adapter(struct drm_device *dev, +extern int intel_opregion_notify_adapter(struct drm_i915_private *dev_priv, pci_power_t state); -extern int intel_opregion_get_panel_type(struct drm_device *dev); +extern int intel_opregion_get_panel_type(struct drm_i915_private *dev_priv); #else -static inline int intel_opregion_setup(struct drm_device *dev) { return 0; } -static inline void intel_opregion_init(struct drm_device *dev) { return; } -static inline void intel_opregion_fini(struct drm_device *dev) { return; } +static inline int intel_opregion_setup(struct drm_i915_private *dev) { return 0; } +static inline void intel_opregion_init(struct drm_i915_private *dev) { } +static inline void intel_opregion_fini(struct drm_i915_private *dev) { } static inline void intel_opregion_asle_intr(struct drm_i915_private *dev_priv) { } @@ -3630,11 +3630,11 @@ intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, bool enable) return 0; } static inline int -intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state) +intel_opregion_notify_adapter(struct drm_i915_private *dev, pci_power_t state) { return 0; } -static inline int intel_opregion_get_panel_type(struct drm_device *dev) +static inline int intel_opregion_get_panel_type(struct drm_i915_private *dev) { return -ENODEV; } diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 8b68c48..624e755 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -213,7 +213,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, dev_priv->vbt.lvds_dither = lvds_options->pixel_dither; - ret = intel_opregion_get_panel_type(dev_priv->dev); + ret = intel_opregion_get_panel_type(dev_priv); if (ret >= 0) { WARN_ON(ret > 0xf); panel_type = ret; diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 8347fd8..f9cdec8 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -240,10 +240,11 @@ struct opregion_asle_ext { #define MAX_DSLP 1500 -static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out) +static int swsci(struct drm_i915_private *dev_priv, + u32 function, u32 parm, u32 *parm_out) { - struct drm_i915_private *dev_priv = dev->dev_private; struct opregion_swsci *swsci = dev_priv->opregion.swsci; + struct pci_dev *pdev = dev_priv->dev->pdev; u32 main_function, sub_function, scic; u16 swsci_val; u32 dslp; @@ -293,16 +294,16 @@ static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out) swsci->scic = scic; /* Ensure SCI event is selected and event trigger is cleared. */ - pci_read_config_word(dev->pdev, SWSCI, &swsci_val); + pci_read_config_word(pdev, SWSCI, &swsci_val); if (!(swsci_val & SWSCI_SCISEL) || (swsci_val & SWSCI_GSSCIE)) { swsci_val |= SWSCI_SCISEL; swsci_val &= ~SWSCI_GSSCIE; - pci_write_config_word(dev->pdev, SWSCI, swsci_val); + pci_write_config_word(pdev, SWSCI, swsci_val); } /* Use event trigger to tell bios to check the mail. */ swsci_val |= SWSCI_GSSCIE; - pci_write_config_word(dev->pdev, SWSCI, swsci_val); + pci_write_config_word(pdev, SWSCI, swsci_val); /* Poll for the result. */ #define C (((scic = swsci->scic) & SWSCI_SCIC_INDICATOR) == 0) @@ -336,13 +337,13 @@ static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out) int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, bool enable) { - struct drm_device *dev = intel_encoder->base.dev; + struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev); u32 parm = 0; u32 type = 0; u32 port; /* don't care about old stuff for now */ - if (!HAS_DDI(dev)) + if (!HAS_DDI(dev_priv)) return 0; if (intel_encoder->type == INTEL_OUTPUT_DSI) @@ -382,7 +383,7 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, parm |= type << (16 + port * 3); - return swsci(dev, SWSCI_SBCB_DISPLAY_POWER_STATE, parm, NULL); + return swsci(dev_priv, SWSCI_SBCB_DISPLAY_POWER_STATE, parm, NULL); } static const struct { @@ -396,27 +397,28 @@ static const struct { { PCI_D3cold, 0x04 }, }; -int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state) +int intel_opregion_notify_adapter(struct drm_i915_private *dev_priv, + pci_power_t state) { int i; - if (!HAS_DDI(dev)) + if (!HAS_DDI(dev_priv)) return 0; for (i = 0; i < ARRAY_SIZE(power_state_map); i++) { if (state == power_state_map[i].pci_power_state) - return swsci(dev, SWSCI_SBCB_ADAPTER_POWER_STATE, + return swsci(dev_priv, SWSCI_SBCB_ADAPTER_POWER_STATE, power_state_map[i].parm, NULL); } return -EINVAL; } -static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) +static u32 asle_set_backlight(struct drm_i915_private *dev_priv, u32 bclp) { - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_connector *connector; struct opregion_asle *asle = dev_priv->opregion.asle; + struct drm_device *dev = dev_priv->dev; DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp); @@ -449,7 +451,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) return 0; } -static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi) +static u32 asle_set_als_illum(struct drm_i915_private *dev_priv, u32 alsi) { /* alsi is the current ALS reading in lux. 0 indicates below sensor range, 0xffff indicates above sensor range. 1-0xfffe are valid */ @@ -457,13 +459,13 @@ static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi) return ASLC_ALS_ILLUM_FAILED; } -static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb) +static u32 asle_set_pwm_freq(struct drm_i915_private *dev_priv, u32 pfmb) { DRM_DEBUG_DRIVER("PWM freq is not supported\n"); return ASLC_PWM_FREQ_FAILED; } -static u32 asle_set_pfit(struct drm_device *dev, u32 pfit) +static u32 asle_set_pfit(struct drm_i915_private *dev_priv, u32 pfit) { /* Panel fitting is currently controlled by the X code, so this is a noop until modesetting support works fully */ @@ -471,13 +473,13 @@ static u32 asle_set_pfit(struct drm_device *dev, u32 pfit) return ASLC_PFIT_FAILED; } -static u32 asle_set_supported_rotation_angles(struct drm_device *dev, u32 srot) +static u32 asle_set_supported_rotation_angles(struct drm_i915_private *dev_priv, u32 srot) { DRM_DEBUG_DRIVER("SROT is not supported\n"); return ASLC_ROTATION_ANGLES_FAILED; } -static u32 asle_set_button_array(struct drm_device *dev, u32 iuer) +static u32 asle_set_button_array(struct drm_i915_private *dev_priv, u32 iuer) { if (!iuer) DRM_DEBUG_DRIVER("Button array event is not supported (nothing)\n"); @@ -495,7 +497,7 @@ static u32 asle_set_button_array(struct drm_device *dev, u32 iuer) return ASLC_BUTTON_ARRAY_FAILED; } -static u32 asle_set_convertible(struct drm_device *dev, u32 iuer) +static u32 asle_set_convertible(struct drm_i915_private *dev_priv, u32 iuer) { if (iuer & ASLE_IUER_CONVERTIBLE) DRM_DEBUG_DRIVER("Convertible is not supported (clamshell)\n"); @@ -505,7 +507,7 @@ static u32 asle_set_convertible(struct drm_device *dev, u32 iuer) return ASLC_CONVERTIBLE_FAILED; } -static u32 asle_set_docking(struct drm_device *dev, u32 iuer) +static u32 asle_set_docking(struct drm_i915_private *dev_priv, u32 iuer) { if (iuer & ASLE_IUER_DOCKING) DRM_DEBUG_DRIVER("Docking is not supported (docked)\n"); @@ -515,7 +517,7 @@ static u32 asle_set_docking(struct drm_device *dev, u32 iuer) return ASLC_DOCKING_FAILED; } -static u32 asle_isct_state(struct drm_device *dev) +static u32 asle_isct_state(struct drm_i915_private *dev_priv) { DRM_DEBUG_DRIVER("ISCT is not supported\n"); return ASLC_ISCT_STATE_FAILED; @@ -527,7 +529,6 @@ static void asle_work(struct work_struct *work) container_of(work, struct intel_opregion, asle_work); struct drm_i915_private *dev_priv = container_of(opregion, struct drm_i915_private, opregion); - struct drm_device *dev = dev_priv->dev; struct opregion_asle *asle = dev_priv->opregion.asle; u32 aslc_stat = 0; u32 aslc_req; @@ -544,32 +545,32 @@ static void asle_work(struct work_struct *work) } if (aslc_req & ASLC_SET_ALS_ILLUM) - aslc_stat |= asle_set_als_illum(dev, asle->alsi); + aslc_stat |= asle_set_als_illum(dev_priv, asle->alsi); if (aslc_req & ASLC_SET_BACKLIGHT) - aslc_stat |= asle_set_backlight(dev, asle->bclp); + aslc_stat |= asle_set_backlight(dev_priv, asle->bclp); if (aslc_req & ASLC_SET_PFIT) - aslc_stat |= asle_set_pfit(dev, asle->pfit); + aslc_stat |= asle_set_pfit(dev_priv, asle->pfit); if (aslc_req & ASLC_SET_PWM_FREQ) - aslc_stat |= asle_set_pwm_freq(dev, asle->pfmb); + aslc_stat |= asle_set_pwm_freq(dev_priv, asle->pfmb); if (aslc_req & ASLC_SUPPORTED_ROTATION_ANGLES) - aslc_stat |= asle_set_supported_rotation_angles(dev, + aslc_stat |= asle_set_supported_rotation_angles(dev_priv, asle->srot); if (aslc_req & ASLC_BUTTON_ARRAY) - aslc_stat |= asle_set_button_array(dev, asle->iuer); + aslc_stat |= asle_set_button_array(dev_priv, asle->iuer); if (aslc_req & ASLC_CONVERTIBLE_INDICATOR) - aslc_stat |= asle_set_convertible(dev, asle->iuer); + aslc_stat |= asle_set_convertible(dev_priv, asle->iuer); if (aslc_req & ASLC_DOCKING_INDICATOR) - aslc_stat |= asle_set_docking(dev, asle->iuer); + aslc_stat |= asle_set_docking(dev_priv, asle->iuer); if (aslc_req & ASLC_ISCT_STATE_CHANGE) - aslc_stat |= asle_isct_state(dev); + aslc_stat |= asle_isct_state(dev_priv); asle->aslc = aslc_stat; } @@ -656,10 +657,10 @@ static void set_did(struct intel_opregion *opregion, int i, u32 val) } } -static void intel_didl_outputs(struct drm_device *dev) +static void intel_didl_outputs(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_opregion *opregion = &dev_priv->opregion; + struct pci_dev *pdev = dev_priv->dev->pdev; struct drm_connector *connector; acpi_handle handle; struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL; @@ -668,7 +669,7 @@ static void intel_didl_outputs(struct drm_device *dev) u32 temp, max_outputs; int i = 0; - handle = ACPI_HANDLE(&dev->pdev->dev); + handle = ACPI_HANDLE(&pdev->dev); if (!handle || acpi_bus_get_device(handle, &acpi_dev)) return; @@ -723,7 +724,7 @@ end: blind_set: i = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + list_for_each_entry(connector, &dev_priv->dev->mode_config.connector_list, head) { int output_type = ACPI_OTHER_OUTPUT; if (i >= max_outputs) { DRM_DEBUG_KMS("More than %u outputs in connector list\n", @@ -759,9 +760,8 @@ blind_set: goto end; } -static void intel_setup_cadls(struct drm_device *dev) +static void intel_setup_cadls(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_opregion *opregion = &dev_priv->opregion; int i = 0; u32 disp_id; @@ -778,17 +778,16 @@ static void intel_setup_cadls(struct drm_device *dev) } while (++i < 8 && disp_id != 0); } -void intel_opregion_init(struct drm_device *dev) +void intel_opregion_init(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_opregion *opregion = &dev_priv->opregion; if (!opregion->header) return; if (opregion->acpi) { - intel_didl_outputs(dev); - intel_setup_cadls(dev); + intel_didl_outputs(dev_priv); + intel_setup_cadls(dev_priv); /* Notify BIOS we are ready to handle ACPI video ext notifs. * Right now, all the events are handled by the ACPI video module. @@ -806,9 +805,8 @@ void intel_opregion_init(struct drm_device *dev) } } -void intel_opregion_fini(struct drm_device *dev) +void intel_opregion_fini(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_opregion *opregion = &dev_priv->opregion; if (!opregion->header) @@ -840,9 +838,8 @@ void intel_opregion_fini(struct drm_device *dev) opregion->lid_state = NULL; } -static void swsci_setup(struct drm_device *dev) +static void swsci_setup(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_opregion *opregion = &dev_priv->opregion; bool requested_callbacks = false; u32 tmp; @@ -852,7 +849,7 @@ static void swsci_setup(struct drm_device *dev) opregion->swsci_sbcb_sub_functions = 1; /* We use GBDA to ask for supported GBDA calls. */ - if (swsci(dev, SWSCI_GBDA_SUPPORTED_CALLS, 0, &tmp) == 0) { + if (swsci(dev_priv, SWSCI_GBDA_SUPPORTED_CALLS, 0, &tmp) == 0) { /* make the bits match the sub-function codes */ tmp <<= 1; opregion->swsci_gbda_sub_functions |= tmp; @@ -863,7 +860,7 @@ static void swsci_setup(struct drm_device *dev) * must not call interfaces that are not specifically requested by the * bios. */ - if (swsci(dev, SWSCI_GBDA_REQUESTED_CALLBACKS, 0, &tmp) == 0) { + if (swsci(dev_priv, SWSCI_GBDA_REQUESTED_CALLBACKS, 0, &tmp) == 0) { /* here, the bits already match sub-function codes */ opregion->swsci_sbcb_sub_functions |= tmp; requested_callbacks = true; @@ -874,7 +871,7 @@ static void swsci_setup(struct drm_device *dev) * the callback is _requested_. But we still can't call interfaces that * are not requested. */ - if (swsci(dev, SWSCI_SBCB_SUPPORTED_CALLBACKS, 0, &tmp) == 0) { + if (swsci(dev_priv, SWSCI_SBCB_SUPPORTED_CALLBACKS, 0, &tmp) == 0) { /* make the bits match the sub-function codes */ u32 low = tmp & 0x7ff; u32 high = tmp & ~0xfff; /* bit 11 is reserved */ @@ -916,10 +913,10 @@ static const struct dmi_system_id intel_no_opregion_vbt[] = { { } }; -int intel_opregion_setup(struct drm_device *dev) +int intel_opregion_setup(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_opregion *opregion = &dev_priv->opregion; + struct pci_dev *pdev = dev_priv->dev->pdev; u32 asls, mboxes; char buf[sizeof(OPREGION_SIGNATURE)]; int err = 0; @@ -931,7 +928,7 @@ int intel_opregion_setup(struct drm_device *dev) BUILD_BUG_ON(sizeof(struct opregion_asle) != 0x100); BUILD_BUG_ON(sizeof(struct opregion_asle_ext) != 0x400); - pci_read_config_dword(dev->pdev, ASLS, &asls); + pci_read_config_dword(pdev, ASLS, &asls); DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls); if (asls == 0) { DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n"); @@ -963,7 +960,7 @@ int intel_opregion_setup(struct drm_device *dev) if (mboxes & MBOX_SWSCI) { DRM_DEBUG_DRIVER("SWSCI supported\n"); opregion->swsci = base + OPREGION_SWSCI_OFFSET; - swsci_setup(dev); + swsci_setup(dev_priv); } if (mboxes & MBOX_ASLE) { @@ -1012,12 +1009,12 @@ err_out: } int -intel_opregion_get_panel_type(struct drm_device *dev) +intel_opregion_get_panel_type(struct drm_i915_private *dev_priv) { u32 panel_details; int ret; - ret = swsci(dev, SWSCI_GBDA_PANEL_DETAILS, 0x0, &panel_details); + ret = swsci(dev_priv, SWSCI_GBDA_PANEL_DETAILS, 0x0, &panel_details); if (ret) { DRM_DEBUG_KMS("Failed to get panel details from OpRegion (%d)\n", ret); -- cgit v0.10.2 From 03d92e4779b82e03f3fbf6631156eb0727fc75d4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 23 May 2016 15:08:10 +0100 Subject: drm/i915/opregion: Rename init/fini functions to register/unregister Current intel_opregion_init is called during the driver registration phase and intel_opregion_fini from the unregistration phase. Rename the functions so that this is clear from their names. The phases tell us what we expect the existing hw state to be, e.g. whether interrupts are still enabled etc. It should be noted that the opregion init/fini routines are asymmetric and this is carried across into their new names. Indeed, their new names make it even clearer that perhaps all is not well in the opregion suspend/resume sequence (as well in the module unload). Signed-off-by: Chris Wilson Cc: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1464012490-30961-2-git-send-email-chris@chris-wilson.co.uk Reviewed-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 3489c2b..aee5e59 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1379,7 +1379,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) if (INTEL_INFO(dev_priv)->num_pipes) { /* Must be done after probing outputs */ - intel_opregion_init(dev_priv); + intel_opregion_register(dev_priv); acpi_video_register(); } @@ -1398,7 +1398,7 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv) i915_audio_component_cleanup(dev_priv); intel_gpu_ips_teardown(); acpi_video_unregister(); - intel_opregion_fini(dev_priv); + intel_opregion_unregister(dev_priv); i915_teardown_sysfs(dev_priv->dev); i915_gem_shrinker_cleanup(dev_priv); } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 7627bbe..943d7b2 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -631,7 +631,7 @@ static int i915_drm_suspend(struct drm_device *dev) intel_opregion_notify_adapter(dev_priv, opregion_target_state); intel_uncore_forcewake_reset(dev_priv, false); - intel_opregion_fini(dev_priv); + intel_opregion_unregister(dev_priv); intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true); @@ -794,7 +794,7 @@ static int i915_drm_resume(struct drm_device *dev) /* Config may have changed between suspend and resume */ drm_helper_hpd_irq_event(dev); - intel_opregion_init(dev_priv); + intel_opregion_register(dev_priv); intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING, false); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index caf7e45..17fe272 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3609,8 +3609,8 @@ bool intel_bios_is_port_hpd_inverted(struct drm_i915_private *dev_priv, /* intel_opregion.c */ #ifdef CONFIG_ACPI extern int intel_opregion_setup(struct drm_i915_private *dev_priv); -extern void intel_opregion_init(struct drm_i915_private *dev_priv); -extern void intel_opregion_fini(struct drm_i915_private *dev_priv); +extern void intel_opregion_register(struct drm_i915_private *dev_priv); +extern void intel_opregion_unregister(struct drm_i915_private *dev_priv); extern void intel_opregion_asle_intr(struct drm_i915_private *dev_priv); extern int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, bool enable); diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index f9cdec8..f6d8a21d 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -778,7 +778,7 @@ static void intel_setup_cadls(struct drm_i915_private *dev_priv) } while (++i < 8 && disp_id != 0); } -void intel_opregion_init(struct drm_i915_private *dev_priv) +void intel_opregion_register(struct drm_i915_private *dev_priv) { struct intel_opregion *opregion = &dev_priv->opregion; @@ -805,7 +805,7 @@ void intel_opregion_init(struct drm_i915_private *dev_priv) } } -void intel_opregion_fini(struct drm_i915_private *dev_priv) +void intel_opregion_unregister(struct drm_i915_private *dev_priv) { struct intel_opregion *opregion = &dev_priv->opregion; -- cgit v0.10.2 From 9558d15dc2df1bf699b92836f815a5e70c76f17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:20 +0300 Subject: drm/i915: Fix BXT min_pixclk after state readout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4e5ca60fd35a ("drm/i915: Use ilk_max_pixel_rate() for BXT cdclk calculation") tried to change BXT to use ilk_max_pixel_rate() to compute the pipe pixel rate. I failed to notice that there was another place in the state readout code that needs the same treatment. So let's change that one too. Should probably just change things to always compuyte the pipe pixel rates, instead of just doing on platforms that can change cdclk dynamically. But for now let's just move BXT fully over to the side that uses ilk_pipe_pixel_rate(). Cc: Jani Nikula Fixes: 4e5ca60fd35a ("drm/i915: Use ilk_max_pixel_rate() for BXT cdclk calculation") Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-2-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 60ffbfd..9e7bc1d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15128,18 +15128,16 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) if (crtc_state->base.active) { dev_priv->active_crtcs |= 1 << crtc->pipe; - if (IS_BROADWELL(dev_priv)) { + if (IS_BROXTON(dev_priv) || IS_BROADWELL(dev_priv)) pixclk = ilk_pipe_pixel_rate(crtc_state); - - /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */ - if (crtc_state->ips_enabled) - pixclk = DIV_ROUND_UP(pixclk * 100, 95); - } else if (IS_VALLEYVIEW(dev_priv) || - IS_CHERRYVIEW(dev_priv) || - IS_BROXTON(dev_priv)) + else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) pixclk = crtc_state->base.adjusted_mode.crtc_clock; else WARN_ON(dev_priv->display.modeset_calc_cdclk); + + /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */ + if (IS_BROADWELL(dev_priv) && crtc_state->ips_enabled) + pixclk = DIV_ROUND_UP(pixclk * 100, 95); } dev_priv->min_pixclk[crtc->pipe] = pixclk; -- cgit v0.10.2 From c89e39f32763bbaeba0b66606bda7893a25489ac Mon Sep 17 00:00:00 2001 From: Clint Taylor Date: Fri, 13 May 2016 23:41:21 +0300 Subject: drm/i915/skl: SKL CDCLK change on modeset tracking VCO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WARNING: Using ChromeOS with an eDP panel and a 4K@60 DP monitor connected to DDI1 the system will hard hang during a cold boot. Occurs when DDI1 is enabled when the cdclk is less then required. DP connected to DDI2 and HPD on either port works correctly. Set cdclk based on the max required pixel clock based on VCO selected. Track boot vco instead of boot cdclk. The vco is now tracked at the atomic level and all CRTCs updated if the required vco is changed. Not tested with eDP v1.4 panels that require 8640 vco due to availability. V1: initial version V2: add vco tracking in intel_dp_compute_config(), rename skl_boot_cdclk. V3: rebase, V2 feedback not possible as encoders are not aware of atomic. V4: track target vco is atomic state. modeset all CRTCs if vco changes V5: rename atomic variable, cleaner if/else logic, use existing vco if encoder does not return a new vco value. check_patch.pl cleanup V6: simplify logic in intel_modeset_checks. V7: reorder an IF for readability and whitespace fix. V8: use dev_cdclk for tracking new cdclk during atomic V9: correctly handle vco 8640 when crtcs==0 V10: Clean up if else in crtcs==0 V11: Rebase for new intel_dpll_mgr.c Reviewed-by: Ville Syrjälä Signed-off-by: Clint Taylor [vsyrjala: rebased due to churn] Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-3-git-send-email-ville.syrjala@linux.intel.com diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 17fe272..edef5e2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1815,7 +1815,7 @@ struct drm_i915_private { int num_fence_regs; /* 8 on pre-965, 16 otherwise */ unsigned int fsb_freq, mem_freq, is_ddr3; - unsigned int skl_boot_cdclk; + unsigned int skl_vco_freq; unsigned int cdclk_freq, max_cdclk_freq, atomic_cdclk_freq; unsigned int max_dotclk_freq; unsigned int rawclk_freq; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9e7bc1d..964e964 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5460,7 +5460,7 @@ static const struct skl_cdclk_entry { { .freq = 675000, .vco = 8100 }, }; -static unsigned int skl_cdclk_get_vco(unsigned int freq) +unsigned int skl_cdclk_get_vco(unsigned int freq) { unsigned int i; @@ -5618,17 +5618,21 @@ void skl_uninit_cdclk(struct drm_i915_private *dev_priv) void skl_init_cdclk(struct drm_i915_private *dev_priv) { - unsigned int vco; + unsigned int cdclk; /* DPLL0 not enabled (happens on early BIOS versions) */ if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) { /* enable DPLL0 */ - vco = skl_cdclk_get_vco(dev_priv->skl_boot_cdclk); - skl_dpll0_enable(dev_priv, vco); + if (dev_priv->skl_vco_freq != 8640) + dev_priv->skl_vco_freq = 8100; + skl_dpll0_enable(dev_priv, dev_priv->skl_vco_freq); + cdclk = ((dev_priv->skl_vco_freq == 8100) ? 337500 : 308570); + } else { + cdclk = dev_priv->cdclk_freq; } - /* set CDCLK to the frequency the BIOS chose */ - skl_set_cdclk(dev_priv, dev_priv->skl_boot_cdclk); + /* set CDCLK to the lowest frequency, Modeset follows */ + skl_set_cdclk(dev_priv, cdclk); /* enable DBUF power */ I915_WRITE(DBUF_CTL, I915_READ(DBUF_CTL) | DBUF_POWER_REQUEST); @@ -5644,7 +5648,7 @@ int skl_sanitize_cdclk(struct drm_i915_private *dev_priv) { uint32_t lcpll1 = I915_READ(LCPLL1_CTL); uint32_t cdctl = I915_READ(CDCLK_CTL); - int freq = dev_priv->skl_boot_cdclk; + int freq = dev_priv->cdclk_freq; /* * check if the pre-os intialized the display @@ -5668,11 +5672,7 @@ int skl_sanitize_cdclk(struct drm_i915_private *dev_priv) /* All well; nothing to sanitize */ return false; sanitize: - /* - * As of now initialize with max cdclk till - * we get dynamic cdclk support - * */ - dev_priv->skl_boot_cdclk = dev_priv->max_cdclk_freq; + skl_init_cdclk(dev_priv); /* we did have to sanitize */ @@ -9645,6 +9645,73 @@ static void broadwell_modeset_commit_cdclk(struct drm_atomic_state *old_state) broadwell_set_cdclk(dev, req_cdclk); } +static int skl_modeset_calc_cdclk(struct drm_atomic_state *state) +{ + struct intel_atomic_state *intel_state = to_intel_atomic_state(state); + struct drm_i915_private *dev_priv = to_i915(state->dev); + const int max_pixclk = ilk_max_pixel_rate(state); + int cdclk; + + /* + * FIXME should also account for plane ratio + * once 64bpp pixel formats are supported. + */ + + if (intel_state->cdclk_pll_vco == 8640) { + /* vco 8640 */ + if (max_pixclk > 540000) + cdclk = 617140; + else if (max_pixclk > 432000) + cdclk = 540000; + else if (max_pixclk > 308570) + cdclk = 432000; + else + cdclk = 308570; + } else { + /* VCO 8100 */ + if (max_pixclk > 540000) + cdclk = 675000; + else if (max_pixclk > 450000) + cdclk = 540000; + else if (max_pixclk > 337500) + cdclk = 450000; + else + cdclk = 337500; + } + + /* + * FIXME move the cdclk caclulation to + * compute_config() so we can fail gracegully. + */ + if (cdclk > dev_priv->max_cdclk_freq) { + DRM_ERROR("requested cdclk (%d kHz) exceeds max (%d kHz)\n", + cdclk, dev_priv->max_cdclk_freq); + cdclk = dev_priv->max_cdclk_freq; + } + + intel_state->cdclk = intel_state->dev_cdclk = cdclk; + if (!intel_state->active_crtcs) + intel_state->dev_cdclk = ((intel_state->cdclk_pll_vco == 8640) ? + 308570 : 337500); + + + return 0; +} + +static void skl_modeset_commit_cdclk(struct drm_atomic_state *old_state) +{ + struct drm_device *dev = old_state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned int req_cdclk = to_intel_atomic_state(old_state)->dev_cdclk; + + /* + * FIXME disable/enable PLL should wrap set_cdclk() + */ + skl_set_cdclk(dev_priv, req_cdclk); + + dev_priv->skl_vco_freq = to_intel_atomic_state(old_state)->cdclk_pll_vco; +} + static int haswell_crtc_compute_clock(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state) { @@ -12575,9 +12642,15 @@ static int intel_modeset_checks(struct drm_atomic_state *state) * adjusted_mode bits in the crtc directly. */ if (dev_priv->display.modeset_calc_cdclk) { + if (!intel_state->cdclk_pll_vco) + intel_state->cdclk_pll_vco = dev_priv->skl_vco_freq; + ret = dev_priv->display.modeset_calc_cdclk(state); + if (ret < 0) + return ret; - if (!ret && intel_state->dev_cdclk != dev_priv->cdclk_freq) + if (intel_state->dev_cdclk != dev_priv->cdclk_freq || + intel_state->cdclk_pll_vco != dev_priv->skl_vco_freq) ret = intel_modeset_all_pipes(state); if (ret < 0) @@ -13063,7 +13136,8 @@ static int intel_atomic_commit(struct drm_device *dev, drm_atomic_helper_update_legacy_modeset_state(state->dev, state); if (dev_priv->display.modeset_commit_cdclk && - intel_state->dev_cdclk != dev_priv->cdclk_freq) + (intel_state->dev_cdclk != dev_priv->cdclk_freq || + intel_state->cdclk_pll_vco != dev_priv->skl_vco_freq)) dev_priv->display.modeset_commit_cdclk(state); intel_modeset_verify_disabled(dev); @@ -14449,6 +14523,11 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv) broxton_modeset_commit_cdclk; dev_priv->display.modeset_calc_cdclk = broxton_modeset_calc_cdclk; + } else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) { + dev_priv->display.modeset_commit_cdclk = + skl_modeset_commit_cdclk; + dev_priv->display.modeset_calc_cdclk = + skl_modeset_calc_cdclk; } } @@ -15128,7 +15207,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) if (crtc_state->base.active) { dev_priv->active_crtcs |= 1 << crtc->pipe; - if (IS_BROXTON(dev_priv) || IS_BROADWELL(dev_priv)) + if (INTEL_GEN(dev_priv) >= 9 || IS_BROADWELL(dev_priv)) pixclk = ilk_pipe_pixel_rate(crtc_state); else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) pixclk = crtc_state->base.adjusted_mode.crtc_clock; diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index c283ba4..e99e306 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -1194,6 +1194,7 @@ skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, struct intel_shared_dpll *pll; uint32_t ctrl1, cfgcr1, cfgcr2; int clock = crtc_state->port_clock; + uint32_t vco = 8100; /* * See comment in intel_dpll_hw_state to understand why we always use 0 @@ -1236,17 +1237,17 @@ skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, case 162000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0); break; - /* TBD: For DP link rates 2.16 GHz and 4.32 GHz, VCO is 8640 which - results in CDCLK change. Need to handle the change of CDCLK by - disabling pipes and re-enabling them */ case 108000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0); + vco = 8640; break; case 216000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0); + vco = 8640; break; } + to_intel_atomic_state(crtc_state->base.state)->cdclk_pll_vco = vco; cfgcr1 = cfgcr2 = 0; } else { return NULL; @@ -1639,7 +1640,7 @@ static void intel_ddi_pll_init(struct drm_device *dev) int cdclk_freq; cdclk_freq = dev_priv->display.get_display_clock_speed(dev); - dev_priv->skl_boot_cdclk = cdclk_freq; + dev_priv->skl_vco_freq = skl_cdclk_get_vco(cdclk_freq); if (skl_sanitize_cdclk(dev_priv)) DRM_DEBUG_KMS("Sanitized cdclk programmed by pre-os\n"); if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0741b2d..8e8ce98 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -306,6 +306,9 @@ struct intel_atomic_state { struct intel_flip_work *work[I915_MAX_PIPES]; + /* SKL/KBL Only */ + unsigned int cdclk_pll_vco; + struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS]; /* @@ -1277,6 +1280,7 @@ void gen9_enable_dc5(struct drm_i915_private *dev_priv); void skl_init_cdclk(struct drm_i915_private *dev_priv); int skl_sanitize_cdclk(struct drm_i915_private *dev_priv); void skl_uninit_cdclk(struct drm_i915_private *dev_priv); +unsigned int skl_cdclk_get_vco(unsigned int freq); void skl_enable_dc6(struct drm_i915_private *dev_priv); void skl_disable_dc6(struct drm_i915_private *dev_priv); void intel_dp_get_m_n(struct intel_crtc *crtc, -- cgit v0.10.2 From 14d41b3b0e2ffbed309e68c87031986016d7bcac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:22 +0300 Subject: drm/i915: Move the SKL DPLL0 VCO computation into intel_dp_compute_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shared plls won't get assigned until the .compute_clocks() hook gets called, which happens from the crtc .atomic_check hook. That's too late as the cdclk computation has already happened. So let's move the DPLL0 VCO computation into intel_dp_compute_config() so that it's done when the cdclk computation happens. Also only do it for eDP since we only pick DPLL0 for eDP. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-4-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index cccf9bc..8b67e0f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1578,6 +1578,27 @@ found: &pipe_config->dp_m2_n2); } + /* + * DPLL0 VCO may need to be adjusted to get the correct + * clock for eDP. This will affect cdclk as well. + */ + if (is_edp(intel_dp) && + (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))) { + int vco; + + switch (pipe_config->port_clock / 2) { + case 108000: + case 216000: + vco = 8640; + break; + default: + vco = 8100; + break; + } + + to_intel_atomic_state(pipe_config->base.state)->cdclk_pll_vco = vco; + } + if (!HAS_DDI(dev)) intel_dp_set_clock(encoder, pipe_config); diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index e99e306..43ba60b 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -1194,7 +1194,6 @@ skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, struct intel_shared_dpll *pll; uint32_t ctrl1, cfgcr1, cfgcr2; int clock = crtc_state->port_clock; - uint32_t vco = 8100; /* * See comment in intel_dpll_hw_state to understand why we always use 0 @@ -1239,15 +1238,12 @@ skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, break; case 108000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0); - vco = 8640; break; case 216000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0); - vco = 8640; break; } - to_intel_atomic_state(crtc_state->base.state)->cdclk_pll_vco = vco; cfgcr1 = cfgcr2 = 0; } else { return NULL; -- cgit v0.10.2 From a8ca49345253923059df2663f48e72039095f63e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:23 +0300 Subject: drm/i915: Extract skl_calc_cdclk() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have many places where we want to pick a suitable cdclk frequency for skl based on the dotclock and lcpll vco. Split that code into a small helper and call it from all over. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-5-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 964e964..78f3918 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5447,6 +5447,30 @@ void broxton_uninit_cdclk(struct drm_i915_private *dev_priv) broxton_set_cdclk(dev_priv, 19200); } +static int skl_calc_cdclk(int max_pixclk, int vco) +{ + if (vco == 8640) { + if (max_pixclk > 540000) + return 617140; + else if (max_pixclk > 432000) + return 540000; + else if (max_pixclk > 308570) + return 432000; + else + return 308570; + } else { + /* VCO 8100 */ + if (max_pixclk > 540000) + return 675000; + else if (max_pixclk > 450000) + return 540000; + else if (max_pixclk > 337500) + return 450000; + else + return 337500; + } +} + static const struct skl_cdclk_entry { unsigned int freq; unsigned int vco; @@ -5477,15 +5501,10 @@ unsigned int skl_cdclk_get_vco(unsigned int freq) static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) { - int min_cdclk; + int min_cdclk = skl_calc_cdclk(0, vco); u32 val; /* select the minimum CDCLK before enabling DPLL 0 */ - if (vco == 8640) - min_cdclk = 308570; - else - min_cdclk = 337500; - val = CDCLK_FREQ_337_308 | skl_cdclk_decimal(min_cdclk); I915_WRITE(CDCLK_CTL, val); POSTING_READ(CDCLK_CTL); @@ -5497,7 +5516,7 @@ skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) * 8100 while the eDP 1.4 alternate link rates need a VCO of 8640. * The modeset code is responsible for the selection of the exact link * rate later on, with the constraint of choosing a frequency that - * works with required_vco. + * works with vco. */ val = I915_READ(DPLL_CTRL1); @@ -5626,7 +5645,7 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv) if (dev_priv->skl_vco_freq != 8640) dev_priv->skl_vco_freq = 8100; skl_dpll0_enable(dev_priv, dev_priv->skl_vco_freq); - cdclk = ((dev_priv->skl_vco_freq == 8100) ? 337500 : 308570); + cdclk = skl_calc_cdclk(0, dev_priv->skl_vco_freq); } else { cdclk = dev_priv->cdclk_freq; } @@ -9650,34 +9669,14 @@ static int skl_modeset_calc_cdclk(struct drm_atomic_state *state) struct intel_atomic_state *intel_state = to_intel_atomic_state(state); struct drm_i915_private *dev_priv = to_i915(state->dev); const int max_pixclk = ilk_max_pixel_rate(state); + int vco = intel_state->cdclk_pll_vco; int cdclk; /* * FIXME should also account for plane ratio * once 64bpp pixel formats are supported. */ - - if (intel_state->cdclk_pll_vco == 8640) { - /* vco 8640 */ - if (max_pixclk > 540000) - cdclk = 617140; - else if (max_pixclk > 432000) - cdclk = 540000; - else if (max_pixclk > 308570) - cdclk = 432000; - else - cdclk = 308570; - } else { - /* VCO 8100 */ - if (max_pixclk > 540000) - cdclk = 675000; - else if (max_pixclk > 450000) - cdclk = 540000; - else if (max_pixclk > 337500) - cdclk = 450000; - else - cdclk = 337500; - } + cdclk = skl_calc_cdclk(max_pixclk, vco); /* * FIXME move the cdclk caclulation to @@ -9691,9 +9690,7 @@ static int skl_modeset_calc_cdclk(struct drm_atomic_state *state) intel_state->cdclk = intel_state->dev_cdclk = cdclk; if (!intel_state->active_crtcs) - intel_state->dev_cdclk = ((intel_state->cdclk_pll_vco == 8640) ? - 308570 : 337500); - + intel_state->dev_cdclk = skl_calc_cdclk(0, vco); return 0; } -- cgit v0.10.2 From ea61791e598e3ddd26578958246c6ea631eeefbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:24 +0300 Subject: drm/i915: Actually read out DPLL0 vco on skl from hardware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we're trying to guess which lcpll vco frequency is used use based on the cdclk. That doesn't work for cdclk==540 since both vco frequencies can generate a 540 Mhz output. Let's stop guessing and just read the actual vco frequency from the hardware. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-6-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 78f3918..27b4b88 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5471,31 +5471,35 @@ static int skl_calc_cdclk(int max_pixclk, int vco) } } -static const struct skl_cdclk_entry { - unsigned int freq; - unsigned int vco; -} skl_cdclk_frequencies[] = { - { .freq = 308570, .vco = 8640 }, - { .freq = 337500, .vco = 8100 }, - { .freq = 432000, .vco = 8640 }, - { .freq = 450000, .vco = 8100 }, - { .freq = 540000, .vco = 8100 }, - { .freq = 617140, .vco = 8640 }, - { .freq = 675000, .vco = 8100 }, -}; - -unsigned int skl_cdclk_get_vco(unsigned int freq) +static void +skl_dpll0_update(struct drm_i915_private *dev_priv) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(skl_cdclk_frequencies); i++) { - const struct skl_cdclk_entry *e = &skl_cdclk_frequencies[i]; + u32 val; - if (e->freq == freq) - return e->vco; + val = I915_READ(LCPLL1_CTL); + if ((val & LCPLL_PLL_ENABLE) == 0) { + dev_priv->skl_vco_freq = 0; + return; } - return 8100; + val = I915_READ(DPLL_CTRL1); + + switch (val & DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0)) { + case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, SKL_DPLL0): + case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, SKL_DPLL0): + case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, SKL_DPLL0): + case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, SKL_DPLL0): + dev_priv->skl_vco_freq = 8100; + break; + case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, SKL_DPLL0): + case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, SKL_DPLL0): + dev_priv->skl_vco_freq = 8640; + break; + default: + MISSING_CASE(val & DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0)); + dev_priv->skl_vco_freq = 0; + break; + } } static void @@ -6540,43 +6544,40 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, static int skylake_get_display_clock_speed(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); - uint32_t lcpll1 = I915_READ(LCPLL1_CTL); - uint32_t cdctl = I915_READ(CDCLK_CTL); - uint32_t linkrate; + uint32_t cdctl; - if (!(lcpll1 & LCPLL_PLL_ENABLE)) - return 24000; /* 24MHz is the cd freq with NSSC ref */ + skl_dpll0_update(dev_priv); - if ((cdctl & CDCLK_FREQ_SEL_MASK) == CDCLK_FREQ_540) - return 540000; + if (dev_priv->skl_vco_freq == 0) + return 24000; /* 24MHz is the cd freq with NSSC ref */ - linkrate = (I915_READ(DPLL_CTRL1) & - DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0)) >> 1; + cdctl = I915_READ(CDCLK_CTL); - if (linkrate == DPLL_CTRL1_LINK_RATE_2160 || - linkrate == DPLL_CTRL1_LINK_RATE_1080) { - /* vco 8640 */ + if (dev_priv->skl_vco_freq == 8640) { switch (cdctl & CDCLK_FREQ_SEL_MASK) { case CDCLK_FREQ_450_432: return 432000; case CDCLK_FREQ_337_308: return 308570; + case CDCLK_FREQ_540: + return 540000; case CDCLK_FREQ_675_617: return 617140; default: - WARN(1, "Unknown cd freq selection\n"); + MISSING_CASE(cdctl & CDCLK_FREQ_SEL_MASK); } } else { - /* vco 8100 */ switch (cdctl & CDCLK_FREQ_SEL_MASK) { case CDCLK_FREQ_450_432: return 450000; case CDCLK_FREQ_337_308: return 337500; + case CDCLK_FREQ_540: + return 540000; case CDCLK_FREQ_675_617: return 675000; default: - WARN(1, "Unknown cd freq selection\n"); + MISSING_CASE(cdctl & CDCLK_FREQ_SEL_MASK); } } diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 43ba60b..5391ab6 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -1633,14 +1633,8 @@ static void intel_ddi_pll_init(struct drm_device *dev) uint32_t val = I915_READ(LCPLL_CTL); if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { - int cdclk_freq; - - cdclk_freq = dev_priv->display.get_display_clock_speed(dev); - dev_priv->skl_vco_freq = skl_cdclk_get_vco(cdclk_freq); if (skl_sanitize_cdclk(dev_priv)) DRM_DEBUG_KMS("Sanitized cdclk programmed by pre-os\n"); - if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) - DRM_ERROR("LCPLL1 is disabled\n"); } else if (!IS_BROXTON(dev_priv)) { /* * The LCPLL register should be turned on by the BIOS. For now -- cgit v0.10.2 From 2f2a121aba7652608bbe84574241e799cad35a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:25 +0300 Subject: drm/i915: Report the current DPLL0 vco on SKL/KBL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-7-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 27b4b88..ff07662 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5240,8 +5240,13 @@ static void intel_update_cdclk(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; dev_priv->cdclk_freq = dev_priv->display.get_display_clock_speed(dev); - DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz\n", - dev_priv->cdclk_freq); + + if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) + DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz, VCO: %d MHz\n", + dev_priv->cdclk_freq, dev_priv->skl_vco_freq); + else + DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz\n", + dev_priv->cdclk_freq); /* * 9:0 CMBUS [sic] CDCLK frequency (cdfreq): -- cgit v0.10.2 From 1cd593e009db55d5844056305309bb52639d71a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:26 +0300 Subject: drm/i915: Allow enable/disable of DPLL0 around cdclk changes on SKL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case we originally guessed wrong which lcpll vco frequency to use, we will need to shut down the pll and restart it when reprogamming the cdclk. This also allows us to track the actual vco frequency in dev_priv instead of just a guess. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-8-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ff07662..9c50b9b8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5546,6 +5546,8 @@ skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) if (wait_for(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK, 5)) DRM_ERROR("DPLL0 not locked\n"); + + dev_priv->skl_vco_freq = vco; } static void @@ -5554,6 +5556,8 @@ skl_dpll0_disable(struct drm_i915_private *dev_priv) I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) & ~LCPLL_PLL_ENABLE); if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1)) DRM_ERROR("Couldn't disable DPLL0\n"); + + dev_priv->skl_vco_freq = 0; } static bool skl_cdclk_pcu_ready(struct drm_i915_private *dev_priv) @@ -5583,12 +5587,14 @@ static bool skl_cdclk_wait_for_pcu_ready(struct drm_i915_private *dev_priv) return false; } -static void skl_set_cdclk(struct drm_i915_private *dev_priv, int cdclk) +static void skl_set_cdclk(struct drm_i915_private *dev_priv, int cdclk, int vco) { struct drm_device *dev = dev_priv->dev; u32 freq_select, pcu_ack; - DRM_DEBUG_DRIVER("Changing CDCLK to %dKHz\n", cdclk); + WARN_ON((cdclk == 24000) != (vco == 0)); + + DRM_DEBUG_DRIVER("Changing CDCLK to %d kHz (VCO %d MHz)\n", cdclk, vco); if (!skl_cdclk_wait_for_pcu_ready(dev_priv)) { DRM_ERROR("failed to inform PCU about cdclk change\n"); @@ -5619,6 +5625,13 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, int cdclk) break; } + if (dev_priv->skl_vco_freq != 0 && + dev_priv->skl_vco_freq != vco) + skl_dpll0_disable(dev_priv); + + if (dev_priv->skl_vco_freq != vco) + skl_dpll0_enable(dev_priv, vco); + I915_WRITE(CDCLK_CTL, freq_select | skl_cdclk_decimal(cdclk)); POSTING_READ(CDCLK_CTL); @@ -5641,26 +5654,21 @@ void skl_uninit_cdclk(struct drm_i915_private *dev_priv) if (I915_READ(DBUF_CTL) & DBUF_POWER_STATE) DRM_ERROR("DBuf power disable timeout\n"); - skl_dpll0_disable(dev_priv); + skl_set_cdclk(dev_priv, 24000, 0); } void skl_init_cdclk(struct drm_i915_private *dev_priv) { - unsigned int cdclk; - /* DPLL0 not enabled (happens on early BIOS versions) */ - if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) { - /* enable DPLL0 */ - if (dev_priv->skl_vco_freq != 8640) - dev_priv->skl_vco_freq = 8100; - skl_dpll0_enable(dev_priv, dev_priv->skl_vco_freq); - cdclk = skl_calc_cdclk(0, dev_priv->skl_vco_freq); - } else { - cdclk = dev_priv->cdclk_freq; - } + if (dev_priv->skl_vco_freq == 0) { + int cdclk, vco; - /* set CDCLK to the lowest frequency, Modeset follows */ - skl_set_cdclk(dev_priv, cdclk); + /* set CDCLK to the lowest frequency, Modeset follows */ + vco = 8100; + cdclk = skl_calc_cdclk(0, vco); + + skl_set_cdclk(dev_priv, cdclk, vco); + } /* enable DBUF power */ I915_WRITE(DBUF_CTL, I915_READ(DBUF_CTL) | DBUF_POWER_REQUEST); @@ -9703,16 +9711,12 @@ static int skl_modeset_calc_cdclk(struct drm_atomic_state *state) static void skl_modeset_commit_cdclk(struct drm_atomic_state *old_state) { - struct drm_device *dev = old_state->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - unsigned int req_cdclk = to_intel_atomic_state(old_state)->dev_cdclk; - - /* - * FIXME disable/enable PLL should wrap set_cdclk() - */ - skl_set_cdclk(dev_priv, req_cdclk); + struct drm_i915_private *dev_priv = to_i915(old_state->dev); + struct intel_atomic_state *intel_state = to_intel_atomic_state(old_state); + unsigned int req_cdclk = intel_state->dev_cdclk; + unsigned int req_vco = intel_state->cdclk_pll_vco; - dev_priv->skl_vco_freq = to_intel_atomic_state(old_state)->cdclk_pll_vco; + skl_set_cdclk(dev_priv, req_cdclk, req_vco); } static int haswell_crtc_compute_clock(struct intel_crtc *crtc, -- cgit v0.10.2 From b204535204fe9c1f647195ca587f210b18249904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:27 +0300 Subject: drm/i915: Keep track of preferred cdclk vco frequency on SKL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that skl_vco_freq tracks the actual DPLL0 vco frequency, we'll need something that keeps track of which vco frequency we want to use in case the current vco is 0. This would be important across supend/resume since we'll disable DPLL0 around those parts. We'll also update our idea of max cdclk/dotclock when the preferred vco changes. That could happen if out initial guess was wrong, and later eDP would force us to change it. One issue here could be that changing the max dotclock could cause our mode list to change during next time the displays get probed. But I don't see a good way to avoid that, except perhaps by allowing either vco frequency to be used as needed. But the docs suggest that such usage wasn't really inteded. Also need to make sure we don't update our max_cdclk value before we have a preferred vco value, which means moving that to happen after the cdclk sanitation. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-9-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index edef5e2..36ed636 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1816,6 +1816,7 @@ struct drm_i915_private { unsigned int fsb_freq, mem_freq, is_ddr3; unsigned int skl_vco_freq; + unsigned int skl_preferred_vco_freq; unsigned int cdclk_freq, max_cdclk_freq, atomic_cdclk_freq; unsigned int max_dotclk_freq; unsigned int rawclk_freq; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9c50b9b8..2d8630f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5185,21 +5185,34 @@ static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv) return max_cdclk_freq*90/100; } +static int skl_calc_cdclk(int max_pixclk, int vco); + static void intel_update_max_cdclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK; + int max_cdclk, vco; + + vco = dev_priv->skl_preferred_vco_freq; + WARN_ON(vco != 8100 && vco != 8640); + /* + * Use the lower (vco 8640) cdclk values as a + * first guess. skl_calc_cdclk() will correct it + * if the preferred vco is 8100 instead. + */ if (limit == SKL_DFSM_CDCLK_LIMIT_675) - dev_priv->max_cdclk_freq = 675000; + max_cdclk = 617140; else if (limit == SKL_DFSM_CDCLK_LIMIT_540) - dev_priv->max_cdclk_freq = 540000; + max_cdclk = 540000; else if (limit == SKL_DFSM_CDCLK_LIMIT_450) - dev_priv->max_cdclk_freq = 450000; + max_cdclk = 432000; else - dev_priv->max_cdclk_freq = 337500; + max_cdclk = 308570; + + dev_priv->max_cdclk_freq = skl_calc_cdclk(max_cdclk, vco); } else if (IS_BROXTON(dev)) { dev_priv->max_cdclk_freq = 624000; } else if (IS_BROADWELL(dev)) { @@ -5256,9 +5269,6 @@ static void intel_update_cdclk(struct drm_device *dev) */ if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->cdclk_freq, 1000)); - - if (dev_priv->max_cdclk_freq == 0) - intel_update_max_cdclk(dev); } /* convert from kHz to .1 fixpoint MHz with -1MHz offset */ @@ -5507,12 +5517,24 @@ skl_dpll0_update(struct drm_i915_private *dev_priv) } } +void skl_set_preferred_cdclk_vco(struct drm_i915_private *dev_priv, int vco) +{ + bool changed = dev_priv->skl_preferred_vco_freq != vco; + + dev_priv->skl_preferred_vco_freq = vco; + + if (changed) + intel_update_max_cdclk(dev_priv->dev); +} + static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) { int min_cdclk = skl_calc_cdclk(0, vco); u32 val; + WARN_ON(vco != 8100 && vco != 8640); + /* select the minimum CDCLK before enabling DPLL 0 */ val = CDCLK_FREQ_337_308 | skl_cdclk_decimal(min_cdclk); I915_WRITE(CDCLK_CTL, val); @@ -5548,6 +5570,9 @@ skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) DRM_ERROR("DPLL0 not locked\n"); dev_priv->skl_vco_freq = vco; + + /* We'll want to keep using the current vco from now on. */ + skl_set_preferred_cdclk_vco(dev_priv, vco); } static void @@ -5664,7 +5689,9 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv) int cdclk, vco; /* set CDCLK to the lowest frequency, Modeset follows */ - vco = 8100; + vco = dev_priv->skl_preferred_vco_freq; + if (vco == 0) + vco = 8100; cdclk = skl_calc_cdclk(0, vco); skl_set_cdclk(dev_priv, cdclk, vco); @@ -12651,6 +12678,8 @@ static int intel_modeset_checks(struct drm_atomic_state *state) if (dev_priv->display.modeset_calc_cdclk) { if (!intel_state->cdclk_pll_vco) intel_state->cdclk_pll_vco = dev_priv->skl_vco_freq; + if (!intel_state->cdclk_pll_vco) + intel_state->cdclk_pll_vco = dev_priv->skl_preferred_vco_freq; ret = dev_priv->display.modeset_calc_cdclk(state); if (ret < 0) @@ -14905,6 +14934,9 @@ void intel_modeset_init(struct drm_device *dev) intel_shared_dpll_init(dev); + if (dev_priv->max_cdclk_freq == 0) + intel_update_max_cdclk(dev); + /* Just disable it once at startup */ i915_disable_vga(dev); intel_setup_outputs(dev); diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 5391ab6..34ec149 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -1635,6 +1635,11 @@ static void intel_ddi_pll_init(struct drm_device *dev) if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { if (skl_sanitize_cdclk(dev_priv)) DRM_DEBUG_KMS("Sanitized cdclk programmed by pre-os\n"); + + /* We'll want to keep using the current vco from now on */ + if (dev_priv->skl_vco_freq != 0) + skl_set_preferred_cdclk_vco(dev_priv, + dev_priv->skl_vco_freq); } else if (!IS_BROXTON(dev_priv)) { /* * The LCPLL register should be turned on by the BIOS. For now diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8e8ce98..2bee217 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1143,6 +1143,7 @@ void i915_audio_component_init(struct drm_i915_private *dev_priv); void i915_audio_component_cleanup(struct drm_i915_private *dev_priv); /* intel_display.c */ +void skl_set_preferred_cdclk_vco(struct drm_i915_private *dev_priv, int vco); void intel_update_rawclk(struct drm_i915_private *dev_priv); int vlv_get_cck_clock(struct drm_i915_private *dev_priv, const char *name, u32 reg, int ref_freq); -- cgit v0.10.2 From 09492498ee631041bfc60f2dc1960e246b8a7120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:28 +0300 Subject: drm/i915: Beef up skl_sanitize_cdclk() a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also verify the DPLL_CTRL1 register value in skl_sanitize_cdclk(), throw out a few unneeded variables, and write the CDCLK_CTL check a bit more legible way. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-10-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2d8630f..b2adb01 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5709,9 +5709,7 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv) int skl_sanitize_cdclk(struct drm_i915_private *dev_priv) { - uint32_t lcpll1 = I915_READ(LCPLL1_CTL); - uint32_t cdctl = I915_READ(CDCLK_CTL); - int freq = dev_priv->cdclk_freq; + uint32_t cdctl, expected; /* * check if the pre-os intialized the display @@ -5722,7 +5720,14 @@ int skl_sanitize_cdclk(struct drm_i915_private *dev_priv) goto sanitize; /* Is PLL enabled and locked ? */ - if (!((lcpll1 & LCPLL_PLL_ENABLE) && (lcpll1 & LCPLL_PLL_LOCK))) + if ((I915_READ(LCPLL1_CTL) & (LCPLL_PLL_ENABLE | LCPLL_PLL_LOCK)) != + (LCPLL_PLL_ENABLE | LCPLL_PLL_LOCK)) + goto sanitize; + + if ((I915_READ(DPLL_CTRL1) & (DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | + DPLL_CTRL1_SSC(SKL_DPLL0) | + DPLL_CTRL1_OVERRIDE(SKL_DPLL0))) != + DPLL_CTRL1_OVERRIDE(SKL_DPLL0)) goto sanitize; /* DPLL okay; verify the cdclock @@ -5731,7 +5736,10 @@ int skl_sanitize_cdclk(struct drm_i915_private *dev_priv) * decimal part is programmed wrong from BIOS where pre-os does not * enable display. Verify the same as well. */ - if (cdctl == ((cdctl & CDCLK_FREQ_SEL_MASK) | skl_cdclk_decimal(freq))) + cdctl = I915_READ(CDCLK_CTL); + expected = (cdctl & CDCLK_FREQ_SEL_MASK) | + skl_cdclk_decimal(dev_priv->cdclk_freq); + if (cdctl == expected) /* All well; nothing to sanitize */ return false; sanitize: -- cgit v0.10.2 From 9f7eb31af2968a194b29f67ec10776685a81afc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:29 +0300 Subject: drm/i915: Unify SKL cdclk init paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we initialize cdclk on SKL from two different places, depending on whether it's during driver init or resume. Let's unify it to happen from the same place always, and that place will be the display core init function. To do this we first run through the cdclk sanitation code, which will first verify that the PLL is programmed correctly, after which we can read out the current cdclk frequency, and once the cdclk is known we verify that the cdclk "decimal" frequency is programmed correctly. If any of these fail we will force a cdclk change, and to be safe we also force the PLL to be turned off and on again. If the sanitation step didn't notice anything amiss, we'll skip the cdclk programming which will prevent cdclk reprogramming when the displays might be active. We can also toss in a few WARNs about the register values into skl_update_dpll0() since we now know that the PLL state should always be sane when that function is called. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-11-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b2adb01..58b8d75 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5497,8 +5497,15 @@ skl_dpll0_update(struct drm_i915_private *dev_priv) return; } + WARN_ON((val & LCPLL_PLL_LOCK) == 0); + val = I915_READ(DPLL_CTRL1); + WARN_ON((val & (DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | + DPLL_CTRL1_SSC(SKL_DPLL0) | + DPLL_CTRL1_OVERRIDE(SKL_DPLL0))) != + DPLL_CTRL1_OVERRIDE(SKL_DPLL0)); + switch (val & DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0)) { case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, SKL_DPLL0): case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, SKL_DPLL0): @@ -5668,6 +5675,8 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, int cdclk, int vco) intel_update_cdclk(dev); } +static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv); + void skl_uninit_cdclk(struct drm_i915_private *dev_priv) { /* disable DBUF power */ @@ -5684,10 +5693,19 @@ void skl_uninit_cdclk(struct drm_i915_private *dev_priv) void skl_init_cdclk(struct drm_i915_private *dev_priv) { - /* DPLL0 not enabled (happens on early BIOS versions) */ - if (dev_priv->skl_vco_freq == 0) { - int cdclk, vco; + int cdclk, vco; + + skl_sanitize_cdclk(dev_priv); + if (dev_priv->cdclk_freq != 0 && dev_priv->skl_vco_freq != 0) { + /* + * Use the current vco as our initial + * guess as to what the preferred vco is. + */ + if (dev_priv->skl_preferred_vco_freq == 0) + skl_set_preferred_cdclk_vco(dev_priv, + dev_priv->skl_vco_freq); + } else { /* set CDCLK to the lowest frequency, Modeset follows */ vco = dev_priv->skl_preferred_vco_freq; if (vco == 0) @@ -5707,7 +5725,7 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv) DRM_ERROR("DBuf power enable timeout\n"); } -int skl_sanitize_cdclk(struct drm_i915_private *dev_priv) +static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv) { uint32_t cdctl, expected; @@ -5730,6 +5748,8 @@ int skl_sanitize_cdclk(struct drm_i915_private *dev_priv) DPLL_CTRL1_OVERRIDE(SKL_DPLL0)) goto sanitize; + intel_update_cdclk(dev_priv->dev); + /* DPLL okay; verify the cdclock * * Noticed in some instances that the freq selection is correct but @@ -5741,13 +5761,15 @@ int skl_sanitize_cdclk(struct drm_i915_private *dev_priv) skl_cdclk_decimal(dev_priv->cdclk_freq); if (cdctl == expected) /* All well; nothing to sanitize */ - return false; -sanitize: + return; - skl_init_cdclk(dev_priv); +sanitize: + DRM_DEBUG_KMS("Sanitizing cdclk programmed by pre-os\n"); - /* we did have to sanitize */ - return true; + /* force cdclk programming */ + dev_priv->cdclk_freq = 0; + /* force full PLL disable + enable */ + dev_priv->skl_vco_freq = -1; } /* Adjust CDclk dividers to allow high res or save power if possible */ diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 34ec149..6b70e1e 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -1630,17 +1630,10 @@ static const struct intel_shared_dpll_funcs bxt_ddi_pll_funcs = { static void intel_ddi_pll_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t val = I915_READ(LCPLL_CTL); - if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { - if (skl_sanitize_cdclk(dev_priv)) - DRM_DEBUG_KMS("Sanitized cdclk programmed by pre-os\n"); + if (INTEL_GEN(dev_priv) < 9) { + uint32_t val = I915_READ(LCPLL_CTL); - /* We'll want to keep using the current vco from now on */ - if (dev_priv->skl_vco_freq != 0) - skl_set_preferred_cdclk_vco(dev_priv, - dev_priv->skl_vco_freq); - } else if (!IS_BROXTON(dev_priv)) { /* * The LCPLL register should be turned on by the BIOS. For now * let's just check its state and print errors in case diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2bee217..3854b2e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1279,7 +1279,6 @@ void bxt_enable_dc9(struct drm_i915_private *dev_priv); void bxt_disable_dc9(struct drm_i915_private *dev_priv); void gen9_enable_dc5(struct drm_i915_private *dev_priv); void skl_init_cdclk(struct drm_i915_private *dev_priv); -int skl_sanitize_cdclk(struct drm_i915_private *dev_priv); void skl_uninit_cdclk(struct drm_i915_private *dev_priv); unsigned int skl_cdclk_get_vco(unsigned int freq); void skl_enable_dc6(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index b69b935..fefe22c 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -2200,12 +2200,9 @@ static void skl_display_core_init(struct drm_i915_private *dev_priv, mutex_unlock(&power_domains->lock); - if (!resume) - return; - skl_init_cdclk(dev_priv); - if (dev_priv->csr.dmc_payload) + if (resume && dev_priv->csr.dmc_payload) intel_csr_load_program(dev_priv); } -- cgit v0.10.2 From 70c2c184065e642642b563ae36ff3db682a5eee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:30 +0300 Subject: drm/i915: Move SKL+ DBUF enable/disable to display core init/uninit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SKL and BXT have the same snippets of code for enabling disabling the DBUF. Extract those into helpers and move the calls from init/unit_cdclk() to the display core init/init since this stuff isn't really about cdclk. Also doing the enable twice shouldn't hurt since you're just setting the request bit again when it was already set. We can also toss in a few WARNs about the register values into skl_get_dpll0_vco() now that we know that things should always be sane there. Flatten skl_init_cdclk() while at it. v2: s/skl/gen9/ in function names (Imre) Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-12-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 58b8d75..6b2b965 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5400,18 +5400,6 @@ static bool broxton_cdclk_is_enabled(struct drm_i915_private *dev_priv) /* TODO: Check for a valid CDCLK rate */ - if (!(I915_READ(DBUF_CTL) & DBUF_POWER_REQUEST)) { - DRM_DEBUG_DRIVER("CDCLK enabled, but DBUF power not requested\n"); - - return false; - } - - if (!(I915_READ(DBUF_CTL) & DBUF_POWER_STATE)) { - DRM_DEBUG_DRIVER("CDCLK enabled, but DBUF power hasn't settled\n"); - - return false; - } - return true; } @@ -5438,26 +5426,10 @@ void broxton_init_cdclk(struct drm_i915_private *dev_priv) * here, it belongs to modeset time */ broxton_set_cdclk(dev_priv, 624000); - - I915_WRITE(DBUF_CTL, I915_READ(DBUF_CTL) | DBUF_POWER_REQUEST); - POSTING_READ(DBUF_CTL); - - udelay(10); - - if (!(I915_READ(DBUF_CTL) & DBUF_POWER_STATE)) - DRM_ERROR("DBuf power enable timeout!\n"); } void broxton_uninit_cdclk(struct drm_i915_private *dev_priv) { - I915_WRITE(DBUF_CTL, I915_READ(DBUF_CTL) & ~DBUF_POWER_REQUEST); - POSTING_READ(DBUF_CTL); - - udelay(10); - - if (I915_READ(DBUF_CTL) & DBUF_POWER_STATE) - DRM_ERROR("DBuf power disable timeout!\n"); - /* Set minimum (bypass) frequency, in effect turning off the DE PLL */ broxton_set_cdclk(dev_priv, 19200); } @@ -5679,15 +5651,6 @@ static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv); void skl_uninit_cdclk(struct drm_i915_private *dev_priv) { - /* disable DBUF power */ - I915_WRITE(DBUF_CTL, I915_READ(DBUF_CTL) & ~DBUF_POWER_REQUEST); - POSTING_READ(DBUF_CTL); - - udelay(10); - - if (I915_READ(DBUF_CTL) & DBUF_POWER_STATE) - DRM_ERROR("DBuf power disable timeout\n"); - skl_set_cdclk(dev_priv, 24000, 0); } @@ -5705,24 +5668,15 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv) if (dev_priv->skl_preferred_vco_freq == 0) skl_set_preferred_cdclk_vco(dev_priv, dev_priv->skl_vco_freq); - } else { - /* set CDCLK to the lowest frequency, Modeset follows */ - vco = dev_priv->skl_preferred_vco_freq; - if (vco == 0) - vco = 8100; - cdclk = skl_calc_cdclk(0, vco); - - skl_set_cdclk(dev_priv, cdclk, vco); + return; } - /* enable DBUF power */ - I915_WRITE(DBUF_CTL, I915_READ(DBUF_CTL) | DBUF_POWER_REQUEST); - POSTING_READ(DBUF_CTL); - - udelay(10); + vco = dev_priv->skl_preferred_vco_freq; + if (vco == 0) + vco = 8100; + cdclk = skl_calc_cdclk(0, vco); - if (!(I915_READ(DBUF_CTL) & DBUF_POWER_STATE)) - DRM_ERROR("DBuf power enable timeout\n"); + skl_set_cdclk(dev_priv, cdclk, vco); } static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index fefe22c..dc74f38 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -2176,6 +2176,28 @@ static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv) mutex_unlock(&power_domains->lock); } +static void gen9_dbuf_enable(struct drm_i915_private *dev_priv) +{ + I915_WRITE(DBUF_CTL, I915_READ(DBUF_CTL) | DBUF_POWER_REQUEST); + POSTING_READ(DBUF_CTL); + + udelay(10); + + if (!(I915_READ(DBUF_CTL) & DBUF_POWER_STATE)) + DRM_ERROR("DBuf power enable timeout\n"); +} + +static void gen9_dbuf_disable(struct drm_i915_private *dev_priv) +{ + I915_WRITE(DBUF_CTL, I915_READ(DBUF_CTL) & ~DBUF_POWER_REQUEST); + POSTING_READ(DBUF_CTL); + + udelay(10); + + if (I915_READ(DBUF_CTL) & DBUF_POWER_STATE) + DRM_ERROR("DBuf power disable timeout!\n"); +} + static void skl_display_core_init(struct drm_i915_private *dev_priv, bool resume) { @@ -2202,6 +2224,8 @@ static void skl_display_core_init(struct drm_i915_private *dev_priv, skl_init_cdclk(dev_priv); + gen9_dbuf_enable(dev_priv); + if (resume && dev_priv->csr.dmc_payload) intel_csr_load_program(dev_priv); } @@ -2213,6 +2237,8 @@ static void skl_display_core_uninit(struct drm_i915_private *dev_priv) gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); + gen9_dbuf_disable(dev_priv); + skl_uninit_cdclk(dev_priv); /* The spec doesn't call for removing the reset handshake flag */ @@ -2257,6 +2283,9 @@ void bxt_display_core_init(struct drm_i915_private *dev_priv, mutex_unlock(&power_domains->lock); broxton_init_cdclk(dev_priv); + + gen9_dbuf_enable(dev_priv); + broxton_ddi_phy_init(dev_priv); broxton_cdclk_verify_state(dev_priv); @@ -2274,6 +2303,9 @@ void bxt_display_core_uninit(struct drm_i915_private *dev_priv) gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); broxton_ddi_phy_uninit(dev_priv); + + gen9_dbuf_disable(dev_priv); + broxton_uninit_cdclk(dev_priv); /* The spec doesn't call for removing the reset handshake flag */ -- cgit v0.10.2 From 487ed2e4e9d62363ddd5fab2407100d3436fd0c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:31 +0300 Subject: drm/i915: Make 308 and 671 MHz cdclks more accurate on SKL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SKL 308.57 MHz cdclk is probably 8640/28 = ~308.571 Mhz. Similartly the 617.14 MHz cdclk is probably 8640/14 = ~617.143 MHz. Let's use the slightly more accurate numbers. Potentially we might change to computing all of these based on dividers, but let's stick to the current theme for now.. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-13-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6b2b965..5c23521 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5204,13 +5204,13 @@ static void intel_update_max_cdclk(struct drm_device *dev) * if the preferred vco is 8100 instead. */ if (limit == SKL_DFSM_CDCLK_LIMIT_675) - max_cdclk = 617140; + max_cdclk = 617143; else if (limit == SKL_DFSM_CDCLK_LIMIT_540) max_cdclk = 540000; else if (limit == SKL_DFSM_CDCLK_LIMIT_450) max_cdclk = 432000; else - max_cdclk = 308570; + max_cdclk = 308571; dev_priv->max_cdclk_freq = skl_calc_cdclk(max_cdclk, vco); } else if (IS_BROXTON(dev)) { @@ -5438,13 +5438,13 @@ static int skl_calc_cdclk(int max_pixclk, int vco) { if (vco == 8640) { if (max_pixclk > 540000) - return 617140; + return 617143; else if (max_pixclk > 432000) return 540000; - else if (max_pixclk > 308570) + else if (max_pixclk > 308571) return 432000; else - return 308570; + return 308571; } else { /* VCO 8100 */ if (max_pixclk > 540000) @@ -5616,13 +5616,13 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, int cdclk, int vco) freq_select = CDCLK_FREQ_540; pcu_ack = 2; break; - case 308570: + case 308571: case 337500: default: freq_select = CDCLK_FREQ_337_308; pcu_ack = 0; break; - case 617140: + case 617143: case 675000: freq_select = CDCLK_FREQ_675_617; pcu_ack = 3; @@ -6582,11 +6582,11 @@ static int skylake_get_display_clock_speed(struct drm_device *dev) case CDCLK_FREQ_450_432: return 432000; case CDCLK_FREQ_337_308: - return 308570; + return 308571; case CDCLK_FREQ_540: return 540000; case CDCLK_FREQ_675_617: - return 617140; + return 617143; default: MISSING_CASE(cdctl & CDCLK_FREQ_SEL_MASK); } -- cgit v0.10.2 From 63911d7295524e59205ecfa3b2db437544c52eb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:32 +0300 Subject: drm/i915: Rename skl_vco_freq to cdclk_pll.vco MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We'll want to store the cdclk PLL (whatever PLL that is in reality) vco frequency somewhere on other platforms too, so let's rename the skl_vco_freq to cdclk_pll.vco, and let's store it in kHz instead of MHz to match most of the other clocks. v2: Drop the spurious > vs != change (Imre) Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-14-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 36ed636..f8d8a81 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1815,7 +1815,6 @@ struct drm_i915_private { int num_fence_regs; /* 8 on pre-965, 16 otherwise */ unsigned int fsb_freq, mem_freq, is_ddr3; - unsigned int skl_vco_freq; unsigned int skl_preferred_vco_freq; unsigned int cdclk_freq, max_cdclk_freq, atomic_cdclk_freq; unsigned int max_dotclk_freq; @@ -1823,6 +1822,10 @@ struct drm_i915_private { unsigned int hpll_freq; unsigned int czclk_freq; + struct { + unsigned int vco; + } cdclk_pll; + /** * wq - Driver workqueue for GEM. * diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5c23521..40893c0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5196,7 +5196,7 @@ static void intel_update_max_cdclk(struct drm_device *dev) int max_cdclk, vco; vco = dev_priv->skl_preferred_vco_freq; - WARN_ON(vco != 8100 && vco != 8640); + WARN_ON(vco != 8100000 && vco != 8640000); /* * Use the lower (vco 8640) cdclk values as a @@ -5255,8 +5255,8 @@ static void intel_update_cdclk(struct drm_device *dev) dev_priv->cdclk_freq = dev_priv->display.get_display_clock_speed(dev); if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) - DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz, VCO: %d MHz\n", - dev_priv->cdclk_freq, dev_priv->skl_vco_freq); + DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz, VCO: %d kHz\n", + dev_priv->cdclk_freq, dev_priv->cdclk_pll.vco); else DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz\n", dev_priv->cdclk_freq); @@ -5436,7 +5436,7 @@ void broxton_uninit_cdclk(struct drm_i915_private *dev_priv) static int skl_calc_cdclk(int max_pixclk, int vco) { - if (vco == 8640) { + if (vco == 8640000) { if (max_pixclk > 540000) return 617143; else if (max_pixclk > 432000) @@ -5446,7 +5446,6 @@ static int skl_calc_cdclk(int max_pixclk, int vco) else return 308571; } else { - /* VCO 8100 */ if (max_pixclk > 540000) return 675000; else if (max_pixclk > 450000) @@ -5465,7 +5464,7 @@ skl_dpll0_update(struct drm_i915_private *dev_priv) val = I915_READ(LCPLL1_CTL); if ((val & LCPLL_PLL_ENABLE) == 0) { - dev_priv->skl_vco_freq = 0; + dev_priv->cdclk_pll.vco = 0; return; } @@ -5483,15 +5482,15 @@ skl_dpll0_update(struct drm_i915_private *dev_priv) case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, SKL_DPLL0): case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, SKL_DPLL0): case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, SKL_DPLL0): - dev_priv->skl_vco_freq = 8100; + dev_priv->cdclk_pll.vco = 8100000; break; case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, SKL_DPLL0): case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, SKL_DPLL0): - dev_priv->skl_vco_freq = 8640; + dev_priv->cdclk_pll.vco = 8640000; break; default: MISSING_CASE(val & DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0)); - dev_priv->skl_vco_freq = 0; + dev_priv->cdclk_pll.vco = 0; break; } } @@ -5512,7 +5511,7 @@ skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) int min_cdclk = skl_calc_cdclk(0, vco); u32 val; - WARN_ON(vco != 8100 && vco != 8640); + WARN_ON(vco != 8100000 && vco != 8640000); /* select the minimum CDCLK before enabling DPLL 0 */ val = CDCLK_FREQ_337_308 | skl_cdclk_decimal(min_cdclk); @@ -5533,7 +5532,7 @@ skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) val &= ~(DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | DPLL_CTRL1_SSC(SKL_DPLL0) | DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0)); val |= DPLL_CTRL1_OVERRIDE(SKL_DPLL0); - if (vco == 8640) + if (vco == 8640000) val |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, SKL_DPLL0); else @@ -5548,7 +5547,7 @@ skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) if (wait_for(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK, 5)) DRM_ERROR("DPLL0 not locked\n"); - dev_priv->skl_vco_freq = vco; + dev_priv->cdclk_pll.vco = vco; /* We'll want to keep using the current vco from now on. */ skl_set_preferred_cdclk_vco(dev_priv, vco); @@ -5561,7 +5560,7 @@ skl_dpll0_disable(struct drm_i915_private *dev_priv) if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1)) DRM_ERROR("Couldn't disable DPLL0\n"); - dev_priv->skl_vco_freq = 0; + dev_priv->cdclk_pll.vco = 0; } static bool skl_cdclk_pcu_ready(struct drm_i915_private *dev_priv) @@ -5598,7 +5597,7 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, int cdclk, int vco) WARN_ON((cdclk == 24000) != (vco == 0)); - DRM_DEBUG_DRIVER("Changing CDCLK to %d kHz (VCO %d MHz)\n", cdclk, vco); + DRM_DEBUG_DRIVER("Changing CDCLK to %d kHz (VCO %d kHz)\n", cdclk, vco); if (!skl_cdclk_wait_for_pcu_ready(dev_priv)) { DRM_ERROR("failed to inform PCU about cdclk change\n"); @@ -5629,11 +5628,11 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, int cdclk, int vco) break; } - if (dev_priv->skl_vco_freq != 0 && - dev_priv->skl_vco_freq != vco) + if (dev_priv->cdclk_pll.vco != 0 && + dev_priv->cdclk_pll.vco != vco) skl_dpll0_disable(dev_priv); - if (dev_priv->skl_vco_freq != vco) + if (dev_priv->cdclk_pll.vco != vco) skl_dpll0_enable(dev_priv, vco); I915_WRITE(CDCLK_CTL, freq_select | skl_cdclk_decimal(cdclk)); @@ -5660,20 +5659,20 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv) skl_sanitize_cdclk(dev_priv); - if (dev_priv->cdclk_freq != 0 && dev_priv->skl_vco_freq != 0) { + if (dev_priv->cdclk_freq != 0 && dev_priv->cdclk_pll.vco != 0) { /* * Use the current vco as our initial * guess as to what the preferred vco is. */ if (dev_priv->skl_preferred_vco_freq == 0) skl_set_preferred_cdclk_vco(dev_priv, - dev_priv->skl_vco_freq); + dev_priv->cdclk_pll.vco); return; } vco = dev_priv->skl_preferred_vco_freq; if (vco == 0) - vco = 8100; + vco = 8100000; cdclk = skl_calc_cdclk(0, vco); skl_set_cdclk(dev_priv, cdclk, vco); @@ -5723,7 +5722,7 @@ sanitize: /* force cdclk programming */ dev_priv->cdclk_freq = 0; /* force full PLL disable + enable */ - dev_priv->skl_vco_freq = -1; + dev_priv->cdclk_pll.vco = -1; } /* Adjust CDclk dividers to allow high res or save power if possible */ @@ -6572,12 +6571,12 @@ static int skylake_get_display_clock_speed(struct drm_device *dev) skl_dpll0_update(dev_priv); - if (dev_priv->skl_vco_freq == 0) + if (dev_priv->cdclk_pll.vco == 0) return 24000; /* 24MHz is the cd freq with NSSC ref */ cdctl = I915_READ(CDCLK_CTL); - if (dev_priv->skl_vco_freq == 8640) { + if (dev_priv->cdclk_pll.vco == 8640000) { switch (cdctl & CDCLK_FREQ_SEL_MASK) { case CDCLK_FREQ_450_432: return 432000; @@ -12661,7 +12660,7 @@ static int intel_modeset_checks(struct drm_atomic_state *state) */ if (dev_priv->display.modeset_calc_cdclk) { if (!intel_state->cdclk_pll_vco) - intel_state->cdclk_pll_vco = dev_priv->skl_vco_freq; + intel_state->cdclk_pll_vco = dev_priv->cdclk_pll.vco; if (!intel_state->cdclk_pll_vco) intel_state->cdclk_pll_vco = dev_priv->skl_preferred_vco_freq; @@ -12670,7 +12669,7 @@ static int intel_modeset_checks(struct drm_atomic_state *state) return ret; if (intel_state->dev_cdclk != dev_priv->cdclk_freq || - intel_state->cdclk_pll_vco != dev_priv->skl_vco_freq) + intel_state->cdclk_pll_vco != dev_priv->cdclk_pll.vco) ret = intel_modeset_all_pipes(state); if (ret < 0) @@ -13157,7 +13156,7 @@ static int intel_atomic_commit(struct drm_device *dev, if (dev_priv->display.modeset_commit_cdclk && (intel_state->dev_cdclk != dev_priv->cdclk_freq || - intel_state->cdclk_pll_vco != dev_priv->skl_vco_freq)) + intel_state->cdclk_pll_vco != dev_priv->cdclk_pll.vco)) dev_priv->display.modeset_commit_cdclk(state); intel_modeset_verify_disabled(dev); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 8b67e0f..aa9c59e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1589,10 +1589,10 @@ found: switch (pipe_config->port_clock / 2) { case 108000: case 216000: - vco = 8640; + vco = 8640000; break; default: - vco = 8100; + vco = 8100000; break; } -- cgit v0.10.2 From 709e05c3c46e866243f369a46ca5552a5c1e6b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:33 +0300 Subject: drm/i915: Store cdclk PLL reference clock under dev_priv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Future platforms will have multiple options for the cdclk PLL reference clock, so let's start tracking that under dev_priv alreday on SKL, although on SKL it's always 24 MHz. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-15-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f8d8a81..78d38c2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1823,7 +1823,7 @@ struct drm_i915_private { unsigned int czclk_freq; struct { - unsigned int vco; + unsigned int vco, ref; } cdclk_pll; /** diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 40893c0..5777163 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5255,8 +5255,9 @@ static void intel_update_cdclk(struct drm_device *dev) dev_priv->cdclk_freq = dev_priv->display.get_display_clock_speed(dev); if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) - DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz, VCO: %d kHz\n", - dev_priv->cdclk_freq, dev_priv->cdclk_pll.vco); + DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz, VCO: %d kHz, ref: %d kHz\n", + dev_priv->cdclk_freq, dev_priv->cdclk_pll.vco, + dev_priv->cdclk_pll.ref); else DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz\n", dev_priv->cdclk_freq); @@ -5462,6 +5463,8 @@ skl_dpll0_update(struct drm_i915_private *dev_priv) { u32 val; + dev_priv->cdclk_pll.ref = 24000; + val = I915_READ(LCPLL1_CTL); if ((val & LCPLL_PLL_ENABLE) == 0) { dev_priv->cdclk_pll.vco = 0; @@ -5650,7 +5653,7 @@ static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv); void skl_uninit_cdclk(struct drm_i915_private *dev_priv) { - skl_set_cdclk(dev_priv, 24000, 0); + skl_set_cdclk(dev_priv, dev_priv->cdclk_pll.ref, 0); } void skl_init_cdclk(struct drm_i915_private *dev_priv) @@ -6572,7 +6575,7 @@ static int skylake_get_display_clock_speed(struct drm_device *dev) skl_dpll0_update(dev_priv); if (dev_priv->cdclk_pll.vco == 0) - return 24000; /* 24MHz is the cd freq with NSSC ref */ + return dev_priv->cdclk_pll.ref; cdctl = I915_READ(CDCLK_CTL); @@ -6604,8 +6607,7 @@ static int skylake_get_display_clock_speed(struct drm_device *dev) } } - /* error case, do as if DPLL0 isn't enabled */ - return 24000; + return dev_priv->cdclk_pll.ref; } static int broxton_get_display_clock_speed(struct drm_device *dev) -- cgit v0.10.2 From 2b73001e739d3db8474472b7e6585ef9ee4b946e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:34 +0300 Subject: drm/i915: Extract bxt DE PLL enable/disable from broxton_set_cdclk() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling and disalbing the DE PLL are two nice self contained operations, so let's move them into a few small helper functions. Makes it easier to see the forest from the trees in broxton_set_cdclk(). Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-16-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5777163..521ad13 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5278,6 +5278,31 @@ static int skl_cdclk_decimal(int cdclk) return DIV_ROUND_CLOSEST(cdclk - 1000, 500); } +static void bxt_de_pll_disable(struct drm_i915_private *dev_priv) +{ + I915_WRITE(BXT_DE_PLL_ENABLE, 0); + + /* Timeout 200us */ + if (wait_for((I915_READ(BXT_DE_PLL_ENABLE) & BXT_DE_PLL_LOCK) == 0, 1)) + DRM_ERROR("timeout waiting for DE PLL unlock\n"); +} + +static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, u32 ratio) +{ + u32 val; + + val = I915_READ(BXT_DE_PLL_CTL); + val &= ~BXT_DE_PLL_RATIO_MASK; + val |= ratio; + I915_WRITE(BXT_DE_PLL_CTL, val); + + I915_WRITE(BXT_DE_PLL_ENABLE, BXT_DE_PLL_PLL_ENABLE); + + /* Timeout 200us */ + if (wait_for((I915_READ(BXT_DE_PLL_ENABLE) & BXT_DE_PLL_LOCK) != 0, 1)) + DRM_ERROR("timeout waiting for DE PLL lock\n"); +} + static void broxton_set_cdclk(struct drm_i915_private *dev_priv, int cdclk) { uint32_t divider; @@ -5345,25 +5370,13 @@ static void broxton_set_cdclk(struct drm_i915_private *dev_priv, int cdclk) */ if (cdclk == 19200 || cdclk == 624000 || current_cdclk == 624000) { - I915_WRITE(BXT_DE_PLL_ENABLE, ~BXT_DE_PLL_PLL_ENABLE); - /* Timeout 200us */ - if (wait_for(!(I915_READ(BXT_DE_PLL_ENABLE) & BXT_DE_PLL_LOCK), - 1)) - DRM_ERROR("timout waiting for DE PLL unlock\n"); + bxt_de_pll_disable(dev_priv); } if (cdclk != 19200) { uint32_t val; - val = I915_READ(BXT_DE_PLL_CTL); - val &= ~BXT_DE_PLL_RATIO_MASK; - val |= ratio; - I915_WRITE(BXT_DE_PLL_CTL, val); - - I915_WRITE(BXT_DE_PLL_ENABLE, BXT_DE_PLL_PLL_ENABLE); - /* Timeout 200us */ - if (wait_for(I915_READ(BXT_DE_PLL_ENABLE) & BXT_DE_PLL_LOCK, 1)) - DRM_ERROR("timeout waiting for DE PLL lock\n"); + bxt_de_pll_enable(dev_priv, ratio); val = divider | skl_cdclk_decimal(cdclk); /* -- cgit v0.10.2 From 83d7c81f6a6a28b7c3f3512b1d09d37593aaa43b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:35 +0300 Subject: drm/i915: Store BXT DE PLL vco and ref clocks in dev_priv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have need to know the DE PLL refclk and output frequency in various cdclk calculations, so let's store those in dev_priv. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-17-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 521ad13..6382241 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5254,7 +5254,7 @@ static void intel_update_cdclk(struct drm_device *dev) dev_priv->cdclk_freq = dev_priv->display.get_display_clock_speed(dev); - if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) + if (INTEL_GEN(dev_priv) >= 9) DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz, VCO: %d kHz, ref: %d kHz\n", dev_priv->cdclk_freq, dev_priv->cdclk_pll.vco, dev_priv->cdclk_pll.ref); @@ -5285,6 +5285,8 @@ static void bxt_de_pll_disable(struct drm_i915_private *dev_priv) /* Timeout 200us */ if (wait_for((I915_READ(BXT_DE_PLL_ENABLE) & BXT_DE_PLL_LOCK) == 0, 1)) DRM_ERROR("timeout waiting for DE PLL unlock\n"); + + dev_priv->cdclk_pll.vco = 0; } static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, u32 ratio) @@ -5301,6 +5303,8 @@ static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, u32 ratio) /* Timeout 200us */ if (wait_for((I915_READ(BXT_DE_PLL_ENABLE) & BXT_DE_PLL_LOCK) != 0, 1)) DRM_ERROR("timeout waiting for DE PLL lock\n"); + + dev_priv->cdclk_pll.vco = ratio * dev_priv->cdclk_pll.ref; } static void broxton_set_cdclk(struct drm_i915_private *dev_priv, int cdclk) @@ -6623,6 +6627,25 @@ static int skylake_get_display_clock_speed(struct drm_device *dev) return dev_priv->cdclk_pll.ref; } +static void bxt_de_pll_update(struct drm_i915_private *dev_priv) +{ + u32 val; + + dev_priv->cdclk_pll.ref = 19200; + + val = I915_READ(BXT_DE_PLL_ENABLE); + if ((val & BXT_DE_PLL_PLL_ENABLE) == 0) { + dev_priv->cdclk_pll.vco = 0; + return; + } + + WARN_ON((val & BXT_DE_PLL_LOCK) == 0); + + val = I915_READ(BXT_DE_PLL_CTL); + dev_priv->cdclk_pll.vco = (val & BXT_DE_PLL_RATIO_MASK) * + dev_priv->cdclk_pll.ref; +} + static int broxton_get_display_clock_speed(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); @@ -6631,6 +6654,8 @@ static int broxton_get_display_clock_speed(struct drm_device *dev) uint32_t pll_enab = I915_READ(BXT_DE_PLL_ENABLE); int cdclk; + bxt_de_pll_update(dev_priv); + if (!(pll_enab & BXT_DE_PLL_PLL_ENABLE)) return 19200; -- cgit v0.10.2 From 089c6fd503b050eb9996e02e8675dfabb48e51e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:36 +0300 Subject: drm/i915: Update cached cdclk state from broxton_init_cdclk() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's make sure our cached cdclk state is accurate right after broxton_init_cdclk() whether or not we end up changing the cdclk frequency. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-18-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6382241..4dfeb6e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5428,13 +5428,10 @@ bool broxton_cdclk_verify_state(struct drm_i915_private *dev_priv) void broxton_init_cdclk(struct drm_i915_private *dev_priv) { - /* check if cd clock is enabled */ - if (broxton_cdclk_is_enabled(dev_priv)) { - DRM_DEBUG_KMS("CDCLK already enabled, won't reprogram it\n"); - return; - } + intel_update_cdclk(dev_priv->dev); - DRM_DEBUG_KMS("CDCLK not enabled, enabling it\n"); + if (dev_priv->cdclk_pll.vco != 0) + return; /* * FIXME: -- cgit v0.10.2 From f59862422d6cf4980a6bad23a2e53c25273b9c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:37 +0300 Subject: drm/i915: Rewrite broxton_get_display_clock_speed() in terms of the DE PLL vco/refclk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we've read out the DE PLL vco and refclk, we can just use them in the cdclk calculation. While at it switch over to DIV_ROUND_CLOSEST(). Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-19-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4dfeb6e..4a1f659 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6646,31 +6646,36 @@ static void bxt_de_pll_update(struct drm_i915_private *dev_priv) static int broxton_get_display_clock_speed(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); - uint32_t cdctl = I915_READ(CDCLK_CTL); - uint32_t pll_ratio = I915_READ(BXT_DE_PLL_CTL) & BXT_DE_PLL_RATIO_MASK; - uint32_t pll_enab = I915_READ(BXT_DE_PLL_ENABLE); - int cdclk; + u32 divider; + int div, vco; bxt_de_pll_update(dev_priv); - if (!(pll_enab & BXT_DE_PLL_PLL_ENABLE)) - return 19200; + vco = dev_priv->cdclk_pll.vco; + if (vco == 0) + return dev_priv->cdclk_pll.ref; - cdclk = 19200 * pll_ratio / 2; + divider = I915_READ(CDCLK_CTL) & BXT_CDCLK_CD2X_DIV_SEL_MASK; - switch (cdctl & BXT_CDCLK_CD2X_DIV_SEL_MASK) { + switch (divider) { case BXT_CDCLK_CD2X_DIV_SEL_1: - return cdclk; /* 576MHz or 624MHz */ + div = 2; + break; case BXT_CDCLK_CD2X_DIV_SEL_1_5: - return cdclk * 2 / 3; /* 384MHz */ + div = 3; + break; case BXT_CDCLK_CD2X_DIV_SEL_2: - return cdclk / 2; /* 288MHz */ + div = 4; + break; case BXT_CDCLK_CD2X_DIV_SEL_4: - return cdclk / 4; /* 144MHz */ + div = 8; + break; + default: + MISSING_CASE(divider); + return dev_priv->cdclk_pll.ref; } - /* error case, do as if DE PLL isn't enabled */ - return 19200; + return DIV_ROUND_CLOSEST(vco, div); } static int broadwell_get_display_clock_speed(struct drm_device *dev) -- cgit v0.10.2 From 5f199dfa8dda965d1b2fc83bd8f8e205d2b8f9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:38 +0300 Subject: drm/i915: Make bxt_set_cdclk() operate in terms of the current vs target DE PLL vco MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make bxt_set_cdclk() more readable by looking at current vs. target DE PLL vco to determine if the DE PLL needs disabling and/or enabling. We can also calculate the CD2X divider simply as (vco/cdclk) instead of depending on magic numbers. The magic numbers are still needed though, but only to map the supported cdclk frequencies to corresponding DE PLL frequencies. Note that w'll now program CDCLK_CTL correctly even for the bypass case. Actually the CD2X divider should not matter in that case since the hardware will bypass it too, but the "decimal" part should matter (if we want to do gmbus/aux with the bypass enabled). Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-20-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4a1f659..a0b46b5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5278,6 +5278,30 @@ static int skl_cdclk_decimal(int cdclk) return DIV_ROUND_CLOSEST(cdclk - 1000, 500); } +static int bxt_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk) +{ + int ratio; + + if (cdclk == dev_priv->cdclk_pll.ref) + return 0; + + switch (cdclk) { + default: + MISSING_CASE(cdclk); + case 144000: + case 288000: + case 384000: + case 576000: + ratio = 60; + break; + case 624000: + ratio = 65; + break; + } + + return dev_priv->cdclk_pll.ref * ratio; +} + static void bxt_de_pll_disable(struct drm_i915_private *dev_priv) { I915_WRITE(BXT_DE_PLL_ENABLE, 0); @@ -5289,13 +5313,14 @@ static void bxt_de_pll_disable(struct drm_i915_private *dev_priv) dev_priv->cdclk_pll.vco = 0; } -static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, u32 ratio) +static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, int vco) { + int ratio = DIV_ROUND_CLOSEST(vco, dev_priv->cdclk_pll.ref); u32 val; val = I915_READ(BXT_DE_PLL_CTL); val &= ~BXT_DE_PLL_RATIO_MASK; - val |= ratio; + val |= BXT_DE_PLL_RATIO(ratio); I915_WRITE(BXT_DE_PLL_CTL, val); I915_WRITE(BXT_DE_PLL_ENABLE, BXT_DE_PLL_PLL_ENABLE); @@ -5304,54 +5329,42 @@ static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, u32 ratio) if (wait_for((I915_READ(BXT_DE_PLL_ENABLE) & BXT_DE_PLL_LOCK) != 0, 1)) DRM_ERROR("timeout waiting for DE PLL lock\n"); - dev_priv->cdclk_pll.vco = ratio * dev_priv->cdclk_pll.ref; + dev_priv->cdclk_pll.vco = vco; } static void broxton_set_cdclk(struct drm_i915_private *dev_priv, int cdclk) { - uint32_t divider; - uint32_t ratio; - uint32_t current_cdclk; - int ret; + u32 val, divider; + int vco, ret; - /* frequency = 19.2MHz * ratio / 2 / div{1,1.5,2,4} */ - switch (cdclk) { - case 144000: + vco = bxt_de_pll_vco(dev_priv, cdclk); + + DRM_DEBUG_DRIVER("Changing CDCLK to %d kHz (VCO %d kHz)\n", cdclk, vco); + + /* cdclk = vco / 2 / div{1,1.5,2,4} */ + switch (DIV_ROUND_CLOSEST(vco, cdclk)) { + case 8: divider = BXT_CDCLK_CD2X_DIV_SEL_4; - ratio = BXT_DE_PLL_RATIO(60); break; - case 288000: + case 4: divider = BXT_CDCLK_CD2X_DIV_SEL_2; - ratio = BXT_DE_PLL_RATIO(60); break; - case 384000: + case 3: divider = BXT_CDCLK_CD2X_DIV_SEL_1_5; - ratio = BXT_DE_PLL_RATIO(60); break; - case 576000: + case 2: divider = BXT_CDCLK_CD2X_DIV_SEL_1; - ratio = BXT_DE_PLL_RATIO(60); - break; - case 624000: - divider = BXT_CDCLK_CD2X_DIV_SEL_1; - ratio = BXT_DE_PLL_RATIO(65); - break; - case 19200: - /* - * Bypass frequency with DE PLL disabled. Init ratio, divider - * to suppress GCC warning. - */ - ratio = 0; - divider = 0; break; default: - DRM_ERROR("unsupported CDCLK freq %d", cdclk); + WARN_ON(cdclk != dev_priv->cdclk_pll.ref); + WARN_ON(vco != 0); - return; + divider = BXT_CDCLK_CD2X_DIV_SEL_1; + break; } - mutex_lock(&dev_priv->rps.hw_lock); /* Inform power controller of upcoming frequency change */ + mutex_lock(&dev_priv->rps.hw_lock); ret = sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, 0x80000000); mutex_unlock(&dev_priv->rps.hw_lock); @@ -5362,40 +5375,26 @@ static void broxton_set_cdclk(struct drm_i915_private *dev_priv, int cdclk) return; } - current_cdclk = I915_READ(CDCLK_CTL) & CDCLK_FREQ_DECIMAL_MASK; - /* convert from .1 fixpoint MHz with -1MHz offset to kHz */ - current_cdclk = current_cdclk * 500 + 1000; - - /* - * DE PLL has to be disabled when - * - setting to 19.2MHz (bypass, PLL isn't used) - * - before setting to 624MHz (PLL needs toggling) - * - before setting to any frequency from 624MHz (PLL needs toggling) - */ - if (cdclk == 19200 || cdclk == 624000 || - current_cdclk == 624000) { + if (dev_priv->cdclk_pll.vco != 0 && + dev_priv->cdclk_pll.vco != vco) bxt_de_pll_disable(dev_priv); - } - if (cdclk != 19200) { - uint32_t val; - - bxt_de_pll_enable(dev_priv, ratio); + if (dev_priv->cdclk_pll.vco != vco) + bxt_de_pll_enable(dev_priv, vco); - val = divider | skl_cdclk_decimal(cdclk); - /* - * FIXME if only the cd2x divider needs changing, it could be done - * without shutting off the pipe (if only one pipe is active). - */ - val |= BXT_CDCLK_CD2X_PIPE_NONE; - /* - * Disable SSA Precharge when CD clock frequency < 500 MHz, - * enable otherwise. - */ - if (cdclk >= 500000) - val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE; - I915_WRITE(CDCLK_CTL, val); - } + val = divider | skl_cdclk_decimal(cdclk); + /* + * FIXME if only the cd2x divider needs changing, it could be done + * without shutting off the pipe (if only one pipe is active). + */ + val |= BXT_CDCLK_CD2X_PIPE_NONE; + /* + * Disable SSA Precharge when CD clock frequency < 500 MHz, + * enable otherwise. + */ + if (cdclk >= 500000) + val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE; + I915_WRITE(CDCLK_CTL, val); mutex_lock(&dev_priv->rps.hw_lock); ret = sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, @@ -5445,8 +5444,7 @@ void broxton_init_cdclk(struct drm_i915_private *dev_priv) void broxton_uninit_cdclk(struct drm_i915_private *dev_priv) { - /* Set minimum (bypass) frequency, in effect turning off the DE PLL */ - broxton_set_cdclk(dev_priv, 19200); + broxton_set_cdclk(dev_priv, dev_priv->cdclk_pll.ref); } static int skl_calc_cdclk(int max_pixclk, int vco) -- cgit v0.10.2 From 342be926e0368018d9c22c4ab54d4a2bc6e9c15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:39 +0300 Subject: drm/i915: Replace bxt_verify_cdclk_state() with a more generic cdclk check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than having a BXT specific function to make sure the DE PLL is enabled after disabling DC6, let's just make sure the current cdclk is the same as what we last programmed. Having another check in bxt_display_core_init() almost immediately after the cdclk init seems redundant, so let's just kill that one. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-21-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a0b46b5..d53b670 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5410,21 +5410,6 @@ static void broxton_set_cdclk(struct drm_i915_private *dev_priv, int cdclk) intel_update_cdclk(dev_priv->dev); } -static bool broxton_cdclk_is_enabled(struct drm_i915_private *dev_priv) -{ - if (!(I915_READ(BXT_DE_PLL_ENABLE) & BXT_DE_PLL_PLL_ENABLE)) - return false; - - /* TODO: Check for a valid CDCLK rate */ - - return true; -} - -bool broxton_cdclk_verify_state(struct drm_i915_private *dev_priv) -{ - return broxton_cdclk_is_enabled(dev_priv); -} - void broxton_init_cdclk(struct drm_i915_private *dev_priv) { intel_update_cdclk(dev_priv->dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3854b2e..03d4b1a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1270,7 +1270,6 @@ void hsw_enable_pc8(struct drm_i915_private *dev_priv); void hsw_disable_pc8(struct drm_i915_private *dev_priv); void broxton_init_cdclk(struct drm_i915_private *dev_priv); void broxton_uninit_cdclk(struct drm_i915_private *dev_priv); -bool broxton_cdclk_verify_state(struct drm_i915_private *dev_priv); void broxton_ddi_phy_init(struct drm_i915_private *dev_priv); void broxton_ddi_phy_uninit(struct drm_i915_private *dev_priv); void broxton_ddi_phy_verify_state(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index dc74f38..a174118 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -811,10 +811,11 @@ static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv, { gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); - if (IS_BROXTON(dev_priv)) { - broxton_cdclk_verify_state(dev_priv); + WARN_ON(dev_priv->cdclk_freq != + dev_priv->display.get_display_clock_speed(dev_priv->dev)); + + if (IS_BROXTON(dev_priv)) broxton_ddi_phy_verify_state(dev_priv); - } } static void gen9_dc_off_power_well_disable(struct drm_i915_private *dev_priv, @@ -2288,7 +2289,6 @@ void bxt_display_core_init(struct drm_i915_private *dev_priv, broxton_ddi_phy_init(dev_priv); - broxton_cdclk_verify_state(dev_priv); broxton_ddi_phy_verify_state(dev_priv); if (resume && dev_priv->csr.dmc_payload) -- cgit v0.10.2 From d1b32c32e8943d18a104f347fbe40c46276011d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 13 May 2016 23:41:40 +0300 Subject: drm/i915: Set BXT cdclk to minimum initially MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case the driver is initialized without active displays, we should just drop the cdclk to the minimum frequency right off the bat. There might not be a modeset to drop it to the minimum late rafter all. With DMC supposedly we should always have the cdclk up and running. The DMC will shut the DE PLL down when appropriate, so let's nuke the related FIXMEs as well. Trying to do anything different would go against the expectations of the DMC firmware, and we all know how fragile the DMC firmware is. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463172100-24715-22-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d53b670..fd171fd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -119,6 +119,7 @@ static int ilk_max_pixel_rate(struct drm_atomic_state *state); static void intel_modeset_verify_crtc(struct drm_crtc *crtc, struct drm_crtc_state *old_state, struct drm_crtc_state *new_state); +static int broxton_calc_cdclk(int max_pixclk); struct intel_limit { struct { @@ -5421,10 +5422,8 @@ void broxton_init_cdclk(struct drm_i915_private *dev_priv) * FIXME: * - The initial CDCLK needs to be read from VBT. * Need to make this change after VBT has changes for BXT. - * - check if setting the max (or any) cdclk freq is really necessary - * here, it belongs to modeset time */ - broxton_set_cdclk(dev_priv, 624000); + broxton_set_cdclk(dev_priv, broxton_calc_cdclk(0)); } void broxton_uninit_cdclk(struct drm_i915_private *dev_priv) @@ -5864,10 +5863,6 @@ static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv, static int broxton_calc_cdclk(int max_pixclk) { - /* - * FIXME: - * - set 19.2MHz bypass frequency if there are no active pipes - */ if (max_pixclk > 576000) return 624000; else if (max_pixclk > 384000) -- cgit v0.10.2 From 18a8067c5748054d7731957ec3c46697a6a9ac1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 16 May 2016 16:59:40 +0300 Subject: drm/i915: Assert the dbuf is enabled when disabling DC5/6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like with cdclk, the DMC is supposed to manage dbuf enabling/disabling. Let's make sure it has correctly restored the dbuf state to enabled when we disable the DC states. v2: s/skl/gen9/ in function name (Imre) Cc: Imre Deak Suggested-by: Imre Deak Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463407180-28993-1-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index a174118..fe8faf3 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -806,6 +806,15 @@ static bool gen9_dc_off_power_well_enabled(struct drm_i915_private *dev_priv, return (I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5_DC6_MASK) == 0; } +static void gen9_assert_dbuf_enabled(struct drm_i915_private *dev_priv) +{ + u32 tmp = I915_READ(DBUF_CTL); + + WARN((tmp & (DBUF_POWER_STATE | DBUF_POWER_REQUEST)) != + (DBUF_POWER_STATE | DBUF_POWER_REQUEST), + "Unexpected DBuf power power state (0x%08x)\n", tmp); +} + static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { @@ -814,6 +823,8 @@ static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv, WARN_ON(dev_priv->cdclk_freq != dev_priv->display.get_display_clock_speed(dev_priv->dev)); + gen9_assert_dbuf_enabled(dev_priv); + if (IS_BROXTON(dev_priv)) broxton_ddi_phy_verify_state(dev_priv); } -- cgit v0.10.2 From 2335986dd46f4fdfd11d613b68f4879c92726b47 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Mon, 23 May 2016 16:34:35 +0100 Subject: drm/i915/guc: Disable automatic GuC firmware loading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New GuC code is logging errors at runtime suspend and resume which causes CI testing to log "orange" status. Default to not trying to load the firmware until this is resolved. Example of the log: [drm] RC6 on [drm:intel_runtime_suspend] Suspending device [drm:host2guc_action [i915]] *ERROR* GUC: host2guc action 0x501 failed. ret=-110 status=0x00000501 response=0x40000000 ... [drm:intel_runtime_resume] Resuming device [drm:host2guc_action [i915]] *ERROR* GUC: host2guc action 0x502 failed. ret=-110 status=0x00000502 response=0x40000000 [drm:intel_runtime_resume] Device resumed Signed-off-by: Tvrtko Ursulin Cc: Dave Gordon Cc: Ville Syrjälä Cc: Chris Harris Reviewed-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/1464017675-12257-1-git-send-email-tvrtko.ursulin@linux.intel.com diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 21a323c..9a5d58b 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -53,7 +53,7 @@ struct i915_params i915 __read_mostly = { .verbose_state_checks = 1, .nuclear_pageflip = 0, .edp_vswing = 0, - .enable_guc_loading = -1, + .enable_guc_loading = 0, .enable_guc_submission = 0, .guc_log_level = -1, .enable_dp_mst = true, @@ -197,7 +197,7 @@ MODULE_PARM_DESC(edp_vswing, module_param_named_unsafe(enable_guc_loading, i915.enable_guc_loading, int, 0400); MODULE_PARM_DESC(enable_guc_loading, "Enable GuC firmware loading " - "(-1=auto [default], 0=never, 1=if available, 2=required)"); + "(-1=auto, 0=never [default], 1=if available, 2=required)"); module_param_named_unsafe(enable_guc_submission, i915.enable_guc_submission, int, 0400); MODULE_PARM_DESC(enable_guc_submission, -- cgit v0.10.2 From e2efd13007cbdfb21a973faccddf967d86165d69 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 24 May 2016 14:53:34 +0100 Subject: drm/i915: Rename struct intel_context Our goal is to rename the anonymous per-engine struct beneath the current intel_context. However, after a lively debate resolving around the confusion between intel_context_engine and intel_engine_context, the realisation is that the two structs target different users. The outer struct is API / user facing, and so carries the higher level GEM information. The inner struct is hw facing. Thus we want to name the inner struct intel_context and the outer one i915_gem_context. As the first step, we need to rename the current struct: s/struct intel_context/struct i915_gem_context/ which fits much better with its constructors already conveying the i915_gem_context prefix! Signed-off-by: Chris Wilson Cc: Dave Gordon Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1464098023-3294-1-git-send-email-chris@chris-wilson.co.uk diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e606c6a..424e11e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -199,7 +199,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) seq_printf(m, " (frontbuffer: 0x%03x)", obj->frontbuffer_bits); } -static void describe_ctx(struct seq_file *m, struct intel_context *ctx) +static void describe_ctx(struct seq_file *m, struct i915_gem_context *ctx) { seq_putc(m, ctx->legacy_hw_ctx.initialized ? 'I' : 'i'); seq_putc(m, ctx->remap_slice ? 'R' : 'r'); @@ -2000,7 +2000,7 @@ static int i915_context_status(struct seq_file *m, void *unused) struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *engine; - struct intel_context *ctx; + struct i915_gem_context *ctx; enum intel_engine_id id; int ret; @@ -2046,7 +2046,7 @@ static int i915_context_status(struct seq_file *m, void *unused) } static void i915_dump_lrc_obj(struct seq_file *m, - struct intel_context *ctx, + struct i915_gem_context *ctx, struct intel_engine_cs *engine) { struct page *page; @@ -2094,7 +2094,7 @@ static int i915_dump_lrc(struct seq_file *m, void *unused) struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *engine; - struct intel_context *ctx; + struct i915_gem_context *ctx; int ret; if (!i915.enable_execlists) { @@ -2274,7 +2274,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data) static int per_file_ctx(int id, void *ptr, void *data) { - struct intel_context *ctx = ptr; + struct i915_gem_context *ctx = ptr; struct seq_file *m = data; struct i915_hw_ppgtt *ppgtt = ctx->ppgtt; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 78d38c2..961ef40 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -831,7 +831,7 @@ struct i915_ctx_hang_stats { #define CONTEXT_NO_ZEROMAP (1<<0) /** - * struct intel_context - as the name implies, represents a context. + * struct i915_gem_context - as the name implies, represents a context. * @ref: reference count. * @user_handle: userspace tracking identity for this context. * @remap_slice: l3 row remapping information. @@ -849,7 +849,7 @@ struct i915_ctx_hang_stats { * Contexts are memory images used by the hardware to store copies of their * internal state. */ -struct intel_context { +struct i915_gem_context { struct kref ref; int user_handle; uint8_t remap_slice; @@ -1710,7 +1710,7 @@ struct i915_execbuffer_params { uint64_t batch_obj_vm_offset; struct intel_engine_cs *engine; struct drm_i915_gem_object *batch_obj; - struct intel_context *ctx; + struct i915_gem_context *ctx; struct drm_i915_gem_request *request; }; @@ -2017,7 +2017,7 @@ struct drm_i915_private { void (*stop_engine)(struct intel_engine_cs *engine); } gt; - struct intel_context *kernel_context; + struct i915_gem_context *kernel_context; /* perform PHY state sanity checks? */ bool chv_phy_assert[2]; @@ -2385,7 +2385,7 @@ struct drm_i915_gem_request { * i915_gem_request_free() will then decrement the refcount on the * context. */ - struct intel_context *ctx; + struct i915_gem_context *ctx; struct intel_ringbuffer *ringbuf; /** @@ -2397,7 +2397,7 @@ struct drm_i915_gem_request { * we keep the previous context pinned until the following (this) * request is retired. */ - struct intel_context *previous_context; + struct i915_gem_context *previous_context; /** Batch buffer related to this request if any (used for error state dump only) */ @@ -2441,7 +2441,7 @@ struct drm_i915_gem_request { struct drm_i915_gem_request * __must_check i915_gem_request_alloc(struct intel_engine_cs *engine, - struct intel_context *ctx); + struct i915_gem_context *ctx); void i915_gem_request_free(struct kref *req_ref); int i915_gem_request_add_to_client(struct drm_i915_gem_request *req, struct drm_file *file); @@ -3427,22 +3427,22 @@ void i915_gem_context_reset(struct drm_device *dev); int i915_gem_context_open(struct drm_device *dev, struct drm_file *file); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct drm_i915_gem_request *req); -struct intel_context * +struct i915_gem_context * i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id); void i915_gem_context_free(struct kref *ctx_ref); struct drm_i915_gem_object * i915_gem_alloc_context_obj(struct drm_device *dev, size_t size); -static inline void i915_gem_context_reference(struct intel_context *ctx) +static inline void i915_gem_context_reference(struct i915_gem_context *ctx) { kref_get(&ctx->ref); } -static inline void i915_gem_context_unreference(struct intel_context *ctx) +static inline void i915_gem_context_unreference(struct i915_gem_context *ctx) { kref_put(&ctx->ref, i915_gem_context_free); } -static inline bool i915_gem_context_is_default(const struct intel_context *c) +static inline bool i915_gem_context_is_default(const struct i915_gem_context *c) { return c->user_handle == DEFAULT_CONTEXT_HANDLE; } diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f78d4ca..3472280 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2689,7 +2689,7 @@ void __i915_add_request(struct drm_i915_gem_request *request, } static bool i915_context_is_banned(struct drm_i915_private *dev_priv, - const struct intel_context *ctx) + const struct i915_gem_context *ctx) { unsigned long elapsed; @@ -2714,7 +2714,7 @@ static bool i915_context_is_banned(struct drm_i915_private *dev_priv, } static void i915_set_reset_status(struct drm_i915_private *dev_priv, - struct intel_context *ctx, + struct i915_gem_context *ctx, const bool guilty) { struct i915_ctx_hang_stats *hs; @@ -2742,7 +2742,7 @@ void i915_gem_request_free(struct kref *req_ref) static inline int __i915_gem_request_alloc(struct intel_engine_cs *engine, - struct intel_context *ctx, + struct i915_gem_context *ctx, struct drm_i915_gem_request **req_out) { struct drm_i915_private *dev_priv = engine->i915; @@ -2818,7 +2818,7 @@ err: */ struct drm_i915_gem_request * i915_gem_request_alloc(struct intel_engine_cs *engine, - struct intel_context *ctx) + struct i915_gem_context *ctx) { struct drm_i915_gem_request *req; int err; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 2aedd18..8484da2 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -134,7 +134,7 @@ static int get_context_size(struct drm_i915_private *dev_priv) return ret; } -static void i915_gem_context_clean(struct intel_context *ctx) +static void i915_gem_context_clean(struct i915_gem_context *ctx) { struct i915_hw_ppgtt *ppgtt = ctx->ppgtt; struct i915_vma *vma, *next; @@ -151,7 +151,7 @@ static void i915_gem_context_clean(struct intel_context *ctx) void i915_gem_context_free(struct kref *ctx_ref) { - struct intel_context *ctx = container_of(ctx_ref, typeof(*ctx), ref); + struct i915_gem_context *ctx = container_of(ctx_ref, typeof(*ctx), ref); trace_i915_context_free(ctx); @@ -234,12 +234,12 @@ static int assign_hw_id(struct drm_i915_private *dev_priv, unsigned *out) return 0; } -static struct intel_context * +static struct i915_gem_context * __create_hw_context(struct drm_device *dev, struct drm_i915_file_private *file_priv) { struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_context *ctx; + struct i915_gem_context *ctx; int ret; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); @@ -296,12 +296,12 @@ err_out: * context state of the GPU for applications that don't utilize HW contexts, as * well as an idle case. */ -static struct intel_context * +static struct i915_gem_context * i915_gem_create_context(struct drm_device *dev, struct drm_i915_file_private *file_priv) { const bool is_global_default_ctx = file_priv == NULL; - struct intel_context *ctx; + struct i915_gem_context *ctx; int ret = 0; BUG_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -352,7 +352,7 @@ err_destroy: return ERR_PTR(ret); } -static void i915_gem_context_unpin(struct intel_context *ctx, +static void i915_gem_context_unpin(struct i915_gem_context *ctx, struct intel_engine_cs *engine) { if (i915.enable_execlists) { @@ -369,7 +369,7 @@ void i915_gem_context_reset(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; if (i915.enable_execlists) { - struct intel_context *ctx; + struct i915_gem_context *ctx; list_for_each_entry(ctx, &dev_priv->context_list, link) intel_lr_context_reset(dev_priv, ctx); @@ -381,7 +381,7 @@ void i915_gem_context_reset(struct drm_device *dev) int i915_gem_context_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_context *ctx; + struct i915_gem_context *ctx; /* Init should only be called once per module load. Eventually the * restriction on the context_disabled check can be loosened. */ @@ -449,7 +449,7 @@ void i915_gem_context_lost(struct drm_i915_private *dev_priv) void i915_gem_context_fini(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_context *dctx = dev_priv->kernel_context; + struct i915_gem_context *dctx = dev_priv->kernel_context; if (dctx->legacy_hw_ctx.rcs_state) i915_gem_object_ggtt_unpin(dctx->legacy_hw_ctx.rcs_state); @@ -462,7 +462,7 @@ void i915_gem_context_fini(struct drm_device *dev) static int context_idr_cleanup(int id, void *p, void *data) { - struct intel_context *ctx = p; + struct i915_gem_context *ctx = p; i915_gem_context_unreference(ctx); return 0; @@ -471,7 +471,7 @@ static int context_idr_cleanup(int id, void *p, void *data) int i915_gem_context_open(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; - struct intel_context *ctx; + struct i915_gem_context *ctx; idr_init(&file_priv->context_idr); @@ -495,12 +495,12 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) idr_destroy(&file_priv->context_idr); } -struct intel_context * +struct i915_gem_context * i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id) { - struct intel_context *ctx; + struct i915_gem_context *ctx; - ctx = (struct intel_context *)idr_find(&file_priv->context_idr, id); + ctx = idr_find(&file_priv->context_idr, id); if (!ctx) return ERR_PTR(-ENOENT); @@ -641,7 +641,7 @@ static int remap_l3(struct drm_i915_gem_request *req, int slice) static inline bool skip_rcs_switch(struct i915_hw_ppgtt *ppgtt, struct intel_engine_cs *engine, - struct intel_context *to) + struct i915_gem_context *to) { if (to->remap_slice) return false; @@ -658,7 +658,7 @@ static inline bool skip_rcs_switch(struct i915_hw_ppgtt *ppgtt, static bool needs_pd_load_pre(struct i915_hw_ppgtt *ppgtt, struct intel_engine_cs *engine, - struct intel_context *to) + struct i915_gem_context *to) { if (!ppgtt) return false; @@ -683,7 +683,7 @@ needs_pd_load_pre(struct i915_hw_ppgtt *ppgtt, static bool needs_pd_load_post(struct i915_hw_ppgtt *ppgtt, - struct intel_context *to, + struct i915_gem_context *to, u32 hw_flags) { if (!ppgtt) @@ -700,10 +700,10 @@ needs_pd_load_post(struct i915_hw_ppgtt *ppgtt, static int do_rcs_switch(struct drm_i915_gem_request *req) { - struct intel_context *to = req->ctx; + struct i915_gem_context *to = req->ctx; struct intel_engine_cs *engine = req->engine; struct i915_hw_ppgtt *ppgtt = to->ppgtt ?: req->i915->mm.aliasing_ppgtt; - struct intel_context *from; + struct i915_gem_context *from; u32 hw_flags; int ret, i; @@ -859,7 +859,7 @@ int i915_switch_context(struct drm_i915_gem_request *req) if (engine->id != RCS || req->ctx->legacy_hw_ctx.rcs_state == NULL) { - struct intel_context *to = req->ctx; + struct i915_gem_context *to = req->ctx; struct i915_hw_ppgtt *ppgtt = to->ppgtt ?: req->i915->mm.aliasing_ppgtt; @@ -897,7 +897,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, { struct drm_i915_gem_context_create *args = data; struct drm_i915_file_private *file_priv = file->driver_priv; - struct intel_context *ctx; + struct i915_gem_context *ctx; int ret; if (!contexts_enabled(dev)) @@ -926,7 +926,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, { struct drm_i915_gem_context_destroy *args = data; struct drm_i915_file_private *file_priv = file->driver_priv; - struct intel_context *ctx; + struct i915_gem_context *ctx; int ret; if (args->pad != 0) @@ -958,7 +958,7 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data, { struct drm_i915_file_private *file_priv = file->driver_priv; struct drm_i915_gem_context_param *args = data; - struct intel_context *ctx; + struct i915_gem_context *ctx; int ret; ret = i915_mutex_lock_interruptible(dev); @@ -1001,7 +1001,7 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data, { struct drm_i915_file_private *file_priv = file->driver_priv; struct drm_i915_gem_context_param *args = data; - struct intel_context *ctx; + struct i915_gem_context *ctx; int ret; ret = i915_mutex_lock_interruptible(dev); @@ -1047,7 +1047,7 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_reset_stats *args = data; struct i915_ctx_hang_stats *hs; - struct intel_context *ctx; + struct i915_gem_context *ctx; int ret; if (args->flags || args->pad) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index a54a243..e61b92d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -716,7 +716,7 @@ eb_vma_misplaced(struct i915_vma *vma) static int i915_gem_execbuffer_reserve(struct intel_engine_cs *engine, struct list_head *vmas, - struct intel_context *ctx, + struct i915_gem_context *ctx, bool *need_relocs) { struct drm_i915_gem_object *obj; @@ -828,7 +828,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, struct intel_engine_cs *engine, struct eb_vmas *eb, struct drm_i915_gem_exec_object2 *exec, - struct intel_context *ctx) + struct i915_gem_context *ctx) { struct drm_i915_gem_relocation_entry *reloc; struct i915_address_space *vm; @@ -1065,11 +1065,11 @@ validate_exec_list(struct drm_device *dev, return 0; } -static struct intel_context * +static struct i915_gem_context * i915_gem_validate_context(struct drm_device *dev, struct drm_file *file, struct intel_engine_cs *engine, const u32 ctx_id) { - struct intel_context *ctx = NULL; + struct i915_gem_context *ctx = NULL; struct i915_ctx_hang_stats *hs; if (engine->id != RCS && ctx_id != DEFAULT_CONTEXT_HANDLE) @@ -1430,7 +1430,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_i915_gem_object *batch_obj; struct drm_i915_gem_exec_object2 shadow_exec_entry; struct intel_engine_cs *engine; - struct intel_context *ctx; + struct i915_gem_context *ctx; struct i915_address_space *vm; struct i915_execbuffer_params params_master; /* XXX: will be removed later */ struct i915_execbuffer_params *params = ¶ms_master; diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c index 42a8508..b42a3ad 100644 --- a/drivers/gpu/drm/i915/i915_guc_submission.c +++ b/drivers/gpu/drm/i915/i915_guc_submission.c @@ -360,7 +360,7 @@ static void guc_init_ctx_desc(struct intel_guc *guc, struct drm_i915_gem_object *client_obj = client->client_obj; struct drm_i915_private *dev_priv = guc_to_i915(guc); struct intel_engine_cs *engine; - struct intel_context *ctx = client->owner; + struct i915_gem_context *ctx = client->owner; struct guc_context_desc desc; struct sg_table *sg; enum intel_engine_id id; @@ -426,7 +426,7 @@ static void guc_init_ctx_desc(struct intel_guc *guc, desc.wq_size = client->wq_size; /* - * XXX: Take LRCs from an existing intel_context if this is not an + * XXX: Take LRCs from an existing context if this is not an * IsKMDCreatedContext client */ desc.desc_private = (uintptr_t)client; @@ -700,7 +700,7 @@ static void guc_client_free(struct drm_device *dev, */ static struct i915_guc_client *guc_client_alloc(struct drm_device *dev, uint32_t priority, - struct intel_context *ctx) + struct i915_gem_context *ctx) { struct i915_guc_client *client; struct drm_i915_private *dev_priv = dev->dev_private; @@ -938,7 +938,7 @@ int i915_guc_submission_enable(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_guc *guc = &dev_priv->guc; - struct intel_context *ctx = dev_priv->kernel_context; + struct i915_gem_context *ctx = dev_priv->kernel_context; struct i915_guc_client *client; /* client for execbuf submission */ @@ -989,7 +989,7 @@ int intel_guc_suspend(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_guc *guc = &dev_priv->guc; - struct intel_context *ctx; + struct i915_gem_context *ctx; u32 data[3]; if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS) @@ -1015,7 +1015,7 @@ int intel_guc_resume(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_guc *guc = &dev_priv->guc; - struct intel_context *ctx; + struct i915_gem_context *ctx; u32 data[3]; if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS) diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 37b6444..02507bf 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -203,7 +203,7 @@ i915_l3_write(struct file *filp, struct kobject *kobj, struct drm_minor *dminor = dev_to_drm_minor(dev); struct drm_device *drm_dev = dminor->dev; struct drm_i915_private *dev_priv = drm_dev->dev_private; - struct intel_context *ctx; + struct i915_gem_context *ctx; u32 *temp = NULL; /* Just here to make handling failures easy */ int slice = (int)(uintptr_t)attr->private; int ret; diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 20b2e40..6768db0 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -734,12 +734,12 @@ DEFINE_EVENT(i915_ppgtt, i915_ppgtt_release, * the context. */ DECLARE_EVENT_CLASS(i915_context, - TP_PROTO(struct intel_context *ctx), + TP_PROTO(struct i915_gem_context *ctx), TP_ARGS(ctx), TP_STRUCT__entry( __field(u32, dev) - __field(struct intel_context *, ctx) + __field(struct i915_gem_context *, ctx) __field(struct i915_address_space *, vm) ), @@ -754,12 +754,12 @@ DECLARE_EVENT_CLASS(i915_context, ) DEFINE_EVENT(i915_context, i915_context_create, - TP_PROTO(struct intel_context *ctx), + TP_PROTO(struct i915_gem_context *ctx), TP_ARGS(ctx) ); DEFINE_EVENT(i915_context, i915_context_free, - TP_PROTO(struct intel_context *ctx), + TP_PROTO(struct i915_gem_context *ctx), TP_ARGS(ctx) ); @@ -771,13 +771,13 @@ DEFINE_EVENT(i915_context, i915_context_free, * called only if full ppgtt is enabled. */ TRACE_EVENT(switch_mm, - TP_PROTO(struct intel_engine_cs *engine, struct intel_context *to), + TP_PROTO(struct intel_engine_cs *engine, struct i915_gem_context *to), TP_ARGS(engine, to), TP_STRUCT__entry( __field(u32, ring) - __field(struct intel_context *, to) + __field(struct i915_gem_context *, to) __field(struct i915_address_space *, vm) __field(u32, dev) ), diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 7b1a5a3..41601c7 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -64,7 +64,7 @@ struct drm_i915_gem_request; struct i915_guc_client { struct drm_i915_gem_object *client_obj; void *client_base; /* first page (only) of above */ - struct intel_context *owner; + struct i915_gem_context *owner; struct intel_guc *guc; uint32_t priority; uint32_t ctx_index; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 0d1772a..3d95b26 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -231,9 +231,9 @@ enum { /* Typical size of the average request (2 pipecontrols and a MI_BB) */ #define EXECLISTS_REQUEST_SIZE 64 /* bytes */ -static int execlists_context_deferred_alloc(struct intel_context *ctx, +static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, struct intel_engine_cs *engine); -static int intel_lr_context_pin(struct intel_context *ctx, +static int intel_lr_context_pin(struct i915_gem_context *ctx, struct intel_engine_cs *engine); /** @@ -315,7 +315,7 @@ logical_ring_init_platform_invariants(struct intel_engine_cs *engine) * bits 55-63: group ID, currently unused and set to 0 */ static void -intel_lr_context_descriptor_update(struct intel_context *ctx, +intel_lr_context_descriptor_update(struct i915_gem_context *ctx, struct intel_engine_cs *engine) { u64 desc; @@ -330,7 +330,7 @@ intel_lr_context_descriptor_update(struct intel_context *ctx, ctx->engine[engine->id].lrc_desc = desc; } -uint64_t intel_lr_context_descriptor(struct intel_context *ctx, +uint64_t intel_lr_context_descriptor(struct i915_gem_context *ctx, struct intel_engine_cs *engine) { return ctx->engine[engine->id].lrc_desc; @@ -929,7 +929,7 @@ int logical_ring_flush_all_caches(struct drm_i915_gem_request *req) return 0; } -static int intel_lr_context_pin(struct intel_context *ctx, +static int intel_lr_context_pin(struct i915_gem_context *ctx, struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = ctx->i915; @@ -985,7 +985,7 @@ err: return ret; } -void intel_lr_context_unpin(struct intel_context *ctx, +void intel_lr_context_unpin(struct i915_gem_context *ctx, struct intel_engine_cs *engine) { struct drm_i915_gem_object *ctx_obj; @@ -2046,7 +2046,7 @@ logical_ring_setup(struct drm_device *dev, enum intel_engine_id id) static int logical_ring_init(struct intel_engine_cs *engine) { - struct intel_context *dctx = engine->i915->kernel_context; + struct i915_gem_context *dctx = engine->i915->kernel_context; int ret; ret = i915_cmd_parser_init_ring(engine); @@ -2270,7 +2270,7 @@ static u32 intel_lr_indirect_ctx_offset(struct intel_engine_cs *engine) } static int -populate_lr_context(struct intel_context *ctx, +populate_lr_context(struct i915_gem_context *ctx, struct drm_i915_gem_object *ctx_obj, struct intel_engine_cs *engine, struct intel_ringbuffer *ringbuf) @@ -2418,7 +2418,7 @@ populate_lr_context(struct intel_context *ctx, * takes care of the bits that are LRC related: the per-engine backing * objects and the logical ringbuffer. */ -void intel_lr_context_free(struct intel_context *ctx) +void intel_lr_context_free(struct i915_gem_context *ctx) { int i; @@ -2486,7 +2486,7 @@ uint32_t intel_lr_context_size(struct intel_engine_cs *engine) * * Return: non-zero on error. */ -static int execlists_context_deferred_alloc(struct intel_context *ctx, +static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, struct intel_engine_cs *engine) { struct drm_i915_gem_object *ctx_obj; @@ -2536,7 +2536,7 @@ error_deref_obj: } void intel_lr_context_reset(struct drm_i915_private *dev_priv, - struct intel_context *ctx) + struct i915_gem_context *ctx) { struct intel_engine_cs *engine; diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 1afba03..eb2e1d1 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -99,16 +99,18 @@ static inline void intel_logical_ring_emit_reg(struct intel_ringbuffer *ringbuf, #define LRC_PPHWSP_PN (LRC_GUCSHR_PN + 1) #define LRC_STATE_PN (LRC_PPHWSP_PN + 1) -void intel_lr_context_free(struct intel_context *ctx); +struct i915_gem_context; + +void intel_lr_context_free(struct i915_gem_context *ctx); uint32_t intel_lr_context_size(struct intel_engine_cs *engine); -void intel_lr_context_unpin(struct intel_context *ctx, +void intel_lr_context_unpin(struct i915_gem_context *ctx, struct intel_engine_cs *engine); struct drm_i915_private; void intel_lr_context_reset(struct drm_i915_private *dev_priv, - struct intel_context *ctx); -uint64_t intel_lr_context_descriptor(struct intel_context *ctx, + struct i915_gem_context *ctx); +uint64_t intel_lr_context_descriptor(struct i915_gem_context *ctx, struct intel_engine_cs *engine); /* Execlists */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 929e7b4..b33c876 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -119,7 +119,7 @@ struct intel_ringbuffer { u32 last_retired_head; }; -struct intel_context; +struct i915_gem_context; struct drm_i915_reg_table; /* @@ -310,7 +310,7 @@ struct intel_engine_cs { wait_queue_head_t irq_queue; - struct intel_context *last_context; + struct i915_gem_context *last_context; struct intel_ring_hangcheck hangcheck; -- cgit v0.10.2 From 499f2697da1d6afb66a2b2377ad67952bcddbe65 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 24 May 2016 14:53:35 +0100 Subject: drm/i915: Apply lockdep annotations to i915_gem_context.c Markup the functions that require the caller to hold struct_mutex with lockdep_assert_held(). In the hopefully not-too-distant future we will split the struct_mutex up, and in doing so we need to be sure that we know what it protects - here the lockdep annotations are invaluable. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1464098023-3294-2-git-send-email-chris@chris-wilson.co.uk Link: http://patchwork.freedesktop.org/patch/msgid/1464098023-3294-2-git-send-email-chris@chris-wilson.co.uk diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 961ef40..820748d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3439,6 +3439,7 @@ static inline void i915_gem_context_reference(struct i915_gem_context *ctx) static inline void i915_gem_context_unreference(struct i915_gem_context *ctx) { + lockdep_assert_held(&ctx->i915->dev->struct_mutex); kref_put(&ctx->ref, i915_gem_context_free); } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 8484da2..6b4c5adf 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -153,6 +153,7 @@ void i915_gem_context_free(struct kref *ctx_ref) { struct i915_gem_context *ctx = container_of(ctx_ref, typeof(*ctx), ref); + lockdep_assert_held(&ctx->i915->dev->struct_mutex); trace_i915_context_free(ctx); if (i915.enable_execlists) @@ -181,6 +182,8 @@ i915_gem_alloc_context_obj(struct drm_device *dev, size_t size) struct drm_i915_gem_object *obj; int ret; + lockdep_assert_held(&dev->struct_mutex); + obj = i915_gem_object_create(dev, size); if (IS_ERR(obj)) return obj; @@ -304,7 +307,7 @@ i915_gem_create_context(struct drm_device *dev, struct i915_gem_context *ctx; int ret = 0; - BUG_ON(!mutex_is_locked(&dev->struct_mutex)); + lockdep_assert_held(&dev->struct_mutex); ctx = __create_hw_context(dev, file_priv); if (IS_ERR(ctx)) @@ -368,6 +371,8 @@ void i915_gem_context_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + lockdep_assert_held(&dev->struct_mutex); + if (i915.enable_execlists) { struct i915_gem_context *ctx; @@ -433,6 +438,8 @@ void i915_gem_context_lost(struct drm_i915_private *dev_priv) { struct intel_engine_cs *engine; + lockdep_assert_held(&dev_priv->dev->struct_mutex); + for_each_engine(engine, dev_priv) { if (engine->last_context == NULL) continue; @@ -451,6 +458,8 @@ void i915_gem_context_fini(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct i915_gem_context *dctx = dev_priv->kernel_context; + lockdep_assert_held(&dev->struct_mutex); + if (dctx->legacy_hw_ctx.rcs_state) i915_gem_object_ggtt_unpin(dctx->legacy_hw_ctx.rcs_state); @@ -491,6 +500,8 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; + lockdep_assert_held(&dev->struct_mutex); + idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL); idr_destroy(&file_priv->context_idr); } @@ -500,6 +511,8 @@ i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id) { struct i915_gem_context *ctx; + lockdep_assert_held(&file_priv->dev_priv->dev->struct_mutex); + ctx = idr_find(&file_priv->context_idr, id); if (!ctx) return ERR_PTR(-ENOENT); @@ -852,10 +865,9 @@ unpin_out: int i915_switch_context(struct drm_i915_gem_request *req) { struct intel_engine_cs *engine = req->engine; - struct drm_i915_private *dev_priv = req->i915; WARN_ON(i915.enable_execlists); - WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); + lockdep_assert_held(&req->i915->dev->struct_mutex); if (engine->id != RCS || req->ctx->legacy_hw_ctx.rcs_state == NULL) { -- cgit v0.10.2 From ca585b5d0a8ea5c39428d7728b3cf4d409287b39 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 24 May 2016 14:53:36 +0100 Subject: drm/i915: Rename and inline i915_gem_context_get() i915_gem_context_get() is a very simple wrapper around idr_find(), so simple that it would be smaller to do the lookup inline. Also we use the verb 'lookup' to return a pointer from a handle, freeing 'get' to imply obtaining a reference to the context. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1464098023-3294-3-git-send-email-chris@chris-wilson.co.uk diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 820748d..e0c9320 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3427,11 +3427,24 @@ void i915_gem_context_reset(struct drm_device *dev); int i915_gem_context_open(struct drm_device *dev, struct drm_file *file); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct drm_i915_gem_request *req); -struct i915_gem_context * -i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id); void i915_gem_context_free(struct kref *ctx_ref); struct drm_i915_gem_object * i915_gem_alloc_context_obj(struct drm_device *dev, size_t size); + +static inline struct i915_gem_context * +i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id) +{ + struct i915_gem_context *ctx; + + lockdep_assert_held(&file_priv->dev_priv->dev->struct_mutex); + + ctx = idr_find(&file_priv->context_idr, id); + if (!ctx) + return ERR_PTR(-ENOENT); + + return ctx; +} + static inline void i915_gem_context_reference(struct i915_gem_context *ctx) { kref_get(&ctx->ref); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 6b4c5adf..a3f9adb 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -506,20 +506,6 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) idr_destroy(&file_priv->context_idr); } -struct i915_gem_context * -i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id) -{ - struct i915_gem_context *ctx; - - lockdep_assert_held(&file_priv->dev_priv->dev->struct_mutex); - - ctx = idr_find(&file_priv->context_idr, id); - if (!ctx) - return ERR_PTR(-ENOENT); - - return ctx; -} - static inline int mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags) { @@ -951,7 +937,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, if (ret) return ret; - ctx = i915_gem_context_get(file_priv, args->ctx_id); + ctx = i915_gem_context_lookup(file_priv, args->ctx_id); if (IS_ERR(ctx)) { mutex_unlock(&dev->struct_mutex); return PTR_ERR(ctx); @@ -977,7 +963,7 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data, if (ret) return ret; - ctx = i915_gem_context_get(file_priv, args->ctx_id); + ctx = i915_gem_context_lookup(file_priv, args->ctx_id); if (IS_ERR(ctx)) { mutex_unlock(&dev->struct_mutex); return PTR_ERR(ctx); @@ -1020,7 +1006,7 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data, if (ret) return ret; - ctx = i915_gem_context_get(file_priv, args->ctx_id); + ctx = i915_gem_context_lookup(file_priv, args->ctx_id); if (IS_ERR(ctx)) { mutex_unlock(&dev->struct_mutex); return PTR_ERR(ctx); @@ -1072,7 +1058,7 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev, if (ret) return ret; - ctx = i915_gem_context_get(file->driver_priv, args->ctx_id); + ctx = i915_gem_context_lookup(file->driver_priv, args->ctx_id); if (IS_ERR(ctx)) { mutex_unlock(&dev->struct_mutex); return PTR_ERR(ctx); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index e61b92d..84d9903 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1075,7 +1075,7 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file, if (engine->id != RCS && ctx_id != DEFAULT_CONTEXT_HANDLE) return ERR_PTR(-EINVAL); - ctx = i915_gem_context_get(file->driver_priv, ctx_id); + ctx = i915_gem_context_lookup(file->driver_priv, ctx_id); if (IS_ERR(ctx)) return ctx; -- cgit v0.10.2 From 9021ad03d05710192f6d50f6732b9d2354113cd0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 24 May 2016 14:53:37 +0100 Subject: drm/i915: Name the inner most per-engine intel_context struct We want to give a name to the currently anonymous per-engine struct inside the context, so that we can assign it to a local variable and save clumsy typing. The name we have chosen is intel_context as it reflects the HW facing portion of the context state (the logical context state, the registers, the ringbuffer etc). Signed-off-by: Chris Wilson Cc: Dave Gordon Cc: Tvrtko Ursulin Reviewed-by Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1464098023-3294-4-git-send-email-chris@chris-wilson.co.uk diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e0c9320..784978d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -869,7 +869,7 @@ struct i915_gem_context { } legacy_hw_ctx; /* Execlists */ - struct { + struct intel_context { struct drm_i915_gem_object *state; struct intel_ringbuffer *ringbuf; int pin_count; diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c index b42a3ad..7b3c96e 100644 --- a/drivers/gpu/drm/i915/i915_guc_submission.c +++ b/drivers/gpu/drm/i915/i915_guc_submission.c @@ -363,7 +363,6 @@ static void guc_init_ctx_desc(struct intel_guc *guc, struct i915_gem_context *ctx = client->owner; struct guc_context_desc desc; struct sg_table *sg; - enum intel_engine_id id; u32 gfx_addr; memset(&desc, 0, sizeof(desc)); @@ -373,10 +372,10 @@ static void guc_init_ctx_desc(struct intel_guc *guc, desc.priority = client->priority; desc.db_id = client->doorbell_id; - for_each_engine_id(engine, dev_priv, id) { + for_each_engine(engine, dev_priv) { + struct intel_context *ce = &ctx->engine[engine->id]; struct guc_execlist_context *lrc = &desc.lrc[engine->guc_id]; struct drm_i915_gem_object *obj; - uint64_t ctx_desc; /* TODO: We have a design issue to be solved here. Only when we * receive the first batch, we know which engine is used by the @@ -385,20 +384,18 @@ static void guc_init_ctx_desc(struct intel_guc *guc, * for now who owns a GuC client. But for future owner of GuC * client, need to make sure lrc is pinned prior to enter here. */ - obj = ctx->engine[id].state; - if (!obj) + if (!ce->state) break; /* XXX: continue? */ - ctx_desc = intel_lr_context_descriptor(ctx, engine); - lrc->context_desc = (u32)ctx_desc; + lrc->context_desc = lower_32_bits(ce->lrc_desc); /* The state page is after PPHWSP */ - gfx_addr = i915_gem_obj_ggtt_offset(obj); + gfx_addr = i915_gem_obj_ggtt_offset(ce->state); lrc->ring_lcra = gfx_addr + LRC_STATE_PN * PAGE_SIZE; lrc->context_id = (client->ctx_index << GUC_ELC_CTXID_OFFSET) | (engine->guc_id << GUC_ELC_ENGINE_OFFSET); - obj = ctx->engine[id].ringbuf->obj; + obj = ce->ringbuf->obj; gfx_addr = i915_gem_obj_ggtt_offset(obj); lrc->ring_begin = gfx_addr; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 3d95b26..a1dba67 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -300,7 +300,7 @@ logical_ring_init_platform_invariants(struct intel_engine_cs *engine) * descriptor for a pinned context * * @ctx: Context to work on - * @ring: Engine the descriptor will be used with + * @engine: Engine the descriptor will be used with * * The context descriptor encodes various attributes of a context, * including its GTT address and some flags. Because it's fairly @@ -318,16 +318,17 @@ static void intel_lr_context_descriptor_update(struct i915_gem_context *ctx, struct intel_engine_cs *engine) { + struct intel_context *ce = &ctx->engine[engine->id]; u64 desc; BUILD_BUG_ON(MAX_CONTEXT_HW_ID > (1<ctx_desc_template; /* bits 0-11 */ - desc |= ctx->engine[engine->id].lrc_vma->node.start + /* bits 12-31 */ - LRC_PPHWSP_PN * PAGE_SIZE; + desc |= ce->lrc_vma->node.start + LRC_PPHWSP_PN * PAGE_SIZE; + /* bits 12-31 */ desc |= (u64)ctx->hw_id << GEN8_CTX_ID_SHIFT; /* bits 32-52 */ - ctx->engine[engine->id].lrc_desc = desc; + ce->lrc_desc = desc; } uint64_t intel_lr_context_descriptor(struct i915_gem_context *ctx, @@ -674,6 +675,7 @@ static int execlists_move_to_gpu(struct drm_i915_gem_request *req, int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request) { struct intel_engine_cs *engine = request->engine; + struct intel_context *ce = &request->ctx->engine[engine->id]; int ret; /* Flush enough space to reduce the likelihood of waiting after @@ -682,13 +684,13 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request */ request->reserved_space += EXECLISTS_REQUEST_SIZE; - if (request->ctx->engine[engine->id].state == NULL) { + if (!ce->state) { ret = execlists_context_deferred_alloc(request->ctx, engine); if (ret) return ret; } - request->ringbuf = request->ctx->engine[engine->id].ringbuf; + request->ringbuf = ce->ringbuf; if (i915.enable_guc_submission) { /* @@ -709,12 +711,12 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request if (ret) goto err_unpin; - if (!request->ctx->engine[engine->id].initialised) { + if (!ce->initialised) { ret = engine->init_context(request); if (ret) goto err_unpin; - request->ctx->engine[engine->id].initialised = true; + ce->initialised = true; } /* Note that after this point, we have committed to using @@ -933,24 +935,22 @@ static int intel_lr_context_pin(struct i915_gem_context *ctx, struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = ctx->i915; - struct drm_i915_gem_object *ctx_obj; - struct intel_ringbuffer *ringbuf; + struct intel_context *ce = &ctx->engine[engine->id]; void *vaddr; u32 *lrc_reg_state; int ret; lockdep_assert_held(&ctx->i915->dev->struct_mutex); - if (ctx->engine[engine->id].pin_count++) + if (ce->pin_count++) return 0; - ctx_obj = ctx->engine[engine->id].state; - ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN, - PIN_OFFSET_BIAS | GUC_WOPCM_TOP); + ret = i915_gem_obj_ggtt_pin(ce->state, GEN8_LR_CONTEXT_ALIGN, + PIN_OFFSET_BIAS | GUC_WOPCM_TOP); if (ret) goto err; - vaddr = i915_gem_object_pin_map(ctx_obj); + vaddr = i915_gem_object_pin_map(ce->state); if (IS_ERR(vaddr)) { ret = PTR_ERR(vaddr); goto unpin_ctx_obj; @@ -958,17 +958,17 @@ static int intel_lr_context_pin(struct i915_gem_context *ctx, lrc_reg_state = vaddr + LRC_STATE_PN * PAGE_SIZE; - ringbuf = ctx->engine[engine->id].ringbuf; - ret = intel_pin_and_map_ringbuffer_obj(dev_priv, ringbuf); + ret = intel_pin_and_map_ringbuffer_obj(dev_priv, ce->ringbuf); if (ret) goto unpin_map; i915_gem_context_reference(ctx); - ctx->engine[engine->id].lrc_vma = i915_gem_obj_to_ggtt(ctx_obj); + ce->lrc_vma = i915_gem_obj_to_ggtt(ce->state); intel_lr_context_descriptor_update(ctx, engine); - lrc_reg_state[CTX_RING_BUFFER_START+1] = ringbuf->vma->node.start; - ctx->engine[engine->id].lrc_reg_state = lrc_reg_state; - ctx_obj->dirty = true; + + lrc_reg_state[CTX_RING_BUFFER_START+1] = ce->ringbuf->vma->node.start; + ce->lrc_reg_state = lrc_reg_state; + ce->state->dirty = true; /* Invalidate GuC TLB. */ if (i915.enable_guc_submission) @@ -977,34 +977,33 @@ static int intel_lr_context_pin(struct i915_gem_context *ctx, return 0; unpin_map: - i915_gem_object_unpin_map(ctx_obj); + i915_gem_object_unpin_map(ce->state); unpin_ctx_obj: - i915_gem_object_ggtt_unpin(ctx_obj); + i915_gem_object_ggtt_unpin(ce->state); err: - ctx->engine[engine->id].pin_count = 0; + ce->pin_count = 0; return ret; } void intel_lr_context_unpin(struct i915_gem_context *ctx, struct intel_engine_cs *engine) { - struct drm_i915_gem_object *ctx_obj; + struct intel_context *ce = &ctx->engine[engine->id]; lockdep_assert_held(&ctx->i915->dev->struct_mutex); - GEM_BUG_ON(ctx->engine[engine->id].pin_count == 0); + GEM_BUG_ON(ce->pin_count == 0); - if (--ctx->engine[engine->id].pin_count) + if (--ce->pin_count) return; - intel_unpin_ringbuffer_obj(ctx->engine[engine->id].ringbuf); + intel_unpin_ringbuffer_obj(ce->ringbuf); - ctx_obj = ctx->engine[engine->id].state; - i915_gem_object_unpin_map(ctx_obj); - i915_gem_object_ggtt_unpin(ctx_obj); + i915_gem_object_unpin_map(ce->state); + i915_gem_object_ggtt_unpin(ce->state); - ctx->engine[engine->id].lrc_vma = NULL; - ctx->engine[engine->id].lrc_desc = 0; - ctx->engine[engine->id].lrc_reg_state = NULL; + ce->lrc_vma = NULL; + ce->lrc_desc = 0; + ce->lrc_reg_state = NULL; i915_gem_context_unreference(ctx); } @@ -2490,12 +2489,13 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, struct intel_engine_cs *engine) { struct drm_i915_gem_object *ctx_obj; + struct intel_context *ce = &ctx->engine[engine->id]; uint32_t context_size; struct intel_ringbuffer *ringbuf; int ret; WARN_ON(ctx->legacy_hw_ctx.rcs_state != NULL); - WARN_ON(ctx->engine[engine->id].state); + WARN_ON(ce->state); context_size = round_up(intel_lr_context_size(engine), 4096); @@ -2520,9 +2520,9 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, goto error_ringbuf; } - ctx->engine[engine->id].ringbuf = ringbuf; - ctx->engine[engine->id].state = ctx_obj; - ctx->engine[engine->id].initialised = engine->init_context == NULL; + ce->ringbuf = ringbuf; + ce->state = ctx_obj; + ce->initialised = engine->init_context == NULL; return 0; @@ -2530,8 +2530,8 @@ error_ringbuf: intel_ringbuffer_free(ringbuf); error_deref_obj: drm_gem_object_unreference(&ctx_obj->base); - ctx->engine[engine->id].ringbuf = NULL; - ctx->engine[engine->id].state = NULL; + ce->ringbuf = NULL; + ce->state = NULL; return ret; } @@ -2541,10 +2541,8 @@ void intel_lr_context_reset(struct drm_i915_private *dev_priv, struct intel_engine_cs *engine; for_each_engine(engine, dev_priv) { - struct drm_i915_gem_object *ctx_obj = - ctx->engine[engine->id].state; - struct intel_ringbuffer *ringbuf = - ctx->engine[engine->id].ringbuf; + struct intel_context *ce = &ctx->engine[engine->id]; + struct drm_i915_gem_object *ctx_obj = ce->state; void *vaddr; uint32_t *reg_state; @@ -2563,7 +2561,7 @@ void intel_lr_context_reset(struct drm_i915_private *dev_priv, i915_gem_object_unpin_map(ctx_obj); - ringbuf->head = 0; - ringbuf->tail = 0; + ce->ringbuf->head = 0; + ce->ringbuf->tail = 0; } } -- cgit v0.10.2 From c6aab9161a0343e63f44043cf22b6d67a3250143 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 24 May 2016 14:53:38 +0100 Subject: drm/i915: Move pinning of dev_priv->kernel_context into its creator Rather than have every context ask "am I owned by the kernel? pin!", move that logic into the creator of the kernel context, in order to improve code comprehension. v2: Throw away the user_handle on failure to allocate the ppgtt. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1464098023-3294-5-git-send-email-chris@chris-wilson.co.uk diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index a3f9adb..104d481 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -303,9 +303,7 @@ static struct i915_gem_context * i915_gem_create_context(struct drm_device *dev, struct drm_i915_file_private *file_priv) { - const bool is_global_default_ctx = file_priv == NULL; struct i915_gem_context *ctx; - int ret = 0; lockdep_assert_held(&dev->struct_mutex); @@ -313,30 +311,15 @@ i915_gem_create_context(struct drm_device *dev, if (IS_ERR(ctx)) return ctx; - if (is_global_default_ctx && ctx->legacy_hw_ctx.rcs_state) { - /* We may need to do things with the shrinker which - * require us to immediately switch back to the default - * context. This can cause a problem as pinning the - * default context also requires GTT space which may not - * be available. To avoid this we always pin the default - * context. - */ - ret = i915_gem_obj_ggtt_pin(ctx->legacy_hw_ctx.rcs_state, - get_context_alignment(to_i915(dev)), 0); - if (ret) { - DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret); - goto err_destroy; - } - } - if (USES_FULL_PPGTT(dev)) { struct i915_hw_ppgtt *ppgtt = i915_ppgtt_create(dev, file_priv); - if (IS_ERR_OR_NULL(ppgtt)) { + if (IS_ERR(ppgtt)) { DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n", PTR_ERR(ppgtt)); - ret = PTR_ERR(ppgtt); - goto err_unpin; + idr_remove(&file_priv->context_idr, ctx->user_handle); + i915_gem_context_unreference(ctx); + return ERR_CAST(ppgtt); } ctx->ppgtt = ppgtt; @@ -345,14 +328,6 @@ i915_gem_create_context(struct drm_device *dev, trace_i915_context_create(ctx); return ctx; - -err_unpin: - if (is_global_default_ctx && ctx->legacy_hw_ctx.rcs_state) - i915_gem_object_ggtt_unpin(ctx->legacy_hw_ctx.rcs_state); -err_destroy: - idr_remove(&file_priv->context_idr, ctx->user_handle); - i915_gem_context_unreference(ctx); - return ERR_PTR(ret); } static void i915_gem_context_unpin(struct i915_gem_context *ctx, @@ -426,6 +401,26 @@ int i915_gem_context_init(struct drm_device *dev) return PTR_ERR(ctx); } + if (ctx->legacy_hw_ctx.rcs_state) { + int ret; + + /* We may need to do things with the shrinker which + * require us to immediately switch back to the default + * context. This can cause a problem as pinning the + * default context also requires GTT space which may not + * be available. To avoid this we always pin the default + * context. + */ + ret = i915_gem_obj_ggtt_pin(ctx->legacy_hw_ctx.rcs_state, + get_context_alignment(dev_priv), 0); + if (ret) { + DRM_ERROR("Failed to pinned default global context (error %d)\n", + ret); + i915_gem_context_unreference(ctx); + return ret; + } + } + dev_priv->kernel_context = ctx; DRM_DEBUG_DRIVER("%s context support initialized\n", -- cgit v0.10.2 From d28b99ab8c812a582469f04a698081d495e4bd8f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 24 May 2016 14:53:39 +0100 Subject: drm/i915: Show i915_gem_context owner in debugfs Print the context's owner (via the pid under file_priv) under debugfs. In doing so, we must be careful that the filp is not accessed after it is freed (notified via i915_gem_context_close). v2: Mark the file_priv as closed. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1464098023-3294-6-git-send-email-chris@chris-wilson.co.uk diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 424e11e..05b9e5e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2014,9 +2014,23 @@ static int i915_context_status(struct seq_file *m, void *unused) continue; seq_printf(m, "HW context %u ", ctx->hw_id); + if (IS_ERR(ctx->file_priv)) { + seq_puts(m, "(deleted) "); + } else if (ctx->file_priv) { + struct pid *pid = ctx->file_priv->file->pid; + struct task_struct *task; + + task = get_pid_task(pid, PIDTYPE_PID); + if (task) { + seq_printf(m, "(%s [%d]) ", + task->comm, task->pid); + put_task_struct(task); + } + } else { + seq_puts(m, "(kernel) "); + } + describe_ctx(m, ctx); - if (ctx == dev_priv->kernel_context) - seq_printf(m, "(kernel context) "); if (i915.enable_execlists) { seq_putc(m, '\n'); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 104d481..8d8c79b 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -468,6 +468,7 @@ static int context_idr_cleanup(int id, void *p, void *data) { struct i915_gem_context *ctx = p; + ctx->file_priv = ERR_PTR(-EBADF); i915_gem_context_unreference(ctx); return 0; } @@ -938,7 +939,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, return PTR_ERR(ctx); } - idr_remove(&ctx->file_priv->context_idr, ctx->user_handle); + idr_remove(&file_priv->context_idr, ctx->user_handle); i915_gem_context_unreference(ctx); mutex_unlock(&dev->struct_mutex); -- cgit v0.10.2 From 0ca5fa3a6bf8c3d4c89f5194578cb10639bc97b4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 24 May 2016 14:53:40 +0100 Subject: drm/i915: Put the kernel_context in drm_i915_private next to its friends Just move the kernel_context member of drm_i915_private next to the engines it is associated with. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1464098023-3294-7-git-send-email-chris@chris-wilson.co.uk diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 784978d..b2428bc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1760,6 +1760,7 @@ struct drm_i915_private { wait_queue_head_t gmbus_wait_queue; struct pci_dev *bridge_dev; + struct i915_gem_context *kernel_context; struct intel_engine_cs engine[I915_NUM_ENGINES]; struct drm_i915_gem_object *semaphore_obj; uint32_t last_seqno, next_seqno; @@ -2017,8 +2018,6 @@ struct drm_i915_private { void (*stop_engine)(struct intel_engine_cs *engine); } gt; - struct i915_gem_context *kernel_context; - /* perform PHY state sanity checks? */ bool chv_phy_assert[2]; diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c index 7b3c96e..ac72451 100644 --- a/drivers/gpu/drm/i915/i915_guc_submission.c +++ b/drivers/gpu/drm/i915/i915_guc_submission.c @@ -935,11 +935,12 @@ int i915_guc_submission_enable(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_guc *guc = &dev_priv->guc; - struct i915_gem_context *ctx = dev_priv->kernel_context; struct i915_guc_client *client; /* client for execbuf submission */ - client = guc_client_alloc(dev, GUC_CTX_PRIORITY_KMD_NORMAL, ctx); + client = guc_client_alloc(dev, + GUC_CTX_PRIORITY_KMD_NORMAL, + dev_priv->kernel_context); if (!client) { DRM_ERROR("Failed to create execbuf guc_client\n"); return -ENOMEM; -- cgit v0.10.2 From bca44d8055b494dd035325cf8c439d5bb21c89d1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 24 May 2016 14:53:41 +0100 Subject: drm/i915: Merge legacy+execlists context structs struct intel_context contains two substructs, one for the legacy RCS and one for every execlists engine. Since legacy RCS is a subset of the execlists engine support, just combine the two substructs. v2: Only pin the default context for legacy mode (the object only exists for legacy, but adding i915.enable_execlists provides symmetry with the cleanup functions). Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1464098023-3294-8-git-send-email-chris@chris-wilson.co.uk diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 05b9e5e..757dc0f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -199,13 +199,6 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) seq_printf(m, " (frontbuffer: 0x%03x)", obj->frontbuffer_bits); } -static void describe_ctx(struct seq_file *m, struct i915_gem_context *ctx) -{ - seq_putc(m, ctx->legacy_hw_ctx.initialized ? 'I' : 'i'); - seq_putc(m, ctx->remap_slice ? 'R' : 'r'); - seq_putc(m, ' '); -} - static int i915_gem_object_list_info(struct seq_file *m, void *data) { struct drm_info_node *node = m->private; @@ -2001,7 +1994,6 @@ static int i915_context_status(struct seq_file *m, void *unused) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *engine; struct i915_gem_context *ctx; - enum intel_engine_id id; int ret; ret = mutex_lock_interruptible(&dev->struct_mutex); @@ -2009,10 +2001,6 @@ static int i915_context_status(struct seq_file *m, void *unused) return ret; list_for_each_entry(ctx, &dev_priv->context_list, link) { - if (!i915.enable_execlists && - ctx->legacy_hw_ctx.rcs_state == NULL) - continue; - seq_printf(m, "HW context %u ", ctx->hw_id); if (IS_ERR(ctx->file_priv)) { seq_puts(m, "(deleted) "); @@ -2030,25 +2018,19 @@ static int i915_context_status(struct seq_file *m, void *unused) seq_puts(m, "(kernel) "); } - describe_ctx(m, ctx); + seq_putc(m, ctx->remap_slice ? 'R' : 'r'); + seq_putc(m, '\n'); - if (i915.enable_execlists) { + for_each_engine(engine, dev_priv) { + struct intel_context *ce = &ctx->engine[engine->id]; + + seq_printf(m, "%s: ", engine->name); + seq_putc(m, ce->initialised ? 'I' : 'i'); + if (ce->state) + describe_obj(m, ce->state); + if (ce->ringbuf) + describe_ctx_ringbuf(m, ce->ringbuf); seq_putc(m, '\n'); - for_each_engine_id(engine, dev_priv, id) { - struct drm_i915_gem_object *ctx_obj = - ctx->engine[id].state; - struct intel_ringbuffer *ringbuf = - ctx->engine[id].ringbuf; - - seq_printf(m, "%s: ", engine->name); - if (ctx_obj) - describe_obj(m, ctx_obj); - if (ringbuf) - describe_ctx_ringbuf(m, ringbuf); - seq_putc(m, '\n'); - } - } else { - describe_obj(m, ctx->legacy_hw_ctx.rcs_state); } seq_putc(m, '\n'); @@ -2063,10 +2045,10 @@ static void i915_dump_lrc_obj(struct seq_file *m, struct i915_gem_context *ctx, struct intel_engine_cs *engine) { + struct drm_i915_gem_object *ctx_obj = ctx->engine[engine->id].state; struct page *page; uint32_t *reg_state; int j; - struct drm_i915_gem_object *ctx_obj = ctx->engine[engine->id].state; unsigned long ggtt_offset = 0; seq_printf(m, "CONTEXT: %s %u\n", engine->name, ctx->hw_id); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b2428bc..5832082 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -862,13 +862,6 @@ struct i915_gem_context { /* Unique identifier for this context, used by the hw for tracking */ unsigned hw_id; - /* Legacy ring buffer submission */ - struct { - struct drm_i915_gem_object *rcs_state; - bool initialized; - } legacy_hw_ctx; - - /* Execlists */ struct intel_context { struct drm_i915_gem_object *state; struct intel_ringbuffer *ringbuf; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 8d8c79b..a3b11aa 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -152,13 +152,11 @@ static void i915_gem_context_clean(struct i915_gem_context *ctx) void i915_gem_context_free(struct kref *ctx_ref) { struct i915_gem_context *ctx = container_of(ctx_ref, typeof(*ctx), ref); + int i; lockdep_assert_held(&ctx->i915->dev->struct_mutex); trace_i915_context_free(ctx); - if (i915.enable_execlists) - intel_lr_context_free(ctx); - /* * This context is going away and we need to remove all VMAs still * around. This is to handle imported shared objects for which @@ -168,8 +166,19 @@ void i915_gem_context_free(struct kref *ctx_ref) i915_ppgtt_put(ctx->ppgtt); - if (ctx->legacy_hw_ctx.rcs_state) - drm_gem_object_unreference(&ctx->legacy_hw_ctx.rcs_state->base); + for (i = 0; i < I915_NUM_ENGINES; i++) { + struct intel_context *ce = &ctx->engine[i]; + + if (!ce->state) + continue; + + WARN_ON(ce->pin_count); + if (ce->ringbuf) + intel_ringbuffer_free(ce->ringbuf); + + drm_gem_object_unreference(&ce->state->base); + } + list_del(&ctx->link); ida_simple_remove(&ctx->i915->context_hw_ida, ctx->hw_id); @@ -266,7 +275,7 @@ __create_hw_context(struct drm_device *dev, ret = PTR_ERR(obj); goto err_out; } - ctx->legacy_hw_ctx.rcs_state = obj; + ctx->engine[RCS].state = obj; } /* Default context will never have a file_priv */ @@ -336,8 +345,11 @@ static void i915_gem_context_unpin(struct i915_gem_context *ctx, if (i915.enable_execlists) { intel_lr_context_unpin(ctx, engine); } else { - if (engine->id == RCS && ctx->legacy_hw_ctx.rcs_state) - i915_gem_object_ggtt_unpin(ctx->legacy_hw_ctx.rcs_state); + struct intel_context *ce = &ctx->engine[engine->id]; + + if (ce->state) + i915_gem_object_ggtt_unpin(ce->state); + i915_gem_context_unreference(ctx); } } @@ -401,7 +413,7 @@ int i915_gem_context_init(struct drm_device *dev) return PTR_ERR(ctx); } - if (ctx->legacy_hw_ctx.rcs_state) { + if (!i915.enable_execlists && ctx->engine[RCS].state) { int ret; /* We may need to do things with the shrinker which @@ -411,7 +423,7 @@ int i915_gem_context_init(struct drm_device *dev) * be available. To avoid this we always pin the default * context. */ - ret = i915_gem_obj_ggtt_pin(ctx->legacy_hw_ctx.rcs_state, + ret = i915_gem_obj_ggtt_pin(ctx->engine[RCS].state, get_context_alignment(dev_priv), 0); if (ret) { DRM_ERROR("Failed to pinned default global context (error %d)\n", @@ -436,15 +448,17 @@ void i915_gem_context_lost(struct drm_i915_private *dev_priv) lockdep_assert_held(&dev_priv->dev->struct_mutex); for_each_engine(engine, dev_priv) { - if (engine->last_context == NULL) - continue; + if (engine->last_context) { + i915_gem_context_unpin(engine->last_context, engine); + engine->last_context = NULL; + } - i915_gem_context_unpin(engine->last_context, engine); - engine->last_context = NULL; + /* Force the GPU state to be reinitialised on enabling */ + dev_priv->kernel_context->engine[engine->id].initialised = + engine->init_context == NULL; } /* Force the GPU state to be reinitialised on enabling */ - dev_priv->kernel_context->legacy_hw_ctx.initialized = false; dev_priv->kernel_context->remap_slice = ALL_L3_SLICES(dev_priv); } @@ -455,8 +469,8 @@ void i915_gem_context_fini(struct drm_device *dev) lockdep_assert_held(&dev->struct_mutex); - if (dctx->legacy_hw_ctx.rcs_state) - i915_gem_object_ggtt_unpin(dctx->legacy_hw_ctx.rcs_state); + if (!i915.enable_execlists && dctx->engine[RCS].state) + i915_gem_object_ggtt_unpin(dctx->engine[RCS].state); i915_gem_context_unreference(dctx); dev_priv->kernel_context = NULL; @@ -564,7 +578,7 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags) intel_ring_emit(engine, MI_NOOP); intel_ring_emit(engine, MI_SET_CONTEXT); intel_ring_emit(engine, - i915_gem_obj_ggtt_offset(req->ctx->legacy_hw_ctx.rcs_state) | + i915_gem_obj_ggtt_offset(req->ctx->engine[RCS].state) | flags); /* * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP @@ -641,7 +655,7 @@ static inline bool skip_rcs_switch(struct i915_hw_ppgtt *ppgtt, if (to->remap_slice) return false; - if (!to->legacy_hw_ctx.initialized) + if (!to->engine[RCS].initialised) return false; if (ppgtt && (intel_engine_flag(engine) & ppgtt->pd_dirty_rings)) @@ -706,7 +720,7 @@ static int do_rcs_switch(struct drm_i915_gem_request *req) return 0; /* Trying to pin first makes error handling easier. */ - ret = i915_gem_obj_ggtt_pin(to->legacy_hw_ctx.rcs_state, + ret = i915_gem_obj_ggtt_pin(to->engine[RCS].state, get_context_alignment(engine->i915), 0); if (ret) @@ -729,7 +743,7 @@ static int do_rcs_switch(struct drm_i915_gem_request *req) * * XXX: We need a real interface to do this instead of trickery. */ - ret = i915_gem_object_set_to_gtt_domain(to->legacy_hw_ctx.rcs_state, false); + ret = i915_gem_object_set_to_gtt_domain(to->engine[RCS].state, false); if (ret) goto unpin_out; @@ -744,7 +758,7 @@ static int do_rcs_switch(struct drm_i915_gem_request *req) goto unpin_out; } - if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to)) + if (!to->engine[RCS].initialised || i915_gem_context_is_default(to)) /* NB: If we inhibit the restore, the context is not allowed to * die because future work may end up depending on valid address * space. This means we must enforce that a page table load @@ -768,8 +782,8 @@ static int do_rcs_switch(struct drm_i915_gem_request *req) * MI_SET_CONTEXT instead of when the next seqno has completed. */ if (from != NULL) { - from->legacy_hw_ctx.rcs_state->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION; - i915_vma_move_to_active(i915_gem_obj_to_ggtt(from->legacy_hw_ctx.rcs_state), req); + from->engine[RCS].state->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION; + i915_vma_move_to_active(i915_gem_obj_to_ggtt(from->engine[RCS].state), req); /* As long as MI_SET_CONTEXT is serializing, ie. it flushes the * whole damn pipeline, we don't need to explicitly mark the * object dirty. The only exception is that the context must be @@ -777,10 +791,10 @@ static int do_rcs_switch(struct drm_i915_gem_request *req) * able to defer doing this until we know the object would be * swapped, but there is no way to do that yet. */ - from->legacy_hw_ctx.rcs_state->dirty = 1; + from->engine[RCS].state->dirty = 1; /* obj is kept alive until the next request by its active ref */ - i915_gem_object_ggtt_unpin(from->legacy_hw_ctx.rcs_state); + i915_gem_object_ggtt_unpin(from->engine[RCS].state); i915_gem_context_unreference(from); } i915_gem_context_reference(to); @@ -815,19 +829,19 @@ static int do_rcs_switch(struct drm_i915_gem_request *req) to->remap_slice &= ~(1<legacy_hw_ctx.initialized) { + if (!to->engine[RCS].initialised) { if (engine->init_context) { ret = engine->init_context(req); if (ret) return ret; } - to->legacy_hw_ctx.initialized = true; + to->engine[RCS].initialised = true; } return 0; unpin_out: - i915_gem_object_ggtt_unpin(to->legacy_hw_ctx.rcs_state); + i915_gem_object_ggtt_unpin(to->engine[RCS].state); return ret; } @@ -851,8 +865,7 @@ int i915_switch_context(struct drm_i915_gem_request *req) WARN_ON(i915.enable_execlists); lockdep_assert_held(&req->i915->dev->struct_mutex); - if (engine->id != RCS || - req->ctx->legacy_hw_ctx.rcs_state == NULL) { + if (!req->ctx->engine[engine->id].state) { struct i915_gem_context *to = req->ctx; struct i915_hw_ppgtt *ppgtt = to->ppgtt ?: req->i915->mm.aliasing_ppgtt; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a1dba67..5371503 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -2410,31 +2410,6 @@ populate_lr_context(struct i915_gem_context *ctx, } /** - * intel_lr_context_free() - free the LRC specific bits of a context - * @ctx: the LR context to free. - * - * The real context freeing is done in i915_gem_context_free: this only - * takes care of the bits that are LRC related: the per-engine backing - * objects and the logical ringbuffer. - */ -void intel_lr_context_free(struct i915_gem_context *ctx) -{ - int i; - - for (i = I915_NUM_ENGINES; --i >= 0; ) { - struct intel_ringbuffer *ringbuf = ctx->engine[i].ringbuf; - struct drm_i915_gem_object *ctx_obj = ctx->engine[i].state; - - if (!ctx_obj) - continue; - - WARN_ON(ctx->engine[i].pin_count); - intel_ringbuffer_free(ringbuf); - drm_gem_object_unreference(&ctx_obj->base); - } -} - -/** * intel_lr_context_size() - return the size of the context for an engine * @ring: which engine to find the context size for * @@ -2494,7 +2469,6 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, struct intel_ringbuffer *ringbuf; int ret; - WARN_ON(ctx->legacy_hw_ctx.rcs_state != NULL); WARN_ON(ce->state); context_size = round_up(intel_lr_context_size(engine), 4096); diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index eb2e1d1..a8db42a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -101,7 +101,6 @@ static inline void intel_logical_ring_emit_reg(struct intel_ringbuffer *ringbuf, struct i915_gem_context; -void intel_lr_context_free(struct i915_gem_context *ctx); uint32_t intel_lr_context_size(struct intel_engine_cs *engine); void intel_lr_context_unpin(struct i915_gem_context *ctx, struct intel_engine_cs *engine); -- cgit v0.10.2 From 8d59bc6ae9133b9986130835a060dc2532d04b00 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 24 May 2016 14:53:42 +0100 Subject: drm/i915: Rearrange i915_gem_context Pack the integers and related types together inside the struct. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1464098023-3294-9-git-send-email-chris@chris-wilson.co.uk diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5832082..85a7c44 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -829,7 +829,6 @@ struct i915_ctx_hang_stats { /* This must match up with the value previously used for execbuf2.rsvd1. */ #define DEFAULT_CONTEXT_HANDLE 0 -#define CONTEXT_NO_ZEROMAP (1<<0) /** * struct i915_gem_context - as the name implies, represents a context. * @ref: reference count. @@ -851,28 +850,31 @@ struct i915_ctx_hang_stats { */ struct i915_gem_context { struct kref ref; - int user_handle; - uint8_t remap_slice; struct drm_i915_private *i915; - int flags; struct drm_i915_file_private *file_priv; - struct i915_ctx_hang_stats hang_stats; struct i915_hw_ppgtt *ppgtt; + struct i915_ctx_hang_stats hang_stats; + /* Unique identifier for this context, used by the hw for tracking */ + unsigned long flags; unsigned hw_id; + u32 user_handle; +#define CONTEXT_NO_ZEROMAP (1<<0) struct intel_context { struct drm_i915_gem_object *state; struct intel_ringbuffer *ringbuf; - int pin_count; struct i915_vma *lrc_vma; - u64 lrc_desc; uint32_t *lrc_reg_state; + u64 lrc_desc; + int pin_count; bool initialised; } engine[I915_NUM_ENGINES]; struct list_head link; + + u8 remap_slice; }; enum fb_op_origin { -- cgit v0.10.2 From 15da95656dc44538fa71e3c00fc65db05b4a4788 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 24 May 2016 14:53:43 +0100 Subject: drm/i915/debugfs: Show context objects in i915_gem_objects One of the uses for i915_gem_objects is pin-pointing leaks. For this, we can compare the number of allocated objects and who owns them, a discrepancy here often indicates a kernel bug. One allocator of unreported objects is for backing context objects, so include those in the listing. v2: Take filelist_mutex which requires a little dance with struct_mutex to avoid nesting filelist_mutex inside struct_mutex. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1464098023-3294-10-git-send-email-chris@chris-wilson.co.uk diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 757dc0f..b29ba16 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -417,6 +417,42 @@ static void print_batch_pool_stats(struct seq_file *m, print_file_stats(m, "[k]batch pool", stats); } +static int per_file_ctx_stats(int id, void *ptr, void *data) +{ + struct i915_gem_context *ctx = ptr; + int n; + + for (n = 0; n < ARRAY_SIZE(ctx->engine); n++) { + if (ctx->engine[n].state) + per_file_stats(0, ctx->engine[n].state, data); + if (ctx->engine[n].ringbuf) + per_file_stats(0, ctx->engine[n].ringbuf->obj, data); + } + + return 0; +} + +static void print_context_stats(struct seq_file *m, + struct drm_i915_private *dev_priv) +{ + struct file_stats stats; + struct drm_file *file; + + memset(&stats, 0, sizeof(stats)); + + mutex_lock(&dev_priv->dev->struct_mutex); + if (dev_priv->kernel_context) + per_file_ctx_stats(0, dev_priv->kernel_context, &stats); + + list_for_each_entry(file, &dev_priv->dev->filelist, lhead) { + struct drm_i915_file_private *fpriv = file->driver_priv; + idr_for_each(&fpriv->context_idr, per_file_ctx_stats, &stats); + } + mutex_unlock(&dev_priv->dev->struct_mutex); + + print_file_stats(m, "[k]contexts", stats); +} + #define count_vmas(list, member) do { \ list_for_each_entry(vma, list, member) { \ size += i915_gem_obj_total_ggtt_size(vma->obj); \ @@ -521,10 +557,10 @@ static int i915_gem_object_info(struct seq_file *m, void* data) seq_putc(m, '\n'); print_batch_pool_stats(m, dev_priv); - mutex_unlock(&dev->struct_mutex); mutex_lock(&dev->filelist_mutex); + print_context_stats(m, dev_priv); list_for_each_entry_reverse(file, &dev->filelist, lhead) { struct file_stats stats; struct task_struct *task; -- cgit v0.10.2 From 5a21b6650a239ebc020912968a44047701104159 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 24 May 2016 17:13:53 +0200 Subject: drm/i915: Revert async unpin and nonblocking atomic commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts the following patches: d55dbd06bb5e1399aba9ab5227465339d1bbefff drm/i915: Allow nonblocking update of pageflips. 15c86bdb760185e871c7a0f559978328aa500971 drm/i915: Check for unpin correctness. 95c2ccdc82d520f59ae3b6fdc097b63c9b7082bb Reapply "drm/i915: Avoid stalling on pending flips for legacy cursor updates" a6747b7304a9d66758a196d885dab8bbfa5e7d1f drm/i915: Make unpin async. 03f476e1fcb42fca88fc50b94b0d3adbdbe887f0 drm/i915: Prepare connectors for nonblocking checks. 2099deffef4404f949ba1b68d2b17e0608190bc2 drm/i915: Pass atomic states to fbc update functions. ee7171af72c39c18b7d7571419a4ac6ca30aea66 drm/i915: Remove reset_counter from intel_crtc. 2ee004f7c59b2e642f0bb2834f847d756f2dd7b7 drm/i915: Remove queue_flip pointer. b8d2afae557dbb9b9c7bc6f6ec4f5278f3c4c34e drm/i915: Remove use_mmio_flip kernel parameter. 8dd634d922615ec3a9af7976029110ec037f8b50 drm/i915: Remove cs based page flip support. 143f73b3bf48c089b40f58462dd7f7c199fd4f0f drm/i915: Rework intel_crtc_page_flip to be almost atomic, v3. 84fc494b64e8c591be446a966b7447a9db519c88 drm/i915: Add the exclusive fence to plane_state. 6885843ae164e11f6c802209d06921e678a3f3f3 drm/i915: Convert flip_work to a list. aa420ddd8eeaa5df579894a412289e4d07c2fee9 drm/i915: Allow mmio updates on all platforms, v2. afee4d8707ab1f21b7668de995be3a5961e83582 Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates" "drm/i915: Allow nonblocking update of pageflips" should have been split up, misses a proper commit message and seems to cause issues in the legacy page_flip path as demonstrated by kms_flip. "drm/i915: Make unpin async" doesn't handle the unthrottled cursor updates correctly, leading to an apparent pin count leak. This is caught by the WARN_ON in i915_gem_object_do_pin which screams if we have more than DRM_I915_GEM_OBJECT_MAX_PIN_COUNT pins. Unfortuantely we can't just revert these two because this patch series came with a built-in bisect breakage in the form of temporarily removing the unthrottled cursor update hack for legacy cursor ioctl. Therefore there's no other option than to revert the entire pile :( There's one tiny conflict in intel_drv.h due to other patches, nothing serious. Normally I'd wait a bit longer with doing a maintainer revert, but since the minimal set of patches we need to revert (due to the bisect breakage) is so big, time is running out fast. And very soon (especially after a few attempts at fixing issues) it'll be really hard to revert things cleanly. Lessons learned: - Not a good idea to rush the review (done by someone fairly new to the area) and not make sure domain experts had a chance to read it. - Patches should be properly split up. I only looked at the two patches that should be reverted in detail, but both look like the mix up different things in one patch. - Patches really should have proper commit messages. Especially when doing more than one thing, and especially when touching critical and tricky core code. - Building a patch series and r-b stamping it when it has a built-in bisect breakage is not a good idea. - I also think we need to stop building up technical debt by postponing atomic igt testcases even longer. I think it's clear that there's enough corner cases in this beast that we really need to have the testcases _before_ the next step lands. Cc: Ville Syrjälä Cc: Maarten Lankhorst Cc: Patrik Jakobsson Cc: John Harrison Cc: Chris Wilson Acked-by: Maarten Lankhorst Acked-by: Ville Syrjälä Acked-by: Dave Airlie Acked-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index b29ba16..ac7e569 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -621,52 +621,6 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data) return 0; } -static void i915_dump_pageflip(struct seq_file *m, - struct drm_i915_private *dev_priv, - struct intel_crtc *crtc, - struct intel_flip_work *work) -{ - const char pipe = pipe_name(crtc->pipe); - u32 pending; - int i; - - pending = atomic_read(&work->pending); - if (pending) { - seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n", - pipe, plane_name(crtc->plane)); - } else { - seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n", - pipe, plane_name(crtc->plane)); - } - - for (i = 0; i < work->num_planes; i++) { - struct intel_plane_state *old_plane_state = work->old_plane_state[i]; - struct drm_plane *plane = old_plane_state->base.plane; - struct drm_i915_gem_request *req = old_plane_state->wait_req; - struct intel_engine_cs *engine; - - seq_printf(m, "[PLANE:%i] part of flip.\n", plane->base.id); - - if (!req) { - seq_printf(m, "Plane not associated with any engine\n"); - continue; - } - - engine = i915_gem_request_get_engine(req); - - seq_printf(m, "Plane blocked on %s at seqno %x, next seqno %x [current breadcrumb %x], completed? %d\n", - engine->name, - i915_gem_request_get_seqno(req), - dev_priv->next_seqno, - engine->get_seqno(engine), - i915_gem_request_completed(req, true)); - } - - seq_printf(m, "Flip queued on frame %d, now %d\n", - pending ? work->flip_queued_vblank : -1, - intel_crtc_get_vblank_counter(crtc)); -} - static int i915_gem_pageflip_info(struct seq_file *m, void *data) { struct drm_info_node *node = m->private; @@ -685,13 +639,48 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) struct intel_flip_work *work; spin_lock_irq(&dev->event_lock); - if (list_empty(&crtc->flip_work)) { + work = crtc->flip_work; + if (work == NULL) { seq_printf(m, "No flip due on pipe %c (plane %c)\n", pipe, plane); } else { - list_for_each_entry(work, &crtc->flip_work, head) { - i915_dump_pageflip(m, dev_priv, crtc, work); - seq_puts(m, "\n"); + u32 pending; + u32 addr; + + pending = atomic_read(&work->pending); + if (pending) { + seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n", + pipe, plane); + } else { + seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n", + pipe, plane); + } + if (work->flip_queued_req) { + struct intel_engine_cs *engine = i915_gem_request_get_engine(work->flip_queued_req); + + seq_printf(m, "Flip queued on %s at seqno %x, next seqno %x [current breadcrumb %x], completed? %d\n", + engine->name, + i915_gem_request_get_seqno(work->flip_queued_req), + dev_priv->next_seqno, + engine->get_seqno(engine), + i915_gem_request_completed(work->flip_queued_req, true)); + } else + seq_printf(m, "Flip not associated with any ring\n"); + seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n", + work->flip_queued_vblank, + work->flip_ready_vblank, + intel_crtc_get_vblank_counter(crtc)); + seq_printf(m, "%d prepares\n", atomic_read(&work->pending)); + + if (INTEL_INFO(dev)->gen >= 4) + addr = I915_HI_DISPBASE(I915_READ(DSPSURF(crtc->plane))); + else + addr = I915_READ(DSPADDR(crtc->plane)); + seq_printf(m, "Current scanout address 0x%08x\n", addr); + + if (work->pending_flip_obj) { + seq_printf(m, "New framebuffer address 0x%08lx\n", (long)work->gtt_offset); + seq_printf(m, "MMIO update completed? %d\n", addr == work->gtt_offset); } } spin_unlock_irq(&dev->event_lock); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 85a7c44..e4c8e34 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -618,6 +618,11 @@ struct drm_i915_display_funcs { void (*audio_codec_disable)(struct intel_encoder *encoder); void (*fdi_link_train)(struct drm_crtc *crtc); void (*init_clock_gating)(struct drm_device *dev); + int (*queue_flip)(struct drm_device *dev, struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, + struct drm_i915_gem_request *req, + uint32_t flags); void (*hpd_irq_setup)(struct drm_i915_private *dev_priv); /* clock updates for mode set */ /* cursor updates */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index fc2b2a7..caaf1e2 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -136,12 +136,6 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = { POSTING_READ(type##IIR); \ } while (0) -static void -intel_finish_page_flip_cs(struct drm_i915_private *dev_priv, unsigned pipe) -{ - DRM_DEBUG_KMS("Finished page flip\n"); -} - /* * We should clear IMR at preinstall/uninstall, and just check at postinstall. */ @@ -1637,11 +1631,16 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) } } -static void intel_pipe_handle_vblank(struct drm_i915_private *dev_priv, +static bool intel_pipe_handle_vblank(struct drm_i915_private *dev_priv, enum pipe pipe) { - if (drm_handle_vblank(dev_priv->dev, pipe)) + bool ret; + + ret = drm_handle_vblank(dev_priv->dev, pipe); + if (ret) intel_finish_page_flip_mmio(dev_priv, pipe); + + return ret; } static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv, @@ -1708,8 +1707,9 @@ static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv, enum pipe pipe; for_each_pipe(dev_priv, pipe) { - if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS) - intel_pipe_handle_vblank(dev_priv, pipe); + if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS && + intel_pipe_handle_vblank(dev_priv, pipe)) + intel_check_page_flip(dev_priv, pipe); if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) intel_finish_page_flip_cs(dev_priv, pipe); @@ -2155,8 +2155,9 @@ static void ilk_display_irq_handler(struct drm_i915_private *dev_priv, DRM_ERROR("Poison interrupt\n"); for_each_pipe(dev_priv, pipe) { - if (de_iir & DE_PIPE_VBLANK(pipe)) - intel_pipe_handle_vblank(dev_priv, pipe); + if (de_iir & DE_PIPE_VBLANK(pipe) && + intel_pipe_handle_vblank(dev_priv, pipe)) + intel_check_page_flip(dev_priv, pipe); if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe)) intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe); @@ -2205,8 +2206,9 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv, intel_opregion_asle_intr(dev_priv); for_each_pipe(dev_priv, pipe) { - if (de_iir & (DE_PIPE_VBLANK_IVB(pipe))) - intel_pipe_handle_vblank(dev_priv, pipe); + if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)) && + intel_pipe_handle_vblank(dev_priv, pipe)) + intel_check_page_flip(dev_priv, pipe); /* plane/pipes map 1:1 on ilk+ */ if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) @@ -2405,8 +2407,9 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) ret = IRQ_HANDLED; I915_WRITE(GEN8_DE_PIPE_IIR(pipe), iir); - if (iir & GEN8_PIPE_VBLANK) - intel_pipe_handle_vblank(dev_priv, pipe); + if (iir & GEN8_PIPE_VBLANK && + intel_pipe_handle_vblank(dev_priv, pipe)) + intel_check_page_flip(dev_priv, pipe); flip_done = iir; if (INTEL_INFO(dev_priv)->gen >= 9) @@ -3972,6 +3975,37 @@ static int i8xx_irq_postinstall(struct drm_device *dev) return 0; } +/* + * Returns true when a page flip has completed. + */ +static bool i8xx_handle_vblank(struct drm_i915_private *dev_priv, + int plane, int pipe, u32 iir) +{ + u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); + + if (!intel_pipe_handle_vblank(dev_priv, pipe)) + return false; + + if ((iir & flip_pending) == 0) + goto check_page_flip; + + /* We detect FlipDone by looking for the change in PendingFlip from '1' + * to '0' on the following vblank, i.e. IIR has the Pendingflip + * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence + * the flip is completed (no longer pending). Since this doesn't raise + * an interrupt per se, we watch for the change at vblank. + */ + if (I915_READ16(ISR) & flip_pending) + goto check_page_flip; + + intel_finish_page_flip_cs(dev_priv, pipe); + return true; + +check_page_flip: + intel_check_page_flip(dev_priv, pipe); + return false; +} + static irqreturn_t i8xx_irq_handler(int irq, void *arg) { struct drm_device *dev = arg; @@ -4024,8 +4058,13 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) notify_ring(&dev_priv->engine[RCS]); for_each_pipe(dev_priv, pipe) { - if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS) - intel_pipe_handle_vblank(dev_priv, pipe); + int plane = pipe; + if (HAS_FBC(dev_priv)) + plane = !plane; + + if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && + i8xx_handle_vblank(dev_priv, plane, pipe, iir)) + flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane); if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) i9xx_pipe_crc_irq_handler(dev_priv, pipe); @@ -4125,6 +4164,37 @@ static int i915_irq_postinstall(struct drm_device *dev) return 0; } +/* + * Returns true when a page flip has completed. + */ +static bool i915_handle_vblank(struct drm_i915_private *dev_priv, + int plane, int pipe, u32 iir) +{ + u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); + + if (!intel_pipe_handle_vblank(dev_priv, pipe)) + return false; + + if ((iir & flip_pending) == 0) + goto check_page_flip; + + /* We detect FlipDone by looking for the change in PendingFlip from '1' + * to '0' on the following vblank, i.e. IIR has the Pendingflip + * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence + * the flip is completed (no longer pending). Since this doesn't raise + * an interrupt per se, we watch for the change at vblank. + */ + if (I915_READ(ISR) & flip_pending) + goto check_page_flip; + + intel_finish_page_flip_cs(dev_priv, pipe); + return true; + +check_page_flip: + intel_check_page_flip(dev_priv, pipe); + return false; +} + static irqreturn_t i915_irq_handler(int irq, void *arg) { struct drm_device *dev = arg; @@ -4185,8 +4255,13 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) notify_ring(&dev_priv->engine[RCS]); for_each_pipe(dev_priv, pipe) { - if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS) - intel_pipe_handle_vblank(dev_priv, pipe); + int plane = pipe; + if (HAS_FBC(dev_priv)) + plane = !plane; + + if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && + i915_handle_vblank(dev_priv, plane, pipe, iir)) + flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane); if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) blc_event = true; @@ -4414,8 +4489,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) notify_ring(&dev_priv->engine[VCS]); for_each_pipe(dev_priv, pipe) { - if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS) - intel_pipe_handle_vblank(dev_priv, pipe); + if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS && + i915_handle_vblank(dev_priv, pipe, pipe, iir)) + flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe); if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) blc_event = true; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 9a5d58b..5e18cf9 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -49,6 +49,7 @@ struct i915_params i915 __read_mostly = { .invert_brightness = 0, .disable_display = 0, .enable_cmd_parser = 1, + .use_mmio_flip = 0, .mmio_debug = 0, .verbose_state_checks = 1, .nuclear_pageflip = 0, @@ -174,6 +175,10 @@ module_param_named_unsafe(enable_cmd_parser, i915.enable_cmd_parser, int, 0600); MODULE_PARM_DESC(enable_cmd_parser, "Enable command parsing (1=enabled [default], 0=disabled)"); +module_param_named_unsafe(use_mmio_flip, i915.use_mmio_flip, int, 0600); +MODULE_PARM_DESC(use_mmio_flip, + "use MMIO flips (-1=never, 0=driver discretion [default], 1=always)"); + module_param_named(mmio_debug, i915.mmio_debug, int, 0600); MODULE_PARM_DESC(mmio_debug, "Enable the MMIO debug code for the first N failures (default: off). " diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 658ce73..1323261 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -48,6 +48,7 @@ struct i915_params { int enable_guc_loading; int enable_guc_submission; int guc_log_level; + int use_mmio_flip; int mmio_debug; int edp_vswing; unsigned int inject_load_failure; diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index b4927f6..50ff90a 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -311,17 +311,6 @@ intel_atomic_state_alloc(struct drm_device *dev) void intel_atomic_state_clear(struct drm_atomic_state *s) { struct intel_atomic_state *state = to_intel_atomic_state(s); - int i; - - for (i = 0; i < ARRAY_SIZE(state->work); i++) { - struct intel_flip_work *work = state->work[i]; - - if (work) - intel_free_flip_work(work); - - state->work[i] = NULL; - } - drm_atomic_state_default_clear(&state->base); state->dpll_set = state->modeset = false; } diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 2ab45f1..7de7721 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -102,7 +102,6 @@ intel_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { WARN_ON(state && to_intel_plane_state(state)->wait_req); - WARN_ON(state && state->fence); drm_atomic_helper_plane_destroy_state(plane, state); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fd171fd..46429e7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -48,6 +48,11 @@ #include #include +static bool is_mmio_work(struct intel_flip_work *work) +{ + return work->mmio_work.func; +} + /* Primary plane formats for gen <= 3 */ static const uint32_t i8xx_primary_formats[] = { DRM_FORMAT_C8, @@ -108,6 +113,8 @@ static void vlv_prepare_pll(struct intel_crtc *crtc, const struct intel_crtc_state *pipe_config); static void chv_prepare_pll(struct intel_crtc *crtc, const struct intel_crtc_state *pipe_config); +static void intel_begin_crtc_commit(struct drm_crtc *, struct drm_crtc_state *); +static void intel_finish_crtc_commit(struct drm_crtc *, struct drm_crtc_state *); static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state); static void skylake_pfit_enable(struct intel_crtc *crtc); @@ -116,9 +123,6 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc); static void intel_modeset_setup_hw_state(struct drm_device *dev); static void intel_pre_disable_primary_noatomic(struct drm_crtc *crtc); static int ilk_max_pixel_rate(struct drm_atomic_state *state); -static void intel_modeset_verify_crtc(struct drm_crtc *crtc, - struct drm_crtc_state *old_state, - struct drm_crtc_state *new_state); static int broxton_calc_cdclk(int max_pixclk); struct intel_limit { @@ -2524,6 +2528,20 @@ out_unref_obj: return false; } +/* Update plane->state->fb to match plane->fb after driver-internal updates */ +static void +update_state_fb(struct drm_plane *plane) +{ + if (plane->fb == plane->state->fb) + return; + + if (plane->state->fb) + drm_framebuffer_unreference(plane->state->fb); + plane->state->fb = plane->fb; + if (plane->state->fb) + drm_framebuffer_reference(plane->state->fb); +} + static void intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, struct intel_initial_plane_config *plane_config) @@ -3096,6 +3114,14 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, return -ENODEV; } +static void intel_complete_page_flips(struct drm_i915_private *dev_priv) +{ + struct intel_crtc *crtc; + + for_each_intel_crtc(dev_priv->dev, crtc) + intel_finish_page_flip_cs(dev_priv, crtc->pipe); +} + static void intel_update_primary_planes(struct drm_device *dev) { struct drm_crtc *crtc; @@ -3136,6 +3162,13 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv) void intel_finish_reset(struct drm_i915_private *dev_priv) { + /* + * Flips in the rings will be nuked by the reset, + * so complete all pending flips so that user space + * will get its events and not get stuck. + */ + intel_complete_page_flips(dev_priv); + /* no reset support for gen2 */ if (IS_GEN2(dev_priv)) return; @@ -3178,7 +3211,20 @@ void intel_finish_reset(struct drm_i915_private *dev_priv) static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) { - return !list_empty_careful(&to_intel_crtc(crtc)->flip_work); + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + unsigned reset_counter; + bool pending; + + reset_counter = i915_reset_counter(&to_i915(dev)->gpu_error); + if (intel_crtc->reset_counter != reset_counter) + return false; + + spin_lock_irq(&dev->event_lock); + pending = to_intel_crtc(crtc)->flip_work != NULL; + spin_unlock_irq(&dev->event_lock); + + return pending; } static void intel_update_pipe_config(struct intel_crtc *crtc, @@ -3754,7 +3800,7 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev) if (atomic_read(&crtc->unpin_work_count) == 0) continue; - if (!list_empty_careful(&crtc->flip_work)) + if (crtc->flip_work) intel_wait_for_vblank(dev, crtc->pipe); return true; @@ -3763,30 +3809,23 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev) return false; } -static void page_flip_completed(struct intel_crtc *intel_crtc, struct intel_flip_work *work) +static void page_flip_completed(struct intel_crtc *intel_crtc) { struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); - struct drm_plane_state *new_plane_state; - struct drm_plane *primary = intel_crtc->base.primary; + struct intel_flip_work *work = intel_crtc->flip_work; + + intel_crtc->flip_work = NULL; if (work->event) drm_crtc_send_vblank_event(&intel_crtc->base, work->event); drm_crtc_vblank_put(&intel_crtc->base); - new_plane_state = &work->old_plane_state[0]->base; - if (work->num_planes >= 1 && - new_plane_state->plane == primary && - new_plane_state->fb) - trace_i915_flip_complete(intel_crtc->plane, - intel_fb_obj(new_plane_state->fb)); - - if (work->can_async_unpin) { - list_del_init(&work->head); - wake_up_all(&dev_priv->pending_flip_queue); - } - + wake_up_all(&dev_priv->pending_flip_queue); queue_work(dev_priv->wq, &work->unpin_work); + + trace_i915_flip_complete(intel_crtc->plane, + work->pending_flip_obj); } static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) @@ -3805,7 +3844,18 @@ static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) if (ret < 0) return ret; - WARN(ret == 0, "Stuck page flip\n"); + if (ret == 0) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_flip_work *work; + + spin_lock_irq(&dev->event_lock); + work = intel_crtc->flip_work; + if (work && !is_mmio_work(work)) { + WARN_ONCE(1, "Removing stuck page flip\n"); + page_flip_completed(intel_crtc); + } + spin_unlock_irq(&dev->event_lock); + } return 0; } @@ -4536,6 +4586,39 @@ intel_pre_disable_primary_noatomic(struct drm_crtc *crtc) } } +static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc); + struct drm_atomic_state *old_state = old_crtc_state->base.state; + struct intel_crtc_state *pipe_config = + to_intel_crtc_state(crtc->base.state); + struct drm_device *dev = crtc->base.dev; + struct drm_plane *primary = crtc->base.primary; + struct drm_plane_state *old_pri_state = + drm_atomic_get_existing_plane_state(old_state, primary); + + intel_frontbuffer_flip(dev, pipe_config->fb_bits); + + crtc->wm.cxsr_allowed = true; + + if (pipe_config->update_wm_post && pipe_config->base.active) + intel_update_watermarks(&crtc->base); + + if (old_pri_state) { + struct intel_plane_state *primary_state = + to_intel_plane_state(primary->state); + struct intel_plane_state *old_primary_state = + to_intel_plane_state(old_pri_state); + + intel_fbc_post_update(crtc); + + if (primary_state->visible && + (needs_modeset(&pipe_config->base) || + !old_primary_state->visible)) + intel_post_enable_primary(&crtc->base); + } +} + static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state) { struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc); @@ -4555,7 +4638,7 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state) struct intel_plane_state *old_primary_state = to_intel_plane_state(old_pri_state); - intel_fbc_pre_update(crtc, pipe_config, primary_state); + intel_fbc_pre_update(crtc); if (old_primary_state->visible && (modeset || !primary_state->visible)) @@ -5145,21 +5228,18 @@ modeset_get_crtc_power_domains(struct drm_crtc *crtc, struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum intel_display_power_domain domain; - unsigned long domains, new_domains, old_domains, ms_domain = 0; + unsigned long domains, new_domains, old_domains; old_domains = intel_crtc->enabled_power_domains; intel_crtc->enabled_power_domains = new_domains = get_crtc_power_domains(crtc, crtc_state); - if (needs_modeset(&crtc_state->base)) - ms_domain = BIT(POWER_DOMAIN_MODESET); - - domains = (new_domains & ~old_domains) | ms_domain; + domains = new_domains & ~old_domains; for_each_power_domain(domain, domains) intel_display_power_get(dev_priv, domain); - return (old_domains & ~new_domains) | ms_domain; + return old_domains & ~new_domains; } static void modeset_put_power_domains(struct drm_i915_private *dev_priv, @@ -6193,7 +6273,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) return; if (to_intel_plane_state(crtc->primary->state)->visible) { - WARN_ON(list_empty(&intel_crtc->flip_work)); + WARN_ON(intel_crtc->flip_work); intel_pre_disable_primary_noatomic(crtc); @@ -6245,12 +6325,6 @@ int intel_display_suspend(struct drm_device *dev) DRM_ERROR("Suspending crtc's failed with %i\n", ret); else dev_priv->modeset_restore_state = state; - - /* - * Make sure all unpin_work completes before returning. - */ - flush_workqueue(dev_priv->wq); - return ret; } @@ -6264,10 +6338,9 @@ void intel_encoder_destroy(struct drm_encoder *encoder) /* Cross check the actual hw state with our own modeset state tracking (and it's * internal consistency). */ -static void intel_connector_verify_state(struct intel_connector *connector, - struct drm_connector_state *conn_state) +static void intel_connector_verify_state(struct intel_connector *connector) { - struct drm_crtc *crtc = conn_state->crtc; + struct drm_crtc *crtc = connector->base.state->crtc; DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.base.id, @@ -6275,6 +6348,7 @@ static void intel_connector_verify_state(struct intel_connector *connector, if (connector->get_hw_state(connector)) { struct intel_encoder *encoder = connector->encoder; + struct drm_connector_state *conn_state = connector->base.state; I915_STATE_WARN(!crtc, "connector enabled without attached crtc\n"); @@ -6296,7 +6370,7 @@ static void intel_connector_verify_state(struct intel_connector *connector, } else { I915_STATE_WARN(crtc && crtc->state->active, "attached crtc is active, but connector isn't\n"); - I915_STATE_WARN(!crtc && conn_state->best_encoder, + I915_STATE_WARN(!crtc && connector->base.state->best_encoder, "best encoder set without crtc!\n"); } } @@ -10854,13 +10928,6 @@ void intel_mark_idle(struct drm_i915_private *dev_priv) intel_runtime_pm_put(dev_priv); } -void intel_free_flip_work(struct intel_flip_work *work) -{ - kfree(work->old_connector_state); - kfree(work->new_connector_state); - kfree(work); -} - static void intel_crtc_destroy(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -10868,162 +10935,117 @@ static void intel_crtc_destroy(struct drm_crtc *crtc) struct intel_flip_work *work; spin_lock_irq(&dev->event_lock); - while (!list_empty(&intel_crtc->flip_work)) { - work = list_first_entry(&intel_crtc->flip_work, - struct intel_flip_work, head); - list_del_init(&work->head); - spin_unlock_irq(&dev->event_lock); + work = intel_crtc->flip_work; + intel_crtc->flip_work = NULL; + spin_unlock_irq(&dev->event_lock); + if (work) { cancel_work_sync(&work->mmio_work); cancel_work_sync(&work->unpin_work); - intel_free_flip_work(work); - - spin_lock_irq(&dev->event_lock); + kfree(work); } - spin_unlock_irq(&dev->event_lock); drm_crtc_cleanup(crtc); kfree(intel_crtc); } -static void intel_crtc_post_flip_update(struct intel_flip_work *work, - struct drm_crtc *crtc) -{ - struct intel_crtc_state *crtc_state = work->new_crtc_state; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - if (crtc_state->disable_cxsr) - intel_crtc->wm.cxsr_allowed = true; - - if (crtc_state->update_wm_post && crtc_state->base.active) - intel_update_watermarks(crtc); - - if (work->num_planes > 0 && - work->old_plane_state[0]->base.plane == crtc->primary) { - struct intel_plane_state *plane_state = - work->new_plane_state[0]; - - if (plane_state->visible && - (needs_modeset(&crtc_state->base) || - !work->old_plane_state[0]->visible)) - intel_post_enable_primary(crtc); - } -} - static void intel_unpin_work_fn(struct work_struct *__work) { struct intel_flip_work *work = container_of(__work, struct intel_flip_work, unpin_work); - struct drm_crtc *crtc = work->old_crtc_state->base.crtc; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int i; - - if (work->fb_bits) - intel_frontbuffer_flip_complete(dev, work->fb_bits); - - /* - * Unless work->can_async_unpin is false, there's no way to ensure - * that work->new_crtc_state contains valid memory during unpin - * because intel_atomic_commit may free it before this runs. - */ - if (!work->can_async_unpin) { - intel_crtc_post_flip_update(work, crtc); - - if (dev_priv->display.optimize_watermarks) - dev_priv->display.optimize_watermarks(work->new_crtc_state); - } - - if (work->fb_bits & to_intel_plane(crtc->primary)->frontbuffer_bit) - intel_fbc_post_update(intel_crtc); - - if (work->put_power_domains) - modeset_put_power_domains(dev_priv, work->put_power_domains); - - /* Make sure mmio work is completely finished before freeing all state here. */ - flush_work(&work->mmio_work); - - if (!work->can_async_unpin && - (work->new_crtc_state->update_pipe || - needs_modeset(&work->new_crtc_state->base))) { - /* This must be called before work is unpinned for serialization. */ - intel_modeset_verify_crtc(crtc, &work->old_crtc_state->base, - &work->new_crtc_state->base); - - for (i = 0; i < work->num_new_connectors; i++) { - struct drm_connector_state *conn_state = - work->new_connector_state[i]; - struct drm_connector *con = conn_state->connector; - - WARN_ON(!con); - - intel_connector_verify_state(to_intel_connector(con), - conn_state); - } - } - - for (i = 0; i < work->num_old_connectors; i++) { - struct drm_connector_state *old_con_state = - work->old_connector_state[i]; - struct drm_connector *con = - old_con_state->connector; + struct intel_crtc *crtc = to_intel_crtc(work->crtc); + struct drm_device *dev = crtc->base.dev; + struct drm_plane *primary = crtc->base.primary; - con->funcs->atomic_destroy_state(con, old_con_state); - } + if (is_mmio_work(work)) + flush_work(&work->mmio_work); - if (!work->can_async_unpin || !list_empty(&work->head)) { - spin_lock_irq(&dev->event_lock); - WARN(list_empty(&work->head) != work->can_async_unpin, - "[CRTC:%i] Pin work %p async %i with %i planes, active %i -> %i ms %i\n", - crtc->base.id, work, work->can_async_unpin, work->num_planes, - work->old_crtc_state->base.active, work->new_crtc_state->base.active, - needs_modeset(&work->new_crtc_state->base)); + mutex_lock(&dev->struct_mutex); + intel_unpin_fb_obj(work->old_fb, primary->state->rotation); + drm_gem_object_unreference(&work->pending_flip_obj->base); - if (!list_empty(&work->head)) - list_del(&work->head); + if (work->flip_queued_req) + i915_gem_request_assign(&work->flip_queued_req, NULL); + mutex_unlock(&dev->struct_mutex); - wake_up_all(&dev_priv->pending_flip_queue); - spin_unlock_irq(&dev->event_lock); - } + intel_frontbuffer_flip_complete(dev, to_intel_plane(primary)->frontbuffer_bit); + intel_fbc_post_update(crtc); + drm_framebuffer_unreference(work->old_fb); - /* New crtc_state freed? */ - if (work->free_new_crtc_state) - intel_crtc_destroy_state(crtc, &work->new_crtc_state->base); + BUG_ON(atomic_read(&crtc->unpin_work_count) == 0); + atomic_dec(&crtc->unpin_work_count); - intel_crtc_destroy_state(crtc, &work->old_crtc_state->base); + kfree(work); +} - for (i = 0; i < work->num_planes; i++) { - struct intel_plane_state *old_plane_state = - work->old_plane_state[i]; - struct drm_framebuffer *old_fb = old_plane_state->base.fb; - struct drm_plane *plane = old_plane_state->base.plane; - struct drm_i915_gem_request *req; +/* Is 'a' after or equal to 'b'? */ +static bool g4x_flip_count_after_eq(u32 a, u32 b) +{ + return !((a - b) & 0x80000000); +} - req = old_plane_state->wait_req; - old_plane_state->wait_req = NULL; - if (req) - i915_gem_request_unreference(req); +static bool __pageflip_finished_cs(struct intel_crtc *crtc, + struct intel_flip_work *work) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned reset_counter; - fence_put(old_plane_state->base.fence); - old_plane_state->base.fence = NULL; + reset_counter = i915_reset_counter(&dev_priv->gpu_error); + if (crtc->reset_counter != reset_counter) + return true; - if (old_fb && - (plane->type != DRM_PLANE_TYPE_CURSOR || - !INTEL_INFO(dev_priv)->cursor_needs_physical)) { - mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(old_fb, old_plane_state->base.rotation); - mutex_unlock(&dev->struct_mutex); - } + /* + * The relevant registers doen't exist on pre-ctg. + * As the flip done interrupt doesn't trigger for mmio + * flips on gmch platforms, a flip count check isn't + * really needed there. But since ctg has the registers, + * include it in the check anyway. + */ + if (INTEL_INFO(dev)->gen < 5 && !IS_G4X(dev)) + return true; - intel_plane_destroy_state(plane, &old_plane_state->base); - } + /* + * BDW signals flip done immediately if the plane + * is disabled, even if the plane enable is already + * armed to occur at the next vblank :( + */ - if (!WARN_ON(atomic_read(&intel_crtc->unpin_work_count) == 0)) - atomic_dec(&intel_crtc->unpin_work_count); + /* + * A DSPSURFLIVE check isn't enough in case the mmio and CS flips + * used the same base address. In that case the mmio flip might + * have completed, but the CS hasn't even executed the flip yet. + * + * A flip count check isn't enough as the CS might have updated + * the base address just after start of vblank, but before we + * managed to process the interrupt. This means we'd complete the + * CS flip too soon. + * + * Combining both checks should get us a good enough result. It may + * still happen that the CS flip has been executed, but has not + * yet actually completed. But in case the base address is the same + * anyway, we don't really care. + */ + return (I915_READ(DSPSURFLIVE(crtc->plane)) & ~0xfff) == + crtc->flip_work->gtt_offset && + g4x_flip_count_after_eq(I915_READ(PIPE_FLIPCOUNT_G4X(crtc->pipe)), + crtc->flip_work->flip_count); +} - intel_free_flip_work(work); +static bool +__pageflip_finished_mmio(struct intel_crtc *crtc, + struct intel_flip_work *work) +{ + /* + * MMIO work completes when vblank is different from + * flip_queued_vblank. + * + * Reset counter value doesn't matter, this is handled by + * i915_wait_request finishing early, so no need to handle + * reset here. + */ + return intel_crtc_get_vblank_counter(crtc) != work->flip_queued_vblank; } @@ -11035,11 +11057,37 @@ static bool pageflip_finished(struct intel_crtc *crtc, smp_rmb(); + if (is_mmio_work(work)) + return __pageflip_finished_mmio(crtc, work); + else + return __pageflip_finished_cs(crtc, work); +} + +void intel_finish_page_flip_cs(struct drm_i915_private *dev_priv, int pipe) +{ + struct drm_device *dev = dev_priv->dev; + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_flip_work *work; + unsigned long flags; + + /* Ignore early vblank irqs */ + if (!crtc) + return; + /* - * MMIO work completes when vblank is different from - * flip_queued_vblank. + * This is called both by irq handlers and the reset code (to complete + * lost pageflips) so needs the full irqsave spinlocks. */ - return intel_crtc_get_vblank_counter(crtc) != work->flip_queued_vblank; + spin_lock_irqsave(&dev->event_lock, flags); + work = intel_crtc->flip_work; + + if (work != NULL && + !is_mmio_work(work) && + pageflip_finished(intel_crtc, work)) + page_flip_completed(intel_crtc); + + spin_unlock_irqrestore(&dev->event_lock, flags); } void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe) @@ -11059,130 +11107,756 @@ void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe) * lost pageflips) so needs the full irqsave spinlocks. */ spin_lock_irqsave(&dev->event_lock, flags); - while (!list_empty(&intel_crtc->flip_work)) { - work = list_first_entry(&intel_crtc->flip_work, - struct intel_flip_work, - head); + work = intel_crtc->flip_work; - if (!pageflip_finished(intel_crtc, work) || - work_busy(&work->unpin_work)) - break; + if (work != NULL && + is_mmio_work(work) && + pageflip_finished(intel_crtc, work)) + page_flip_completed(intel_crtc); - page_flip_completed(intel_crtc, work); - } spin_unlock_irqrestore(&dev->event_lock, flags); } -static void intel_mmio_flip_work_func(struct work_struct *w) +static inline void intel_mark_page_flip_active(struct intel_crtc *crtc, + struct intel_flip_work *work) { - struct intel_flip_work *work = - container_of(w, struct intel_flip_work, mmio_work); - struct drm_crtc *crtc = work->old_crtc_state->base.crtc; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_crtc_state *crtc_state = work->new_crtc_state; - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_request *req; - int i, ret; + work->flip_queued_vblank = intel_crtc_get_vblank_counter(crtc); - if (!needs_modeset(&crtc_state->base) && crtc_state->update_pipe) { - work->put_power_domains = - modeset_get_crtc_power_domains(crtc, crtc_state); - } + /* Ensure that the work item is consistent when activating it ... */ + smp_mb__before_atomic(); + atomic_set(&work->pending, 1); +} - for (i = 0; i < work->num_planes; i++) { - struct intel_plane_state *old_plane_state = work->old_plane_state[i]; +static int intel_gen2_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, + struct drm_i915_gem_request *req, + uint32_t flags) +{ + struct intel_engine_cs *engine = req->engine; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + u32 flip_mask; + int ret; - /* For framebuffer backed by dmabuf, wait for fence */ - if (old_plane_state->base.fence) - WARN_ON(fence_wait(old_plane_state->base.fence, false) < 0); + ret = intel_ring_begin(req, 6); + if (ret) + return ret; - req = old_plane_state->wait_req; - if (!req) - continue; + /* Can't queue multiple flips, so wait for the previous + * one to finish before executing the next. + */ + if (intel_crtc->plane) + flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; + else + flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; + intel_ring_emit(engine, MI_WAIT_FOR_EVENT | flip_mask); + intel_ring_emit(engine, MI_NOOP); + intel_ring_emit(engine, MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + intel_ring_emit(engine, fb->pitches[0]); + intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset); + intel_ring_emit(engine, 0); /* aux display base address, unused */ - WARN_ON(__i915_wait_request(req, false, NULL, - &dev_priv->rps.mmioflips)); - } + return 0; +} - ret = drm_crtc_vblank_get(crtc); - I915_STATE_WARN(ret < 0, "enabling vblank failed with %i\n", ret); +static int intel_gen3_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, + struct drm_i915_gem_request *req, + uint32_t flags) +{ + struct intel_engine_cs *engine = req->engine; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + u32 flip_mask; + int ret; - if (work->num_planes && - work->old_plane_state[0]->base.plane == crtc->primary) - intel_fbc_enable(intel_crtc, work->new_crtc_state, work->new_plane_state[0]); + ret = intel_ring_begin(req, 6); + if (ret) + return ret; - intel_frontbuffer_flip_prepare(dev, work->fb_bits); + if (intel_crtc->plane) + flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; + else + flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; + intel_ring_emit(engine, MI_WAIT_FOR_EVENT | flip_mask); + intel_ring_emit(engine, MI_NOOP); + intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + intel_ring_emit(engine, fb->pitches[0]); + intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset); + intel_ring_emit(engine, MI_NOOP); - intel_pipe_update_start(intel_crtc); - if (!needs_modeset(&crtc_state->base)) { - if (crtc_state->base.color_mgmt_changed || crtc_state->update_pipe) { - intel_color_set_csc(&crtc_state->base); - intel_color_load_luts(&crtc_state->base); - } + return 0; +} - if (crtc_state->update_pipe) - intel_update_pipe_config(intel_crtc, work->old_crtc_state); - else if (INTEL_INFO(dev)->gen >= 9) - skl_detach_scalers(intel_crtc); - } +static int intel_gen4_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, + struct drm_i915_gem_request *req, + uint32_t flags) +{ + struct intel_engine_cs *engine = req->engine; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + uint32_t pf, pipesrc; + int ret; - for (i = 0; i < work->num_planes; i++) { - struct intel_plane_state *new_plane_state = work->new_plane_state[i]; - struct intel_plane *plane = to_intel_plane(new_plane_state->base.plane); + ret = intel_ring_begin(req, 4); + if (ret) + return ret; - if (new_plane_state->visible) - plane->update_plane(&plane->base, crtc_state, new_plane_state); - else - plane->disable_plane(&plane->base, crtc); - } + /* i965+ uses the linear or tiled offsets from the + * Display Registers (which do not change across a page-flip) + * so we need only reprogram the base address. + */ + intel_ring_emit(engine, MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + intel_ring_emit(engine, fb->pitches[0]); + intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset | + obj->tiling_mode); + + /* XXX Enabling the panel-fitter across page-flip is so far + * untested on non-native modes, so ignore it for now. + * pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE; + */ + pf = 0; + pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; + intel_ring_emit(engine, pf | pipesrc); - intel_pipe_update_end(intel_crtc, work); + return 0; } -/** - * intel_wm_need_update - Check whether watermarks need updating - * @plane: drm plane - * @state: new plane state - * - * Check current plane state versus the new one to determine whether - * watermarks need to be recalculated. - * - * Returns true or false. - */ -static bool intel_wm_need_update(struct drm_plane *plane, - struct drm_plane_state *state) +static int intel_gen6_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, + struct drm_i915_gem_request *req, + uint32_t flags) { - struct intel_plane_state *new = to_intel_plane_state(state); - struct intel_plane_state *cur = to_intel_plane_state(plane->state); + struct intel_engine_cs *engine = req->engine; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + uint32_t pf, pipesrc; + int ret; - /* Update watermarks on tiling or size changes. */ - if (new->visible != cur->visible) - return true; + ret = intel_ring_begin(req, 4); + if (ret) + return ret; - if (!cur->base.fb || !new->base.fb) - return false; + intel_ring_emit(engine, MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + intel_ring_emit(engine, fb->pitches[0] | obj->tiling_mode); + intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset); - if (cur->base.fb->modifier[0] != new->base.fb->modifier[0] || - cur->base.rotation != new->base.rotation || - drm_rect_width(&new->src) != drm_rect_width(&cur->src) || - drm_rect_height(&new->src) != drm_rect_height(&cur->src) || - drm_rect_width(&new->dst) != drm_rect_width(&cur->dst) || - drm_rect_height(&new->dst) != drm_rect_height(&cur->dst)) - return true; + /* Contrary to the suggestions in the documentation, + * "Enable Panel Fitter" does not seem to be required when page + * flipping with a non-native mode, and worse causes a normal + * modeset to fail. + * pf = I915_READ(PF_CTL(intel_crtc->pipe)) & PF_ENABLE; + */ + pf = 0; + pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; + intel_ring_emit(engine, pf | pipesrc); - return false; + return 0; } -static bool needs_scaling(struct intel_plane_state *state) +static int intel_gen7_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, + struct drm_i915_gem_request *req, + uint32_t flags) { - int src_w = drm_rect_width(&state->src) >> 16; - int src_h = drm_rect_height(&state->src) >> 16; - int dst_w = drm_rect_width(&state->dst); - int dst_h = drm_rect_height(&state->dst); + struct intel_engine_cs *engine = req->engine; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + uint32_t plane_bit = 0; + int len, ret; - return (src_w != dst_w || src_h != dst_h); -} + switch (intel_crtc->plane) { + case PLANE_A: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_A; + break; + case PLANE_B: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_B; + break; + case PLANE_C: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_C; + break; + default: + WARN_ONCE(1, "unknown plane in flip command\n"); + return -ENODEV; + } + + len = 4; + if (engine->id == RCS) { + len += 6; + /* + * On Gen 8, SRM is now taking an extra dword to accommodate + * 48bits addresses, and we need a NOOP for the batch size to + * stay even. + */ + if (IS_GEN8(dev)) + len += 2; + } + + /* + * BSpec MI_DISPLAY_FLIP for IVB: + * "The full packet must be contained within the same cache line." + * + * Currently the LRI+SRM+MI_DISPLAY_FLIP all fit within the same + * cacheline, if we ever start emitting more commands before + * the MI_DISPLAY_FLIP we may need to first emit everything else, + * then do the cacheline alignment, and finally emit the + * MI_DISPLAY_FLIP. + */ + ret = intel_ring_cacheline_align(req); + if (ret) + return ret; + + ret = intel_ring_begin(req, len); + if (ret) + return ret; + + /* Unmask the flip-done completion message. Note that the bspec says that + * we should do this for both the BCS and RCS, and that we must not unmask + * more than one flip event at any time (or ensure that one flip message + * can be sent by waiting for flip-done prior to queueing new flips). + * Experimentation says that BCS works despite DERRMR masking all + * flip-done completion events and that unmasking all planes at once + * for the RCS also doesn't appear to drop events. Setting the DERRMR + * to zero does lead to lockups within MI_DISPLAY_FLIP. + */ + if (engine->id == RCS) { + intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(1)); + intel_ring_emit_reg(engine, DERRMR); + intel_ring_emit(engine, ~(DERRMR_PIPEA_PRI_FLIP_DONE | + DERRMR_PIPEB_PRI_FLIP_DONE | + DERRMR_PIPEC_PRI_FLIP_DONE)); + if (IS_GEN8(dev)) + intel_ring_emit(engine, MI_STORE_REGISTER_MEM_GEN8 | + MI_SRM_LRM_GLOBAL_GTT); + else + intel_ring_emit(engine, MI_STORE_REGISTER_MEM | + MI_SRM_LRM_GLOBAL_GTT); + intel_ring_emit_reg(engine, DERRMR); + intel_ring_emit(engine, engine->scratch.gtt_offset + 256); + if (IS_GEN8(dev)) { + intel_ring_emit(engine, 0); + intel_ring_emit(engine, MI_NOOP); + } + } + + intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 | plane_bit); + intel_ring_emit(engine, (fb->pitches[0] | obj->tiling_mode)); + intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset); + intel_ring_emit(engine, (MI_NOOP)); + + return 0; +} + +static bool use_mmio_flip(struct intel_engine_cs *engine, + struct drm_i915_gem_object *obj) +{ + /* + * This is not being used for older platforms, because + * non-availability of flip done interrupt forces us to use + * CS flips. Older platforms derive flip done using some clever + * tricks involving the flip_pending status bits and vblank irqs. + * So using MMIO flips there would disrupt this mechanism. + */ + + if (engine == NULL) + return true; + + if (INTEL_GEN(engine->i915) < 5) + return false; + + if (i915.use_mmio_flip < 0) + return false; + else if (i915.use_mmio_flip > 0) + return true; + else if (i915.enable_execlists) + return true; + else if (obj->base.dma_buf && + !reservation_object_test_signaled_rcu(obj->base.dma_buf->resv, + false)) + return true; + else + return engine != i915_gem_request_get_engine(obj->last_write_req); +} + +static void skl_do_mmio_flip(struct intel_crtc *intel_crtc, + unsigned int rotation, + struct intel_flip_work *work) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb = intel_crtc->base.primary->fb; + const enum pipe pipe = intel_crtc->pipe; + u32 ctl, stride, tile_height; + + ctl = I915_READ(PLANE_CTL(pipe, 0)); + ctl &= ~PLANE_CTL_TILED_MASK; + switch (fb->modifier[0]) { + case DRM_FORMAT_MOD_NONE: + break; + case I915_FORMAT_MOD_X_TILED: + ctl |= PLANE_CTL_TILED_X; + break; + case I915_FORMAT_MOD_Y_TILED: + ctl |= PLANE_CTL_TILED_Y; + break; + case I915_FORMAT_MOD_Yf_TILED: + ctl |= PLANE_CTL_TILED_YF; + break; + default: + MISSING_CASE(fb->modifier[0]); + } + + /* + * The stride is either expressed as a multiple of 64 bytes chunks for + * linear buffers or in number of tiles for tiled buffers. + */ + if (intel_rotation_90_or_270(rotation)) { + /* stride = Surface height in tiles */ + tile_height = intel_tile_height(dev_priv, fb->modifier[0], 0); + stride = DIV_ROUND_UP(fb->height, tile_height); + } else { + stride = fb->pitches[0] / + intel_fb_stride_alignment(dev_priv, fb->modifier[0], + fb->pixel_format); + } + + /* + * Both PLANE_CTL and PLANE_STRIDE are not updated on vblank but on + * PLANE_SURF updates, the update is then guaranteed to be atomic. + */ + I915_WRITE(PLANE_CTL(pipe, 0), ctl); + I915_WRITE(PLANE_STRIDE(pipe, 0), stride); + + I915_WRITE(PLANE_SURF(pipe, 0), work->gtt_offset); + POSTING_READ(PLANE_SURF(pipe, 0)); +} + +static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc, + struct intel_flip_work *work) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_framebuffer *intel_fb = + to_intel_framebuffer(intel_crtc->base.primary->fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + i915_reg_t reg = DSPCNTR(intel_crtc->plane); + u32 dspcntr; + + dspcntr = I915_READ(reg); + + if (obj->tiling_mode != I915_TILING_NONE) + dspcntr |= DISPPLANE_TILED; + else + dspcntr &= ~DISPPLANE_TILED; + + I915_WRITE(reg, dspcntr); + + I915_WRITE(DSPSURF(intel_crtc->plane), work->gtt_offset); + POSTING_READ(DSPSURF(intel_crtc->plane)); +} + +static void intel_mmio_flip_work_func(struct work_struct *w) +{ + struct intel_flip_work *work = + container_of(w, struct intel_flip_work, mmio_work); + struct intel_crtc *crtc = to_intel_crtc(work->crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct intel_framebuffer *intel_fb = + to_intel_framebuffer(crtc->base.primary->fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + + if (work->flip_queued_req) + WARN_ON(__i915_wait_request(work->flip_queued_req, + false, NULL, + &dev_priv->rps.mmioflips)); + + /* For framebuffer backed by dmabuf, wait for fence */ + if (obj->base.dma_buf) + WARN_ON(reservation_object_wait_timeout_rcu(obj->base.dma_buf->resv, + false, false, + MAX_SCHEDULE_TIMEOUT) < 0); + + intel_pipe_update_start(crtc); + + if (INTEL_GEN(dev_priv) >= 9) + skl_do_mmio_flip(crtc, work->rotation, work); + else + /* use_mmio_flip() retricts MMIO flips to ilk+ */ + ilk_do_mmio_flip(crtc, work); + + intel_pipe_update_end(crtc, work); +} + +static int intel_default_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, + struct drm_i915_gem_request *req, + uint32_t flags) +{ + return -ENODEV; +} + +static bool __pageflip_stall_check_cs(struct drm_i915_private *dev_priv, + struct intel_crtc *intel_crtc, + struct intel_flip_work *work) +{ + u32 addr, vblank; + + if (!atomic_read(&work->pending)) + return false; + + smp_rmb(); + + vblank = intel_crtc_get_vblank_counter(intel_crtc); + if (work->flip_ready_vblank == 0) { + if (work->flip_queued_req && + !i915_gem_request_completed(work->flip_queued_req, true)) + return false; + + work->flip_ready_vblank = vblank; + } + + if (vblank - work->flip_ready_vblank < 3) + return false; + + /* Potential stall - if we see that the flip has happened, + * assume a missed interrupt. */ + if (INTEL_GEN(dev_priv) >= 4) + addr = I915_HI_DISPBASE(I915_READ(DSPSURF(intel_crtc->plane))); + else + addr = I915_READ(DSPADDR(intel_crtc->plane)); + + /* There is a potential issue here with a false positive after a flip + * to the same address. We could address this by checking for a + * non-incrementing frame counter. + */ + return addr == work->gtt_offset; +} + +void intel_check_page_flip(struct drm_i915_private *dev_priv, int pipe) +{ + struct drm_device *dev = dev_priv->dev; + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_flip_work *work; + + WARN_ON(!in_interrupt()); + + if (crtc == NULL) + return; + + spin_lock(&dev->event_lock); + work = intel_crtc->flip_work; + + if (work != NULL && !is_mmio_work(work) && + __pageflip_stall_check_cs(dev_priv, intel_crtc, work)) { + WARN_ONCE(1, + "Kicking stuck page flip: queued at %d, now %d\n", + work->flip_queued_vblank, intel_crtc_get_vblank_counter(intel_crtc)); + page_flip_completed(intel_crtc); + work = NULL; + } + + if (work != NULL && !is_mmio_work(work) && + intel_crtc_get_vblank_counter(intel_crtc) - work->flip_queued_vblank > 1) + intel_queue_rps_boost_for_request(work->flip_queued_req); + spin_unlock(&dev->event_lock); +} + +static int intel_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t page_flip_flags) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *old_fb = crtc->primary->fb; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_plane *primary = crtc->primary; + enum pipe pipe = intel_crtc->pipe; + struct intel_flip_work *work; + struct intel_engine_cs *engine; + bool mmio_flip; + struct drm_i915_gem_request *request = NULL; + int ret; + + /* + * drm_mode_page_flip_ioctl() should already catch this, but double + * check to be safe. In the future we may enable pageflipping from + * a disabled primary plane. + */ + if (WARN_ON(intel_fb_obj(old_fb) == NULL)) + return -EBUSY; + + /* Can't change pixel format via MI display flips. */ + if (fb->pixel_format != crtc->primary->fb->pixel_format) + return -EINVAL; + + /* + * TILEOFF/LINOFF registers can't be changed via MI display flips. + * Note that pitch changes could also affect these register. + */ + if (INTEL_INFO(dev)->gen > 3 && + (fb->offsets[0] != crtc->primary->fb->offsets[0] || + fb->pitches[0] != crtc->primary->fb->pitches[0])) + return -EINVAL; + + if (i915_terminally_wedged(&dev_priv->gpu_error)) + goto out_hang; + + work = kzalloc(sizeof(*work), GFP_KERNEL); + if (work == NULL) + return -ENOMEM; + + work->event = event; + work->crtc = crtc; + work->old_fb = old_fb; + INIT_WORK(&work->unpin_work, intel_unpin_work_fn); + + ret = drm_crtc_vblank_get(crtc); + if (ret) + goto free_work; + + /* We borrow the event spin lock for protecting flip_work */ + spin_lock_irq(&dev->event_lock); + if (intel_crtc->flip_work) { + /* Before declaring the flip queue wedged, check if + * the hardware completed the operation behind our backs. + */ + if (pageflip_finished(intel_crtc, intel_crtc->flip_work)) { + DRM_DEBUG_DRIVER("flip queue: previous flip completed, continuing\n"); + page_flip_completed(intel_crtc); + } else { + DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); + spin_unlock_irq(&dev->event_lock); + + drm_crtc_vblank_put(crtc); + kfree(work); + return -EBUSY; + } + } + intel_crtc->flip_work = work; + spin_unlock_irq(&dev->event_lock); + + if (atomic_read(&intel_crtc->unpin_work_count) >= 2) + flush_workqueue(dev_priv->wq); + + /* Reference the objects for the scheduled work. */ + drm_framebuffer_reference(work->old_fb); + drm_gem_object_reference(&obj->base); + + crtc->primary->fb = fb; + update_state_fb(crtc->primary); + intel_fbc_pre_update(intel_crtc); + + work->pending_flip_obj = obj; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto cleanup; + + intel_crtc->reset_counter = i915_reset_counter(&dev_priv->gpu_error); + if (__i915_reset_in_progress_or_wedged(intel_crtc->reset_counter)) { + ret = -EIO; + goto cleanup; + } + + atomic_inc(&intel_crtc->unpin_work_count); + + if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev)) + work->flip_count = I915_READ(PIPE_FLIPCOUNT_G4X(pipe)) + 1; + + if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) { + engine = &dev_priv->engine[BCS]; + if (obj->tiling_mode != intel_fb_obj(work->old_fb)->tiling_mode) + /* vlv: DISPLAY_FLIP fails to change tiling */ + engine = NULL; + } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { + engine = &dev_priv->engine[BCS]; + } else if (INTEL_INFO(dev)->gen >= 7) { + engine = i915_gem_request_get_engine(obj->last_write_req); + if (engine == NULL || engine->id != RCS) + engine = &dev_priv->engine[BCS]; + } else { + engine = &dev_priv->engine[RCS]; + } + + mmio_flip = use_mmio_flip(engine, obj); + + /* When using CS flips, we want to emit semaphores between rings. + * However, when using mmio flips we will create a task to do the + * synchronisation, so all we want here is to pin the framebuffer + * into the display plane and skip any waits. + */ + if (!mmio_flip) { + ret = i915_gem_object_sync(obj, engine, &request); + if (!ret && !request) { + request = i915_gem_request_alloc(engine, NULL); + ret = PTR_ERR_OR_ZERO(request); + } + + if (ret) + goto cleanup_pending; + } + + ret = intel_pin_and_fence_fb_obj(fb, primary->state->rotation); + if (ret) + goto cleanup_pending; + + work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary), + obj, 0); + work->gtt_offset += intel_crtc->dspaddr_offset; + work->rotation = crtc->primary->state->rotation; + + if (mmio_flip) { + INIT_WORK(&work->mmio_work, intel_mmio_flip_work_func); + + i915_gem_request_assign(&work->flip_queued_req, + obj->last_write_req); + + schedule_work(&work->mmio_work); + } else { + i915_gem_request_assign(&work->flip_queued_req, request); + ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request, + page_flip_flags); + if (ret) + goto cleanup_unpin; + + intel_mark_page_flip_active(intel_crtc, work); + + i915_add_request_no_flush(request); + } + + i915_gem_track_fb(intel_fb_obj(old_fb), obj, + to_intel_plane(primary)->frontbuffer_bit); + mutex_unlock(&dev->struct_mutex); + + intel_frontbuffer_flip_prepare(dev, + to_intel_plane(primary)->frontbuffer_bit); + + trace_i915_flip_request(intel_crtc->plane, obj); + + return 0; + +cleanup_unpin: + intel_unpin_fb_obj(fb, crtc->primary->state->rotation); +cleanup_pending: + if (!IS_ERR_OR_NULL(request)) + i915_add_request_no_flush(request); + atomic_dec(&intel_crtc->unpin_work_count); + mutex_unlock(&dev->struct_mutex); +cleanup: + crtc->primary->fb = old_fb; + update_state_fb(crtc->primary); + + drm_gem_object_unreference_unlocked(&obj->base); + drm_framebuffer_unreference(work->old_fb); + + spin_lock_irq(&dev->event_lock); + intel_crtc->flip_work = NULL; + spin_unlock_irq(&dev->event_lock); + + drm_crtc_vblank_put(crtc); +free_work: + kfree(work); + + if (ret == -EIO) { + struct drm_atomic_state *state; + struct drm_plane_state *plane_state; + +out_hang: + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + +retry: + plane_state = drm_atomic_get_plane_state(state, primary); + ret = PTR_ERR_OR_ZERO(plane_state); + if (!ret) { + drm_atomic_set_fb_for_plane(plane_state, fb); + + ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); + if (!ret) + ret = drm_atomic_commit(state); + } + + if (ret == -EDEADLK) { + drm_modeset_backoff(state->acquire_ctx); + drm_atomic_state_clear(state); + goto retry; + } + + if (ret) + drm_atomic_state_free(state); + + if (ret == 0 && event) { + spin_lock_irq(&dev->event_lock); + drm_crtc_send_vblank_event(crtc, event); + spin_unlock_irq(&dev->event_lock); + } + } + return ret; +} + + +/** + * intel_wm_need_update - Check whether watermarks need updating + * @plane: drm plane + * @state: new plane state + * + * Check current plane state versus the new one to determine whether + * watermarks need to be recalculated. + * + * Returns true or false. + */ +static bool intel_wm_need_update(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct intel_plane_state *new = to_intel_plane_state(state); + struct intel_plane_state *cur = to_intel_plane_state(plane->state); + + /* Update watermarks on tiling or size changes. */ + if (new->visible != cur->visible) + return true; + + if (!cur->base.fb || !new->base.fb) + return false; + + if (cur->base.fb->modifier[0] != new->base.fb->modifier[0] || + cur->base.rotation != new->base.rotation || + drm_rect_width(&new->src) != drm_rect_width(&cur->src) || + drm_rect_height(&new->src) != drm_rect_height(&cur->src) || + drm_rect_width(&new->dst) != drm_rect_width(&cur->dst) || + drm_rect_height(&new->dst) != drm_rect_height(&cur->dst)) + return true; + + return false; +} + +static bool needs_scaling(struct intel_plane_state *state) +{ + int src_w = drm_rect_width(&state->src) >> 16; + int src_h = drm_rect_height(&state->src) >> 16; + int dst_w = drm_rect_width(&state->dst); + int dst_h = drm_rect_height(&state->dst); + + return (src_w != dst_w || src_h != dst_h); +} int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, struct drm_plane_state *plane_state) @@ -11416,6 +12090,8 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, static const struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_set_base_atomic = intel_pipe_set_base_atomic, + .atomic_begin = intel_begin_crtc_commit, + .atomic_flush = intel_finish_crtc_commit, .atomic_check = intel_crtc_atomic_check, }; @@ -12255,8 +12931,7 @@ verify_connector_state(struct drm_device *dev, struct drm_crtc *crtc) if (state->crtc != crtc) continue; - intel_connector_verify_state(to_intel_connector(connector), - connector->state); + intel_connector_verify_state(to_intel_connector(connector)); I915_STATE_WARN(state->best_encoder != encoder, "connector's atomic encoder doesn't match legacy encoder\n"); @@ -12458,7 +13133,12 @@ intel_modeset_verify_crtc(struct drm_crtc *crtc, struct drm_crtc_state *old_state, struct drm_crtc_state *new_state) { + if (!needs_modeset(new_state) && + !to_intel_crtc_state(new_state)->update_pipe) + return; + verify_wm_state(crtc, new_state); + verify_connector_state(crtc->dev, crtc); verify_crtc_state(crtc, old_state, new_state); verify_shared_dpll_state(crtc->dev, crtc, old_state, new_state); } @@ -12810,83 +13490,32 @@ static int intel_atomic_check(struct drm_device *dev, return calc_watermark_data(state); } -static bool needs_work(struct drm_crtc_state *crtc_state) -{ - /* hw state checker needs to run */ - if (needs_modeset(crtc_state)) - return true; - - /* unpin old fb's, possibly vblank update */ - if (crtc_state->planes_changed) - return true; - - /* pipe parameters need to be updated, and hw state checker */ - if (to_intel_crtc_state(crtc_state)->update_pipe) - return true; - - /* vblank event requested? */ - if (crtc_state->event) - return true; - - return false; -} - static int intel_atomic_prepare_commit(struct drm_device *dev, struct drm_atomic_state *state, bool nonblock) { struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_atomic_state *intel_state = to_intel_atomic_state(state); struct drm_plane_state *plane_state; struct drm_crtc_state *crtc_state; struct drm_plane *plane; struct drm_crtc *crtc; int i, ret; - for_each_crtc_in_state(state, crtc, crtc_state, i) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_flip_work *work; - - if (!state->legacy_cursor_update) { - ret = intel_crtc_wait_for_pending_flips(crtc); - if (ret) - return ret; - - if (atomic_read(&intel_crtc->unpin_work_count) >= 2) - flush_workqueue(dev_priv->wq); - } + if (nonblock) { + DRM_DEBUG_KMS("i915 does not yet support nonblocking commit\n"); + return -EINVAL; + } - /* test if we need to update something */ - if (!needs_work(crtc_state)) + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (state->legacy_cursor_update) continue; - intel_state->work[i] = work = - kzalloc(sizeof(**intel_state->work), GFP_KERNEL); - - if (!work) - return -ENOMEM; - - if (needs_modeset(crtc_state) || - to_intel_crtc_state(crtc_state)->update_pipe) { - work->num_old_connectors = hweight32(crtc->state->connector_mask); - - work->old_connector_state = kcalloc(work->num_old_connectors, - sizeof(*work->old_connector_state), - GFP_KERNEL); - - work->num_new_connectors = hweight32(crtc_state->connector_mask); - work->new_connector_state = kcalloc(work->num_new_connectors, - sizeof(*work->new_connector_state), - GFP_KERNEL); - - if (!work->old_connector_state || !work->new_connector_state) - return -ENOMEM; - } - } + ret = intel_crtc_wait_for_pending_flips(crtc); + if (ret) + return ret; - if (intel_state->modeset && nonblock) { - DRM_DEBUG_ATOMIC("Nonblock modesets are not yet supported!\n"); - return -EINVAL; + if (atomic_read(&to_intel_crtc(crtc)->unpin_work_count) >= 2) + flush_workqueue(dev_priv->wq); } ret = mutex_lock_interruptible(&dev->struct_mutex); @@ -12901,15 +13530,6 @@ static int intel_atomic_prepare_commit(struct drm_device *dev, struct intel_plane_state *intel_plane_state = to_intel_plane_state(plane_state); - if (plane_state->fence) { - long lret = fence_wait(plane_state->fence, true); - - if (lret < 0) { - ret = lret; - break; - } - } - if (!intel_plane_state->wait_req) continue; @@ -12939,157 +13559,69 @@ u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc) return dev->driver->get_vblank_counter(dev, crtc->pipe); } -static void intel_prepare_work(struct drm_crtc *crtc, - struct intel_flip_work *work, - struct drm_atomic_state *state, - struct drm_crtc_state *old_crtc_state) +static void intel_atomic_wait_for_vblanks(struct drm_device *dev, + struct drm_i915_private *dev_priv, + unsigned crtc_mask) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct drm_plane_state *old_plane_state; - struct drm_plane *plane; - int i, j = 0; + unsigned last_vblank_count[I915_MAX_PIPES]; + enum pipe pipe; + int ret; - INIT_WORK(&work->unpin_work, intel_unpin_work_fn); - INIT_WORK(&work->mmio_work, intel_mmio_flip_work_func); - atomic_inc(&intel_crtc->unpin_work_count); + if (!crtc_mask) + return; - for_each_plane_in_state(state, plane, old_plane_state, i) { - struct intel_plane_state *old_state = to_intel_plane_state(old_plane_state); - struct intel_plane_state *new_state = to_intel_plane_state(plane->state); + for_each_pipe(dev_priv, pipe) { + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; - if (old_state->base.crtc != crtc && - new_state->base.crtc != crtc) + if (!((1 << pipe) & crtc_mask)) continue; - if (plane->type == DRM_PLANE_TYPE_PRIMARY) { - plane->fb = new_state->base.fb; - crtc->x = new_state->base.src_x >> 16; - crtc->y = new_state->base.src_y >> 16; + ret = drm_crtc_vblank_get(crtc); + if (WARN_ON(ret != 0)) { + crtc_mask &= ~(1 << pipe); + continue; } - old_state->wait_req = new_state->wait_req; - new_state->wait_req = NULL; - - old_state->base.fence = new_state->base.fence; - new_state->base.fence = NULL; - - /* remove plane state from the atomic state and move it to work */ - old_plane_state->state = NULL; - state->planes[i] = NULL; - state->plane_states[i] = NULL; - - work->old_plane_state[j] = old_state; - work->new_plane_state[j++] = new_state; + last_vblank_count[pipe] = drm_crtc_vblank_count(crtc); } - old_crtc_state->state = NULL; - state->crtcs[drm_crtc_index(crtc)] = NULL; - state->crtc_states[drm_crtc_index(crtc)] = NULL; - - work->old_crtc_state = to_intel_crtc_state(old_crtc_state); - work->new_crtc_state = to_intel_crtc_state(crtc->state); - work->num_planes = j; - - work->event = crtc->state->event; - crtc->state->event = NULL; - - if (needs_modeset(crtc->state) || work->new_crtc_state->update_pipe) { - struct drm_connector *conn; - struct drm_connector_state *old_conn_state; - int k = 0; - - j = 0; - - /* - * intel_unpin_work_fn cannot depend on the connector list - * because it may be freed from underneath it, so add - * them all to the work struct while we're holding locks. - */ - for_each_connector_in_state(state, conn, old_conn_state, i) { - if (old_conn_state->crtc == crtc) { - work->old_connector_state[j++] = old_conn_state; - - state->connectors[i] = NULL; - state->connector_states[i] = NULL; - } - } - - /* If another crtc has stolen the connector from state, - * then for_each_connector_in_state is no longer reliable, - * so use drm_for_each_connector here. - */ - drm_for_each_connector(conn, state->dev) - if (conn->state->crtc == crtc) - work->new_connector_state[k++] = conn->state; - - WARN(j != work->num_old_connectors, "j = %i, expected %i\n", j, work->num_old_connectors); - WARN(k != work->num_new_connectors, "k = %i, expected %i\n", k, work->num_new_connectors); - } else if (!work->new_crtc_state->update_wm_post) - work->can_async_unpin = true; - - work->fb_bits = work->new_crtc_state->fb_bits; -} - -static void intel_schedule_unpin(struct drm_crtc *crtc, - struct intel_atomic_state *state, - struct intel_flip_work *work) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - - to_intel_crtc(crtc)->config = work->new_crtc_state; - - queue_work(dev_priv->wq, &work->unpin_work); -} + for_each_pipe(dev_priv, pipe) { + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + long lret; -static void intel_schedule_flip(struct drm_crtc *crtc, - struct intel_atomic_state *state, - struct intel_flip_work *work, - bool nonblock) -{ - struct intel_crtc_state *crtc_state = work->new_crtc_state; + if (!((1 << pipe) & crtc_mask)) + continue; - if (crtc_state->base.planes_changed || - needs_modeset(&crtc_state->base) || - crtc_state->update_pipe) { - if (nonblock) - schedule_work(&work->mmio_work); - else - intel_mmio_flip_work_func(&work->mmio_work); - } else { - int ret; + lret = wait_event_timeout(dev->vblank[pipe].queue, + last_vblank_count[pipe] != + drm_crtc_vblank_count(crtc), + msecs_to_jiffies(50)); - ret = drm_crtc_vblank_get(crtc); - I915_STATE_WARN(ret < 0, "enabling vblank failed with %i\n", ret); + WARN(!lret, "pipe %c vblank wait timed out\n", pipe_name(pipe)); - work->flip_queued_vblank = intel_crtc_get_vblank_counter(to_intel_crtc(crtc)); - smp_mb__before_atomic(); - atomic_set(&work->pending, 1); + drm_crtc_vblank_put(crtc); } } -static void intel_schedule_update(struct drm_crtc *crtc, - struct intel_atomic_state *state, - struct intel_flip_work *work, - bool nonblock) +static bool needs_vblank_wait(struct intel_crtc_state *crtc_state) { - struct drm_device *dev = crtc->dev; - struct intel_crtc_state *pipe_config = work->new_crtc_state; + /* fb updated, need to unpin old fb */ + if (crtc_state->fb_changed) + return true; - if (!pipe_config->base.active && work->can_async_unpin) { - INIT_LIST_HEAD(&work->head); - intel_schedule_unpin(crtc, state, work); - return; - } + /* wm changes, need vblank before final wm's */ + if (crtc_state->update_wm_post) + return true; - spin_lock_irq(&dev->event_lock); - list_add_tail(&work->head, &to_intel_crtc(crtc)->flip_work); - spin_unlock_irq(&dev->event_lock); + /* + * cxsr is re-enabled after vblank. + * This is already handled by crtc_state->update_wm_post, + * but added for clarity. + */ + if (crtc_state->disable_cxsr) + return true; - if (!pipe_config->base.active) - intel_schedule_unpin(crtc, state, work); - else - intel_schedule_flip(crtc, state, work, nonblock); + return false; } /** @@ -13116,7 +13648,11 @@ static int intel_atomic_commit(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc_state *old_crtc_state; struct drm_crtc *crtc; + struct intel_crtc_state *intel_cstate; int ret = 0, i; + bool hw_check = intel_state->modeset; + unsigned long put_domains[I915_MAX_PIPES] = {}; + unsigned crtc_vblank_mask = 0; ret = intel_atomic_prepare_commit(dev, state, nonblock); if (ret) { @@ -13134,20 +13670,27 @@ static int intel_atomic_commit(struct drm_device *dev, sizeof(intel_state->min_pixclk)); dev_priv->active_crtcs = intel_state->active_crtcs; dev_priv->atomic_cdclk_freq = intel_state->cdclk; + + intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET); } for_each_crtc_in_state(state, crtc, old_crtc_state, i) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + if (needs_modeset(crtc->state) || + to_intel_crtc_state(crtc->state)->update_pipe) { + hw_check = true; + + put_domains[to_intel_crtc(crtc)->pipe] = + modeset_get_crtc_power_domains(crtc, + to_intel_crtc_state(crtc->state)); + } + if (!needs_modeset(crtc->state)) continue; intel_pre_plane_update(to_intel_crtc_state(old_crtc_state)); - intel_state->work[i]->put_power_domains = - modeset_get_crtc_power_domains(crtc, - to_intel_crtc_state(crtc->state)); - if (old_crtc_state->active) { intel_crtc_disable_planes(crtc, old_crtc_state->plane_mask); dev_priv->display.crtc_disable(crtc); @@ -13184,9 +13727,11 @@ static int intel_atomic_commit(struct drm_device *dev, /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_crtc_in_state(state, crtc, old_crtc_state, i) { - struct intel_flip_work *work = intel_state->work[i]; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); bool modeset = needs_modeset(crtc->state); + struct intel_crtc_state *pipe_config = + to_intel_crtc_state(crtc->state); + bool update_pipe = !modeset && pipe_config->update_pipe; if (modeset && crtc->state->active) { update_scanline_offset(to_intel_crtc(crtc)); @@ -13196,30 +13741,53 @@ static int intel_atomic_commit(struct drm_device *dev, if (!modeset) intel_pre_plane_update(to_intel_crtc_state(old_crtc_state)); - if (!work) { - if (!list_empty_careful(&intel_crtc->flip_work)) { - spin_lock_irq(&dev->event_lock); - if (!list_empty(&intel_crtc->flip_work)) - work = list_last_entry(&intel_crtc->flip_work, - struct intel_flip_work, head); - - if (work && work->new_crtc_state == to_intel_crtc_state(old_crtc_state)) { - work->free_new_crtc_state = true; - state->crtc_states[i] = NULL; - state->crtcs[i] = NULL; - } - spin_unlock_irq(&dev->event_lock); - } - continue; - } + if (crtc->state->active && + drm_atomic_get_existing_plane_state(state, crtc->primary)) + intel_fbc_enable(intel_crtc); + + if (crtc->state->active && + (crtc->state->planes_changed || update_pipe)) + drm_atomic_helper_commit_planes_on_crtc(old_crtc_state); - intel_state->work[i] = NULL; - intel_prepare_work(crtc, work, state, old_crtc_state); - intel_schedule_update(crtc, intel_state, work, nonblock); + if (pipe_config->base.active && needs_vblank_wait(pipe_config)) + crtc_vblank_mask |= 1 << i; } /* FIXME: add subpixel order */ + if (!state->legacy_cursor_update) + intel_atomic_wait_for_vblanks(dev, dev_priv, crtc_vblank_mask); + + /* + * Now that the vblank has passed, we can go ahead and program the + * optimal watermarks on platforms that need two-step watermark + * programming. + * + * TODO: Move this (and other cleanup) to an async worker eventually. + */ + for_each_crtc_in_state(state, crtc, old_crtc_state, i) { + intel_cstate = to_intel_crtc_state(crtc->state); + + if (dev_priv->display.optimize_watermarks) + dev_priv->display.optimize_watermarks(intel_cstate); + } + + for_each_crtc_in_state(state, crtc, old_crtc_state, i) { + intel_post_plane_update(to_intel_crtc_state(old_crtc_state)); + + if (put_domains[i]) + modeset_put_power_domains(dev_priv, put_domains[i]); + + intel_modeset_verify_crtc(crtc, old_crtc_state, crtc->state); + } + + if (intel_state->modeset) + intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET); + + mutex_lock(&dev->struct_mutex); + drm_atomic_helper_cleanup_planes(dev, state); + mutex_unlock(&dev->struct_mutex); + drm_atomic_state_free(state); /* As one of the primary mmio accessors, KMS has a high likelihood @@ -13283,38 +13851,11 @@ static const struct drm_crtc_funcs intel_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .set_property = drm_atomic_helper_crtc_set_property, .destroy = intel_crtc_destroy, - .page_flip = drm_atomic_helper_page_flip, + .page_flip = intel_crtc_page_flip, .atomic_duplicate_state = intel_crtc_duplicate_state, .atomic_destroy_state = intel_crtc_destroy_state, }; -static struct fence *intel_get_excl_fence(struct drm_i915_gem_object *obj) -{ - struct reservation_object *resv; - - - if (!obj->base.dma_buf) - return NULL; - - resv = obj->base.dma_buf->resv; - - /* For framebuffer backed by dmabuf, wait for fence */ - while (1) { - struct fence *fence_excl, *ret = NULL; - - rcu_read_lock(); - - fence_excl = rcu_dereference(resv->fence_excl); - if (fence_excl) - ret = fence_get_rcu(fence_excl); - - rcu_read_unlock(); - - if (ret == fence_excl) - return ret; - } -} - /** * intel_prepare_plane_fb - Prepare fb for usage on plane * @plane: drm plane to prepare for @@ -13338,20 +13879,11 @@ intel_prepare_plane_fb(struct drm_plane *plane, struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->state->fb); - struct drm_crtc *crtc = new_state->crtc ?: plane->state->crtc; int ret = 0; if (!obj && !old_obj) return 0; - if (WARN_ON(!new_state->state) || WARN_ON(!crtc) || - WARN_ON(!to_intel_atomic_state(new_state->state)->work[to_intel_crtc(crtc)->pipe])) { - if (WARN_ON(old_obj != obj)) - return -EINVAL; - - return 0; - } - if (old_obj) { struct drm_crtc_state *crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, plane->state->crtc); @@ -13376,6 +13908,19 @@ intel_prepare_plane_fb(struct drm_plane *plane, } } + /* For framebuffer backed by dmabuf, wait for fence */ + if (obj && obj->base.dma_buf) { + long lret; + + lret = reservation_object_wait_timeout_rcu(obj->base.dma_buf->resv, + false, true, + MAX_SCHEDULE_TIMEOUT); + if (lret == -ERESTARTSYS) + return lret; + + WARN(lret < 0, "waiting returns %li\n", lret); + } + if (!obj) { ret = 0; } else if (plane->type == DRM_PLANE_TYPE_CURSOR && @@ -13395,8 +13940,6 @@ intel_prepare_plane_fb(struct drm_plane *plane, i915_gem_request_assign(&plane_state->wait_req, obj->last_write_req); - - plane_state->base.fence = intel_get_excl_fence(obj); } i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit); @@ -13439,9 +13982,6 @@ intel_cleanup_plane_fb(struct drm_plane *plane, i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit); i915_gem_request_assign(&old_intel_state->wait_req, NULL); - - fence_put(old_intel_state->base.fence); - old_intel_state->base.fence = NULL; } int @@ -13501,6 +14041,40 @@ intel_check_primary_plane(struct drm_plane *plane, &state->visible); } +static void intel_begin_crtc_commit(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc_state *old_intel_state = + to_intel_crtc_state(old_crtc_state); + bool modeset = needs_modeset(crtc->state); + + /* Perform vblank evasion around commit operation */ + intel_pipe_update_start(intel_crtc); + + if (modeset) + return; + + if (crtc->state->color_mgmt_changed || to_intel_crtc_state(crtc->state)->update_pipe) { + intel_color_set_csc(crtc->state); + intel_color_load_luts(crtc->state); + } + + if (to_intel_crtc_state(crtc->state)->update_pipe) + intel_update_pipe_config(intel_crtc, old_intel_state); + else if (INTEL_INFO(dev)->gen >= 9) + skl_detach_scalers(intel_crtc); +} + +static void intel_finish_crtc_commit(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + intel_pipe_update_end(intel_crtc, NULL); +} + /** * intel_plane_destroy - destroy a plane * @plane: plane to destroy @@ -13811,8 +14385,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->base.state = &crtc_state->base; crtc_state->base.crtc = &intel_crtc->base; - INIT_LIST_HEAD(&intel_crtc->flip_work); - /* initialize shared scalers */ if (INTEL_INFO(dev)->gen >= 9) { if (pipe == PIPE_C) @@ -14568,6 +15140,34 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv) dev_priv->display.modeset_calc_cdclk = skl_modeset_calc_cdclk; } + + switch (INTEL_INFO(dev_priv)->gen) { + case 2: + dev_priv->display.queue_flip = intel_gen2_queue_flip; + break; + + case 3: + dev_priv->display.queue_flip = intel_gen3_queue_flip; + break; + + case 4: + case 5: + dev_priv->display.queue_flip = intel_gen4_queue_flip; + break; + + case 6: + dev_priv->display.queue_flip = intel_gen6_queue_flip; + break; + case 7: + case 8: /* FIXME(BDW): Check that the gen8 RCS flip works. */ + dev_priv->display.queue_flip = intel_gen7_queue_flip; + break; + case 9: + /* Drop through - unsupported since execlist only. */ + default: + /* Default just returns -ENODEV to indicate unsupported */ + dev_priv->display.queue_flip = intel_default_queue_flip; + } } /* @@ -15526,9 +16126,9 @@ void intel_modeset_gem_init(struct drm_device *dev) DRM_ERROR("failed to pin boot fb on pipe %d\n", to_intel_crtc(c)->pipe); drm_framebuffer_unreference(c->primary->fb); - drm_framebuffer_unreference(c->primary->state->fb); - c->primary->fb = c->primary->state->fb = NULL; + c->primary->fb = NULL; c->primary->crtc = c->primary->state->crtc = NULL; + update_state_fb(c->primary); c->state->plane_mask &= ~(1 << drm_plane_index(c->primary)); } } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 03d4b1a..9b5f663 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -304,8 +304,6 @@ struct intel_atomic_state { unsigned int active_crtcs; unsigned int min_pixclk[I915_MAX_PIPES]; - struct intel_flip_work *work[I915_MAX_PIPES]; - /* SKL/KBL Only */ unsigned int cdclk_pll_vco; @@ -646,7 +644,7 @@ struct intel_crtc { unsigned long enabled_power_domains; bool lowfreq_avail; struct intel_overlay *overlay; - struct list_head flip_work; + struct intel_flip_work *flip_work; atomic_t unpin_work_count; @@ -664,6 +662,9 @@ struct intel_crtc { struct intel_crtc_state *config; + /* reset counter value when the last flip was submitted */ + unsigned int reset_counter; + /* Access to these should be protected by dev_priv->irq_lock. */ bool cpu_fifo_underrun_disabled; bool pch_fifo_underrun_disabled; @@ -972,28 +973,20 @@ intel_get_crtc_for_plane(struct drm_device *dev, int plane) } struct intel_flip_work { - struct list_head head; - struct work_struct unpin_work; struct work_struct mmio_work; + struct drm_crtc *crtc; + struct drm_framebuffer *old_fb; + struct drm_i915_gem_object *pending_flip_obj; struct drm_pending_vblank_event *event; atomic_t pending; + u32 flip_count; + u32 gtt_offset; + struct drm_i915_gem_request *flip_queued_req; u32 flip_queued_vblank; - - unsigned put_power_domains; - unsigned num_planes; - - bool can_async_unpin, free_new_crtc_state; - unsigned fb_bits; - - unsigned num_old_connectors, num_new_connectors; - struct drm_connector_state **old_connector_state; - struct drm_connector_state **new_connector_state; - - struct intel_crtc_state *old_crtc_state, *new_crtc_state; - struct intel_plane_state *old_plane_state[I915_MAX_PLANES + 1]; - struct intel_plane_state *new_plane_state[I915_MAX_PLANES + 1]; + u32 flip_ready_vblank; + unsigned int rotation; }; struct intel_load_detect_pipe { @@ -1153,7 +1146,6 @@ unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info bool intel_has_pending_fb_unpin(struct drm_device *dev); void intel_mark_busy(struct drm_i915_private *dev_priv); void intel_mark_idle(struct drm_i915_private *dev_priv); -void intel_free_flip_work(struct intel_flip_work *work); void intel_crtc_restore_mode(struct drm_crtc *crtc); int intel_display_suspend(struct drm_device *dev); void intel_encoder_destroy(struct drm_encoder *encoder); @@ -1206,8 +1198,9 @@ struct drm_framebuffer * __intel_framebuffer_create(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj); +void intel_finish_page_flip_cs(struct drm_i915_private *dev_priv, int pipe); void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe); - +void intel_check_page_flip(struct drm_i915_private *dev_priv, int pipe); int intel_prepare_plane_fb(struct drm_plane *plane, const struct drm_plane_state *new_state); void intel_cleanup_plane_fb(struct drm_plane *plane, @@ -1430,15 +1423,11 @@ static inline void intel_fbdev_restore_mode(struct drm_device *dev) void intel_fbc_choose_crtc(struct drm_i915_private *dev_priv, struct drm_atomic_state *state); bool intel_fbc_is_active(struct drm_i915_private *dev_priv); -void intel_fbc_pre_update(struct intel_crtc *crtc, - struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state); +void intel_fbc_pre_update(struct intel_crtc *crtc); void intel_fbc_post_update(struct intel_crtc *crtc); void intel_fbc_init(struct drm_i915_private *dev_priv); void intel_fbc_init_pipe_state(struct drm_i915_private *dev_priv); -void intel_fbc_enable(struct intel_crtc *crtc, - struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state); +void intel_fbc_enable(struct intel_crtc *crtc); void intel_fbc_disable(struct intel_crtc *crtc); void intel_fbc_global_disable(struct drm_i915_private *dev_priv); void intel_fbc_invalidate(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index d2b0269..0dea5fb 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -480,10 +480,10 @@ static void intel_fbc_deactivate(struct drm_i915_private *dev_priv) intel_fbc_hw_deactivate(dev_priv); } -static bool multiple_pipes_ok(struct intel_crtc *crtc, - struct intel_plane_state *plane_state) +static bool multiple_pipes_ok(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_plane *primary = crtc->base.primary; struct intel_fbc *fbc = &dev_priv->fbc; enum pipe pipe = crtc->pipe; @@ -491,7 +491,9 @@ static bool multiple_pipes_ok(struct intel_crtc *crtc, if (!no_fbc_on_multiple_pipes(dev_priv)) return true; - if (plane_state->visible) + WARN_ON(!drm_modeset_is_locked(&primary->mutex)); + + if (to_intel_plane_state(primary->state)->visible) fbc->visible_pipes_mask |= (1 << pipe); else fbc->visible_pipes_mask &= ~(1 << pipe); @@ -706,16 +708,21 @@ static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc) return effective_w <= max_w && effective_h <= max_h; } -static void intel_fbc_update_state_cache(struct intel_crtc *crtc, - struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state) +static void intel_fbc_update_state_cache(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_fbc *fbc = &dev_priv->fbc; struct intel_fbc_state_cache *cache = &fbc->state_cache; + struct intel_crtc_state *crtc_state = + to_intel_crtc_state(crtc->base.state); + struct intel_plane_state *plane_state = + to_intel_plane_state(crtc->base.primary->state); struct drm_framebuffer *fb = plane_state->base.fb; struct drm_i915_gem_object *obj; + WARN_ON(!drm_modeset_is_locked(&crtc->base.mutex)); + WARN_ON(!drm_modeset_is_locked(&crtc->base.primary->mutex)); + cache->crtc.mode_flags = crtc_state->base.adjusted_mode.flags; if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) cache->crtc.hsw_bdw_pixel_rate = @@ -880,9 +887,7 @@ static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1, return memcmp(params1, params2, sizeof(*params1)) == 0; } -void intel_fbc_pre_update(struct intel_crtc *crtc, - struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state) +void intel_fbc_pre_update(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_fbc *fbc = &dev_priv->fbc; @@ -892,7 +897,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc, mutex_lock(&fbc->lock); - if (!multiple_pipes_ok(crtc, plane_state)) { + if (!multiple_pipes_ok(crtc)) { fbc->no_fbc_reason = "more than one pipe active"; goto deactivate; } @@ -900,7 +905,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc, if (!fbc->enabled || fbc->crtc != crtc) goto unlock; - intel_fbc_update_state_cache(crtc, crtc_state, plane_state); + intel_fbc_update_state_cache(crtc); deactivate: intel_fbc_deactivate(dev_priv); @@ -1084,9 +1089,7 @@ out: * intel_fbc_enable multiple times for the same pipe without an * intel_fbc_disable in the middle, as long as it is deactivated. */ -void intel_fbc_enable(struct intel_crtc *crtc, - struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state) +void intel_fbc_enable(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_fbc *fbc = &dev_priv->fbc; @@ -1099,19 +1102,19 @@ void intel_fbc_enable(struct intel_crtc *crtc, if (fbc->enabled) { WARN_ON(fbc->crtc == NULL); if (fbc->crtc == crtc) { - WARN_ON(!crtc_state->enable_fbc); + WARN_ON(!crtc->config->enable_fbc); WARN_ON(fbc->active); } goto out; } - if (!crtc_state->enable_fbc) + if (!crtc->config->enable_fbc) goto out; WARN_ON(fbc->active); WARN_ON(fbc->crtc != NULL); - intel_fbc_update_state_cache(crtc, crtc_state, plane_state); + intel_fbc_update_state_cache(crtc); if (intel_fbc_alloc_cfb(crtc)) { fbc->no_fbc_reason = "not enough stolen memory"; goto out; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 5371503..5c191a1 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -260,7 +260,9 @@ int intel_sanitize_enable_execlists(struct drm_i915_private *dev_priv, int enabl if (enable_execlists == 0) return 0; - if (HAS_LOGICAL_RING_CONTEXTS(dev_priv) && USES_PPGTT(dev_priv)) + if (HAS_LOGICAL_RING_CONTEXTS(dev_priv) && + USES_PPGTT(dev_priv) && + i915.use_mmio_flip >= 0) return 1; return 0; -- cgit v0.10.2 From 1c3f7700b2830cbcc25fda675ad5e997e1454703 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 May 2016 15:38:32 +0300 Subject: drm/i915/gen9: Assume CDCLK PLL is off if it's not locked MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the CDCLK PLL isn't locked or incorrectly configured we can just assume that it's off resulting in fully re-initializing both CDCLK PLL and CDCLK dividers. This way the CDCLK PLL sanitization added in the following patch can be done on BXT the same way as it's done on SKL. v2: (Ville) - Remove the remaining PLL specific checks from skl_sanitize_cdclk() and depend instead on the corresponding check in skl_dpll0_update(). - Use vco == 0 instead of the corresponding boolean check in skl_sanitize_cdclk(). CC: Ville Syrjälä Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1464093513-16258-1-git-send-email-imre.deak@intel.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 46429e7..d0e4023 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5540,21 +5540,22 @@ skl_dpll0_update(struct drm_i915_private *dev_priv) u32 val; dev_priv->cdclk_pll.ref = 24000; + dev_priv->cdclk_pll.vco = 0; val = I915_READ(LCPLL1_CTL); - if ((val & LCPLL_PLL_ENABLE) == 0) { - dev_priv->cdclk_pll.vco = 0; + if ((val & LCPLL_PLL_ENABLE) == 0) return; - } - WARN_ON((val & LCPLL_PLL_LOCK) == 0); + if (WARN_ON((val & LCPLL_PLL_LOCK) == 0)) + return; val = I915_READ(DPLL_CTRL1); - WARN_ON((val & (DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | - DPLL_CTRL1_SSC(SKL_DPLL0) | - DPLL_CTRL1_OVERRIDE(SKL_DPLL0))) != - DPLL_CTRL1_OVERRIDE(SKL_DPLL0)); + if (WARN_ON((val & (DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | + DPLL_CTRL1_SSC(SKL_DPLL0) | + DPLL_CTRL1_OVERRIDE(SKL_DPLL0))) != + DPLL_CTRL1_OVERRIDE(SKL_DPLL0))) + return; switch (val & DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0)) { case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, SKL_DPLL0): @@ -5569,7 +5570,6 @@ skl_dpll0_update(struct drm_i915_private *dev_priv) break; default: MISSING_CASE(val & DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0)); - dev_priv->cdclk_pll.vco = 0; break; } } @@ -5769,19 +5769,12 @@ static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv) if ((I915_READ(SWF_ILK(0x18)) & 0x00FFFFFF) == 0) goto sanitize; + intel_update_cdclk(dev_priv->dev); /* Is PLL enabled and locked ? */ - if ((I915_READ(LCPLL1_CTL) & (LCPLL_PLL_ENABLE | LCPLL_PLL_LOCK)) != - (LCPLL_PLL_ENABLE | LCPLL_PLL_LOCK)) - goto sanitize; - - if ((I915_READ(DPLL_CTRL1) & (DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | - DPLL_CTRL1_SSC(SKL_DPLL0) | - DPLL_CTRL1_OVERRIDE(SKL_DPLL0))) != - DPLL_CTRL1_OVERRIDE(SKL_DPLL0)) + if (dev_priv->cdclk_pll.vco == 0 || + dev_priv->cdclk_freq == dev_priv->cdclk_pll.ref) goto sanitize; - intel_update_cdclk(dev_priv->dev); - /* DPLL okay; verify the cdclock * * Noticed in some instances that the freq selection is correct but @@ -6681,14 +6674,14 @@ static void bxt_de_pll_update(struct drm_i915_private *dev_priv) u32 val; dev_priv->cdclk_pll.ref = 19200; + dev_priv->cdclk_pll.vco = 0; val = I915_READ(BXT_DE_PLL_ENABLE); - if ((val & BXT_DE_PLL_PLL_ENABLE) == 0) { - dev_priv->cdclk_pll.vco = 0; + if ((val & BXT_DE_PLL_PLL_ENABLE) == 0) return; - } - WARN_ON((val & BXT_DE_PLL_LOCK) == 0); + if (WARN_ON((val & BXT_DE_PLL_LOCK) == 0)) + return; val = I915_READ(BXT_DE_PLL_CTL); dev_priv->cdclk_pll.vco = (val & BXT_DE_PLL_RATIO_MASK) * -- cgit v0.10.2 From d66a21947e2147a0e313825ee461e954e8fe39cb Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 24 May 2016 15:38:33 +0300 Subject: drm/i915/bxt: Sanitize CDCLK to fix breakage during S4 resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I noticed that during S4 resume BIOS incorrectly sets bits 18, 19 which are reserved/MBZ and sets the decimal frequency fields to all 0xff in the CDCLK register. The result is a hard lockup as display register accesses are attempted later. Work around this by sanitizing the CDCLK PLL/dividers the same way it's done on SKL. While this is clearly a BIOS bug which should be fixed separately, it doesn't hurt to check/sanitize this regardless. v2: - Use the same condition for VCO and CDCLK in broxton_init_cdclk as is used in skl_init_cdclk for the same purpose. CC: Ville Syrjälä Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1464093513-16258-2-git-send-email-imre.deak@intel.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d0e4023..d6d075c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5491,11 +5491,58 @@ static void broxton_set_cdclk(struct drm_i915_private *dev_priv, int cdclk) intel_update_cdclk(dev_priv->dev); } -void broxton_init_cdclk(struct drm_i915_private *dev_priv) +static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) { + u32 cdctl, expected; + intel_update_cdclk(dev_priv->dev); - if (dev_priv->cdclk_pll.vco != 0) + if (dev_priv->cdclk_pll.vco == 0 || + dev_priv->cdclk_freq == dev_priv->cdclk_pll.ref) + goto sanitize; + + /* DPLL okay; verify the cdclock + * + * Some BIOS versions leave an incorrect decimal frequency value and + * set reserved MBZ bits in CDCLK_CTL at least during exiting from S4, + * so sanitize this register. + */ + cdctl = I915_READ(CDCLK_CTL); + /* + * Let's ignore the pipe field, since BIOS could have configured the + * dividers both synching to an active pipe, or asynchronously + * (PIPE_NONE). + */ + cdctl &= ~BXT_CDCLK_CD2X_PIPE_NONE; + + expected = (cdctl & BXT_CDCLK_CD2X_DIV_SEL_MASK) | + skl_cdclk_decimal(dev_priv->cdclk_freq); + /* + * Disable SSA Precharge when CD clock frequency < 500 MHz, + * enable otherwise. + */ + if (dev_priv->cdclk_freq >= 500000) + expected |= BXT_CDCLK_SSA_PRECHARGE_ENABLE; + + if (cdctl == expected) + /* All well; nothing to sanitize */ + return; + +sanitize: + DRM_DEBUG_KMS("Sanitizing cdclk programmed by pre-os\n"); + + /* force cdclk programming */ + dev_priv->cdclk_freq = 0; + + /* force full PLL disable + enable */ + dev_priv->cdclk_pll.vco = -1; +} + +void broxton_init_cdclk(struct drm_i915_private *dev_priv) +{ + bxt_sanitize_cdclk(dev_priv); + + if (dev_priv->cdclk_freq != 0 && dev_priv->cdclk_pll.vco != 0) return; /* -- cgit v0.10.2 From f165d2834ceb3d5c29bebadadc27629bebf402ac Mon Sep 17 00:00:00 2001 From: Lyude Date: Wed, 25 May 2016 14:11:02 -0400 Subject: drm/i915/ilk: Don't disable SSC source if it's in use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks to Ville Syrjälä for pointing me towards the cause of this issue. Unfortunately one of the sideaffects of having the refclk for a DPLL set to SSC is that as long as it's set to SSC, the GPU will prevent us from powering down any of the pipes or transcoders using it. A couple of BIOSes enable SSC in both PCH_DREF_CONTROL and in the DPLL configurations. This causes issues on the first modeset, since we don't expect SSC to be left on and as a result, can't successfully power down the pipes or the transcoders using it. Here's an example from this Dell OptiPlex 990: [drm:intel_modeset_init] SSC enabled by BIOS, overriding VBT which says disabled [drm:intel_modeset_init] 2 display pipes available. [drm:intel_update_cdclk] Current CD clock rate: 400000 kHz [drm:intel_update_max_cdclk] Max CD clock rate: 400000 kHz [drm:intel_update_max_cdclk] Max dotclock rate: 360000 kHz vgaarb: device changed decodes: PCI:0000:00:02.0,olddecodes=io+mem,decodes=io+mem:owns=io+mem [drm:intel_crt_reset] crt adpa set to 0xf40000 [drm:intel_dp_init_connector] Adding DP connector on port C [drm:intel_dp_aux_init] registering DPDDC-C bus for card0-DP-1 [drm:ironlake_init_pch_refclk] has_panel 0 has_lvds 0 has_ck505 0 [drm:ironlake_init_pch_refclk] Disabling SSC entirely … later we try committing the first modeset … [drm:intel_dump_pipe_config] [CRTC:26][modeset] config ffff88041b02e800 for pipe A [drm:intel_dump_pipe_config] cpu_transcoder: A … [drm:intel_dump_pipe_config] dpll_hw_state: dpll: 0xc4016001, dpll_md: 0x0, fp0: 0x20e08, fp1: 0x30d07 [drm:intel_dump_pipe_config] planes on this crtc [drm:intel_dump_pipe_config] STANDARD PLANE:23 plane: 0.0 idx: 0 enabled [drm:intel_dump_pipe_config] FB:42, fb = 800x600 format = 0x34325258 [drm:intel_dump_pipe_config] scaler:0 src (0, 0) 800x600 dst (0, 0) 800x600 [drm:intel_dump_pipe_config] CURSOR PLANE:25 plane: 0.1 idx: 1 disabled, scaler_id = 0 [drm:intel_dump_pipe_config] STANDARD PLANE:27 plane: 0.1 idx: 2 disabled, scaler_id = 0 [drm:intel_get_shared_dpll] CRTC:26 allocated PCH DPLL A [drm:intel_get_shared_dpll] using PCH DPLL A for pipe A [drm:ilk_audio_codec_disable] Disable audio codec on port C, pipe A [drm:intel_disable_pipe] disabling pipe A ------------[ cut here ]------------ WARNING: CPU: 1 PID: 130 at drivers/gpu/drm/i915/intel_display.c:1146 intel_disable_pipe+0x297/0x2d0 [i915] pipe_off wait timed out … ---[ end trace 94fc8aa03ae139e8 ]--- [drm:intel_dp_link_down] [drm:ironlake_crtc_disable [i915]] *ERROR* failed to disable transcoder A Later modesets succeed since they reset the DPLL's configuration anyway, but this is enough to get stuck with a big fat warning in dmesg. A better solution would be to add refcounts for the SSC source, but for now leaving the source clock on should suffice. Changes since v3: - Move temp variable into loop - Move checks for using_ssc_source to after we've figured out has_ck505 - Add using_ssc_source to debug output Changes since v2: - Fix debug output for when we disable the CPU source Changes since v1: - Leave the SSC source clock on instead of just shutting it off on all of the DPLL configurations. Cc: stable@vger.kernel.org Reviewed-by: Ville Syrjälä Signed-off-by: Lyude Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1464199863-9397-1-git-send-email-cpaul@redhat.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d6d075c..5b382e8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8358,12 +8358,14 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *encoder; + int i; u32 val, final; bool has_lvds = false; bool has_cpu_edp = false; bool has_panel = false; bool has_ck505 = false; bool can_ssc = false; + bool using_ssc_source = false; /* We need to take the global config into account */ for_each_intel_encoder(dev, encoder) { @@ -8390,8 +8392,22 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) can_ssc = true; } - DRM_DEBUG_KMS("has_panel %d has_lvds %d has_ck505 %d\n", - has_panel, has_lvds, has_ck505); + /* Check if any DPLLs are using the SSC source */ + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + u32 temp = I915_READ(PCH_DPLL(i)); + + if (!(temp & DPLL_VCO_ENABLE)) + continue; + + if ((temp & PLL_REF_INPUT_MASK) == + PLLB_REF_INPUT_SPREADSPECTRUMIN) { + using_ssc_source = true; + break; + } + } + + DRM_DEBUG_KMS("has_panel %d has_lvds %d has_ck505 %d using_ssc_source %d\n", + has_panel, has_lvds, has_ck505, using_ssc_source); /* Ironlake: try to setup display ref clock before DPLL * enabling. This is only under driver's control after @@ -8411,9 +8427,12 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) else final |= DREF_NONSPREAD_SOURCE_ENABLE; - final &= ~DREF_SSC_SOURCE_MASK; final &= ~DREF_CPU_SOURCE_OUTPUT_MASK; - final &= ~DREF_SSC1_ENABLE; + + if (!using_ssc_source) { + final &= ~DREF_SSC_SOURCE_MASK; + final &= ~DREF_SSC1_ENABLE; + } if (has_panel) { final |= DREF_SSC_SOURCE_ENABLE; @@ -8476,7 +8495,7 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) POSTING_READ(PCH_DREF_CONTROL); udelay(200); } else { - DRM_DEBUG_KMS("Disabling SSC entirely\n"); + DRM_DEBUG_KMS("Disabling CPU source output\n"); val &= ~DREF_CPU_SOURCE_OUTPUT_MASK; @@ -8487,16 +8506,20 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) POSTING_READ(PCH_DREF_CONTROL); udelay(200); - /* Turn off the SSC source */ - val &= ~DREF_SSC_SOURCE_MASK; - val |= DREF_SSC_SOURCE_DISABLE; + if (!using_ssc_source) { + DRM_DEBUG_KMS("Disabling SSC source\n"); - /* Turn off SSC1 */ - val &= ~DREF_SSC1_ENABLE; + /* Turn off the SSC source */ + val &= ~DREF_SSC_SOURCE_MASK; + val |= DREF_SSC_SOURCE_DISABLE; - I915_WRITE(PCH_DREF_CONTROL, val); - POSTING_READ(PCH_DREF_CONTROL); - udelay(200); + /* Turn off SSC1 */ + val &= ~DREF_SSC1_ENABLE; + + I915_WRITE(PCH_DREF_CONTROL, val); + POSTING_READ(PCH_DREF_CONTROL); + udelay(200); + } } BUG_ON(val != final); -- cgit v0.10.2 From bb143165510661feda06fd99298b8b3a94af3046 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Fri, 20 May 2016 15:47:06 +0300 Subject: drm/i915: Fix NULL pointer deference when out of PLLs in IVB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit f9476a6c6d0c ("drm/i915: Refactor platform specifics out of intel_get_shared_dpll()"), the ibx_get_dpll() function lacked an error check, that can lead to a NULL pointer dereference when trying to enable three pipes. BUG: unable to handle kernel NULL pointer dereference at 0000000000000068 IP: [] intel_reference_shared_dpll+0x15/0x100 [i915] PGD cec87067 PUD d30ce067 PMD 0 Oops: 0000 [#1] PREEMPT SMP Modules linked in: snd_hda_intel i915 drm_kms_helper drm intel_gtt sch_fq_codel cfg80211 binfmt_misc i2c_algo_bit cfbfillrect syscopyarea cfbimgblt sysfillrect sysimgblt fb_sys_fops cfbcopyarea intel_rapl iosf_mbi x86_pkg_temp_thermal coretemp agpgart kvm_intel snd_hda_codec_hdmi kvm iTCO_wdt snd_hda_codec_realtek snd_hda_codec_generic irqbypass aesni_intel aes_x86_64 glue_helper lrw gf128mul ablk_helper cryptd psmouse pcspkr snd_hda_codec i2c_i801 snd_hwdep snd_hda_core snd_pcm snd_timer lpc_ich mfd_core snd soundcore wmi evdev tpm_tis tpm [last unloaded: drm] CPU: 3 PID: 5810 Comm: kms_flip Tainted: G U W 4.6.0-test+ #3 Hardware name: /DZ77BH-55K, BIOS BHZ7710H.86A.0100.2013.0517.0942 05/17/2013 task: ffff8800d3908040 ti: ffff8801166c8000 task.ti: ffff8801166c8000 RIP: 0010:[] [] intel_reference_shared_dpll+0x15/0x100 [i915] RSP: 0018:ffff8801166cba60 EFLAGS: 00010246 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000002 RDX: 0000000000000001 RSI: ffff8800d07f1bf8 RDI: 0000000000000000 RBP: ffff8801166cba88 R08: 0000000000000002 R09: ffff8800d32e5698 R10: 0000000000000001 R11: ffff8800cc89ac88 R12: ffff8800d07f1bf8 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 FS: 00007f4c3fc8d8c0(0000) GS:ffff88011bcc0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000068 CR3: 00000000d3b4c000 CR4: 00000000001406e0 Stack: 0000000000000000 ffff8800d07f1bf8 0000000000000000 ffff8800d04c0000 0000000000000000 ffff8801166cbaa8 ffffffffa04823a7 ffff8800d07f1bf8 ffff8800d32e5698 ffff8801166cbab8 ffffffffa04840cf ffff8801166cbaf0 Call Trace: [] ibx_get_dpll+0x47/0xa0 [i915] [] intel_get_shared_dpll+0x1f/0x50 [i915] [] ironlake_crtc_compute_clock+0x280/0x430 [i915] [] intel_crtc_atomic_check+0x240/0x320 [i915] [] drm_atomic_helper_check_planes+0x14e/0x1d0 [drm_kms_helper] [] intel_atomic_check+0x5dc/0x1110 [i915] [] drm_atomic_check_only+0x14a/0x660 [drm] [] ? drm_atomic_set_crtc_for_connector+0x96/0x100 [drm] [] drm_atomic_commit+0x17/0x60 [drm] [] restore_fbdev_mode+0x237/0x260 [drm_kms_helper] [] ? drm_modeset_lock_all_ctx+0x9a/0xb0 [drm] [] drm_fb_helper_restore_fbdev_mode_unlocked+0x33/0x80 [drm_kms_helper] [] drm_fb_helper_set_par+0x2d/0x50 [drm_kms_helper] [] drm_fb_helper_hotplug_event+0xaa/0xf0 [drm_kms_helper] [] drm_fb_helper_restore_fbdev_mode_unlocked+0x56/0x80 [drm_kms_helper] [] intel_fbdev_restore_mode+0x22/0x80 [i915] [] i915_driver_lastclose+0xe/0x20 [i915] [] drm_lastclose+0x2e/0x130 [drm] [] drm_release+0x2ac/0x4b0 [drm] [] __fput+0xed/0x1f0 [] ____fput+0xe/0x10 [] task_work_run+0x76/0xb0 [] do_exit+0x3ab/0xc60 [] ? trace_hardirqs_on_caller+0x12f/0x1c0 [] do_group_exit+0x4e/0xc0 [] SyS_exit_group+0x14/0x20 [] entry_SYSCALL_64_fastpath+0x18/0xa8 Code: 14 80 48 8d 34 90 b8 01 00 00 00 d3 e0 09 04 b3 5b 41 5c 5d c3 90 0f 1f 44 00 00 55 48 89 e5 41 57 41 56 49 89 fe 41 55 41 54 53 <44> 8b 67 68 48 89 f3 48 8b be 08 02 00 00 4c 8b 2e e8 15 9d fd RIP [] intel_reference_shared_dpll+0x15/0x100 [i915] RSP CR2: 0000000000000068 Cc: Ville Syrjälä Cc: drm-intel-fixes@lists.freedesktop.org Reported-by: Ville Syrjälä Fixes: f9476a6c6d0c ("drm/i915: Refactor platform specifics out of intel_get_shared_dpll()") Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Ville Syrjälä Tested-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1463748426-5956-1-git-send-email-ander.conselvan.de.oliveira@intel.com diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 6b70e1e..02a7962 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -366,6 +366,9 @@ ibx_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, DPLL_ID_PCH_PLL_B); } + if (!pll) + return NULL; + /* reference the pll */ intel_reference_shared_dpll(pll, crtc_state); -- cgit v0.10.2 From f326115630069063eb55db0236c5fedb3a131fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 May 2016 21:34:18 +0300 Subject: drm/i915: Reject modeset if the dotclock is too high MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reject the modeset if the requested dotclock exceeds the maximum allowed by the hardware. So far we've only checked this on gen2/3 while also handling the double wide vs. single wide pipe selection. Extend the check to all platforms since we have the max dotclock correctly populated now across the board. Testcase: igt/kms_invalid_dotclock Cc: Mika Kahola Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1464114859-15610-1-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5b382e8..682023a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6624,10 +6624,10 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; + int clock_limit = dev_priv->max_dotclk_freq; - /* FIXME should check pixel clock limits on all platforms */ if (INTEL_INFO(dev)->gen < 4) { - int clock_limit = dev_priv->max_cdclk_freq * 9 / 10; + clock_limit = dev_priv->max_cdclk_freq * 9 / 10; /* * Enable double wide mode when the dot clock @@ -6635,16 +6635,16 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, */ if (intel_crtc_supports_double_wide(crtc) && adjusted_mode->crtc_clock > clock_limit) { - clock_limit *= 2; + clock_limit = dev_priv->max_dotclk_freq; pipe_config->double_wide = true; } + } - if (adjusted_mode->crtc_clock > clock_limit) { - DRM_DEBUG_KMS("requested pixel clock (%d kHz) too high (max: %d kHz, double wide: %s)\n", - adjusted_mode->crtc_clock, clock_limit, - yesno(pipe_config->double_wide)); - return -EINVAL; - } + if (adjusted_mode->crtc_clock > clock_limit) { + DRM_DEBUG_KMS("requested pixel clock (%d kHz) too high (max: %d kHz, double wide: %s)\n", + adjusted_mode->crtc_clock, clock_limit, + yesno(pipe_config->double_wide)); + return -EINVAL; } /* -- cgit v0.10.2 From 78108b7c0aeda8a764dc4c3d50e522b6bb7f358b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 27 May 2016 20:59:19 +0300 Subject: drm/i915: Use crtc->name in debug messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have crtc->name, so let's use that in debug messages instead of just printing the more or less useless object ID. v2: Rebased due to intel_dpll_mgr.c, slap on a commit message Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1464371966-15190-2-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 682023a..fecabc7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4278,8 +4278,9 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state) struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); const struct drm_display_mode *adjusted_mode = &state->base.adjusted_mode; - DRM_DEBUG_KMS("Updating scaler for [CRTC:%i] scaler_user index %u.%u\n", - intel_crtc->base.base.id, intel_crtc->pipe, SKL_CRTC_INDEX); + DRM_DEBUG_KMS("Updating scaler for [CRTC:%d:%s] scaler_user index %u.%u\n", + intel_crtc->base.base.id, intel_crtc->base.name, + intel_crtc->pipe, SKL_CRTC_INDEX); return skl_update_scaler(state, !state->base.active, SKL_CRTC_INDEX, &state->scaler_state.scaler_id, BIT(DRM_ROTATE_0), @@ -6323,8 +6324,8 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) dev_priv->display.crtc_disable(crtc); - DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was enabled, now disabled\n", - crtc->base.id); + DRM_DEBUG_KMS("[CRTC:%d:%s] hw state adjusted, was enabled, now disabled\n", + crtc->base.id, crtc->name); WARN_ON(drm_atomic_set_mode_for_crtc(crtc->state, NULL) < 0); crtc->state->active = false; @@ -11932,12 +11933,12 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, struct drm_i915_private *dev_priv = to_i915(dev); struct intel_plane_state *old_plane_state = to_intel_plane_state(plane->state); - int idx = intel_crtc->base.base.id, ret; bool mode_changed = needs_modeset(crtc_state); bool was_crtc_enabled = crtc->state->active; bool is_crtc_enabled = crtc_state->active; bool turn_off, turn_on, visible, was_visible; struct drm_framebuffer *fb = plane_state->fb; + int ret; if (crtc_state && INTEL_INFO(dev)->gen >= 9 && plane->type != DRM_PLANE_TYPE_CURSOR) { @@ -11976,7 +11977,9 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, turn_off = was_visible && (!visible || mode_changed); turn_on = visible && (!was_visible || mode_changed); - DRM_DEBUG_ATOMIC("[CRTC:%i] has [PLANE:%i] with fb %i\n", idx, + DRM_DEBUG_ATOMIC("[CRTC:%d:%s] has [PLANE:%i] with fb %i\n", + intel_crtc->base.base.id, + intel_crtc->base.name, plane->base.id, fb ? fb->base.id : -1); DRM_DEBUG_ATOMIC("[PLANE:%i] visible %i -> %i, off %i, on %i, ms %i\n", @@ -12271,7 +12274,8 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, struct intel_plane_state *state; struct drm_framebuffer *fb; - DRM_DEBUG_KMS("[CRTC:%d]%s config %p for pipe %c\n", crtc->base.base.id, + DRM_DEBUG_KMS("[CRTC:%d:%s]%s config %p for pipe %c\n", + crtc->base.base.id, crtc->base.name, context, pipe_config, pipe_name(crtc->pipe)); DRM_DEBUG_KMS("cpu_transcoder: %s\n", transcoder_name(pipe_config->cpu_transcoder)); @@ -13061,7 +13065,7 @@ verify_crtc_state(struct drm_crtc *crtc, pipe_config->base.crtc = crtc; pipe_config->base.state = old_state; - DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); + DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); active = dev_priv->display.get_pipe_config(intel_crtc, pipe_config); @@ -13878,8 +13882,8 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) state = drm_atomic_state_alloc(dev); if (!state) { - DRM_DEBUG_KMS("[CRTC:%d] crtc restore failed, out of memory", - crtc->base.id); + DRM_DEBUG_KMS("[CRTC:%d:%s] crtc restore failed, out of memory", + crtc->base.id, crtc->name); return; } @@ -15743,8 +15747,8 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) if (INTEL_INFO(dev)->gen < 4 && !intel_check_plane_mapping(crtc)) { bool plane; - DRM_DEBUG_KMS("[CRTC:%d] wrong plane connection detected!\n", - crtc->base.base.id); + DRM_DEBUG_KMS("[CRTC:%d:%s] wrong plane connection detected!\n", + crtc->base.base.id, crtc->base.name); /* Pipe has the wrong plane attached and the plane is active. * Temporarily change the plane mapping and disable everything @@ -15928,8 +15932,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) readout_plane_state(crtc); - DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", - crtc->base.base.id, + DRM_DEBUG_KMS("[CRTC:%d:%s] hw state readout: %s\n", + crtc->base.base.id, crtc->base.name, crtc->active ? "enabled" : "disabled"); } diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 02a7962..c0eff15 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -208,8 +208,8 @@ intel_find_shared_dpll(struct intel_crtc *crtc, if (memcmp(&crtc_state->dpll_hw_state, &shared_dpll[i].hw_state, sizeof(crtc_state->dpll_hw_state)) == 0) { - DRM_DEBUG_KMS("CRTC:%d sharing existing %s (crtc mask 0x%08x, active %x)\n", - crtc->base.base.id, pll->name, + DRM_DEBUG_KMS("[CRTC:%d:%s] sharing existing %s (crtc mask 0x%08x, active %x)\n", + crtc->base.base.id, crtc->base.name, pll->name, shared_dpll[i].crtc_mask, pll->active_mask); return pll; @@ -220,8 +220,8 @@ intel_find_shared_dpll(struct intel_crtc *crtc, for (i = range_min; i <= range_max; i++) { pll = &dev_priv->shared_dplls[i]; if (shared_dpll[i].crtc_mask == 0) { - DRM_DEBUG_KMS("CRTC:%d allocated %s\n", - crtc->base.base.id, pll->name); + DRM_DEBUG_KMS("[CRTC:%d:%s] allocated %s\n", + crtc->base.base.id, crtc->base.name, pll->name); return pll; } } @@ -358,8 +358,8 @@ ibx_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, i = (enum intel_dpll_id) crtc->pipe; pll = &dev_priv->shared_dplls[i]; - DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n", - crtc->base.base.id, pll->name); + DRM_DEBUG_KMS("[CRTC:%d:%s] using pre-allocated %s\n", + crtc->base.base.id, crtc->base.name, pll->name); } else { pll = intel_find_shared_dpll(crtc, crtc_state, DPLL_ID_PCH_PLL_A, @@ -1613,8 +1613,8 @@ bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, i = (enum intel_dpll_id) intel_dig_port->port; pll = intel_get_shared_dpll_by_id(dev_priv, i); - DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n", - crtc->base.base.id, pll->name); + DRM_DEBUG_KMS("[CRTC:%d:%s] using pre-allocated %s\n", + crtc->base.base.id, crtc->base.name, pll->name); intel_reference_shared_dpll(pll, crtc_state); diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 5a101a2..bdf64de 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -490,10 +490,10 @@ retry: } crtcs[i] = new_crtc; - DRM_DEBUG_KMS("connector %s on pipe %c [CRTC:%d]: %dx%d%s\n", + DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n", connector->name, - pipe_name(to_intel_crtc(connector->state->crtc)->pipe), connector->state->crtc->base.id, + connector->state->crtc->name, modes[i]->hdisplay, modes[i]->vdisplay, modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :""); -- cgit v0.10.2 From 72660ce0202601c092f83604326aa7cfd25b5a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 27 May 2016 20:59:20 +0300 Subject: drm/i915: Use plane->name in debug prints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have plane->name, so let's use that in debug messages instead of just printing the more or less useless object ID. v2: slap on a commit message Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1464371966-15190-3-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fecabc7..f636fd3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4310,9 +4310,9 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, bool force_detach = !fb || !plane_state->visible; - DRM_DEBUG_KMS("Updating scaler for [PLANE:%d] scaler_user index %u.%u\n", - intel_plane->base.base.id, intel_crtc->pipe, - drm_plane_index(&intel_plane->base)); + DRM_DEBUG_KMS("Updating scaler for [PLANE:%d:%s] scaler_user index %u.%u\n", + intel_plane->base.base.id, intel_plane->base.name, + intel_crtc->pipe, drm_plane_index(&intel_plane->base)); ret = skl_update_scaler(crtc_state, force_detach, drm_plane_index(&intel_plane->base), @@ -4328,8 +4328,9 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, /* check colorkey */ if (plane_state->ckey.flags != I915_SET_COLORKEY_NONE) { - DRM_DEBUG_KMS("[PLANE:%d] scaling with color key not allowed", - intel_plane->base.base.id); + DRM_DEBUG_KMS("[PLANE:%d:%s] scaling with color key not allowed", + intel_plane->base.base.id, + intel_plane->base.name); return -EINVAL; } @@ -4348,8 +4349,9 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, case DRM_FORMAT_VYUY: break; default: - DRM_DEBUG_KMS("[PLANE:%d] FB:%d unsupported scaling format 0x%x\n", - intel_plane->base.base.id, fb->base.id, fb->pixel_format); + DRM_DEBUG_KMS("[PLANE:%d:%s] FB:%d unsupported scaling format 0x%x\n", + intel_plane->base.base.id, intel_plane->base.name, + fb->base.id, fb->pixel_format); return -EINVAL; } @@ -11977,13 +11979,15 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, turn_off = was_visible && (!visible || mode_changed); turn_on = visible && (!was_visible || mode_changed); - DRM_DEBUG_ATOMIC("[CRTC:%d:%s] has [PLANE:%i] with fb %i\n", + DRM_DEBUG_ATOMIC("[CRTC:%d:%s] has [PLANE:%d:%s] with fb %i\n", intel_crtc->base.base.id, intel_crtc->base.name, - plane->base.id, fb ? fb->base.id : -1); + plane->base.id, plane->name, + fb ? fb->base.id : -1); - DRM_DEBUG_ATOMIC("[PLANE:%i] visible %i -> %i, off %i, on %i, ms %i\n", - plane->base.id, was_visible, visible, + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] visible %i -> %i, off %i, on %i, ms %i\n", + plane->base.id, plane->name, + was_visible, visible, turn_off, turn_on, mode_changed); if (turn_on) { @@ -12376,18 +12380,20 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, state = to_intel_plane_state(plane->state); fb = state->base.fb; if (!fb) { - DRM_DEBUG_KMS("%s PLANE:%d plane: %u.%u idx: %d " - "disabled, scaler_id = %d\n", + DRM_DEBUG_KMS("%s [PLANE:%d:%s] plane: %u.%u idx: %d " + "disabled, scaler_id = %d\n", plane->type == DRM_PLANE_TYPE_CURSOR ? "CURSOR" : "STANDARD", - plane->base.id, intel_plane->pipe, + plane->base.id, plane->name, + intel_plane->pipe, (crtc->base.primary == plane) ? 0 : intel_plane->plane + 1, drm_plane_index(plane), state->scaler_id); continue; } - DRM_DEBUG_KMS("%s PLANE:%d plane: %u.%u idx: %d enabled", + DRM_DEBUG_KMS("%s [PLANE:%d:%s] plane: %u.%u idx: %d enabled", plane->type == DRM_PLANE_TYPE_CURSOR ? "CURSOR" : "STANDARD", - plane->base.id, intel_plane->pipe, + plane->base.id, plane->name, + intel_plane->pipe, crtc->base.primary == plane ? 0 : intel_plane->plane + 1, drm_plane_index(plane)); DRM_DEBUG_KMS("\tFB:%d, fb = %ux%u format = 0x%x", -- cgit v0.10.2 From 4d5d72b7f1a66e5500691dc5cf1e10effc7f6942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 27 May 2016 20:59:21 +0300 Subject: drm/i915: Set crtc->name to "pipe A", "pipe B", etc. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: Fix intel_crtc leak on failure to allocate the name Use a local 'name' variable to make things easier v3: Pass the name as a function arguemnt to drm_crtc_init_with_planes() (Jani) v4: Pass the printf style format string to drm_crtc_init_with_planes() v5: Drop spurious code changes Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1464371966-15190-4-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f636fd3..476d769 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14477,7 +14477,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) goto fail; ret = drm_crtc_init_with_planes(dev, &intel_crtc->base, primary, - cursor, &intel_crtc_funcs, NULL); + cursor, &intel_crtc_funcs, + "pipe %c", pipe_name(pipe)); if (ret) goto fail; -- cgit v0.10.2 From 69ae561f4557d31a1dc6d23db5c2735a5568959c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 27 May 2016 20:59:22 +0300 Subject: drm/i915: Don't leak primary/cursor planes on crtc init failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call intel_plane_destroy() instead of drm_plane_cleanup() so that we also free the plane struct itself when bailing out of the crtc init. And make intel_plane_destroy() NULL tolerant to avoid having to check for it in the caller. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1464371966-15190-5-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 476d769..ada0198 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14157,9 +14157,11 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc, */ void intel_plane_destroy(struct drm_plane *plane) { - struct intel_plane *intel_plane = to_intel_plane(plane); + if (!plane) + return; + drm_plane_cleanup(plane); - kfree(intel_plane); + kfree(to_intel_plane(plane)); } const struct drm_plane_funcs intel_plane_funcs = { @@ -14512,10 +14514,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) return; fail: - if (primary) - drm_plane_cleanup(primary); - if (cursor) - drm_plane_cleanup(cursor); + intel_plane_destroy(primary); + intel_plane_destroy(cursor); kfree(crtc_state); kfree(intel_crtc); } -- cgit v0.10.2 From 38573dc1c316620beb0c27c2517f9b5c2c4ecdd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 27 May 2016 20:59:23 +0300 Subject: drm/i915: Give meaningful names to all the planes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's name our planes in a way that makes sense wrt. the spec: - skl+ -> "plane 1A", "plane 2A", "plane 1C", "cursor A" etc. - g4x+ -> "primary A", "primary B", "sprite A", "cursor C" etc. - pre-g4x -> "plane A", "cursor B" etc. v2: Rebase on top of the fixed/cleaned error paths Use a local 'name' variable to make things easier v3: Pass the name as a function argument to drm_universal_plane_init() (Jani) v3: Pass the printf style string to drm_universal_plane_init() Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1464371966-15190-6-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ada0198..888fc3f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14233,10 +14233,24 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, primary->disable_plane = i9xx_disable_primary_plane; } - ret = drm_universal_plane_init(dev, &primary->base, 0, - &intel_plane_funcs, - intel_primary_formats, num_formats, - DRM_PLANE_TYPE_PRIMARY, NULL); + if (INTEL_INFO(dev)->gen >= 9) + ret = drm_universal_plane_init(dev, &primary->base, 0, + &intel_plane_funcs, + intel_primary_formats, num_formats, + DRM_PLANE_TYPE_PRIMARY, + "plane 1%c", pipe_name(pipe)); + else if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev)) + ret = drm_universal_plane_init(dev, &primary->base, 0, + &intel_plane_funcs, + intel_primary_formats, num_formats, + DRM_PLANE_TYPE_PRIMARY, + "primary %c", pipe_name(pipe)); + else + ret = drm_universal_plane_init(dev, &primary->base, 0, + &intel_plane_funcs, + intel_primary_formats, num_formats, + DRM_PLANE_TYPE_PRIMARY, + "plane %c", plane_name(primary->plane)); if (ret) goto fail; @@ -14394,7 +14408,8 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev, &intel_plane_funcs, intel_cursor_formats, ARRAY_SIZE(intel_cursor_formats), - DRM_PLANE_TYPE_CURSOR, NULL); + DRM_PLANE_TYPE_CURSOR, + "cursor %c", pipe_name(pipe)); if (ret) goto fail; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 97b1a54..324ccb0 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1114,10 +1114,18 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) possible_crtcs = (1 << pipe); - ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, - &intel_plane_funcs, - plane_formats, num_plane_formats, - DRM_PLANE_TYPE_OVERLAY, NULL); + if (INTEL_INFO(dev)->gen >= 9) + ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, + &intel_plane_funcs, + plane_formats, num_plane_formats, + DRM_PLANE_TYPE_OVERLAY, + "plane %d%c", plane + 2, pipe_name(pipe)); + else + ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, + &intel_plane_funcs, + plane_formats, num_plane_formats, + DRM_PLANE_TYPE_OVERLAY, + "sprite %c", sprite_name(pipe, plane)); if (ret) goto fail; -- cgit v0.10.2 From 580d8ed522e0ebbdc83963dc20bc17dbcd283e58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 27 May 2016 20:59:24 +0300 Subject: drm/i915: Give encoders useful names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than let the core generate usless encoder names, let's pass in something that actually identifies the piece of hardware we're dealing with. v2: Use 'DSI %c' instead of 'MIPI %c' for DSI encoders (Jani) v3: Use port_name() in DSI code since we have it Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1464371966-15190-7-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 3fbb6fc..6229681 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -839,7 +839,7 @@ void intel_crt_init(struct drm_device *dev) &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs, - DRM_MODE_ENCODER_DAC, NULL); + DRM_MODE_ENCODER_DAC, "CRT"); intel_connector_attach_encoder(intel_connector, &crt->base); diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index c454744..022b41d 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2347,7 +2347,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port) encoder = &intel_encoder->base; drm_encoder_init(dev, encoder, &intel_ddi_funcs, - DRM_MODE_ENCODER_TMDS, NULL); + DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port)); intel_encoder->compute_config = intel_ddi_compute_config; intel_encoder->enable = intel_enable_ddi; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index aa9c59e..096acbf0 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5590,7 +5590,7 @@ intel_dp_init(struct drm_device *dev, encoder = &intel_encoder->base; if (drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs, - DRM_MODE_ENCODER_TMDS, NULL)) + DRM_MODE_ENCODER_TMDS, "DP %c", port_name(port))) goto err_encoder_init; intel_encoder->compute_config = intel_dp_compute_config; diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 7a34090..f62ca9a 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -534,7 +534,7 @@ intel_dp_create_fake_mst_encoder(struct intel_digital_port *intel_dig_port, enum intel_mst->primary = intel_dig_port; drm_encoder_init(dev, &intel_encoder->base, &intel_dp_mst_enc_funcs, - DRM_MODE_ENCODER_DPMST, NULL); + DRM_MODE_ENCODER_DPMST, "DP-MST %c", pipe_name(pipe)); intel_encoder->type = INTEL_OUTPUT_DP_MST; intel_encoder->crtc_mask = 0x7; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 4009618..cbe2537 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -1450,7 +1450,7 @@ void intel_dsi_init(struct drm_device *dev) connector = &intel_connector->base; drm_encoder_init(dev, encoder, &intel_dsi_funcs, DRM_MODE_ENCODER_DSI, - NULL); + "DSI %c", port_name(port)); intel_encoder->compute_config = intel_dsi_compute_config; intel_encoder->pre_enable = intel_dsi_pre_enable; diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 286baec..a456f2e 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -406,6 +406,18 @@ intel_dvo_get_current_mode(struct drm_connector *connector) return mode; } +static char intel_dvo_port_name(i915_reg_t dvo_reg) +{ + if (i915_mmio_reg_equal(dvo_reg, DVOA)) + return 'A'; + else if (i915_mmio_reg_equal(dvo_reg, DVOB)) + return 'B'; + else if (i915_mmio_reg_equal(dvo_reg, DVOC)) + return 'C'; + else + return '?'; +} + void intel_dvo_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -428,8 +440,6 @@ void intel_dvo_init(struct drm_device *dev) intel_dvo->attached_connector = intel_connector; intel_encoder = &intel_dvo->base; - drm_encoder_init(dev, &intel_encoder->base, - &intel_dvo_enc_funcs, encoder_type, NULL); intel_encoder->disable = intel_disable_dvo; intel_encoder->enable = intel_enable_dvo; @@ -496,6 +506,10 @@ void intel_dvo_init(struct drm_device *dev) if (!dvoinit) continue; + drm_encoder_init(dev, &intel_encoder->base, + &intel_dvo_enc_funcs, encoder_type, + "DVO %c", intel_dvo_port_name(dvo->dvo_reg)); + intel_encoder->type = INTEL_OUTPUT_DVO; intel_encoder->crtc_mask = (1 << 0) | (1 << 1); switch (dvo->type) { diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 6b52c6a..eb455ea 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1945,7 +1945,7 @@ void intel_hdmi_init(struct drm_device *dev, intel_encoder = &intel_dig_port->base; drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs, - DRM_MODE_ENCODER_TMDS, NULL); + DRM_MODE_ENCODER_TMDS, "HDMI %c", port_name(port)); intel_encoder->compute_config = intel_hdmi_compute_config; if (HAS_PCH_SPLIT(dev)) { diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index d65fd94..56eb3bd 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -978,7 +978,7 @@ void intel_lvds_init(struct drm_device *dev) DRM_MODE_CONNECTOR_LVDS); drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs, - DRM_MODE_ENCODER_LVDS, NULL); + DRM_MODE_ENCODER_LVDS, "LVDS"); intel_encoder->enable = intel_enable_lvds; intel_encoder->pre_enable = intel_pre_enable_lvds; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 2128fae..1a71456 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2981,7 +2981,7 @@ bool intel_sdvo_init(struct drm_device *dev, intel_encoder = &intel_sdvo->base; intel_encoder->type = INTEL_OUTPUT_SDVO; drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0, - NULL); + "SDVO %c", port_name(port)); /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 223129d..1f3a0e1 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1591,7 +1591,7 @@ intel_tv_init(struct drm_device *dev) DRM_MODE_CONNECTOR_SVIDEO); drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs, - DRM_MODE_ENCODER_TVDAC, NULL); + DRM_MODE_ENCODER_TVDAC, "TV"); intel_encoder->compute_config = intel_tv_compute_config; intel_encoder->get_config = intel_tv_get_config; -- cgit v0.10.2 From 1d577e02eba737ec586303937ce93f17650c2588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 27 May 2016 20:59:25 +0300 Subject: drm/i915: kill STANDARD/CURSOR plane screams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop yelling the plane type. "STANDARD" doesn't mean anything anyway. Let's just use the plane name here. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1464371966-15190-8-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 888fc3f..fd140c3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12380,31 +12380,24 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, state = to_intel_plane_state(plane->state); fb = state->base.fb; if (!fb) { - DRM_DEBUG_KMS("%s [PLANE:%d:%s] plane: %u.%u idx: %d " - "disabled, scaler_id = %d\n", - plane->type == DRM_PLANE_TYPE_CURSOR ? "CURSOR" : "STANDARD", - plane->base.id, plane->name, - intel_plane->pipe, - (crtc->base.primary == plane) ? 0 : intel_plane->plane + 1, - drm_plane_index(plane), state->scaler_id); + DRM_DEBUG_KMS("[PLANE:%d:%s] disabled, scaler_id = %d\n", + plane->base.id, plane->name, state->scaler_id); continue; } - DRM_DEBUG_KMS("%s [PLANE:%d:%s] plane: %u.%u idx: %d enabled", - plane->type == DRM_PLANE_TYPE_CURSOR ? "CURSOR" : "STANDARD", - plane->base.id, plane->name, - intel_plane->pipe, - crtc->base.primary == plane ? 0 : intel_plane->plane + 1, - drm_plane_index(plane)); - DRM_DEBUG_KMS("\tFB:%d, fb = %ux%u format = 0x%x", - fb->base.id, fb->width, fb->height, fb->pixel_format); - DRM_DEBUG_KMS("\tscaler:%d src (%u, %u) %ux%u dst (%u, %u) %ux%u\n", - state->scaler_id, - state->src.x1 >> 16, state->src.y1 >> 16, - drm_rect_width(&state->src) >> 16, - drm_rect_height(&state->src) >> 16, - state->dst.x1, state->dst.y1, - drm_rect_width(&state->dst), drm_rect_height(&state->dst)); + DRM_DEBUG_KMS("[PLANE:%d:%s] enabled", + plane->base.id, plane->name); + DRM_DEBUG_KMS("\tFB:%d, fb = %ux%u format = %s", + fb->base.id, fb->width, fb->height, + drm_get_format_name(fb->pixel_format)); + DRM_DEBUG_KMS("\tscaler:%d src %dx%d+%d+%d dst %dx%d+%d+%d\n", + state->scaler_id, + state->src.x1 >> 16, state->src.y1 >> 16, + drm_rect_width(&state->src) >> 16, + drm_rect_height(&state->src) >> 16, + state->dst.x1, state->dst.y1, + drm_rect_width(&state->dst), + drm_rect_height(&state->dst)); } } -- cgit v0.10.2 From 1800ad255c4f0fdea3355d7055901482efa7e38a Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Tue, 31 May 2016 13:58:27 +0530 Subject: drm/i915: Update GEN6_PMINTRMSK setup with GuC enabled On Loading, GuC sets PM interrupts routing (bit 31) and clears ARAT expired interrupt (bit 9). Host turbo also updates this register in RPS flows. This patch ensures bit 31 and bit 9 setup by GuC persists. ARAT timer interrupt is needed in GuC for various features. It also facilitates halting GuC and hence achieving RC6. PM interrupt routing will not impact RPS interrupt reception by host as GuC will redirect them. This patch fixes igt test pm_rc6_residency that was failing with guc load/submission enabled. Tested with SKL GuC v6.1 and BXT GuC v5.1 and v8.7. v2: i915_irq/i915_pm decoupling from intel_guc. (ChrisW) v3: restructuring the mask update and rebase w.r.t Ville's patch. (ChrisW) v4: Updating the pm_intr_keep during direct_interrupts_to_guc. (Sagar) Cc: Chris Harris Cc: Zhe Wang Cc: Deepak S Cc: Satyanantha, Rama Gopal M Cc: Akash Goel Testcase: igt/pm_rc6_residency Signed-off-by: Sagar Arun Kamble Tested-by: Matt Roper Reviewed-by: Chris Wilson Signed-off-by: Matt Roper Link: http://patchwork.freedesktop.org/patch/msgid/1464683307-19475-1-git-send-email-sagar.a.kamble@intel.com diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index ac7e569..e4f2c55 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1308,6 +1308,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused) } seq_printf(m, "PM IER=0x%08x IMR=0x%08x ISR=0x%08x IIR=0x%08x, MASK=0x%08x\n", pm_ier, pm_imr, pm_isr, pm_iir, pm_mask); + seq_printf(m, "pm_intr_keep: 0x%08x\n", dev_priv->rps.pm_intr_keep); seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); seq_printf(m, "Render p-state ratio: %d\n", (gt_perf_status & (IS_GEN9(dev) ? 0x1ff00 : 0xff00)) >> 8); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e4c8e34..c1e61ff 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1127,6 +1127,8 @@ struct intel_gen6_power_mgmt { bool interrupts_enabled; u32 pm_iir; + u32 pm_intr_keep; + /* Frequencies are stored in potentially platform dependent multiples. * In other words, *_freq needs to be multiplied by X to be interesting. * Soft limits are those which are used for the dynamic reclocking done diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index caaf1e2..5c73783 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -364,19 +364,7 @@ void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv) u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask) { - /* - * SNB,IVB can while VLV,CHV may hard hang on looping batchbuffer - * if GEN6_PM_UP_EI_EXPIRED is masked. - * - * TODO: verify if this can be reproduced on VLV,CHV. - */ - if (INTEL_INFO(dev_priv)->gen <= 7 && !IS_HASWELL(dev_priv)) - mask &= ~GEN6_PM_RP_UP_EI_EXPIRED; - - if (INTEL_INFO(dev_priv)->gen >= 8) - mask &= ~GEN8_PMINTR_REDIRECT_TO_NON_DISP; - - return mask; + return (mask & ~dev_priv->rps.pm_intr_keep); } void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv) @@ -4578,6 +4566,20 @@ void intel_irq_init(struct drm_i915_private *dev_priv) else dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS; + dev_priv->rps.pm_intr_keep = 0; + + /* + * SNB,IVB can while VLV,CHV may hard hang on looping batchbuffer + * if GEN6_PM_UP_EI_EXPIRED is masked. + * + * TODO: verify if this can be reproduced on VLV,CHV. + */ + if (INTEL_INFO(dev_priv)->gen <= 7 && !IS_HASWELL(dev_priv)) + dev_priv->rps.pm_intr_keep |= GEN6_PM_RP_UP_EI_EXPIRED; + + if (INTEL_INFO(dev_priv)->gen >= 8) + dev_priv->rps.pm_intr_keep |= GEN8_PMINTR_REDIRECT_TO_NON_DISP; + INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work, i915_hangcheck_elapsed); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e307725..0845059 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7031,7 +7031,7 @@ enum skl_disp_power_wells { #define VLV_RCEDATA _MMIO(0xA0BC) #define GEN6_RC6pp_THRESHOLD _MMIO(0xA0C0) #define GEN6_PMINTRMSK _MMIO(0xA168) -#define GEN8_PMINTR_REDIRECT_TO_NON_DISP (1<<31) +#define GEN8_PMINTR_REDIRECT_TO_NON_DISP (1<<31) #define VLV_PWRDWNUPCTL _MMIO(0xA294) #define GEN9_MEDIA_PG_IDLE_HYSTERESIS _MMIO(0xA0C4) #define GEN9_RENDER_PG_IDLE_HYSTERESIS _MMIO(0xA0C8) diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c index 29273e5..f2b88c7 100644 --- a/drivers/gpu/drm/i915/intel_guc_loader.c +++ b/drivers/gpu/drm/i915/intel_guc_loader.c @@ -103,6 +103,7 @@ static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv) { struct intel_engine_cs *engine; int irqs; + u32 tmp; /* tell all command streamers to forward interrupts and vblank to GuC */ irqs = _MASKED_FIELD(GFX_FORWARD_VBLANK_MASK, GFX_FORWARD_VBLANK_ALWAYS); @@ -117,6 +118,16 @@ static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv) I915_WRITE(GUC_BCS_RCS_IER, ~irqs); I915_WRITE(GUC_VCS2_VCS1_IER, ~irqs); I915_WRITE(GUC_WD_VECS_IER, ~irqs); + + /* + * If GuC has routed PM interrupts to itself, don't keep it. + * and keep other interrupts those are unmasked by GuC. + */ + tmp = I915_READ(GEN6_PMINTRMSK); + if (tmp & GEN8_PMINTR_REDIRECT_TO_NON_DISP) { + dev_priv->rps.pm_intr_keep |= ~(tmp & ~GEN8_PMINTR_REDIRECT_TO_NON_DISP); + dev_priv->rps.pm_intr_keep &= ~GEN8_PMINTR_REDIRECT_TO_NON_DISP; + } } static u32 get_gttype(struct drm_i915_private *dev_priv) -- cgit v0.10.2 From 457c52d87e5dac9a4cf1a6a287e60ea7645067d4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 1 Jun 2016 08:27:50 +0100 Subject: drm/i915: Only ignore eDP ports that are connected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the VBT says that a certain port should be eDP (and hence fused off from HDMI), but in reality it isn't, we need to try and acquire the HDMI connection instead. So only trust the VBT edp setting if we can connect to an eDP device on that port. Fixes: d2182a6608 (drm/i915: Don't register HDMI connectors for eDP ports on VLV/CHV) References: https://bugs.freedesktop.org/show_bug.cgi?id=96288 Signed-off-by: Chris Wilson Tested-by: Phidias Chiang Cc: Ville Syrjälä Cc: Jani Nikula Cc: Daniel Vetter Reviewed-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1464766070-31623-1-git-send-email-chris@chris-wilson.co.uk diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fd140c3..08b173c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14702,6 +14702,8 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(PCH_DP_D) & DP_DETECTED) intel_dp_init(dev, PCH_DP_D, PORT_D); } else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) { + bool has_edp; + /* * The DP_DETECTED bit is the latched state of the DDC * SDA pin at boot. However since eDP doesn't require DDC @@ -14711,19 +14713,17 @@ static void intel_setup_outputs(struct drm_device *dev) * eDP ports. Consult the VBT as well as DP_DETECTED to * detect eDP ports. */ - if (I915_READ(VLV_HDMIB) & SDVO_DETECTED && - !intel_dp_is_edp(dev, PORT_B)) + has_edp = intel_dp_is_edp(dev, PORT_B); + if (I915_READ(VLV_DP_B) & DP_DETECTED || has_edp) + has_edp &= intel_dp_init(dev, VLV_DP_B, PORT_B); + if (I915_READ(VLV_HDMIB) & SDVO_DETECTED && !has_edp) intel_hdmi_init(dev, VLV_HDMIB, PORT_B); - if (I915_READ(VLV_DP_B) & DP_DETECTED || - intel_dp_is_edp(dev, PORT_B)) - intel_dp_init(dev, VLV_DP_B, PORT_B); - if (I915_READ(VLV_HDMIC) & SDVO_DETECTED && - !intel_dp_is_edp(dev, PORT_C)) + has_edp = intel_dp_is_edp(dev, PORT_C); + if (I915_READ(VLV_DP_C) & DP_DETECTED || has_edp) + has_edp &= intel_dp_init(dev, VLV_DP_C, PORT_C); + if (I915_READ(VLV_HDMIC) & SDVO_DETECTED && !has_edp) intel_hdmi_init(dev, VLV_HDMIC, PORT_C); - if (I915_READ(VLV_DP_C) & DP_DETECTED || - intel_dp_is_edp(dev, PORT_C)) - intel_dp_init(dev, VLV_DP_C, PORT_C); if (IS_CHERRYVIEW(dev)) { /* eDP not supported on port D, so don't check VBT */ diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 096acbf0..7dfff87 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5568,9 +5568,9 @@ fail: return false; } -void -intel_dp_init(struct drm_device *dev, - i915_reg_t output_reg, enum port port) +bool intel_dp_init(struct drm_device *dev, + i915_reg_t output_reg, + enum port port) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_digital_port *intel_dig_port; @@ -5580,7 +5580,7 @@ intel_dp_init(struct drm_device *dev, intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL); if (!intel_dig_port) - return; + return false; intel_connector = intel_connector_alloc(); if (!intel_connector) @@ -5637,7 +5637,7 @@ intel_dp_init(struct drm_device *dev, if (!intel_dp_init_connector(intel_dig_port, intel_connector)) goto err_init_connector; - return; + return true; err_init_connector: drm_encoder_cleanup(encoder); @@ -5645,8 +5645,7 @@ err_encoder_init: kfree(intel_connector); err_connector_alloc: kfree(intel_dig_port); - - return; + return false; } void intel_dp_mst_suspend(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9b5f663..ebe7b34 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1312,7 +1312,7 @@ void intel_csr_ucode_suspend(struct drm_i915_private *); void intel_csr_ucode_resume(struct drm_i915_private *); /* intel_dp.c */ -void intel_dp_init(struct drm_device *dev, i915_reg_t output_reg, enum port port); +bool intel_dp_init(struct drm_device *dev, i915_reg_t output_reg, enum port port); bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector); void intel_dp_set_link_params(struct intel_dp *intel_dp, -- cgit v0.10.2 From edd4156fd69a141282c79aaa677ab127d711a927 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Mon, 16 May 2016 15:51:58 -0700 Subject: drm/i915: Don't try to calculate relative data rates during hw readout We don't actually read out full plane state during driver startup (only whether the primary plane is enabled/disabled), so all of the src/dest rectangles are invalid at this point. However this calculation was needless anyway since we re-calculate them from scratch on the very first atomic transaction after boot anyway. Signed-off-by: Matt Roper Reviewed-by: Kumar Mahesh Link: http://patchwork.freedesktop.org/patch/msgid/1463439121-28974-2-git-send-email-matthew.d.roper@intel.com diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b6dfd02..3cf36dc 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4046,7 +4046,6 @@ void skl_wm_get_hw_state(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct skl_ddb_allocation *ddb = &dev_priv->wm.skl_hw.ddb; struct drm_crtc *crtc; - struct intel_crtc *intel_crtc; skl_ddb_get_hw_state(dev_priv, ddb); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) @@ -4059,23 +4058,6 @@ void skl_wm_get_hw_state(struct drm_device *dev) /* Easy/common case; just sanitize DDB now if everything off */ memset(ddb, 0, sizeof(*ddb)); } - - /* Calculate plane data rates */ - for_each_intel_crtc(dev, intel_crtc) { - struct intel_crtc_state *cstate = intel_crtc->config; - struct intel_plane *intel_plane; - - for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { - const struct drm_plane_state *pstate = - intel_plane->base.state; - int id = skl_wm_plane_id(intel_plane); - - cstate->wm.skl.plane_data_rate[id] = - skl_plane_relative_data_rate(cstate, pstate, 0); - cstate->wm.skl.plane_y_data_rate[id] = - skl_plane_relative_data_rate(cstate, pstate, 1); - } - } } static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) -- cgit v0.10.2 From cbcfd14b3b3583816bb3ffdd5e880a53a2d3856b Mon Sep 17 00:00:00 2001 From: "Kumar, Mahesh" Date: Tue, 31 May 2016 09:58:59 -0700 Subject: drm/i915/skl+: calculate ddb minimum allocation (v6) don't always use 8 ddb as minimum, instead calculate using proper algorithm. v2: optimizations as per Matt's comments. v3 (by Matt): - Fix boolean logic for !fb test in skl_ddb_min_alloc() - Adjust negative tiling format comparisons in skl_ddb_min_alloc() to improve readability. v4 (by Matt): - Rebase onto recent atomic watermark changes - Slight tweaks to code flow to make the logic more closely match the description in the bspec. v5 (by Matt): - Handle minimum scanline calculation properly for 4 & 8 bpp formats. 8bpp isn't actually possible right now, but it's listed in the bspec so I've included it here for forward compatibility (similar to how we have logic for NV12). v6 (by Matt): - Calculate plane_bpp correctly for non-NV12 formats. (Mahesh) Cc: matthew.d.roper@intel.com Signed-off-by: Kumar, Mahesh Signed-off-by: Matt Roper Reviewed-by: Kumar Mahesh Link: http://patchwork.freedesktop.org/patch/msgid/1464713939-10440-1-git-send-email-matthew.d.roper@intel.com diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3cf36dc..4e0a952 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3042,6 +3042,69 @@ skl_get_total_relative_data_rate(struct intel_crtc_state *intel_cstate) return total_data_rate; } +static uint16_t +skl_ddb_min_alloc(const struct drm_plane_state *pstate, + const int y) +{ + struct drm_framebuffer *fb = pstate->fb; + struct intel_plane_state *intel_pstate = to_intel_plane_state(pstate); + uint32_t src_w, src_h; + uint32_t min_scanlines = 8; + uint8_t plane_bpp; + + if (WARN_ON(!fb)) + return 0; + + /* For packed formats, no y-plane, return 0 */ + if (y && fb->pixel_format != DRM_FORMAT_NV12) + return 0; + + /* For Non Y-tile return 8-blocks */ + if (fb->modifier[0] != I915_FORMAT_MOD_Y_TILED && + fb->modifier[0] != I915_FORMAT_MOD_Yf_TILED) + return 8; + + src_w = drm_rect_width(&intel_pstate->src) >> 16; + src_h = drm_rect_height(&intel_pstate->src) >> 16; + + if (intel_rotation_90_or_270(pstate->rotation)) + swap(src_w, src_h); + + /* Halve UV plane width and height for NV12 */ + if (fb->pixel_format == DRM_FORMAT_NV12 && !y) { + src_w /= 2; + src_h /= 2; + } + + if (fb->pixel_format == DRM_FORMAT_NV12 && !y) + plane_bpp = drm_format_plane_cpp(fb->pixel_format, 1); + else + plane_bpp = drm_format_plane_cpp(fb->pixel_format, 0); + + if (intel_rotation_90_or_270(pstate->rotation)) { + switch (plane_bpp) { + case 1: + min_scanlines = 32; + break; + case 2: + min_scanlines = 16; + break; + case 4: + min_scanlines = 8; + break; + case 8: + min_scanlines = 4; + break; + default: + WARN(1, "Unsupported pixel depth %u for rotation", + plane_bpp); + min_scanlines = 32; + } + } + + return DIV_ROUND_UP((4 * src_w * plane_bpp), 512) * min_scanlines/4 + 3; +} + static int skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, struct skl_ddb_allocation *ddb /* out */) @@ -3104,11 +3167,8 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, continue; } - minimum[id] = 8; - if (pstate->fb->pixel_format == DRM_FORMAT_NV12) - y_minimum[id] = 8; - else - y_minimum[id] = 0; + minimum[id] = skl_ddb_min_alloc(pstate, 0); + y_minimum[id] = skl_ddb_min_alloc(pstate, 1); } for (i = 0; i < PLANE_CURSOR; i++) { -- cgit v0.10.2 From 9c2f7a9d6081072e762189a7341934d6e235cad6 Mon Sep 17 00:00:00 2001 From: "Kumar, Mahesh" Date: Mon, 16 May 2016 15:52:00 -0700 Subject: drm/i915/skl+: calculate plane pixel rate (v4) Don't use pipe pixel rate for plane pixel rate. Calculate plane pixel according to formula adjusted plane_pixel_rate = adjusted pipe_pixel_rate * downscale ammount downscale amount = max[1, src_h/dst_h] * max[1, src_w/dst_w] if 90/270 rotation use rotated width & height v2: use intel_plane_state->visible instead of (fb == NULL) as per Matt's comment. v3 (by Matt): - Keep downscale amount in 16.16 fixed point rather than converting to decimal fixed point. - Store adjusted plane pixel rate in plane state instead of the plane parameters structure that we no longer use. v4 (by Matt): - Significant rebasing onto latest atomic watermark work - Don't bother storing plane pixel rate in state; just calculate it right before the calls that make use of it. - Fix downscale calculations to actually use width values when computing downscale_w rather than copy/pasted height values. Cc: matthew.d.roper@intel.com Signed-off-by: Kumar, Mahesh Signed-off-by: Matt Roper Reviewed-by: Kumar Mahesh Link: http://patchwork.freedesktop.org/patch/msgid/1463439121-28974-4-git-send-email-matthew.d.roper@intel.com diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 4e0a952..ceb1eecd 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -26,6 +26,7 @@ */ #include +#include #include "i915_drv.h" #include "intel_drv.h" #include "../../../platform/x86/intel_ips.h" @@ -2949,6 +2950,46 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, } } +/* + * Determines the downscale amount of a plane for the purposes of watermark calculations. + * The bspec defines downscale amount as: + * + * """ + * Horizontal down scale amount = maximum[1, Horizontal source size / + * Horizontal destination size] + * Vertical down scale amount = maximum[1, Vertical source size / + * Vertical destination size] + * Total down scale amount = Horizontal down scale amount * + * Vertical down scale amount + * """ + * + * Return value is provided in 16.16 fixed point form to retain fractional part. + * Caller should take care of dividing & rounding off the value. + */ +static uint32_t +skl_plane_downscale_amount(const struct intel_plane_state *pstate) +{ + uint32_t downscale_h, downscale_w; + uint32_t src_w, src_h, dst_w, dst_h; + + if (WARN_ON(!pstate->visible)) + return DRM_PLANE_HELPER_NO_SCALING; + + /* n.b., src is 16.16 fixed point, dst is whole integer */ + src_w = drm_rect_width(&pstate->src); + src_h = drm_rect_height(&pstate->src); + dst_w = drm_rect_width(&pstate->dst); + dst_h = drm_rect_height(&pstate->dst); + if (intel_rotation_90_or_270(pstate->base.rotation)) + swap(dst_w, dst_h); + + downscale_h = max(src_h / dst_h, (uint32_t)DRM_PLANE_HELPER_NO_SCALING); + downscale_w = max(src_w / dst_w, (uint32_t)DRM_PLANE_HELPER_NO_SCALING); + + /* Provide result in 16.16 fixed point */ + return (uint64_t)downscale_w * downscale_h >> 16; +} + static unsigned int skl_plane_relative_data_rate(const struct intel_crtc_state *cstate, const struct drm_plane_state *pstate, @@ -3285,6 +3326,30 @@ static uint32_t skl_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal, return ret; } +static uint32_t skl_adjusted_plane_pixel_rate(const struct intel_crtc_state *cstate, + struct intel_plane_state *pstate) +{ + uint64_t adjusted_pixel_rate; + uint64_t downscale_amount; + uint64_t pixel_rate; + + /* Shouldn't reach here on disabled planes... */ + if (WARN_ON(!pstate->visible)) + return 0; + + /* + * Adjusted plane pixel rate is just the pipe's adjusted pixel rate + * with additional adjustments for plane-specific scaling. + */ + adjusted_pixel_rate = skl_pipe_pixel_rate(cstate); + downscale_amount = skl_plane_downscale_amount(pstate); + + pixel_rate = adjusted_pixel_rate * downscale_amount >> 16; + WARN_ON(pixel_rate != clamp_t(uint32_t, pixel_rate, 0, ~0)); + + return pixel_rate; +} + static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, struct intel_crtc_state *cstate, struct intel_plane_state *intel_pstate, @@ -3303,6 +3368,7 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, uint32_t selected_result; uint8_t cpp; uint32_t width = 0, height = 0; + uint32_t plane_pixel_rate; if (latency == 0 || !cstate->base.active || !intel_pstate->visible) { *enabled = false; @@ -3316,9 +3382,10 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, swap(width, height); cpp = drm_format_plane_cpp(fb->pixel_format, 0); - method1 = skl_wm_method1(skl_pipe_pixel_rate(cstate), - cpp, latency); - method2 = skl_wm_method2(skl_pipe_pixel_rate(cstate), + plane_pixel_rate = skl_adjusted_plane_pixel_rate(cstate, intel_pstate); + + method1 = skl_wm_method1(plane_pixel_rate, cpp, latency); + method2 = skl_wm_method2(plane_pixel_rate, cstate->base.adjusted_mode.crtc_htotal, width, cpp, -- cgit v0.10.2 From 8d19d7d9dbc25d1a1ffa602ed9eff25a88c98163 Mon Sep 17 00:00:00 2001 From: "Kumar, Mahesh" Date: Thu, 19 May 2016 15:03:01 -0700 Subject: drm/i915/skl+: Use scaling amount for plane data rate calculation (v4) if downscaling is enabled plane data rate increases according to scaling amount. take scaling amount under consideration while calculating plane data rate v2: Address Matt's comments, where data rate was overridden because of missing else. v3 (by Matt): - Add braces to 'else' branch to match kernel coding style - Adjust final calculation now that skl_plane_downscale_amount() returns 16.16 fixed point value instead of a decimal fixed point v4 (by Matt): - Avoid integer overflow by making sure final multiplication is treated as 64-bit. Cc: matthew.d.roper@intel.com Signed-off-by: Kumar, Mahesh Signed-off-by: Matt Roper Reviewed-by: Kumar Mahesh Link: http://patchwork.freedesktop.org/patch/msgid/1463695381-21368-1-git-send-email-matthew.d.roper@intel.com diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ceb1eecd..0827459 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2997,6 +2997,7 @@ skl_plane_relative_data_rate(const struct intel_crtc_state *cstate, { struct intel_plane_state *intel_pstate = to_intel_plane_state(pstate); struct drm_framebuffer *fb = pstate->fb; + uint32_t down_scale_amount, data_rate; uint32_t width = 0, height = 0; unsigned format = fb ? fb->pixel_format : DRM_FORMAT_XRGB8888; @@ -3016,15 +3017,19 @@ skl_plane_relative_data_rate(const struct intel_crtc_state *cstate, /* for planar format */ if (format == DRM_FORMAT_NV12) { if (y) /* y-plane data rate */ - return width * height * + data_rate = width * height * drm_format_plane_cpp(format, 0); else /* uv-plane data rate */ - return (width / 2) * (height / 2) * + data_rate = (width / 2) * (height / 2) * drm_format_plane_cpp(format, 1); + } else { + /* for packed formats */ + data_rate = width * height * drm_format_plane_cpp(format, 0); } - /* for packed formats */ - return width * height * drm_format_plane_cpp(format, 0); + down_scale_amount = skl_plane_downscale_amount(intel_pstate); + + return (uint64_t)data_rate * down_scale_amount >> 16; } /* -- cgit v0.10.2 From fa05178c5dc3d1a3ad370f101cad01cf9dd3bbf9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 1 Jun 2016 18:08:43 +0100 Subject: drm/i915: Silence "unexpected child device config size" for VBT on 845g MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My old 845g complains that the child_device_size inside its VBT, version 110, is incorrect. Let's fiddle with the version matching such that it works with this VBT (i.e. treat BIOS v110 as having the same size as v108). Fixes [drm:intel_bios_init] *ERROR* Unexpected child device config size 27 (expected 33 for VBT version 110) Whether this is correct, no one knows - but it works for this particular machine. Signed-off-by: Chris Wilson Acked-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1464800923-6054-1-git-send-email-chris@chris-wilson.co.uk diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 624e755..e04e03b 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1206,7 +1206,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv, } if (bdb->version < 106) { expected_size = 22; - } else if (bdb->version < 109) { + } else if (bdb->version < 111) { expected_size = 27; } else if (bdb->version < 195) { BUILD_BUG_ON(sizeof(struct old_child_dev_config) != 33); -- cgit v0.10.2 From df457245b5b7515cf97763ebd8975229e34d4cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 31 May 2016 12:08:34 +0300 Subject: drm/i915: Extract physical display dimensions from VBT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VBT has these mysterious H/V image sizes as part of the display timings. Looking at some dumps those appear to be the physical dimensions in mm. Which makes sense since the timing descriptor matches the format used by EDID detailed timing descriptor, which defines these as "H/V Addressable Video Image Size in mm". So let's use that information from the panel fixed mode to get the physical dimensions for LVDS/eDP/DSI displays. And with that we can fill out the display_info so that userspace can get at it via GetConnector. v2: Use (hi<<8)|lo instead of broken (hi<<4)+lo Handle LVDS and eDP too Cc: Stephen Just Tested-by: Stephen Just Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=96255 Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1464685714-30507-1-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index e04e03b..713a02d 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -139,6 +139,11 @@ fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, else panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC; + panel_fixed_mode->width_mm = (dvo_timing->himage_hi << 8) | + dvo_timing->himage_lo; + panel_fixed_mode->height_mm = (dvo_timing->vimage_hi << 8) | + dvo_timing->vimage_lo; + /* Some VBTs have bogus h/vtotal values */ if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7dfff87..c92d593 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5370,8 +5370,11 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, if (!fixed_mode && dev_priv->vbt.lfp_lvds_vbt_mode) { fixed_mode = drm_mode_duplicate(dev, dev_priv->vbt.lfp_lvds_vbt_mode); - if (fixed_mode) + if (fixed_mode) { fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; + connector->display_info.width_mm = fixed_mode->width_mm; + connector->display_info.height_mm = fixed_mode->height_mm; + } } mutex_unlock(&dev->mode_config.mutex); diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index cbe2537..c70132a 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -1578,6 +1578,9 @@ void intel_dsi_init(struct drm_device *dev) goto err; } + connector->display_info.width_mm = fixed_mode->width_mm; + connector->display_info.height_mm = fixed_mode->height_mm; + intel_panel_init(&intel_connector->panel, fixed_mode, NULL); intel_dsi_add_properties(intel_connector); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 56eb3bd..62eaa89 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -1082,6 +1082,8 @@ void intel_lvds_init(struct drm_device *dev) fixed_mode = drm_mode_duplicate(dev, dev_priv->vbt.lfp_lvds_vbt_mode); if (fixed_mode) { fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; + connector->display_info.width_mm = fixed_mode->width_mm; + connector->display_info.height_mm = fixed_mode->height_mm; goto out; } } diff --git a/drivers/gpu/drm/i915/intel_vbt_defs.h b/drivers/gpu/drm/i915/intel_vbt_defs.h index 4f9799f..68db962 100644 --- a/drivers/gpu/drm/i915/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/intel_vbt_defs.h @@ -403,9 +403,10 @@ struct lvds_dvo_timing { u8 vsync_off:4; u8 rsvd0:6; u8 hsync_off_hi:2; - u8 h_image; - u8 v_image; - u8 max_hv; + u8 himage_lo; + u8 vimage_lo; + u8 vimage_hi:4; + u8 himage_hi:4; u8 h_border; u8 v_border; u8 rsvd1:3; -- cgit v0.10.2 From 1750d59dfa3caf1fc5354a2217f0e83d717c9b22 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 6 Jun 2016 00:29:53 +0200 Subject: drm/i915: Update DRIVER_DATE to 20160606 Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 96d5034..0113207 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -66,7 +66,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20160522" +#define DRIVER_DATE "20160606" #undef WARN_ON /* Many gcc seem to no see through this and fall over :( */ -- cgit v0.10.2